X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fdaemon.c;h=9a1be55dbfc868d14274a138e9bd28c1491dc521;hb=539e96f62300e4afab00e5906a28e3b89301d62e;hp=a011d37fe02d9e3cf5bfb6daf265c11e089b85ed;hpb=91a1e24d09ba1f08b1f8c08815f595187c6ef946;p=openvswitch diff --git a/lib/daemon.c b/lib/daemon.c index a011d37f..9a1be55d 100644 --- a/lib/daemon.c +++ b/lib/daemon.c @@ -20,9 +20,13 @@ #include #include #include +#include #include #include "fatal-signal.h" #include "dirs.h" +#include "lockfile.h" +#include "socket-util.h" +#include "timeval.h" #include "util.h" #define THIS_MODULE VLM_daemon @@ -35,11 +39,14 @@ static bool detach; static char *pidfile; /* Create pidfile even if one already exists and is locked? */ -static bool force; +static bool overwrite_pidfile; -/* Should we chdir to "/". */ +/* Should we chdir to "/"? */ static bool chdir_ = true; +/* File descriptors used by daemonize_start() and daemonize_complete(). */ +static int daemonize_fds[2]; + /* Returns the file name that would be used for a pidfile if 'name' were * provided to set_pidfile(). The caller must free the returned string. */ char * @@ -79,13 +86,20 @@ set_no_chdir(void) chdir_ = false; } +/* Will we chdir to "/" as part of daemonizing? */ +bool +is_chdir_enabled(void) +{ + return chdir_; +} + /* Normally, die_if_already_running() will terminate the program with a message * if a locked pidfile already exists. If this function is called, * die_if_already_running() will merely log a warning. */ void ignore_existing_pidfile(void) { - force = true; + overwrite_pidfile = true; } /* Sets up a following call to daemonize() to detach from the foreground @@ -96,6 +110,13 @@ set_detach(void) detach = true; } +/* Will daemonize() really detach? */ +bool +get_detach(void) +{ + return detach; +} + /* If a pidfile has been configured and that pidfile already exists and is * locked by a running process, returns the pid of the running process. * Otherwise, returns 0. */ @@ -127,7 +148,7 @@ die_if_already_running(void) { pid_t pid = already_running(); if (pid) { - if (!force) { + if (!overwrite_pidfile) { ovs_fatal(0, "%s: already running as pid %ld", get_pidfile(), (long int) pid); } else { @@ -194,55 +215,98 @@ make_pidfile(void) * detaches from the foreground session. */ void daemonize(void) +{ + daemonize_start(); + daemonize_complete(); +} + +/* If daemonization is configured, then starts daemonization, by forking and + * returning in the child process. The parent process hangs around until the + * child lets it know either that it completed startup successfully (by calling + * daemon_complete()) or that it failed to start up (by exiting with a nonzero + * exit code). */ +void +daemonize_start(void) { if (detach) { - char c = 0; - int fds[2]; - if (pipe(fds) < 0) { + pid_t pid; + + if (pipe(daemonize_fds) < 0) { ovs_fatal(errno, "pipe failed"); } - switch (fork()) { - default: - /* Parent process: wait for child to create pidfile, then exit. */ - close(fds[1]); + pid = fork(); + if (pid > 0) { + /* Running in parent process. */ + char c; + + close(daemonize_fds[1]); fatal_signal_fork(); - if (read(fds[0], &c, 1) != 1) { + if (read(daemonize_fds[0], &c, 1) != 1) { + int retval; + int status; + + do { + retval = waitpid(pid, &status, 0); + } while (retval == -1 && errno == EINTR); + + if (retval == pid + && WIFEXITED(status) + && WEXITSTATUS(status)) { + /* Child exited with an error. Convey the same error to + * our parent process as a courtesy. */ + exit(WEXITSTATUS(status)); + } + ovs_fatal(errno, "daemon child failed to signal startup"); } exit(0); - - case 0: - /* Child process. */ - close(fds[0]); + } else if (!pid) { + /* Running in child process. */ + close(daemonize_fds[0]); make_pidfile(); - write(fds[1], &c, 1); - close(fds[1]); - setsid(); - if (chdir_) { - chdir("/"); - } - break; - - case -1: - /* Error. */ + time_postfork(); + lockfile_postfork(); + } else { ovs_fatal(errno, "could not fork"); - break; } } else { make_pidfile(); } } +/* If daemonization is configured, then this function notifies the parent + * process that the child process has completed startup successfully. */ +void +daemonize_complete(void) +{ + if (detach) { + size_t bytes_written; + int error; + + error = write_fully(daemonize_fds[1], "", 1, &bytes_written); + if (error) { + ovs_fatal(error, "could not write to pipe"); + } + + close(daemonize_fds[1]); + setsid(); + if (chdir_) { + ignore(chdir("/")); + } + } +} + void daemon_usage(void) { printf( "\nDaemon options:\n" - " -D, --detach run in background as daemon\n" + " --detach run in background as daemon\n" " --no-chdir do not chdir to '/'\n" - " -P, --pidfile[=FILE] create pidfile (default: %s/%s.pid)\n" - " -f, --force with -P, start even if already running\n", + " --pidfile[=FILE] create pidfile (default: %s/%s.pid)\n" + " --overwrite-pidfile with --pidfile, start even if already " + "running\n", ovs_rundir, program_name); }