28 #define LELY_NO_DAEMON 1
44 #ifndef LELY_DAEMON_TIMEOUT
45 #define LELY_DAEMON_TIMEOUT 1000
49 static void *daemon_handle;
55 static void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv);
56 static void WINAPI Handler(DWORD fdwControl);
57 static int ReportStatus(DWORD dwCurrentState);
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);
64 static SERVICE_STATUS_HANDLE hServiceStatus;
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
76 daemon_start(
const char *name,
int (*init)(
int,
char **),
void (*main)(
void),
77 void (*fini)(
void),
int argc,
char *argv[])
87 SERVICE_TABLE_ENTRYA ServiceTable[] = {
88 { (LPSTR)daemon_name, &ServiceMain }, { NULL, NULL }
90 return StartServiceCtrlDispatcherA(ServiceTable) ? 0 : -1;
97 SetLastError(ERROR_INVALID_PARAMETER);
102 daemon_handler(sig, daemon_handle);
110 DWORD dwCurrentState = 0;
114 case DAEMON_STOP: dwCurrentState = SERVICE_STOPPED;
break;
115 case DAEMON_PAUSE: dwCurrentState = SERVICE_PAUSED;
break;
117 default: SetLastError(ERROR_INVALID_PARAMETER);
return -1;
120 return ReportStatus(dwCurrentState);
124 ServiceMain(DWORD dwArgc, LPSTR *lpszArgv)
128 hServiceStatus = RegisterServiceCtrlHandlerA(daemon_name, Handler);
130 goto error_RegisterServiceCtrlHandlerA;
131 ReportStatus(SERVICE_START_PENDING);
140 void *diag_at_handle;
147 char **argv = malloc((dwArgc + 1) *
sizeof(
char *));
150 for (DWORD i = 0; i < dwArgc; i++)
151 argv[i] = lpszArgv[i];
153 if (daemon_init(dwArgc, argv)) {
160 ReportStatus(SERVICE_RUNNING);
174 ReportStatus(SERVICE_STOPPED);
175 error_RegisterServiceCtrlHandlerA:
183 Handler(DWORD fdwControl)
186 switch (fdwControl) {
187 case SERVICE_CONTROL_STOP:
188 case SERVICE_CONTROL_SHUTDOWN:
189 ReportStatus(SERVICE_STOP_PENDING);
192 case SERVICE_CONTROL_PAUSE:
193 ReportStatus(SERVICE_PAUSE_PENDING);
196 case SERVICE_CONTROL_CONTINUE:
197 ReportStatus(SERVICE_CONTINUE_PENDING);
200 case SERVICE_CONTROL_PARAMCHANGE: sig =
DAEMON_RELOAD;
break;
202 if (fdwControl >= 128 && fdwControl <= 255)
214 ReportStatus(DWORD dwCurrentState)
216 static DWORD dwCheckPoint;
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;
226 case SERVICE_STOPPED:
227 case SERVICE_RUNNING:
228 case SERVICE_PAUSED: ServiceStatus.dwCheckPoint = 0;
break;
232 return SetServiceStatus(hServiceStatus, &ServiceStatus) ? 0 : -1;
235 #elif _POSIX_C_SOURCE >= 200112L
239 #include <sys/stat.h>
242 static int daemon_proc(
void);
243 static void daemon_signal_func(
int sig);
245 static int daemon_thrd_start(
void *arg);
248 static int daemon_pipe[2] = { -1, -1 };
251 daemon_start(
const char *name,
int (*init)(
int,
char **),
void (*main)(
void),
252 void (*fini)(
void),
int argc,
char *argv[])
264 if (init && init(argc, argv)) {
270 if (daemon_proc() == -1) {
277 #if (defined(__CYGWIN__) || defined(__linux__)) && defined(_GNU_SOURCE)
278 result = pipe2(daemon_pipe, O_NONBLOCK | O_CLOEXEC);
285 result = pipe(daemon_pipe);
291 if (fcntl(daemon_pipe[0], F_SETFD, FD_CLOEXEC) == -1) {
296 if (fcntl(daemon_pipe[1], F_SETFD, FD_CLOEXEC) == -1) {
302 if ((flags = fcntl(daemon_pipe[0], F_GETFL, 0)) == -1) {
307 if (fcntl(daemon_pipe[0], F_SETFL, flags | O_NONBLOCK) == -1) {
312 if ((flags = fcntl(daemon_pipe[1], F_GETFL, 0)) == -1) {
317 if (fcntl(daemon_pipe[1], F_SETFL, flags | O_NONBLOCK) == -1) {
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) {
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) {
350 goto error_thrd_create;
361 void *diag_at_handle;
381 sigaction(SIGTERM, &old_term, NULL);
383 sigaction(SIGHUP, &old_hup, NULL);
385 #if !defined(__CYGWIN__) && !defined(__linux__)
388 close(daemon_pipe[1]);
390 close(daemon_pipe[0]);
411 result = write(daemon_pipe[1], &(
unsigned char){ sig }, 1);
412 while (result == -1 && errno == EINTR);
435 default: _Exit(EXIT_SUCCESS);
439 if (chdir(
"/") == -1)
455 default: _Exit(EXIT_SUCCESS);
459 struct sigaction act;
460 act.sa_handler = SIG_IGN;
461 sigemptyset(&act.sa_mask);
463 sigaction(SIGTSTP, &act, NULL);
464 sigaction(SIGTTIN, &act, NULL);
465 sigaction(SIGTTOU, &act, NULL);
474 #if defined(__CYGWIN__) || defined(__linux__)
476 if (open(
"/dev/null", O_RDONLY | O_CLOEXEC) != STDIN_FILENO)
480 if (open(
"/dev/null", O_RDONLY) != STDIN_FILENO)
482 if (fcntl(STDIN_FILENO, F_SETFD, FD_CLOEXEC) == -1)
485 stdin = fdopen(STDIN_FILENO,
"r");
490 fsync(STDOUT_FILENO);
492 close(STDOUT_FILENO);
493 #if defined(__CYGWIN__) || defined(__linux__)
495 if (open(
"/dev/null", O_WRONLY | O_CLOEXEC) != STDOUT_FILENO)
499 if (open(
"/dev/null", O_WRONLY) != STDOUT_FILENO)
501 if (fcntl(STDOUT_FILENO, F_SETFD, FD_CLOEXEC) == -1)
504 stdout = fdopen(STDOUT_FILENO,
"w");
509 fsync(STDERR_FILENO);
511 close(STDERR_FILENO);
512 #if defined(__CYGWIN__) || defined(__linux__)
514 if (open(
"/dev/null", O_RDWR | O_CLOEXEC) != STDERR_FILENO)
518 if (open(
"/dev/null", O_RDWR) != STDERR_FILENO)
520 if (fcntl(STDERR_FILENO, F_SETFD, FD_CLOEXEC) == -1)
523 stderr = fdopen(STDERR_FILENO,
"rw");
531 daemon_signal_func(
int sig)
542 daemon_thrd_start(
void *arg)
549 struct pollfd fds = { .fd = daemon_pipe[0], .events = POLLIN };
551 result = poll(&fds, 1, LELY_DAEMON_TIMEOUT);
552 while (result == -1 && errno == EINTR);
556 unsigned char uc = 0;
558 result = read(daemon_pipe[0], &uc, 1);
559 while (result == -1 && errno == EINTR);
565 daemon_handler(sig, daemon_handle);
605 *phandler = daemon_handler;
607 *phandle = daemon_handle;
613 daemon_handler = handler;
614 daemon_handle = handle;
int daemon_stop(void)
Sends the stop signal to the daemon handler.
int daemon_pause(void)
Sends the pause signal to the daemon handler.
void default_daemon_handler(int sig, void *handle)
The default daemon_signal() handler.
int daemon_signal(int sig)
Sends a signal to a daemon, triggering the execution of the daemon handler.
void daemon_get_handler(daemon_handler_t **phandler, void **phandle)
Retrieves current daemon handler and handle argument.
int daemon_reload(void)
Sends the reload signal to the daemon handler.
void daemon_set_handler(daemon_handler_t *handler, void *handle)
Sets the current daemon handler and its (optional) handle argument.
int daemon_continue(void)
Sends the continue signal to the daemon handler.
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.
int daemon_status(int status)
Sets the current daemon status (one of DAEMON_START, DAEMON_STOP, DAEMON_PAUSE or DAEMON_CONTINUE).
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().
@ DAEMON_START
The status indicating the daemon has started.
@ DAEMON_CONTINUE
The signal/status indicating the daemon SHOULD continue/has continued normal operation.
@ DAEMON_RELOAD
The signal indicating the daemon SHOULD reload its configuration.
@ DAEMON_USER_MAX
The largest possible value of a user-defined signal.
@ DAEMON_PAUSE
The signal/status indicating the daemon SHOULD pause/has paused.
@ DAEMON_STOP
The signal/status indicating the daemon MUST terminate/has terminated.
@ DAEMON_USER_MIN
The smallest possible value of a user-defined signal.
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.
void diag_set_handler(diag_handler_t *handler, void *handle)
Sets the handler function for diag().
void diag_at_set_handler(diag_at_handler_t *handler, void *handle)
Sets the handler function for diag_at().
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().
void diag_at_get_handler(diag_at_handler_t **phandler, void **phandle)
Retrieves the handler function for diag_at().
void daemon_diag_handler(void *handle, enum diag_severity severity, int errc, const char *format, va_list ap)
The diag() handler for daemons.
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().
void diag_get_handler(diag_handler_t **phandler, void **phandle)
Retrieves the handler function for diag().
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.
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.
This header file is part of the C11 and POSIX compatibility library; it includes <unistd....