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