Lely core libraries  2.2.5
daemon.c
Go to the documentation of this file.
1 
24 #include "util.h"
25 
26 #ifndef LELY_NO_DAEMON
27 
28 #ifndef LELY_NO_THREADS
29 #include <lely/libc/threads.h>
30 #endif
31 #include <lely/util/daemon.h>
32 #include <lely/util/diag.h>
33 
34 #include <assert.h>
35 #include <signal.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 
39 #ifndef LELY_DAEMON_TIMEOUT
40 #define LELY_DAEMON_TIMEOUT 1000
41 #endif
42 
43 static daemon_handler_t *daemon_handler = &default_daemon_handler;
44 static void *daemon_handle;
45 
46 #ifdef _WIN32
47 
48 #include <winerror.h>
49 
50 static void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv);
51 static void WINAPI Handler(DWORD fdwControl);
52 static int ReportStatus(DWORD dwCurrentState);
53 
54 static const char *daemon_name;
55 static int (*daemon_init)(int, char **);
56 static void (*daemon_main)(void);
57 static void (*daemon_fini)(void);
58 
59 static SERVICE_STATUS_HANDLE hServiceStatus;
60 
61 static SERVICE_STATUS ServiceStatus = {
62  .dwServiceType = SERVICE_WIN32_OWN_PROCESS,
63  .dwControlsAccepted = SERVICE_ACCEPT_STOP
64  | SERVICE_ACCEPT_PAUSE_CONTINUE
65  | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PARAMCHANGE,
66  .dwWin32ExitCode = NO_ERROR,
67  .dwWaitHint = 2 * LELY_DAEMON_TIMEOUT
68 };
69 
70 int
71 daemon_start(const char *name, int (*init)(int, char **), void (*main)(void),
72  void (*fini)(void), int argc, char *argv[])
73 {
74  (void)argc;
75  (void)argv;
76 
77  daemon_name = name;
78  daemon_init = init;
79  daemon_main = main;
80  daemon_fini = fini;
81 
82  SERVICE_TABLE_ENTRYA ServiceTable[] = {
83  { (LPSTR)daemon_name, &ServiceMain }, { NULL, NULL }
84  };
85  return StartServiceCtrlDispatcherA(ServiceTable) ? 0 : -1;
86 }
87 
88 int
89 daemon_signal(int sig)
90 {
91  if (sig < 0 || sig > DAEMON_USER_MAX) {
92  SetLastError(ERROR_INVALID_PARAMETER);
93  return -1;
94  }
95 
96  if (daemon_handler)
97  daemon_handler(sig, daemon_handle);
98 
99  return 0;
100 }
101 
102 int
103 daemon_status(int status)
104 {
105  DWORD dwCurrentState = 0;
106  switch (status) {
107  case DAEMON_START:
108  case DAEMON_CONTINUE: dwCurrentState = SERVICE_RUNNING; break;
109  case DAEMON_STOP: dwCurrentState = SERVICE_STOPPED; break;
110  case DAEMON_PAUSE: dwCurrentState = SERVICE_PAUSED; break;
111  case DAEMON_RELOAD: break;
112  default: SetLastError(ERROR_INVALID_PARAMETER); return -1;
113  }
114 
115  return ReportStatus(dwCurrentState);
116 }
117 
118 static void WINAPI
119 ServiceMain(DWORD dwArgc, LPSTR *lpszArgv)
120 {
121  assert(lpszArgv);
122 
123  hServiceStatus = RegisterServiceCtrlHandlerA(daemon_name, Handler);
124  if (!hServiceStatus)
125  goto error_RegisterServiceCtrlHandlerA;
126  ReportStatus(SERVICE_START_PENDING);
127 
128  diag_handler_t *diag_handler;
129  void *diag_handle;
130  diag_get_handler(&diag_handler, &diag_handle);
131  diag_set_handler(&daemon_diag_handler, (void *)daemon_name);
132 
133  diag_at_handler_t *diag_at_handler;
134  void *diag_at_handle;
135  diag_at_get_handler(&diag_at_handler, &diag_at_handle);
136  diag_at_set_handler(&daemon_diag_at_handler, (void *)daemon_name);
137 
138  if (daemon_init) {
139  // Make sure the argument list is NULL-terminated.
140  char **argv = malloc((dwArgc + 1) * sizeof(char *));
141  if (!argv)
142  goto error_init;
143  for (DWORD i = 0; i < dwArgc; i++)
144  argv[i] = lpszArgv[i];
145  argv[dwArgc] = NULL;
146  if (daemon_init(dwArgc, argv)) {
147  free(argv);
148  goto error_init;
149  }
150  free(argv);
151  }
152 
153  ReportStatus(SERVICE_RUNNING);
154 
155  assert(daemon_main);
156  daemon_main();
157 
158  if (daemon_fini)
159  daemon_fini();
160 
161  diag_at_set_handler(diag_at_handler, diag_at_handle);
162  diag_set_handler(diag_handler, diag_handle);
163 
164 error_init:
165  ReportStatus(SERVICE_STOPPED);
166 error_RegisterServiceCtrlHandlerA:
167  daemon_fini = NULL;
168  daemon_main = NULL;
169  daemon_init = NULL;
170  daemon_name = NULL;
171 }
172 
173 static void WINAPI
174 Handler(DWORD fdwControl)
175 {
176  int sig = -1;
177  switch (fdwControl) {
178  case SERVICE_CONTROL_STOP:
179  case SERVICE_CONTROL_SHUTDOWN:
180  ReportStatus(SERVICE_STOP_PENDING);
181  sig = DAEMON_STOP;
182  break;
183  case SERVICE_CONTROL_PAUSE:
184  ReportStatus(SERVICE_PAUSE_PENDING);
185  sig = DAEMON_PAUSE;
186  break;
187  case SERVICE_CONTROL_CONTINUE:
188  ReportStatus(SERVICE_CONTINUE_PENDING);
189  sig = DAEMON_CONTINUE;
190  break;
191  case SERVICE_CONTROL_PARAMCHANGE: sig = DAEMON_RELOAD; break;
192  default:
193  if (fdwControl >= 128 && fdwControl <= 255)
194  sig = DAEMON_USER_MIN + (fdwControl - 128);
195  break;
196  };
197 
198  if (sig != -1)
199  daemon_signal(sig);
200 
201  ReportStatus(0);
202 }
203 
204 static int
205 ReportStatus(DWORD dwCurrentState)
206 {
207  static DWORD dwCheckPoint;
208  if (dwCurrentState)
209  ServiceStatus.dwCurrentState = dwCurrentState;
210  switch (ServiceStatus.dwCurrentState) {
211  case SERVICE_START_PENDING:
212  case SERVICE_STOP_PENDING:
213  case SERVICE_PAUSE_PENDING:
214  case SERVICE_CONTINUE_PENDING:
215  ServiceStatus.dwCheckPoint = ++dwCheckPoint;
216  break;
217  case SERVICE_STOPPED:
218  case SERVICE_RUNNING:
219  case SERVICE_PAUSED: ServiceStatus.dwCheckPoint = 0; break;
220  default: break;
221  }
222 
223  return SetServiceStatus(hServiceStatus, &ServiceStatus) ? 0 : -1;
224 }
225 
226 #elif _POSIX_C_SOURCE >= 200112L
227 
228 #include <fcntl.h>
229 #include <poll.h>
230 #include <sys/stat.h>
231 #include <unistd.h>
232 
233 static int daemon_proc(void);
234 static void daemon_signal_func(int sig);
235 #ifndef LELY_NO_THREADS
236 static int daemon_thrd_start(void *arg);
237 #endif
238 
239 static int daemon_pipe[2] = { -1, -1 };
240 
241 int
242 daemon_start(const char *name, int (*init)(int, char **), void (*main)(void),
243  void (*fini)(void), int argc, char *argv[])
244 {
245  assert(main);
246  assert(argc >= 0);
247  assert(argv);
248 
249  int result = 0;
250  int errsv = errno;
251 
252  if (init && init(argc, argv)) {
253  result = -1;
254  errsv = errno;
255  goto error_init;
256  }
257 
258  if (daemon_proc() == -1) {
259  result = -1;
260  errsv = errno;
261  goto error_proc;
262  }
263 
264  // Create a non-blocking self-pipe.
265 #if (defined(__CYGWIN__) || defined(__linux__)) && defined(_GNU_SOURCE)
266  result = pipe2(daemon_pipe, O_NONBLOCK | O_CLOEXEC);
267  if (result == -1) {
268  result = -1;
269  errsv = errno;
270  goto error_pipe;
271  }
272 #else
273  result = pipe(daemon_pipe);
274  if (result == -1) {
275  result = -1;
276  errsv = errno;
277  goto error_pipe;
278  }
279  if (fcntl(daemon_pipe[0], F_SETFD, FD_CLOEXEC) == -1) {
280  result = -1;
281  errsv = errno;
282  goto error_fcntl;
283  }
284  if (fcntl(daemon_pipe[1], F_SETFD, FD_CLOEXEC) == -1) {
285  result = -1;
286  errsv = errno;
287  goto error_fcntl;
288  }
289  int flags;
290  if ((flags = fcntl(daemon_pipe[0], F_GETFL, 0)) == -1) {
291  result = -1;
292  errsv = errno;
293  goto error_fcntl;
294  }
295  if (fcntl(daemon_pipe[0], F_SETFL, flags | O_NONBLOCK) == -1) {
296  result = -1;
297  errsv = errno;
298  goto error_fcntl;
299  }
300  if ((flags = fcntl(daemon_pipe[1], F_GETFL, 0)) == -1) {
301  result = -1;
302  errsv = errno;
303  goto error_fcntl;
304  }
305  if (fcntl(daemon_pipe[1], F_SETFL, flags | O_NONBLOCK) == -1) {
306  result = -1;
307  errsv = errno;
308  goto error_fcntl;
309  }
310 #endif
311 
312  // SIGHUP is interpreted as DAEMON_RELOAD.
313  struct sigaction new_hup, old_hup;
314  new_hup.sa_handler = &daemon_signal_func;
315  sigemptyset(&new_hup.sa_mask);
316  new_hup.sa_flags = 0;
317  if (sigaction(SIGHUP, &new_hup, &old_hup) == -1) {
318  result = -1;
319  errsv = errno;
320  goto error_sighup;
321  }
322 
323  // SIGTERM is interpreted as DAEMON_STOP.
324  struct sigaction new_term, old_term;
325  new_term.sa_handler = &daemon_signal_func;
326  sigemptyset(&new_term.sa_mask);
327  new_term.sa_flags = 0;
328  if (sigaction(SIGTERM, &new_term, &old_term) == -1) {
329  result = -1;
330  errsv = errno;
331  goto error_sigterm;
332  }
333 
334 #ifndef LELY_NO_THREADS
335  thrd_t thr;
336  if (thrd_create(&thr, &daemon_thrd_start, NULL) != thrd_success) {
337  result = -1;
338  goto error_thrd_create;
339  }
340 #endif
341 
342  diag_handler_t *diag_handler;
343  void *diag_handle;
344  diag_get_handler(&diag_handler, &diag_handle);
345  diag_set_handler(&daemon_diag_handler, (void *)name);
346 
347  diag_at_handler_t *diag_at_handler;
348  void *diag_at_handle;
349  diag_at_get_handler(&diag_at_handler, &diag_at_handle);
351 
352  main();
353 
354  daemon_stop();
355 #ifndef LELY_NO_THREADS
356  thrd_join(thr, NULL);
357 #endif
358 
359  diag_at_set_handler(diag_at_handler, diag_at_handle);
360  diag_set_handler(diag_handler, diag_handle);
361 
362 #ifndef LELY_NO_THREADS
363 error_thrd_create:
364 #endif
365  sigaction(SIGTERM, &old_term, NULL);
366 error_sigterm:
367  sigaction(SIGHUP, &old_hup, NULL);
368 error_sighup:
369 #if !defined(__CYGWIN__) && !defined(__linux__)
370 error_fcntl:
371 #endif
372  close(daemon_pipe[1]);
373  daemon_pipe[1] = -1;
374  close(daemon_pipe[0]);
375  daemon_pipe[0] = -1;
376 error_pipe:
377 error_proc:
378  if (fini)
379  fini();
380 error_init:
381  errno = errsv;
382  return result;
383 }
384 
385 int
387 {
388  if (sig < 0 || sig > DAEMON_USER_MAX) {
389  errno = EINVAL;
390  return -1;
391  }
392 
393  int result;
394  do
395  result = write(daemon_pipe[1], &(unsigned char){ sig }, 1);
396  while (result == -1 && errno == EINTR);
397  return result;
398 }
399 
400 int
401 daemon_status(int status)
402 {
403  if (status < 0 || status >= DAEMON_USER_MIN) {
404  errno = EINVAL;
405  return -1;
406  }
407 
408  return 0;
409 }
410 
411 static int
412 daemon_proc(void)
413 {
414  // Fork and exit the parent process to make the orphaned child a child
415  // process of init.
416  switch (fork()) {
417  case 0: break;
418  case -1: return -1;
419  default: _Exit(EXIT_SUCCESS);
420  }
421 
422  // Change working directory to a known path.
423  if (chdir("/") == -1)
424  return -1;
425 
426  // Prevent insecure file privileges.
427  umask(0);
428 
429  // Detach the child process from the parent's tty.
430  if (setsid() == -1)
431  return -1;
432 
433  // Because of the call to setsid(), we are now session leader, which
434  // means we can acquire another controlling tty. Prevent this by forking
435  // again.
436  switch (fork()) {
437  case 0: break;
438  case -1: return -1;
439  default: _Exit(EXIT_SUCCESS);
440  }
441 
442  // Ignore terminal signals we shouldn't be receiving anyway.
443  struct sigaction act;
444  act.sa_handler = SIG_IGN;
445  sigemptyset(&act.sa_mask);
446  act.sa_flags = 0;
447  sigaction(SIGTSTP, &act, NULL);
448  sigaction(SIGTTIN, &act, NULL);
449  sigaction(SIGTTOU, &act, NULL);
450 
451  // Redirect the standard streams to /dev/null. Since the link between
452  // file descriptors and streams is implementation-defined, we close and
453  // open both, to be on the safe side.
454 
455  fsync(STDIN_FILENO);
456  fclose(stdin);
457  close(STDIN_FILENO);
458 #if defined(__CYGWIN__) || defined(__linux__)
459  // cppcheck-suppress leakReturnValNotUsed
460  if (open("/dev/null", O_RDONLY | O_CLOEXEC) != STDIN_FILENO)
461  return -1;
462 #else
463  // cppcheck-suppress leakReturnValNotUsed
464  if (open("/dev/null", O_RDONLY) != STDIN_FILENO)
465  return -1;
466  if (fcntl(STDIN_FILENO, F_SETFD, FD_CLOEXEC) == -1)
467  return -1;
468 #endif
469  stdin = fdopen(STDIN_FILENO, "r");
470  if (!stdin)
471  return -1;
472 
473  fflush(stdout);
474  fsync(STDOUT_FILENO);
475  fclose(stdout);
476  close(STDOUT_FILENO);
477 #if defined(__CYGWIN__) || defined(__linux__)
478  // cppcheck-suppress leakReturnValNotUsed
479  if (open("/dev/null", O_WRONLY | O_CLOEXEC) != STDOUT_FILENO)
480  return -1;
481 #else
482  // cppcheck-suppress leakReturnValNotUsed
483  if (open("/dev/null", O_WRONLY) != STDOUT_FILENO)
484  return -1;
485  if (fcntl(STDOUT_FILENO, F_SETFD, FD_CLOEXEC) == -1)
486  return -1;
487 #endif
488  stdout = fdopen(STDOUT_FILENO, "w");
489  if (!stdout)
490  return -1;
491 
492  fflush(stderr);
493  fsync(STDERR_FILENO);
494  fclose(stderr);
495  close(STDERR_FILENO);
496 #if defined(__CYGWIN__) || defined(__linux__)
497  // cppcheck-suppress leakReturnValNotUsed
498  if (open("/dev/null", O_RDWR | O_CLOEXEC) != STDERR_FILENO)
499  return -1;
500 #else
501  // cppcheck-suppress leakReturnValNotUsed
502  if (open("/dev/null", O_RDWR) != STDERR_FILENO)
503  return -1;
504  if (fcntl(STDERR_FILENO, F_SETFD, FD_CLOEXEC) == -1)
505  return -1;
506 #endif
507  stderr = fdopen(STDERR_FILENO, "rw");
508  if (!stderr)
509  return -1;
510 
511  return 0;
512 }
513 
514 static void
515 daemon_signal_func(int sig)
516 {
517  switch (sig) {
518  case SIGTERM: daemon_stop(); break;
519  case SIGHUP: daemon_reload(); break;
520  default: break;
521  }
522 }
523 
524 #ifndef LELY_NO_THREADS
525 static int
526 daemon_thrd_start(void *arg)
527 {
528  (void)arg;
529 
530  for (;;) {
531  int result;
532  // Monitor the read end of the pipe for incoming data.
533  struct pollfd fds = { .fd = daemon_pipe[0], .events = POLLIN };
534  do
535  result = poll(&fds, 1, LELY_DAEMON_TIMEOUT);
536  while (result == -1 && errno == EINTR);
537  if (result != 1)
538  continue;
539  // Read a single signal value.
540  unsigned char uc = 0;
541  do
542  result = read(daemon_pipe[0], &uc, 1);
543  while (result == -1 && errno == EINTR);
544  if (result < 1)
545  continue;
546  int sig = uc;
547  // Execute the signal handler.
548  if (daemon_handler)
549  daemon_handler(sig, daemon_handle);
550  // Exit if we receive the stop signal.
551  if (sig == DAEMON_STOP)
552  break;
553  }
554 
555  return 0;
556 }
557 #endif
558 
559 #endif // _WIN32
560 
561 int
563 {
564  return daemon_signal(DAEMON_STOP);
565 }
566 
567 int
569 {
571 }
572 
573 int
575 {
576  return daemon_signal(DAEMON_PAUSE);
577 }
578 
579 int
581 {
583 }
584 
585 void
586 daemon_get_handler(daemon_handler_t **phandler, void **phandle)
587 {
588  if (phandler)
589  *phandler = daemon_handler;
590  if (phandle)
591  *phandle = daemon_handle;
592 }
593 
594 void
595 daemon_set_handler(daemon_handler_t *handler, void *handle)
596 {
597  daemon_handler = handler;
598  daemon_handle = handle;
599 }
600 
601 void
602 default_daemon_handler(int sig, void *handle)
603 {
604  (void)handle;
605 
606  switch (sig) {
607  case DAEMON_STOP: daemon_status(DAEMON_STOP); break;
610  }
611 }
612 
613 #endif // !LELY_NO_DAEMON
int daemon_stop(void)
Sends the stop signal to the daemon handler.
Definition: daemon.c:562
int daemon_pause(void)
Sends the pause signal to the daemon handler.
Definition: daemon.c:574
void default_daemon_handler(int sig, void *handle)
The default daemon_signal() handler.
Definition: daemon.c:602
int daemon_signal(int sig)
Sends a signal to a daemon, triggering the execution of the daemon handler.
Definition: daemon.c:386
void daemon_get_handler(daemon_handler_t **phandler, void **phandle)
Retrieves current daemon handler and handle argument.
Definition: daemon.c:586
int daemon_reload(void)
Sends the reload signal to the daemon handler.
Definition: daemon.c:568
void daemon_set_handler(daemon_handler_t *handler, void *handle)
Sets the current daemon handler and its (optional) handle argument.
Definition: daemon.c:595
int daemon_continue(void)
Sends the continue signal to the daemon handler.
Definition: daemon.c:580
int daemon_start(const char *name, int(*init)(int, char **), void(*main)(void), void(*fini)(void), int argc, char *argv[])
Executes the supplied function as a POSIX daemon or Windows service.
Definition: daemon.c:242
int daemon_status(int status)
Sets the current daemon status (one of DAEMON_START, DAEMON_STOP, DAEMON_PAUSE or DAEMON_CONTINUE).
Definition: daemon.c:401
This header file is part of the utilities library; it contains the daemon declarations.
void daemon_handler_t(int sig, void *handle)
The function type of a handler for daemon_signal().
Definition: daemon.h:68
@ DAEMON_START
The status indicating the daemon has started.
Definition: daemon.h:29
@ DAEMON_CONTINUE
The signal/status indicating the daemon SHOULD continue/has continued normal operation.
Definition: daemon.h:41
@ DAEMON_RELOAD
The signal indicating the daemon SHOULD reload its configuration.
Definition: daemon.h:43
@ DAEMON_USER_MAX
The largest possible value of a user-defined signal.
Definition: daemon.h:51
@ DAEMON_PAUSE
The signal/status indicating the daemon SHOULD pause/has paused.
Definition: daemon.h:36
@ DAEMON_STOP
The signal/status indicating the daemon MUST terminate/has terminated.
Definition: daemon.h:34
@ DAEMON_USER_MIN
The smallest possible value of a user-defined signal.
Definition: daemon.h:45
This header file is part of the utilities library; it contains the diagnostic declarations.
void daemon_diag_at_handler(void *handle, enum diag_severity severity, int errc, const struct floc *at, const char *format, va_list ap)
The diag_at() handler for daemons.
Definition: diag.c:256
void diag_set_handler(diag_handler_t *handler, void *handle)
Sets the handler function for diag().
Definition: diag.c:133
void diag_at_set_handler(diag_at_handler_t *handler, void *handle)
Sets the handler function for diag_at().
Definition: diag.c:149
void diag_at_handler_t(void *handle, enum diag_severity severity, int errc, const struct floc *at, const char *format, va_list ap)
The function type of a handler for diag_at().
Definition: diag.h:82
void diag_at_get_handler(diag_at_handler_t **phandler, void **phandle)
Retrieves the handler function for diag_at().
Definition: diag.c:140
void daemon_diag_handler(void *handle, enum diag_severity severity, int errc, const char *format, va_list ap)
The diag() handler for daemons.
Definition: diag.c:249
void diag_handler_t(void *handle, enum diag_severity severity, int errc, const char *format, va_list ap)
The function type of a handler for diag().
Definition: diag.h:68
void diag_get_handler(diag_handler_t **phandler, void **phandle)
Retrieves the handler function for diag().
Definition: diag.c:124
This is the internal header file of the utilities library.
This header file is part of the C11 and POSIX compatibility library; it includes <stdio....
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib....
This header file is part of the C11 and POSIX compatibility library; it includes <threads....
int thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
Creates a new thread executing func(arg).
pthread_t thrd_t
A complete object type that holds an identifier for a thread.
Definition: threads.h:85
int thrd_join(thrd_t thr, int *res)
Joins the thread identified by thr with the current thread by blocking until the other thread has ter...
@ thrd_success
Indicates that the requested operation succeeded.
Definition: threads.h:121
This header file is part of the C11 and POSIX compatibility library; it includes <unistd....