proc-service.h 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803
  1. #include <vector>
  2. #include <string>
  3. #include <list>
  4. #include <sys/types.h>
  5. #include <sys/resource.h>
  6. #include <baseproc-sys.h>
  7. #include <service.h>
  8. #include <dinit-utmp.h>
  9. // This header defines base_proc_service (base process service) and several derivatives, as well as some
  10. // utility functions and classes. See service.h for full details of services.
  11. class process_service;
  12. // Given a string and a list of pairs of (start,end) indices for each argument in that string,
  13. // store a null terminator for the argument. Return a `char *` vector containing the beginning
  14. // of each argument and a trailing nullptr. (The returned array is invalidated if the string is later
  15. // modified).
  16. std::vector<const char *> separate_args(ha_string &s,
  17. const std::list<std::pair<unsigned,unsigned>> &arg_indices);
  18. // Parameters for process execution
  19. struct run_proc_params
  20. {
  21. const char * const *args; // program arguments including executable (args[0])
  22. const char *working_dir; // working directory
  23. const char *logfile; // log file or nullptr (stdout/stderr); must be valid if !on_console
  24. const char *env_file; // file with environment settings (or nullptr)
  25. #if SUPPORT_CGROUPS
  26. const char *run_in_cgroup = nullptr; // cgroup path
  27. #endif
  28. bool on_console; // whether to run on console
  29. bool in_foreground; // if on console: whether to run in foreground
  30. bool unmask_sigint = false; // if in foreground: whether to unmask SIGINT
  31. int wpipefd; // pipe to which error status will be sent (if error occurs)
  32. int csfd; // control socket fd (or -1); may be moved
  33. int socket_fd; // pre-opened socket fd (or -1); may be moved
  34. int notify_fd; // pipe for readiness notification message (or -1); may be moved
  35. int force_notify_fd; // if not -1, notification fd must be moved to this fd
  36. int output_fd; // if not -1, output will be directed here (rather than logfile)
  37. const char *notify_var; // environment variable name where notification fd will be stored, or nullptr
  38. uid_t uid;
  39. gid_t gid;
  40. const std::vector<service_rlimits> &rlimits;
  41. int input_fd = -1; // file descriptor to be used for input (STDIN)
  42. run_proc_params(const char * const *args, const char *working_dir, const char *logfile, int wpipefd,
  43. uid_t uid, gid_t gid, const std::vector<service_rlimits> &rlimits)
  44. : args(args), working_dir(working_dir), logfile(logfile), env_file(nullptr), on_console(false),
  45. in_foreground(false), wpipefd(wpipefd), csfd(-1), socket_fd(-1), notify_fd(-1),
  46. force_notify_fd(-1), output_fd(-1), notify_var(nullptr), uid(uid), gid(gid), rlimits(rlimits)
  47. { }
  48. };
  49. // Error information from process execution transferred via this struct
  50. struct run_proc_err
  51. {
  52. exec_stage stage;
  53. int st_errno;
  54. };
  55. class base_process_service;
  56. // A timer for process restarting. Used to ensure a minimum delay between process restarts (and
  57. // also for timing service stop before the SIGKILL hammer is used).
  58. class process_restart_timer : public eventloop_t::timer_impl<process_restart_timer>
  59. {
  60. public:
  61. base_process_service *service;
  62. explicit process_restart_timer(base_process_service *service_p)
  63. : service(service_p)
  64. {
  65. }
  66. dasynq::rearm timer_expiry(eventloop_t &, int expiry_count);
  67. };
  68. // Watcher for the pipe used to receive exec() failure status errno
  69. class exec_status_pipe_watcher : public eventloop_t::fd_watcher_impl<exec_status_pipe_watcher>
  70. {
  71. public:
  72. base_process_service *service;
  73. dasynq::rearm fd_event(eventloop_t &eloop, int fd, int flags) noexcept;
  74. exec_status_pipe_watcher(base_process_service * sr) noexcept : service(sr) { }
  75. exec_status_pipe_watcher(const exec_status_pipe_watcher &) = delete;
  76. void operator=(const exec_status_pipe_watcher &) = delete;
  77. };
  78. // Like exec_status_pipe_watcher, but for watching status when exec'ing the stop command
  79. class stop_status_pipe_watcher : public eventloop_t::fd_watcher_impl<stop_status_pipe_watcher>
  80. {
  81. public:
  82. process_service *service;
  83. dasynq::rearm fd_event(eventloop_t &eloop, int fd, int flags) noexcept;
  84. stop_status_pipe_watcher(process_service * sr) noexcept : service(sr) { }
  85. stop_status_pipe_watcher(const exec_status_pipe_watcher &) = delete;
  86. void operator=(const exec_status_pipe_watcher &) = delete;
  87. };
  88. // Watcher for readiness notification pipe
  89. class ready_notify_watcher : public eventloop_t::fd_watcher_impl<ready_notify_watcher>
  90. {
  91. public:
  92. base_process_service *service;
  93. dasynq::rearm fd_event(eventloop_t &eloop, int fd, int flags) noexcept;
  94. ready_notify_watcher(base_process_service * sr) noexcept : service(sr) { }
  95. ready_notify_watcher(const ready_notify_watcher &) = delete;
  96. void operator=(const ready_notify_watcher &) = delete;
  97. };
  98. // watcher for main child process
  99. class service_child_watcher : public eventloop_t::child_proc_watcher_impl<service_child_watcher>
  100. {
  101. public:
  102. base_process_service *service;
  103. dasynq::rearm status_change(eventloop_t &eloop, pid_t child, int status) noexcept;
  104. service_child_watcher(base_process_service * sr) noexcept : service(sr) { }
  105. service_child_watcher(const service_child_watcher &) = delete;
  106. void operator=(const service_child_watcher &) = delete;
  107. };
  108. // watcher for the "stop-command" for process services
  109. class stop_child_watcher : public eventloop_t::child_proc_watcher_impl<stop_child_watcher>
  110. {
  111. public:
  112. process_service *service;
  113. dasynq::rearm status_change(eventloop_t &eloop, pid_t child, int status) noexcept;
  114. stop_child_watcher(process_service * sr) noexcept : service(sr) { }
  115. stop_child_watcher(const service_child_watcher &) = delete;
  116. void operator=(const service_child_watcher &) = delete;
  117. };
  118. class log_output_watcher : public eventloop_t::fd_watcher_impl<log_output_watcher>
  119. {
  120. public:
  121. base_process_service *service;
  122. dasynq::rearm fd_event(eventloop_t &eloop, int fd, int flags) noexcept;
  123. log_output_watcher(base_process_service * sr) noexcept : service(sr) { }
  124. log_output_watcher(const ready_notify_watcher &) = delete;
  125. void operator=(const ready_notify_watcher &) = delete;
  126. };
  127. // Base class for process-based services.
  128. class base_process_service : public service_record
  129. {
  130. friend class service_child_watcher;
  131. friend class exec_status_pipe_watcher;
  132. friend class base_process_service_test;
  133. friend class ready_notify_watcher;
  134. friend class log_output_watcher;
  135. protected:
  136. ha_string program_name; // storage for program/script and arguments
  137. // pointer to each argument/part of the program_name, and nullptr:
  138. std::vector<const char *> exec_arg_parts;
  139. ha_string stop_command; // storage for stop program/script and arguments
  140. // pointer to each argument/part of the stop_command, and nullptr:
  141. std::vector<const char *> stop_arg_parts;
  142. string working_dir; // working directory (or empty)
  143. string env_file; // file with environment settings for this service
  144. log_type_id log_type = log_type_id::NONE;
  145. string logfile; // log file name, empty string specifies /dev/null
  146. int logfile_perms = 0; // logfile permissions("mode")
  147. uid_t logfile_uid = -1; // logfile owner user id
  148. gid_t logfile_gid = -1; // logfile group id
  149. unsigned log_buf_max = 0; // log buffer maximum size
  150. unsigned log_buf_size = 0; // log buffer current size
  151. std::vector<char, default_init_allocator<char>> log_buffer;
  152. std::vector<service_rlimits> rlimits; // resource limits
  153. #if SUPPORT_CGROUPS
  154. string run_in_cgroup;
  155. #endif
  156. service_child_watcher child_listener;
  157. exec_status_pipe_watcher child_status_listener;
  158. process_restart_timer process_timer; // timer is used for start, stop and restart
  159. log_output_watcher log_output_listener;
  160. time_val last_start_time;
  161. // Restart interval time and restart count are used to track the number of automatic restarts
  162. // over an interval. Too many restarts over an interval will inhibit further restarts.
  163. time_val restart_interval_time; // current restart interval
  164. int restart_interval_count; // count of restarts within current interval
  165. time_val restart_interval; // maximum restart interval
  166. int max_restart_interval_count; // number of restarts allowed over maximum interval
  167. time_val restart_delay; // delay between restarts
  168. // Time allowed for service stop, after which SIGKILL is sent. 0 to disable.
  169. time_val stop_timeout = {10, 0}; // default of 10 seconds
  170. // Time allowed for service start, after which SIGINT is sent (and then SIGKILL after
  171. // <stop_timeout>). 0 to disable.
  172. time_val start_timeout = {60, 0}; // default of 1 minute
  173. uid_t run_as_uid = -1;
  174. gid_t run_as_gid = -1;
  175. int force_notification_fd = -1; // if set, notification fd for service process is set to this fd
  176. string notification_var; // if set, name of an environment variable for notification fd
  177. pid_t pid = -1; // PID of the process. For a scripted service which is STARTING or STOPPING,
  178. // this is PID of the service script; otherwise it is the PID of the process
  179. // itself (process service).
  180. bp_sys::exit_status exit_status; // Exit status, if the process has exited (pid == -1).
  181. int socket_fd = -1; // For socket-activation services, this is the file descriptor for the socket.
  182. int notification_fd = -1; // If readiness notification is via fd
  183. int log_output_fd = -1; // If logging via buffer/pipe, write end of the pipe
  184. int log_input_fd = -1; // If logging via buffer/pipe, read end of the pipe
  185. // Only one of waiting_restart_timer and waiting_stopstart_timer should be set at any time.
  186. // They indicate that the process timer is armed (and why).
  187. bool waiting_restart_timer : 1;
  188. bool waiting_stopstart_timer : 1;
  189. bool reserved_child_watch : 1;
  190. bool tracking_child : 1; // whether we expect to see child process status
  191. // If executing child process failed, information about the error
  192. run_proc_err exec_err_info;
  193. private:
  194. // Re-launch process
  195. void do_restart() noexcept;
  196. protected:
  197. // Run a child process (call after forking). Note that some parameters specify file descriptors,
  198. // but in general file descriptors may be moved before the exec call.
  199. void run_child_proc(run_proc_params params) noexcept;
  200. // Launch the process with the given arguments, return true on success
  201. bool start_ps_process(const std::vector<const char *> &args, bool on_console) noexcept;
  202. // Restart the process (due to start failure or unexpected termination). Restarts will be
  203. // rate-limited.
  204. bool restart_ps_process() noexcept;
  205. // Perform smooth recovery process
  206. void do_smooth_recovery() noexcept;
  207. // Start the process, return true on success
  208. virtual bool bring_up() noexcept override;
  209. // Called after forking (before executing remote process).
  210. virtual void after_fork(pid_t child_pid) noexcept { }
  211. // Called when the process exits. The exit_status is the status value yielded by
  212. // the "wait" system call.
  213. virtual void handle_exit_status(bp_sys::exit_status exit_status) noexcept = 0;
  214. void handle_unexpected_termination() noexcept;
  215. // Called if an exec fails.
  216. virtual void exec_failed(run_proc_err errcode) noexcept = 0;
  217. // Called if exec succeeds.
  218. virtual void exec_succeeded() noexcept { }
  219. virtual bool can_interrupt_start() noexcept override
  220. {
  221. return waiting_restart_timer || onstart_flags.start_interruptible
  222. || service_record::can_interrupt_start();
  223. }
  224. virtual bool interrupt_start() noexcept override;
  225. void becoming_inactive() noexcept override;
  226. // Get the file descriptor which the process should read input from (STDIN).
  227. // Return false on failure. If input_fd returned is -1, process has no specific input.
  228. virtual bool get_input_fd(int *input_fd) noexcept { *input_fd = -1; return true; }
  229. // Kill with SIGKILL
  230. virtual void kill_with_fire() noexcept;
  231. // Signal the process group of the service process
  232. void kill_pg(int signo) noexcept;
  233. // Open the activation socket, return false on failure
  234. bool open_socket() noexcept;
  235. // Get the readiness notification watcher for this service, if it has one; may return nullptr.
  236. virtual ready_notify_watcher *get_ready_watcher() noexcept
  237. {
  238. return nullptr;
  239. }
  240. bool ensure_log_buffer_backing(unsigned size) noexcept;
  241. public:
  242. // Constructor for a base_process_service. Note that the various parameters not specified here must in
  243. // general be set separately (using the appropriate set_xxx function for each).
  244. base_process_service(service_set *sset, string name, service_type_t record_type_p, ha_string &&command,
  245. const std::list<std::pair<unsigned,unsigned>> &command_offsets,
  246. const std::list<prelim_dep> &deplist_p);
  247. ~base_process_service() noexcept
  248. {
  249. if (reserved_child_watch) {
  250. child_listener.unreserve(event_loop);
  251. }
  252. process_timer.deregister(event_loop);
  253. set_log_mode(log_type_id::NONE);
  254. }
  255. // Set the command to run this service (executable and arguments, nul separated). The command_parts_p
  256. // vector must contain pointers to each part.
  257. void set_command(ha_string &&command_p, std::vector<const char *> &&command_parts_p) noexcept
  258. {
  259. program_name = std::move(command_p);
  260. exec_arg_parts = std::move(command_parts_p);
  261. }
  262. void get_command(ha_string &command_p, std::vector<const char *> &command_parts_p)
  263. {
  264. command_p = program_name;
  265. command_parts_p = exec_arg_parts;
  266. }
  267. // Set the stop command and arguments (may throw std::bad_alloc)
  268. void set_stop_command(ha_string &command,
  269. std::list<std::pair<unsigned,unsigned>> &stop_command_offsets)
  270. {
  271. stop_command = command;
  272. stop_arg_parts = separate_args(stop_command, stop_command_offsets);
  273. }
  274. // Set the stop command as a sequence of nul-terminated parts (arguments).
  275. // command - the command and arguments, each terminated with nul ('\0')
  276. // command_parts - pointers to the beginning of each command part
  277. void set_stop_command(ha_string &&command,
  278. std::vector<const char *> &&command_parts) noexcept
  279. {
  280. stop_command = std::move(command);
  281. stop_arg_parts = std::move(command_parts);
  282. }
  283. void set_logfile_details(string &&logfile, int logfile_perms, uid_t logfile_uid, gid_t logfile_gid)
  284. noexcept
  285. {
  286. this->logfile = std::move(logfile);
  287. this->logfile_perms = logfile_perms;
  288. this->logfile_uid = logfile_uid;
  289. this->logfile_gid = logfile_gid;
  290. }
  291. // Set log buffer maximum size (for if mode is BUFFER). Maximum allowed size is UINT_MAX / 2
  292. // (must be checked by caller).
  293. void set_log_buf_max(unsigned max_size) noexcept
  294. {
  295. this->log_buf_max = max_size;
  296. }
  297. // Set log mode (NONE, BUFFER, FILE, PIPE) (must not change mode when service is not STOPPED).
  298. void set_log_mode(log_type_id log_type) noexcept
  299. {
  300. if (this->log_type == log_type) {
  301. return;
  302. }
  303. if (log_output_fd != -1) {
  304. if (this->log_type == log_type_id::BUFFER) {
  305. log_output_listener.deregister(event_loop);
  306. }
  307. if (!value(log_type).is_in(log_type_id::BUFFER, log_type_id::PIPE)) {
  308. bp_sys::close(log_output_fd);
  309. bp_sys::close(log_input_fd);
  310. log_output_fd = log_input_fd = -1;
  311. }
  312. }
  313. this->log_type = log_type;
  314. }
  315. log_type_id get_log_mode() noexcept
  316. {
  317. return this->log_type;
  318. }
  319. // Set the output pipe descriptors (both read and write end). This is only valid to call for
  320. // log mode PIPE and only when the service has just been loaded. It is intended for transfer
  321. // of fds from a placeholder service.
  322. void set_output_pipe_fds(std::pair<int,int> fds)
  323. {
  324. log_input_fd = fds.first;
  325. log_output_fd = fds.second;
  326. }
  327. std::pair<int,int> transfer_output_pipe() noexcept override
  328. {
  329. std::pair<int,int> r { log_input_fd, log_output_fd };
  330. if (log_type == log_type_id::BUFFER && log_output_fd != -1) {
  331. log_output_listener.deregister(event_loop);
  332. }
  333. log_input_fd = log_output_fd = -1;
  334. return r;
  335. }
  336. int get_output_pipe_fd() noexcept override
  337. {
  338. if (log_input_fd != -1) {
  339. return log_input_fd;
  340. }
  341. int pipefds[2];
  342. if (bp_sys::pipe2(pipefds, O_CLOEXEC) == -1) {
  343. log(loglevel_t::ERROR, get_name(), ": Can't open output pipe: ", std::strerror(errno));
  344. return -1;
  345. }
  346. log_input_fd = pipefds[0];
  347. log_output_fd = pipefds[1];
  348. return log_input_fd;
  349. }
  350. // Get the log buffer (address, length)
  351. std::pair<const char *, unsigned> get_log_buffer() noexcept
  352. {
  353. return {log_buffer.data(), log_buf_size};
  354. }
  355. void clear_log_buffer() noexcept
  356. {
  357. log_buffer.clear();
  358. log_buffer.shrink_to_fit();
  359. log_buf_size = 0;
  360. }
  361. void set_env_file(const std::string &env_file_p)
  362. {
  363. env_file = env_file_p;
  364. }
  365. void set_env_file(std::string &&env_file_p) noexcept
  366. {
  367. env_file = std::move(env_file_p);
  368. }
  369. #if SUPPORT_CGROUPS
  370. void set_cgroup(std::string &&run_in_cgroup_p) noexcept
  371. {
  372. run_in_cgroup = std::move(run_in_cgroup_p);
  373. }
  374. #endif
  375. void set_rlimits(std::vector<service_rlimits> &&rlimits_p)
  376. {
  377. rlimits = std::move(rlimits_p);
  378. }
  379. void set_restart_interval(timespec interval, int max_restarts) noexcept
  380. {
  381. restart_interval = interval;
  382. max_restart_interval_count = max_restarts;
  383. }
  384. void set_restart_delay(timespec delay) noexcept
  385. {
  386. restart_delay = delay;
  387. }
  388. void set_stop_timeout(timespec timeout) noexcept
  389. {
  390. stop_timeout = timeout;
  391. }
  392. void set_start_timeout(timespec timeout) noexcept
  393. {
  394. start_timeout = timeout;
  395. }
  396. // Set an additional signal (other than SIGTERM) to be used to terminate the process
  397. void set_extra_termination_signal(int signo) noexcept
  398. {
  399. this->term_signal = signo;
  400. }
  401. // Set the uid/gid that the service process will be run as
  402. void set_run_as_uid_gid(uid_t uid, gid_t gid) noexcept
  403. {
  404. run_as_uid = uid;
  405. run_as_gid = gid;
  406. }
  407. // Set the working directory
  408. // Note: constructing parameter may throw!
  409. void set_working_dir(string working_dir_p) noexcept
  410. {
  411. working_dir = std::move(working_dir_p);
  412. }
  413. // Set the notification fd number that the service process will use
  414. void set_notification_fd(int fd)
  415. {
  416. force_notification_fd = fd;
  417. }
  418. // Set the name of the environment variable that will be set to the notification fd number
  419. // when the service process is run
  420. void set_notification_var(string &&varname)
  421. {
  422. notification_var = std::move(varname);
  423. }
  424. // The restart/stop timer expired.
  425. void timer_expired() noexcept;
  426. // Accessor for testing:
  427. const std::vector<const char *> & get_exec_arg_parts() noexcept
  428. {
  429. return exec_arg_parts;
  430. }
  431. pid_t get_pid() noexcept override
  432. {
  433. return pid;
  434. }
  435. int get_exit_status() noexcept override
  436. {
  437. return exit_status.as_int();
  438. }
  439. // Get reason for failure to exec process (if stop reason indicates exec failure)
  440. run_proc_err get_exec_err_info()
  441. {
  442. return exec_err_info;
  443. }
  444. };
  445. // Standard process service.
  446. class process_service : public base_process_service
  447. {
  448. friend class stop_child_watcher;
  449. friend class stop_status_pipe_watcher;
  450. friend class base_process_service_test;
  451. protected:
  452. virtual void handle_exit_status(bp_sys::exit_status exit_status) noexcept override;
  453. virtual void exec_failed(run_proc_err errcode) noexcept override;
  454. virtual void exec_succeeded() noexcept override;
  455. virtual void bring_down() noexcept override;
  456. virtual void kill_with_fire() noexcept override;
  457. bool start_stop_process(const std::vector<const char *> &cmd) noexcept;
  458. bool reserved_stop_watch : 1;
  459. bool stop_issued : 1;
  460. pid_t stop_pid = -1;
  461. bp_sys::exit_status stop_status = {};
  462. ready_notify_watcher readiness_watcher;
  463. stop_child_watcher stop_watcher;
  464. stop_status_pipe_watcher stop_pipe_watcher;
  465. bool doing_smooth_recovery = false; // if we are performing smooth recovery
  466. service_record *consumer_for = nullptr;
  467. #if USE_UTMPX
  468. private:
  469. char inittab_id[sizeof(utmpx().ut_id)];
  470. char inittab_line[sizeof(utmpx().ut_line)];
  471. protected:
  472. void after_fork(pid_t child_pid) noexcept override
  473. {
  474. if (*inittab_id || *inittab_line) {
  475. create_utmp_entry(inittab_id, inittab_line, child_pid);
  476. }
  477. }
  478. #endif
  479. protected:
  480. ready_notify_watcher *get_ready_watcher() noexcept override
  481. {
  482. return &readiness_watcher;
  483. }
  484. void handle_stop_exit() noexcept
  485. {
  486. if (!stop_status.did_exit_clean()) {
  487. if (stop_status.did_exit()) {
  488. log(loglevel_t::ERROR, "Service ", get_name(), " stop command terminated with exit code ",
  489. stop_status.get_exit_status());
  490. }
  491. else if (stop_status.was_signalled()) {
  492. log(loglevel_t::ERROR, "Service ", get_name(), " stop command terminated due to signal ",
  493. stop_status.get_term_sig());
  494. }
  495. }
  496. if (pid == -1 || !tracking_child) {
  497. // If service process has already finished, we were just waiting for the stop command
  498. // process:
  499. stop_issued = false; // reset for next time
  500. stopped();
  501. }
  502. }
  503. virtual bool check_restart() noexcept override
  504. {
  505. if (max_restart_interval_count != 0) {
  506. // Check whether we're still in the most recent restart check interval:
  507. time_val current_time;
  508. event_loop.get_time(current_time, clock_type::MONOTONIC);
  509. time_val int_diff = current_time - restart_interval_time;
  510. if (int_diff < restart_interval) {
  511. // Within the restart limiting interval; check number of restarts
  512. if (restart_interval_count >= max_restart_interval_count) {
  513. log(loglevel_t::ERROR, "Service ", get_name(), " restarting too quickly; stopping.");
  514. set_target_state(service_state_t::STOPPED);
  515. return false;
  516. }
  517. ++restart_interval_count;
  518. }
  519. else {
  520. // Not within the last limiting interval; start a new interval
  521. restart_interval_time = current_time;
  522. restart_interval_count = 1;
  523. }
  524. }
  525. return true;
  526. }
  527. bool get_input_fd(int *input_fd) noexcept override
  528. {
  529. if (consumer_for == nullptr) {
  530. *input_fd = -1;
  531. return true;
  532. }
  533. int cfd = consumer_for->get_output_pipe_fd();
  534. if (cfd == -1) return false;
  535. *input_fd = cfd;
  536. return true;
  537. }
  538. process_service(service_set *sset, const string &name, service_type_t s_type, ha_string &&command,
  539. std::list<std::pair<unsigned,unsigned>> &command_offsets,
  540. const std::list<prelim_dep> &depends_p)
  541. : base_process_service(sset, name, s_type, std::move(command), command_offsets,
  542. depends_p), reserved_stop_watch(false), stop_issued(false),
  543. readiness_watcher(this), stop_watcher(this), stop_pipe_watcher(this)
  544. {
  545. }
  546. public:
  547. process_service(service_set *sset, const string &name, ha_string &&command,
  548. std::list<std::pair<unsigned,unsigned>> &command_offsets,
  549. const std::list<prelim_dep> &depends_p)
  550. : base_process_service(sset, name, service_type_t::PROCESS, std::move(command), command_offsets,
  551. depends_p), reserved_stop_watch(false), stop_issued(false),
  552. readiness_watcher(this), stop_watcher(this), stop_pipe_watcher(this)
  553. {
  554. }
  555. #if USE_UTMPX
  556. // Set the id of the process in utmp (the "inittab" id)
  557. void set_utmp_id(const char *id) noexcept
  558. {
  559. strncpy(inittab_id, id, sizeof(inittab_id));
  560. }
  561. // Set the device line of the process in utmp database
  562. void set_utmp_line(const char *line) noexcept
  563. {
  564. strncpy(inittab_line, line, sizeof(inittab_line));
  565. }
  566. // Get the utmp (inittab) id, may not be nul terminated if maximum length!
  567. const char *get_utmp_id() noexcept
  568. {
  569. return inittab_id;
  570. }
  571. // Get the utmp (inittab) line, may not be nul terminated if maximum length!
  572. const char *get_utmp_line() noexcept
  573. {
  574. return inittab_line;
  575. }
  576. constexpr size_t get_utmp_id_size() const noexcept { return sizeof(inittab_id); }
  577. constexpr size_t get_utmp_line_size() const noexcept { return sizeof(inittab_line); }
  578. #endif
  579. // Set this service to consume output of specified service (only call while service stopped).
  580. void set_consumer_for(service_record *consumed) noexcept
  581. {
  582. consumer_for = consumed;
  583. }
  584. service_record *get_consumed() noexcept
  585. {
  586. return consumer_for;
  587. }
  588. ~process_service() noexcept
  589. {
  590. if (reserved_stop_watch) {
  591. stop_watcher.unreserve(event_loop);
  592. }
  593. if (consumer_for != nullptr) {
  594. consumer_for->set_log_consumer(nullptr);
  595. }
  596. }
  597. };
  598. // Bgproc (self-"backgrounding", i.e. double-forking) process service
  599. class bgproc_service : public process_service
  600. {
  601. virtual void handle_exit_status(bp_sys::exit_status exit_status) noexcept override;
  602. virtual void exec_failed(run_proc_err errcode) noexcept override;
  603. enum class pid_result_t {
  604. OK,
  605. FAILED, // failed to read pid or read invalid pid
  606. TERMINATED // read pid successfully, but the process already terminated
  607. };
  608. string pid_file;
  609. // Read the pid-file contents
  610. pid_result_t read_pid_file(bp_sys::exit_status *exit_status) noexcept;
  611. public:
  612. bgproc_service(service_set *sset, const string &name, ha_string &&command,
  613. std::list<std::pair<unsigned,unsigned>> &command_offsets,
  614. const std::list<prelim_dep> &depends_p)
  615. : process_service(sset, name, service_type_t::BGPROCESS, std::move(command), command_offsets,
  616. depends_p)
  617. {
  618. }
  619. ~bgproc_service() noexcept
  620. {
  621. }
  622. void set_pid_file(string &&pid_file) noexcept
  623. {
  624. this->pid_file = std::move(pid_file);
  625. }
  626. const std::string &get_pid_file() noexcept
  627. {
  628. return pid_file;
  629. }
  630. };
  631. // Service which is started and stopped via separate commands
  632. class scripted_service : public base_process_service
  633. {
  634. virtual void handle_exit_status(bp_sys::exit_status exit_status) noexcept override;
  635. virtual void exec_succeeded() noexcept override;
  636. virtual void exec_failed(run_proc_err errcode) noexcept override;
  637. virtual void bring_down() noexcept override;
  638. virtual bool interrupt_start() noexcept override
  639. {
  640. // if base::interrupt_start() returns false, then start hasn't been fully interrupted, but an
  641. // interrupt has been issued:
  642. interrupting_start = ! base_process_service::interrupt_start();
  643. return ! interrupting_start;
  644. }
  645. bool interrupting_start : 1; // running start script (true) or stop script (false)
  646. public:
  647. scripted_service(service_set *sset, const string &name, ha_string &&command,
  648. std::list<std::pair<unsigned,unsigned>> &command_offsets,
  649. const std::list<prelim_dep> &depends_p)
  650. : base_process_service(sset, name, service_type_t::SCRIPTED, std::move(command), command_offsets,
  651. depends_p), interrupting_start(false)
  652. {
  653. }
  654. ~scripted_service() noexcept
  655. {
  656. }
  657. };