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;
629 #endif // !LELY_NO_DAEMON