From: Ben Pfaff Date: Thu, 28 Aug 2008 20:17:16 +0000 (-0700) Subject: Make -P or --pidfile keep programs from running if already running. X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=e9ab3dbf6d648c98f62248907baeea65cfc0505a;p=sliver-openvswitch.git Make -P or --pidfile keep programs from running if already running. --- diff --git a/controller/controller.8.in b/controller/controller.8.in index a82995195..2781fdebf 100644 --- a/controller/controller.8.in +++ b/controller/controller.8.in @@ -117,6 +117,16 @@ the PID of the running process. If \fIpidfile\fR is not specified, or if it does not begin with \fB/\fR, then it is created in \fB@rundir@\fR. +.TP +\fB-f\fR, \fB--force\fR +By default, when \fB-P\fR or \fB--pidfile\fR is specified and the +specified pidfile already exists and is locked by a running process, +\fBcontroller\fR refuses to start. Specify \fB-f\fR or \fB--force\fR +to cause it to instead overwrite the pidfile. + +When \fB-P\fR or \fB--pidfile\fR is not specified, this option has no +effect. + .TP \fB-D\fR, \fB--detach\fR Causes \fBcontroller\fR to detach itself from the foreground session and diff --git a/controller/controller.c b/controller/controller.c index 01037bbb0..2d79afaa4 100644 --- a/controller/controller.c +++ b/controller/controller.c @@ -133,6 +133,7 @@ main(int argc, char *argv[]) fatal(0, "no active or passive switch connections"); } + die_if_already_running(); daemonize(); while (n_switches > 0 || n_listeners > 0) { @@ -231,6 +232,7 @@ parse_options(int argc, char *argv[]) static struct option long_options[] = { {"detach", no_argument, 0, 'D'}, {"pidfile", optional_argument, 0, 'P'}, + {"force", no_argument, 0, 'f'}, {"hub", no_argument, 0, 'H'}, {"noflow", no_argument, 0, 'n'}, {"max-idle", required_argument, 0, OPT_MAX_IDLE}, @@ -260,6 +262,10 @@ parse_options(int argc, char *argv[]) set_pidfile(optarg); break; + case 'f': + ignore_existing_pidfile(); + break; + case 'H': learn_macs = false; break; @@ -314,6 +320,7 @@ usage(void) printf("\nOther options:\n" " -D, --detach run in background as daemon\n" " -P, --pidfile[=FILE] create pidfile (default: %s/controller.pid)\n" + " -f, --force with -P, start even if already running\n" " -H, --hub act as hub instead of learning switch\n" " -n, --noflow pass traffic, but don't add flows\n" " --max-idle=SECS max idle time for new flows\n" diff --git a/include/daemon.h b/include/daemon.h index d7273e026..ee6b0f0fa 100644 --- a/include/daemon.h +++ b/include/daemon.h @@ -34,9 +34,14 @@ #ifndef DAEMON_H #define DAEMON_H 1 +#include + char *make_pidfile_name(const char *name); void set_pidfile(const char *name); +const char *get_pidfile(void); void set_detach(void); void daemonize(void); +void die_if_already_running(void); +void ignore_existing_pidfile(void); #endif /* daemon.h */ diff --git a/lib/daemon.c b/lib/daemon.c index 58581b778..22339f915 100644 --- a/lib/daemon.c +++ b/lib/daemon.c @@ -50,6 +50,9 @@ 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 * @@ -73,6 +76,24 @@ set_pidfile(const char *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 * session, running this process in the background. */ void @@ -81,6 +102,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) { + 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. */ diff --git a/secchan/secchan.8.in b/secchan/secchan.8.in index 620c59f91..e3d297e11 100644 --- a/secchan/secchan.8.in +++ b/secchan/secchan.8.in @@ -207,7 +207,7 @@ that it receives specifies one or more DNS servers. When controller discovery is not performed, this option has no effect. .TP -\fB-f\fR, \fB--fail=\fR[\fBopen\fR|\fBclosed\fR] +\fB-F\fR, \fB--fail=\fR[\fBopen\fR|\fBclosed\fR] The controller is, ordinarily, responsible for setting up all flows on the OpenFlow switch. Thus, if the connection to the controller fails, no new network connections can be set up. If the connection to the @@ -324,6 +324,16 @@ the PID of the running process. If \fIpidfile\fR is not specified, or if it does not begin with \fB/\fR, then it is created in \fB@rundir@\fR. +.TP +\fB-f\fR, \fB--force\fR +By default, when \fB-P\fR or \fB--pidfile\fR is specified and the +specified pidfile already exists and is locked by a running process, +\fBsecchan\fR refuses to start. Specify \fB-f\fR or \fB--force\fR +to cause it to instead overwrite the pidfile. + +When \fB-P\fR or \fB--pidfile\fR is not specified, this option has no +effect. + .TP \fB-D\fR, \fB--detach\fR Causes \fBsecchan\fR to detach itself from the foreground session and diff --git a/secchan/secchan.c b/secchan/secchan.c index e21454029..92d5ed73b 100644 --- a/secchan/secchan.c +++ b/secchan/secchan.c @@ -239,6 +239,7 @@ main(int argc, char *argv[]) fatal(retval, "Could not listen for vlog connections"); } + die_if_already_running(); daemonize(); VLOG_WARN("OpenFlow reference implementation version %s", VERSION); @@ -1361,7 +1362,7 @@ parse_options(int argc, char *argv[], struct settings *s) static struct option long_options[] = { {"accept-vconn", required_argument, 0, OPT_ACCEPT_VCONN}, {"no-resolv-conf", no_argument, 0, OPT_NO_RESOLV_CONF}, - {"fail", required_argument, 0, 'f'}, + {"fail", required_argument, 0, 'F'}, {"inactivity-probe", required_argument, 0, OPT_INACTIVITY_PROBE}, {"max-idle", required_argument, 0, OPT_MAX_IDLE}, {"max-backoff", required_argument, 0, OPT_MAX_BACKOFF}, @@ -1369,6 +1370,7 @@ parse_options(int argc, char *argv[], struct settings *s) {"rate-limit", optional_argument, 0, OPT_RATE_LIMIT}, {"burst-limit", required_argument, 0, OPT_BURST_LIMIT}, {"detach", no_argument, 0, 'D'}, + {"force", no_argument, 0, 'f'}, {"pidfile", optional_argument, 0, 'P'}, {"verbose", optional_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}, @@ -1406,7 +1408,7 @@ parse_options(int argc, char *argv[], struct settings *s) s->update_resolv_conf = false; break; - case 'f': + case 'F': if (!strcmp(optarg, "open")) { s->fail_mode = FAIL_OPEN; } else if (!strcmp(optarg, "closed")) { @@ -1471,6 +1473,10 @@ parse_options(int argc, char *argv[], struct settings *s) set_pidfile(optarg); break; + case 'f': + ignore_existing_pidfile(); + break; + case 'l': if (s->n_listeners >= MAX_MGMT) { fatal(0, "-l or --listen may be specified at most %d times", @@ -1586,7 +1592,7 @@ usage(void) " --accept-vconn=REGEX accept matching discovered controllers\n" " --no-resolv-conf do not update /etc/resolv.conf\n" "\nNetworking options:\n" - " -f, --fail=open|closed when controller connection fails:\n" + " -F, --fail=open|closed when controller connection fails:\n" " closed: drop all packets\n" " open (default): act as learning switch\n" " --inactivity-probe=SECS time between inactivity probes\n" @@ -1601,6 +1607,7 @@ usage(void) "\nOther options:\n" " -D, --detach run in background as daemon\n" " -P, --pidfile[=FILE] create pidfile (default: %s/secchan.pid)\n" + " -f, --force with -P, start even if already running\n" " -v, --verbose=MODULE[:FACILITY[:LEVEL]] set logging levels\n" " -v, --verbose set maximum verbosity level\n" " -h, --help display this help message\n" diff --git a/switch/switch.8.in b/switch/switch.8.in index 1bd0607a8..dfa114adf 100644 --- a/switch/switch.8.in +++ b/switch/switch.8.in @@ -91,6 +91,16 @@ the PID of the running process. If \fIpidfile\fR is not specified, or if it does not begin with \fB/\fR, then it is created in \fB@rundir@\fR. +.TP +\fB-f\fR, \fB--force\fR +By default, when \fB-P\fR or \fB--pidfile\fR is specified and the +specified pidfile already exists and is locked by a running process, +\fBswitch\fR refuses to start. Specify \fB-f\fR or \fB--force\fR +to cause it to instead overwrite the pidfile. + +When \fB-P\fR or \fB--pidfile\fR is not specified, this option has no +effect. + .TP \fB-D\fR, \fB--detach\fR Causes \fBswitch\fR to detach itself from the foreground session and diff --git a/switch/switch.c b/switch/switch.c index 61fbfb985..28a6b4277 100644 --- a/switch/switch.c +++ b/switch/switch.c @@ -126,6 +126,7 @@ main(int argc, char *argv[]) fatal(error, "could not listen for vlog connections"); } + die_if_already_running(); daemonize(); for (;;) { @@ -172,6 +173,7 @@ parse_options(int argc, char *argv[]) {"listen", required_argument, 0, 'l'}, {"detach", no_argument, 0, 'D'}, {"pidfile", optional_argument, 0, 'P'}, + {"force", no_argument, 0, 'f'}, {"verbose", optional_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, @@ -220,6 +222,10 @@ parse_options(int argc, char *argv[]) set_pidfile(optarg); break; + case 'f': + ignore_existing_pidfile(); + break; + case 'v': vlog_set_verbosity(optarg); break; @@ -292,6 +298,7 @@ usage(void) "\nOther options:\n" " -D, --detach run in background as daemon\n" " -P, --pidfile[=FILE] create pidfile (default: %s/switch.pid)\n" + " -f, --force with -P, start even if already running\n" " -v, --verbose=MODULE[:FACILITY[:LEVEL]] set logging levels\n" " -v, --verbose set maximum verbosity level\n" " -h, --help display this help message\n" diff --git a/utilities/ofp-discover.8.in b/utilities/ofp-discover.8.in index 19923a33b..694b3b932 100644 --- a/utilities/ofp-discover.8.in +++ b/utilities/ofp-discover.8.in @@ -83,6 +83,16 @@ The \fIpidfile\fR is created when \fBofp\-discover\fR detaches, so this this option has no effect when one of \fB--exit-without-bind\fR, \fB--exit-after-bind\fR, or \fB--no-detach\fR is also given. +.TP +\fB-f\fR, \fB--force\fR +By default, when \fB-P\fR or \fB--pidfile\fR is specified and the +specified pidfile already exists and is locked by a running process, +\fBcontroller\fR refuses to start. Specify \fB-f\fR or \fB--force\fR +to cause it to instead overwrite the pidfile. + +When \fB-P\fR or \fB--pidfile\fR is not specified, this option has no +effect. + .TP .BR \-h ", " \-\^\-help Prints a brief help message to the console. diff --git a/utilities/ofp-discover.c b/utilities/ofp-discover.c index 70c53ee82..646aec506 100644 --- a/utilities/ofp-discover.c +++ b/utilities/ofp-discover.c @@ -133,6 +133,8 @@ main(int argc, char *argv[]) fatal(retval, "Could not listen for vlog connections"); } + die_if_already_running(); + signal(SIGPIPE, SIG_IGN); for (;;) { fatal_signal_block(); @@ -302,6 +304,7 @@ parse_options(int argc, char *argv[]) {"no-detach", no_argument, 0, OPT_NO_DETACH}, {"timeout", required_argument, 0, 't'}, {"pidfile", optional_argument, 0, 'P'}, + {"force", no_argument, 0, 'f'}, {"verbose", optional_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, @@ -342,6 +345,10 @@ parse_options(int argc, char *argv[]) set_pidfile(optarg); break; + case 'f': + ignore_existing_pidfile(); + break; + case 't': timeout = strtoul(optarg, NULL, 10); if (timeout <= 0) { @@ -401,6 +408,7 @@ usage(void) "\nOther options:\n" " -t, --timeout=SECS give up discovery after SECS seconds\n" " -P, --pidfile[=FILE] create pidfile (default: %s/%s.pid)\n" + " -f, --force with -P, start even if already running\n" " -v, --verbose=MODULE[:FACILITY[:LEVEL]] set logging levels\n" " -v, --verbose set maximum verbosity level\n" " -h, --help display this help message\n"