26 #ifndef LELY_NO_DAEMON 28 #ifndef LELY_NO_THREADS 39 #ifndef LELY_DAEMON_TIMEOUT 40 #define LELY_DAEMON_TIMEOUT 1000 44 static void *daemon_handle;
50 static void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv);
51 static void WINAPI Handler(DWORD fdwControl);
52 static int ReportStatus(DWORD dwCurrentState);
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);
59 static SERVICE_STATUS_HANDLE hServiceStatus;
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
71 daemon_start(
const char *name,
int (*init)(
int,
char **),
void (*main)(
void),
72 void (*fini)(
void),
int argc,
char *argv[])
82 SERVICE_TABLE_ENTRYA ServiceTable[] = {
83 { (LPSTR)daemon_name, &ServiceMain }, { NULL, NULL }
85 return StartServiceCtrlDispatcherA(ServiceTable) ? 0 : -1;
92 SetLastError(ERROR_INVALID_PARAMETER);
97 daemon_handler(sig, daemon_handle);
105 DWORD dwCurrentState = 0;
109 case DAEMON_STOP: dwCurrentState = SERVICE_STOPPED;
break;
110 case DAEMON_PAUSE: dwCurrentState = SERVICE_PAUSED;
break;
112 default: SetLastError(ERROR_INVALID_PARAMETER);
return -1;
115 return ReportStatus(dwCurrentState);
119 ServiceMain(DWORD dwArgc, LPSTR *lpszArgv)
123 hServiceStatus = RegisterServiceCtrlHandlerA(daemon_name, Handler);
125 goto error_RegisterServiceCtrlHandlerA;
126 ReportStatus(SERVICE_START_PENDING);
134 void *diag_at_handle;
140 char **argv = malloc((dwArgc + 1) *
sizeof(
char *));
143 for (DWORD i = 0; i < dwArgc; i++)
144 argv[i] = lpszArgv[i];
146 if (daemon_init(dwArgc, argv)) {
153 ReportStatus(SERVICE_RUNNING);
165 ReportStatus(SERVICE_STOPPED);
166 error_RegisterServiceCtrlHandlerA:
174 Handler(DWORD fdwControl)
177 switch (fdwControl) {
178 case SERVICE_CONTROL_STOP:
179 case SERVICE_CONTROL_SHUTDOWN:
180 ReportStatus(SERVICE_STOP_PENDING);
183 case SERVICE_CONTROL_PAUSE:
184 ReportStatus(SERVICE_PAUSE_PENDING);
187 case SERVICE_CONTROL_CONTINUE:
188 ReportStatus(SERVICE_CONTINUE_PENDING);
191 case SERVICE_CONTROL_PARAMCHANGE: sig =
DAEMON_RELOAD;
break;
193 if (fdwControl >= 128 && fdwControl <= 255)
205 ReportStatus(DWORD dwCurrentState)
207 static DWORD dwCheckPoint;
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;
217 case SERVICE_STOPPED:
218 case SERVICE_RUNNING:
219 case SERVICE_PAUSED: ServiceStatus.dwCheckPoint = 0;
break;
223 return SetServiceStatus(hServiceStatus, &ServiceStatus) ? 0 : -1;
226 #elif _POSIX_C_SOURCE >= 200112L 230 #include <sys/stat.h> 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);
239 static int daemon_pipe[2] = { -1, -1 };
242 daemon_start(
const char *name,
int (*init)(
int,
char **),
void (*main)(
void),
243 void (*fini)(
void),
int argc,
char *argv[])
252 if (init && init(argc, argv)) {
258 if (daemon_proc() == -1) {
265 #if (defined(__CYGWIN__) || defined(__linux__)) && defined(_GNU_SOURCE) 266 result = pipe2(daemon_pipe, O_NONBLOCK | O_CLOEXEC);
273 result = pipe(daemon_pipe);
279 if (fcntl(daemon_pipe[0], F_SETFD, FD_CLOEXEC) == -1) {
284 if (fcntl(daemon_pipe[1], F_SETFD, FD_CLOEXEC) == -1) {
290 if ((flags = fcntl(daemon_pipe[0], F_GETFL, 0)) == -1) {
295 if (fcntl(daemon_pipe[0], F_SETFL, flags | O_NONBLOCK) == -1) {
300 if ((flags = fcntl(daemon_pipe[1], F_GETFL, 0)) == -1) {
305 if (fcntl(daemon_pipe[1], F_SETFL, flags | O_NONBLOCK) == -1) {
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) {
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) {
334 #ifndef LELY_NO_THREADS 338 goto error_thrd_create;
348 void *diag_at_handle;
355 #ifndef LELY_NO_THREADS 362 #ifndef LELY_NO_THREADS 365 sigaction(SIGTERM, &old_term, NULL);
367 sigaction(SIGHUP, &old_hup, NULL);
369 #if !defined(__CYGWIN__) && !defined(__linux__) 372 close(daemon_pipe[1]);
374 close(daemon_pipe[0]);
388 if (sig < 0 || sig > DAEMON_USER_MAX) {
395 result = write(daemon_pipe[1], &(
unsigned char){ sig }, 1);
396 while (result == -1 && errno == EINTR);
419 default: _Exit(EXIT_SUCCESS);
423 if (chdir(
"/") == -1)
439 default: _Exit(EXIT_SUCCESS);
443 struct sigaction act;
444 act.sa_handler = SIG_IGN;
445 sigemptyset(&act.sa_mask);
447 sigaction(SIGTSTP, &act, NULL);
448 sigaction(SIGTTIN, &act, NULL);
449 sigaction(SIGTTOU, &act, NULL);
458 #if defined(__CYGWIN__) || defined(__linux__) 460 if (open(
"/dev/null", O_RDONLY | O_CLOEXEC) != STDIN_FILENO)
464 if (open(
"/dev/null", O_RDONLY) != STDIN_FILENO)
466 if (fcntl(STDIN_FILENO, F_SETFD, FD_CLOEXEC) == -1)
469 stdin = fdopen(STDIN_FILENO,
"r");
474 fsync(STDOUT_FILENO);
476 close(STDOUT_FILENO);
477 #if defined(__CYGWIN__) || defined(__linux__) 479 if (open(
"/dev/null", O_WRONLY | O_CLOEXEC) != STDOUT_FILENO)
483 if (open(
"/dev/null", O_WRONLY) != STDOUT_FILENO)
485 if (fcntl(STDOUT_FILENO, F_SETFD, FD_CLOEXEC) == -1)
488 stdout = fdopen(STDOUT_FILENO,
"w");
493 fsync(STDERR_FILENO);
495 close(STDERR_FILENO);
496 #if defined(__CYGWIN__) || defined(__linux__) 498 if (open(
"/dev/null", O_RDWR | O_CLOEXEC) != STDERR_FILENO)
502 if (open(
"/dev/null", O_RDWR) != STDERR_FILENO)
504 if (fcntl(STDERR_FILENO, F_SETFD, FD_CLOEXEC) == -1)
507 stderr = fdopen(STDERR_FILENO,
"rw");
515 daemon_signal_func(
int sig)
524 #ifndef LELY_NO_THREADS 526 daemon_thrd_start(
void *arg)
533 struct pollfd fds = { .fd = daemon_pipe[0], .events = POLLIN };
535 result = poll(&fds, 1, LELY_DAEMON_TIMEOUT);
536 while (result == -1 && errno == EINTR);
540 unsigned char uc = 0;
542 result = read(daemon_pipe[0], &uc, 1);
543 while (result == -1 && errno == EINTR);
549 daemon_handler(sig, daemon_handle);
589 *phandler = daemon_handler;
591 *phandle = daemon_handle;
597 daemon_handler = handler;
598 daemon_handle = handle;
613 #endif // !LELY_NO_DAEMON The signal indicating the daemon SHOULD reload its configuration.
int daemon_continue(void)
Sends the continue signal to the daemon handler.
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().
This header file is part of the utilities library; it contains the daemon declarations.
void daemon_get_handler(daemon_handler_t **phandler, void **phandle)
Retrieves current daemon handler and handle argument.
void diag_get_handler(diag_handler_t **phandler, void **phandle)
Retrieves the handler function for diag().
int daemon_reload(void)
Sends the reload signal to the daemon handler.
The smallest possible value of a user-defined signal.
The status indicating the daemon has started.
Indicates that the requested operation succeeded.
The signal/status indicating the daemon SHOULD pause/has paused.
pthread_t thrd_t
A complete object type that holds an identifier for a thread.
int daemon_signal(int sig)
Sends a signal to a daemon, triggering the execution of the daemon handler.
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 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 daemon_diag_handler(void *handle, enum diag_severity severity, int errc, const char *format, va_list ap)
The diag() handler for daemons.
This header file is part of the C11 and POSIX compatibility library; it includes <threads.h>, if it exists, and defines any missing functionality.
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...
This header file is part of the C11 and POSIX compatibility library; it includes <unistd.h>, if it exists, and defines any missing functionality.
This is the internal header file of the utilities library.
int daemon_pause(void)
Sends the pause signal to the daemon handler.
int thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
Creates a new thread executing func(arg).
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.
void diag_set_handler(diag_handler_t *handler, void *handle)
Sets the handler function for diag().
This header file is part of the utilities library; it contains the diagnostic declarations.
void diag_at_get_handler(diag_at_handler_t **phandler, void **phandle)
Retrieves the handler function for diag_at().
void diag_at_set_handler(diag_at_handler_t *handler, void *handle)
Sets the handler function for diag_at().
This header file is part of the C11 and POSIX compatibility library; it includes <stdio.h> and defines any missing functionality.
void daemon_set_handler(daemon_handler_t *handler, void *handle)
Sets the current daemon handler and its (optional) handle argument.
The signal/status indicating the daemon SHOULD continue/has continued normal operation.
The signal/status indicating the daemon MUST terminate/has terminated.
int daemon_stop(void)
Sends the stop signal to the daemon handler.
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib.h> and defines any missing functionality.
void default_daemon_handler(int sig, void *handle)
The default daemon_signal() handler.
void daemon_handler_t(int sig, void *handle)
The function type of a handler for daemon_signal().
The largest possible value of a user-defined signal.
int daemon_status(int status)
Sets the current daemon status (one of DAEMON_START, DAEMON_STOP, DAEMON_PAUSE or DAEMON_CONTINUE)...