Make -P or --pidfile keep programs from running if already running.
authorBen Pfaff <blp@nicira.com>
Thu, 28 Aug 2008 20:17:16 +0000 (13:17 -0700)
committerBen Pfaff <blp@nicira.com>
Thu, 28 Aug 2008 20:17:16 +0000 (13:17 -0700)
controller/controller.8.in
controller/controller.c
include/daemon.h
lib/daemon.c
secchan/secchan.8.in
secchan/secchan.c
switch/switch.8.in
switch/switch.c
utilities/ofp-discover.8.in
utilities/ofp-discover.c

index a829951956ff65dca8c410c2909cbdc97bae344b..2781fdebf76da0069998063fbb517e3115004a89 100644 (file)
@@ -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
index 01037bbb0d93851ec37b2ef6df14f8e14292f61e..2d79afaa4fd58bb4c06c16bd73fc5ea1119c2572 100644 (file)
@@ -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"
index d7273e02666a583c487905cff42db6f18f0185bf..ee6b0f0fadca4566a00348e6455467313270c3d3 100644 (file)
 #ifndef DAEMON_H
 #define DAEMON_H 1
 
+#include <stdbool.h>
+
 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 */
index 58581b77890d5d48abd6dc3ceb61300f2d3b7b4d..22339f915800bf3f6a124c09498e3e5495387e24 100644 (file)
@@ -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. */
index 620c59f91686bb2cac1af045999a0e6a61ddfcc3..e3d297e11d4b525a00df750ffb48820e54939784 100644 (file)
@@ -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
index e21454029e1ea353e585e7deb50aff9fbda18f24..92d5ed73b747592c6c096f8950a962b3f181cfd8 100644 (file)
@@ -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"
index 1bd0607a8c6fb1c530f17d5f91759fd3e5115e55..dfa114adfaa2495c319648d273a772b684c1cb55 100644 (file)
@@ -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
index 61fbfb98590b07c3b16b2fa72903587ad7790d21..28a6b427773f2796a3970db4fdcaa226061395d8 100644 (file)
@@ -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"
index 19923a33bd3de65b1ad8f5ab255b7fe7f1620567..694b3b932e5b8530f0ad3f9615c2d5748f54f5eb 100644 (file)
@@ -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.
index 70c53ee82c4f63f892ce76fbcc2de82ea6a6223c..646aec5064756a0f7facff5c339575e564518bb5 100644 (file)
@@ -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"