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 a829951..2781fde 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 01037bb..2d79afa 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 d7273e0..ee6b0f0 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 58581b7..22339f9 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 620c59f..e3d297e 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 e214540..92d5ed7 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 1bd0607..dfa114a 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 61fbfb9..28a6b42 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 19923a3..694b3b9 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 70c53ee..646aec5 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"