#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/wait.h>
#include <unistd.h>
#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
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 *
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
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. */
{
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 {
* 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);
}