From: Stewart Smith Date: Thu, 10 Feb 2011 23:53:25 +0000 (+1100) Subject: add basic bit of daemon-with-notify (mostly just from the Drizzle tree) X-Git-Url: http://git.ozlabs.org/?p=ccan;a=commitdiff_plain;h=4166cb1a3a22ef69d385a99c0a01bcbc41bd69f3 add basic bit of daemon-with-notify (mostly just from the Drizzle tree) --- diff --git a/ccan/daemon-with-notify/LICENSE b/ccan/daemon-with-notify/LICENSE new file mode 120000 index 00000000..f8598ee1 --- /dev/null +++ b/ccan/daemon-with-notify/LICENSE @@ -0,0 +1 @@ +../../licenses/BSD \ No newline at end of file diff --git a/ccan/daemon-with-notify/_info b/ccan/daemon-with-notify/_info new file mode 100644 index 00000000..24f0cfe9 --- /dev/null +++ b/ccan/daemon-with-notify/_info @@ -0,0 +1,62 @@ +#include +#include +#include "config.h" + +/** + * daemon-with-notify - turn a process into a daemon with parent exiting when + * child has decided that it has started correctly. + * + * Daemons should detach themselves thoroughly from the process which launched + * them, and not prevent any filesystems from being unmounted. daemonize() + * helps with the process. + * + * Daemon-with-notify is different in that the child can send a SIGUSR1 to + * the parent to indicate it has started (e.g. after memory allocation and + * other things that may fail) so that the parent can return a success or + * failing exit code and init scripts can pick this up easily. + * + * Example: + * #include + * #include + * #include + * #include + * #include + * + * 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(1, 1, 1)) + * err(1, "Failed to become daemon"); + * } else + * usage(argv[1]); + * } + * sleep(10); /* do some init here */ + * daemon_is_ready(); + * sleep(20); /* will be done in child, detached from parent */ + * 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; +} diff --git a/ccan/daemon-with-notify/daemon.c b/ccan/daemon-with-notify/daemon.c new file mode 100644 index 00000000..4232a034 --- /dev/null +++ b/ccan/daemon-with-notify/daemon.c @@ -0,0 +1,138 @@ +/* $Header: /cvsroot/wikipedia/willow/src/bin/willow/daemon.c,v 1.1 2005/05/02 19:15:21 kateturner Exp $ */ +/* $NetBSD: daemon.c,v 1.9 2003/08/07 16:42:46 agc Exp $ */ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 2010 + * Stewart Smith + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc +# pragma ident "@(#)$Header: /cvsroot/wikipedia/willow/src/bin/willow/daemon.c,v 1.1 2005/05/02 19:15:21 kateturner Exp $" +# pragma ident "$NetBSD: daemon.c,v 1.9 2003/08/07 16:42:46 agc Exp $" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +int daemonize(int nochdir, int noclose, int wait_sigusr1); +int daemon_is_ready(void); +void sigusr1_handler(int sig); + +pid_t parent_pid; + +void sigusr1_handler(int sig) +{ + if (sig == SIGUSR1) + _exit(EXIT_SUCCESS); +} + +int daemon_is_ready() +{ + kill(parent_pid, SIGUSR1); + return 0; +} + +int daemonize(int nochdir, int noclose, int wait_sigusr1) +{ + int fd; + pid_t child= -1; + + parent_pid= getpid(); + signal(SIGUSR1, sigusr1_handler); + + child= fork(); + + switch (child) + { + case -1: + return (-1); + case 0: + break; + default: + if (wait_sigusr1) + { + /* parent */ + int exit_code= -1; + int status; + while (waitpid(child, &status, 0) != child); + if (WIFEXITED(status)) + { + exit_code= WEXITSTATUS(status); + } + if (WIFSIGNALED(status)) + { + exit_code= -1; + } + _exit(exit_code); + } + else + { + _exit(EXIT_SUCCESS); + } + } + + /* child */ + if (setsid() == -1) + return (-1); + + if (nochdir == 0) { + if(chdir("/") != 0) { + perror("chdir"); + return (-1); + } + } + + if (noclose == 0 && (fd = open("/dev/null", O_RDWR, 0)) != -1) { + if(dup2(fd, STDIN_FILENO) < 0) { + perror("dup2 stdin"); + return (-1); + } + if(dup2(fd, STDOUT_FILENO) < 0) { + perror("dup2 stdout"); + return (-1); + } + if(dup2(fd, STDERR_FILENO) < 0) { + perror("dup2 stderr"); + return (-1); + } + + if (fd > STDERR_FILENO) { + if(close(fd) < 0) { + perror("close"); + return (-1); + } + } + } + return (0); +} diff --git a/ccan/daemon-with-notify/test/run.c b/ccan/daemon-with-notify/test/run.c new file mode 100644 index 00000000..9bb966da --- /dev/null +++ b/ccan/daemon-with-notify/test/run.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +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(6); + + 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); + ok1(daemonized.ppid == 1); + 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(); +} diff --git a/licenses/BSD b/licenses/BSD new file mode 100644 index 00000000..9ef4905e --- /dev/null +++ b/licenses/BSD @@ -0,0 +1,23 @@ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE.