committed by
Christian Decker
6 changed files with 201 additions and 0 deletions
@ -0,0 +1 @@ |
|||||
|
../../licenses/BSD-MIT |
@ -0,0 +1,54 @@ |
|||||
|
#include "config.h" |
||||
|
#include <stdio.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
/** |
||||
|
* daemonize - routine to turn a process into a well-behaved daemon. |
||||
|
* |
||||
|
* Daemons should detach themselves thoroughly from the process which launched |
||||
|
* them, and not prevent any filesystems from being unmounted. daemonize() |
||||
|
* helps with the process. |
||||
|
* |
||||
|
* Example: |
||||
|
* #include <ccan/daemonize/daemonize.h> |
||||
|
* #include <ccan/str/str.h> |
||||
|
* #include <err.h> |
||||
|
* #include <unistd.h> |
||||
|
* #include <stdlib.h> |
||||
|
* |
||||
|
* static void usage(const char *name) |
||||
|
* { |
||||
|
* errx(1, "Usage: %s [--daemonize]\n", name); |
||||
|
* } |
||||
|
* |
||||
|
* // Wait for a minute, possibly as a daemon. |
||||
|
* int main(int argc, char *argv[]) |
||||
|
* { |
||||
|
* if (argc != 1) { |
||||
|
* if (argc == 2 && streq(argv[1], "--daemonize")) { |
||||
|
* if (!daemonize()) |
||||
|
* err(1, "Failed to become daemon"); |
||||
|
* } else |
||||
|
* usage(argv[1]); |
||||
|
* } |
||||
|
* sleep(60); |
||||
|
* exit(0); |
||||
|
* } |
||||
|
* |
||||
|
* License: BSD-MIT |
||||
|
*/ |
||||
|
int main(int argc, char *argv[]) |
||||
|
{ |
||||
|
if (argc != 2) |
||||
|
return 1; |
||||
|
|
||||
|
if (strcmp(argv[1], "depends") == 0) { |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
if (strcmp(argv[1], "libs") == 0) { |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
return 1; |
||||
|
} |
@ -0,0 +1,45 @@ |
|||||
|
/* Licensed under BSD-MIT - see LICENSE file for details */ |
||||
|
#include <ccan/daemonize/daemonize.h> |
||||
|
#include <unistd.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/stat.h> |
||||
|
#include <fcntl.h> |
||||
|
|
||||
|
/* This code is based on Stevens Advanced Programming in the UNIX
|
||||
|
* Environment. */ |
||||
|
bool daemonize(void) |
||||
|
{ |
||||
|
pid_t pid; |
||||
|
|
||||
|
/* Separate from our parent via fork, so init inherits us. */ |
||||
|
if ((pid = fork()) < 0) |
||||
|
return false; |
||||
|
/* use _exit() to avoid triggering atexit() processing */ |
||||
|
if (pid != 0) |
||||
|
_exit(0); |
||||
|
|
||||
|
/* Don't hold files open. */ |
||||
|
close(STDIN_FILENO); |
||||
|
close(STDOUT_FILENO); |
||||
|
close(STDERR_FILENO); |
||||
|
|
||||
|
/* Many routines write to stderr; that can cause chaos if used
|
||||
|
* for something else, so set it here. */ |
||||
|
if (open("/dev/null", O_WRONLY) != 0) |
||||
|
return false; |
||||
|
if (dup2(0, STDERR_FILENO) != STDERR_FILENO) |
||||
|
return false; |
||||
|
close(0); |
||||
|
|
||||
|
/* Session leader so ^C doesn't whack us. */ |
||||
|
if (setsid() == (pid_t)-1) |
||||
|
return false; |
||||
|
/* Move off any mount points we might be in. */ |
||||
|
if (chdir("/") != 0) |
||||
|
return false; |
||||
|
|
||||
|
/* Discard our parent's old-fashioned umask prejudices. */ |
||||
|
umask(0); |
||||
|
return true; |
||||
|
} |
@ -0,0 +1,21 @@ |
|||||
|
/* Licensed under BSD-MIT - see LICENSE file for details */ |
||||
|
#ifndef CCAN_DAEMONIZE_H |
||||
|
#define CCAN_DAEMONIZE_H |
||||
|
#include <stdbool.h> |
||||
|
|
||||
|
/**
|
||||
|
* daemonize - turn this process into a daemon. |
||||
|
* |
||||
|
* This routine forks us off to become a daemon. It returns false on failure |
||||
|
* (eg. fork(), chdir or open failed) and sets errno. |
||||
|
* |
||||
|
* Side effects for programmers to be aware of: |
||||
|
* - PID changes (our parent exits, we become child of init) |
||||
|
* - stdin and stdout file descriptors are closed |
||||
|
* - stderr is reopened to /dev/null so you don't reuse it |
||||
|
* - Current working directory changes to / |
||||
|
* - Umask is set to 0. |
||||
|
*/ |
||||
|
bool daemonize(void); |
||||
|
|
||||
|
#endif /* CCAN_DAEMONIZE_H */ |
@ -0,0 +1,76 @@ |
|||||
|
#include <ccan/daemonize/daemonize.h> |
||||
|
#include <ccan/daemonize/daemonize.c> |
||||
|
#include <ccan/tap/tap.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <unistd.h> |
||||
|
#include <err.h> |
||||
|
#include <errno.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
struct child_data { |
||||
|
pid_t pid; |
||||
|
pid_t ppid; |
||||
|
bool in_root_dir; |
||||
|
int read_from_stdin, write_to_stdout, write_to_stderr; |
||||
|
}; |
||||
|
|
||||
|
int main(int argc, char *argv[]) |
||||
|
{ |
||||
|
int fds[2]; |
||||
|
struct child_data daemonized; |
||||
|
pid_t pid; |
||||
|
|
||||
|
plan_tests(5); |
||||
|
|
||||
|
if (pipe(fds) != 0) |
||||
|
err(1, "Failed pipe"); |
||||
|
|
||||
|
/* Since daemonize forks and parent exits, we need to fork
|
||||
|
* that parent. */ |
||||
|
pid = fork(); |
||||
|
if (pid == -1) |
||||
|
err(1, "Failed fork"); |
||||
|
|
||||
|
if (pid == 0) { |
||||
|
char buffer[2]; |
||||
|
pid = getpid(); |
||||
|
daemonize(); |
||||
|
/* Keep valgrind happy about uninitialized bytes. */ |
||||
|
memset(&daemonized, 0, sizeof(daemonized)); |
||||
|
daemonized.pid = getpid(); |
||||
|
daemonized.in_root_dir = (getcwd(buffer, 2) != NULL); |
||||
|
daemonized.read_from_stdin |
||||
|
= read(STDIN_FILENO, buffer, 1) == -1 ? errno : 0; |
||||
|
daemonized.write_to_stdout |
||||
|
= write(STDOUT_FILENO, buffer, 1) == -1 ? errno : 0; |
||||
|
if (write(STDERR_FILENO, buffer, 1) != 1) { |
||||
|
daemonized.write_to_stderr = errno; |
||||
|
if (daemonized.write_to_stderr == 0) |
||||
|
daemonized.write_to_stderr = -1; |
||||
|
} else |
||||
|
daemonized.write_to_stderr = 0; |
||||
|
|
||||
|
/* Make sure parent exits. */ |
||||
|
while (getppid() == pid) |
||||
|
sleep(1); |
||||
|
daemonized.ppid = getppid(); |
||||
|
if (write(fds[1], &daemonized, sizeof(daemonized)) |
||||
|
!= sizeof(daemonized)) |
||||
|
exit(1); |
||||
|
exit(0); |
||||
|
} |
||||
|
|
||||
|
if (read(fds[0], &daemonized, sizeof(daemonized)) != sizeof(daemonized)) |
||||
|
err(1, "Failed read"); |
||||
|
|
||||
|
ok1(daemonized.pid != pid); |
||||
|
#if 0 /* Believe it or not, this fails under Ubuntu 13.10 (Upstart) */
|
||||
|
ok1(daemonized.ppid == 1); |
||||
|
#endif |
||||
|
ok1(daemonized.in_root_dir); |
||||
|
ok1(daemonized.read_from_stdin == EBADF); |
||||
|
ok1(daemonized.write_to_stdout == EBADF); |
||||
|
ok1(daemonized.write_to_stderr == 0); |
||||
|
|
||||
|
return exit_status(); |
||||
|
} |
Loading…
Reference in new issue