X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fdaemon.c;h=b8fc5afe5be524a4656906a0a9e0c6ce5b7a0aaf;hb=5d69c233557908e25f25acaa8d21da10de1a2868;hp=b153dc0c1e51621010344d0b0b1ab1515bff680b;hpb=dae8a4a83cd5f7449dfc153d02cbb93dd7ce7b98;p=sliver-openvswitch.git diff --git a/lib/daemon.c b/lib/daemon.c index b153dc0c1..b8fc5afe5 100644 --- a/lib/daemon.c +++ b/lib/daemon.c @@ -39,6 +39,7 @@ #include #include #include "fatal-signal.h" +#include "dirs.h" #include "util.h" #define THIS_MODULE VLM_daemon @@ -50,6 +51,19 @@ static bool detach; /* Name of pidfile (null if none). */ static char *pidfile; +/* Create pidfile even if one already exists and is locked? */ +static bool force; + +/* 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 * +make_pidfile_name(const char *name) +{ + return (!name ? xasprintf("%s/%s.pid", ofp_rundir, program_name) + : *name == '/' ? xstrdup(name) + : xasprintf("%s/%s", ofp_rundir, name)); +} + /* Sets up a following call to daemonize() to create a pidfile named 'name'. * If 'name' begins with '/', then it is treated as an absolute path. * Otherwise, it is taken relative to RUNDIR, which is $(prefix)/var/run by @@ -60,9 +74,25 @@ void set_pidfile(const char *name) { free(pidfile); - pidfile = (!name ? xasprintf("%s/%s.pid", RUNDIR, program_name) - : *name == '/' ? xstrdup(name) - : xasprintf("%s/%s", RUNDIR, name)); + pidfile = make_pidfile_name(name); +} + +/* Returns an absolute path to the configured pidfile, or a null pointer if no + * pidfile is configured. The caller must not modify or free the returned + * string. */ +const char * +get_pidfile(void) +{ + return pidfile; +} + +/* 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; } /* Sets up a following call to daemonize() to detach from the foreground @@ -73,6 +103,47 @@ set_detach(void) detach = true; } +/* 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. */ +static pid_t +already_running(void) +{ + pid_t pid = 0; + if (pidfile) { + int fd = open(pidfile, O_RDWR); + if (fd >= 0) { + struct flock lck; + lck.l_type = F_WRLCK; + lck.l_whence = SEEK_SET; + lck.l_start = 0; + lck.l_len = 0; + if (fcntl(fd, F_GETLK, &lck) != -1 && lck.l_type != F_UNLCK) { + pid = lck.l_pid; + } + close(fd); + } + } + return pid; +} + +/* If a locked pidfile exists, issue a warning message and, unless + * ignore_existing_pidfile() has been called, terminate the program. */ +void +die_if_already_running(void) +{ + pid_t pid = already_running(); + if (pid) { + if (!force) { + ofp_fatal(0, "%s: already running as pid %ld", + get_pidfile(), (long int) pid); + } else { + VLOG_WARN("%s: %s already running as pid %ld", + get_pidfile(), program_name, (long int) pid); + } + } +} + /* If a pidfile has been configured, creates it and stores the running process' * pid init. Ensures that the pidfile will be deleted when the process * exits. */ @@ -95,7 +166,7 @@ make_pidfile(void) lck.l_whence = SEEK_SET; lck.l_start = 0; lck.l_len = 0; - if (fcntl(fd, F_SETLK, &lck) >= 0) { + if (fcntl(fd, F_SETLK, &lck) != -1) { char *text = xasprintf("%ld\n", pid); if (write(fd, text, strlen(text)) == strlen(text)) { fatal_signal_add_file_to_unlink(pidfile); @@ -134,7 +205,7 @@ daemonize(void) char c = 0; int fds[2]; if (pipe(fds) < 0) { - fatal(errno, "pipe failed"); + ofp_fatal(errno, "pipe failed"); } switch (fork()) { @@ -157,7 +228,7 @@ daemonize(void) case -1: /* Error. */ - fatal(errno, "could not fork"); + ofp_fatal(errno, "could not fork"); break; } } else { @@ -165,3 +236,61 @@ daemonize(void) } } +void +daemon_usage(void) +{ + printf( + "\nDaemon options:\n" + " -D, --detach run in background as daemon\n" + " -P, --pidfile[=FILE] create pidfile (default: %s/%s.pid)\n" + " -f, --force with -P, start even if already running\n", + ofp_rundir, program_name); +} + +/* Opens and reads a PID from 'pidfile'. Returns the nonnegative PID if + * successful, otherwise a negative errno value. */ +pid_t +read_pidfile(const char *pidfile) +{ + char line[128]; + struct flock lck; + FILE *file; + int error; + + file = fopen(pidfile, "r"); + if (!file) { + error = errno; + VLOG_WARN("%s: open: %s", pidfile, strerror(error)); + goto error; + } + + lck.l_type = F_WRLCK; + lck.l_whence = SEEK_SET; + lck.l_start = 0; + lck.l_len = 0; + if (fcntl(fileno(file), F_GETLK, &lck)) { + error = errno; + VLOG_WARN("%s: fcntl: %s", pidfile, strerror(error)); + goto error; + } + + if (!fgets(line, sizeof line, file)) { + error = errno; + VLOG_WARN("%s: read: %s", pidfile, strerror(error)); + goto error; + } + + if (lck.l_pid != strtoul(line, NULL, 10)) { + error = ESRCH; + VLOG_WARN("l_pid (%ld) != %s pid (%s)", + (long int) lck.l_pid, pidfile, line); + goto error; + } + + fclose(file); + return lck.l_pid; + +error: + fclose(file); + return -error; +}