Add --detach and --pidfile options to daemons.
authorBen Pfaff <blp@nicira.com>
Fri, 13 Jun 2008 18:29:39 +0000 (11:29 -0700)
committerBen Pfaff <blp@nicira.com>
Fri, 13 Jun 2008 20:03:51 +0000 (13:03 -0700)
Make.vars
controller/controller.c
include/Makefile.am
include/daemon.h [new file with mode: 0644]
include/fatal-signal.h
include/vlog.h
lib/Makefile.am
lib/daemon.c [new file with mode: 0644]
lib/fatal-signal.c
secchan/secchan.c
switch/switch.c

index 538cde328e348cbd3b3aae7557c0d17c0a9a7afb..ceef15b73f287d32c497e92b0989685f312ad0a0 100644 (file)
--- a/Make.vars
+++ b/Make.vars
@@ -11,6 +11,9 @@ endif
 AM_CFLAGS = $(COMMON_FLAGS)
 AM_CFLAGS += -Wstrict-prototypes -I $(top_srcdir)/include
 
+rundir = $(localstatedir)/run
+AM_CFLAGS += -DRUNDIR=\"$(rundir)\"
+
 if !NDEBUG
 AM_LDFLAGS = -export-dynamic
 endif
index 0cc42589f5e29897c4269869da1c92cb491b6f63..b59d76b583c8d0caab9cc843c17f190334814edf 100644 (file)
@@ -39,6 +39,7 @@
 #include "buffer.h"
 #include "command-line.h"
 #include "compiler.h"
+#include "daemon.h"
 #include "fault.h"
 #include "learning-switch.h"
 #include "poll-loop.h"
@@ -121,6 +122,8 @@ main(int argc, char *argv[])
         fatal(0, "no active or passive switch connections");
     }
 
+    daemonize();
+
     while (n_switches > 0 || n_listeners > 0) {
         int iteration;
         int i;
@@ -213,6 +216,8 @@ static void
 parse_options(int argc, char *argv[])
 {
     static struct option long_options[] = {
+        {"detach",      no_argument, 0, 'D'},
+        {"pidfile",     optional_argument, 0, 'P'},
         {"hub",         no_argument, 0, 'H'},
         {"noflow",      no_argument, 0, 'n'},
         {"verbose",     optional_argument, 0, 'v'},
@@ -233,6 +238,14 @@ parse_options(int argc, char *argv[])
         }
 
         switch (c) {
+        case 'D':
+            set_detach();
+            break;
+
+        case 'P':
+            set_pidfile(optarg ? optarg : "controller.pid");
+            break;
+
         case 'H':
             learn_macs = false;
             break;
@@ -273,10 +286,13 @@ usage(void)
            program_name, program_name);
     vconn_usage(true, true);
     printf("\nOther options:\n"
+           "  -D, --detach            run in background as daemon\n"
+           "  -P, --pidfile[=FILE]    create pidfile (default: %s/controller.pid)\n"
            "  -H, --hub               act as hub instead of learning switch\n"
            "  -n, --noflow            pass traffic, but don't add flows\n"
            "  -v, --verbose           set maximum verbosity level\n"
            "  -h, --help              display this help message\n"
-           "  -V, --version           display version information\n");
+           "  -V, --version           display version information\n",
+           RUNDIR);
     exit(EXIT_SUCCESS);
 }
index f6ee667d633c798f5bfef91d24d6c7afa43a506d..6a839f2b2e56ff608ed8ff610c83a3786d6afe70 100644 (file)
@@ -2,6 +2,7 @@ noinst_HEADERS = \
        buffer.h \
        command-line.h \
        compiler.h \
+       daemon.h \
        dynamic-string.h \
        dpif.h \
        fatal-signal.h \
diff --git a/include/daemon.h b/include/daemon.h
new file mode 100644 (file)
index 0000000..208cee9
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford
+ * Junior University
+ *
+ * We are making the OpenFlow specification and associated documentation
+ * (Software) available for public use and benefit with the expectation
+ * that others will use, modify and enhance the Software and contribute
+ * those enhancements back to the community. However, since we would
+ * like to make the Software available for broadest use, with as few
+ * restrictions as possible permission is hereby granted, free of
+ * charge, to any person obtaining a copy of this Software to deal in
+ * the Software under the copyrights without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The name and trademarks of copyright holder(s) may NOT be used in
+ * advertising or publicity pertaining to the Software or any
+ * derivatives without specific, written prior permission.
+ */
+
+#ifndef DAEMON_H
+#define DAEMON_H 1
+
+void set_pidfile(const char *name);
+void set_detach(void);
+void daemonize(void);
+
+#endif /* daemon.h */
index a3a9c542f81c9543730f15a50335df0dc983d741..39d86fd515e51a70c2c9537cfb0dea48562156a8 100644 (file)
@@ -38,6 +38,7 @@
 void fatal_signal_add_hook(void (*)(void *aux), void *aux);
 void fatal_signal_block(void);
 void fatal_signal_unblock(void);
+void fatal_signal_fork(void);
 
 /* Convenience functions for unlinking files upon termination.
  *
index 2e389f7be90b5f2ca0762ec18c40e29f26eb13fe..1988e5e8e3d0276cba8ab2eaf70b85e9ae966f91 100644 (file)
@@ -64,6 +64,7 @@ enum vlog_facility vlog_get_facility_val(const char *name);
         VLOG_MODULE(chain)                      \
         VLOG_MODULE(controller)                 \
         VLOG_MODULE(ctlpath)                    \
+        VLOG_MODULE(daemon)                     \
         VLOG_MODULE(datapath)                   \
         VLOG_MODULE(dpif)                       \
         VLOG_MODULE(dpctl)                      \
index 0ffc3fdcb2da573c7f144fe67e33514c3516a76f..bd86fa1a3a9caa08dd34d54a157a4699d133fad2 100644 (file)
@@ -5,6 +5,7 @@ noinst_LTLIBRARIES = libopenflow.la
 libopenflow_la_SOURCES = \
        buffer.c \
        command-line.c \
+       daemon.c \
        dynamic-string.c \
        fatal-signal.c \
        fault.c \
diff --git a/lib/daemon.c b/lib/daemon.c
new file mode 100644 (file)
index 0000000..e3c2b13
--- /dev/null
@@ -0,0 +1,121 @@
+/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford
+ * Junior University
+ *
+ * We are making the OpenFlow specification and associated documentation
+ * (Software) available for public use and benefit with the expectation
+ * that others will use, modify and enhance the Software and contribute
+ * those enhancements back to the community. However, since we would
+ * like to make the Software available for broadest use, with as few
+ * restrictions as possible permission is hereby granted, free of
+ * charge, to any person obtaining a copy of this Software to deal in
+ * the Software under the copyrights without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The name and trademarks of copyright holder(s) may NOT be used in
+ * advertising or publicity pertaining to the Software or any
+ * derivatives without specific, written prior permission.
+ */
+
+#include "daemon.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "fatal-signal.h"
+#include "util.h"
+
+#define THIS_MODULE VLM_daemon
+#include "vlog.h"
+
+/* Should we run in the background? */
+static bool detach;
+
+/* Name of pidfile (null if none). */
+static char *pidfile;
+
+/* 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
+ * default. */
+void
+set_pidfile(const char *name)
+{
+    free(pidfile);
+    pidfile = *name == '/' ? xstrdup(name) : xasprintf("%s/%s", RUNDIR, name);
+}
+
+/* Sets up a following call to daemonize() to detach from the foreground
+ * session, running this process in the background.  */
+void
+set_detach(void)
+{
+    detach = true;
+}
+
+/* If a pidfile has been configured, creates it and stores 'pid' in it.  It is
+ * the caller's responsibility to make sure that the pidfile will eventually
+ * be deleted. */
+static void
+make_pidfile(pid_t pid)
+{
+    if (pidfile) {
+        FILE *file;
+
+        file = fopen(pidfile, "w");
+        if (file) {
+            fprintf(file, "%ld\n", (long int) pid);
+            fclose(file);
+        } else {
+            VLOG_ERR("failed to create \"%s\": %s", pidfile, strerror(errno));
+        }
+        free(pidfile);
+        pidfile = NULL;
+    }
+}
+
+/* If configured with set_pidfile() or set_detach(), creates the pid file and
+ * detaches from the foreground session.  */
+void
+daemonize(void)
+{
+    if (detach) {
+        pid_t pid;
+
+        /* Fork and exit from the parent. */
+        pid = fork();
+        if (pid < 0) {
+            fatal(errno, "could not fork");
+        } else if (pid) {
+            fatal_signal_fork();
+            make_pidfile(pid);
+            exit(0);
+        }
+
+        if (pidfile) {
+            fatal_signal_add_file_to_unlink(pidfile);
+        }
+        setsid();
+        chdir("/");
+    } else {
+        if (pidfile) {
+            fatal_signal_add_file_to_unlink(pidfile);
+        }
+        make_pidfile(getpid());
+    }
+}
+
index 0fc75cc29a9947d316dd4cad11be0abbd78c1571..43b27a39a0d0e3b1311eb54402b4fb2e43f8744d 100644 (file)
@@ -123,6 +123,7 @@ fatal_signal_unblock()
 \f
 static char **files;
 static size_t n_files, max_files;
+static bool disabled;
 
 static void unlink_files(void *aux);
 static void do_unlink_files(void);
@@ -169,16 +170,37 @@ fatal_signal_remove_file_to_unlink(const char *file)
 static void
 unlink_files(void *aux UNUSED)
 {
-    do_unlink_files();
+    do_unlink_files(); 
 }
 
 static void
 do_unlink_files(void)
+{
+    if (!disabled) {
+        size_t i;
+
+        for (i = 0; i < n_files; i++) {
+            unlink(files[i]);
+        }
+    }
+}
+\f
+/* Disables the fatal signal hook mechanism.  Following a fork, one of the
+ * resulting processes can call this function to allow it to terminate without
+ * triggering fatal signal processing or removing files.  Fatal signal
+ * processing is still enabled in the other process. */
+void
+fatal_signal_fork(void)
 {
     size_t i;
 
-    for (i = 0; i < n_files; i++) {
-        unlink(files[i]);
+    disabled = true;
+
+    for (i = 0; i < ARRAY_SIZE(fatal_signals); i++) {
+        int sig_nr = fatal_signals[i];
+        if (signal(sig_nr, SIG_DFL) == SIG_IGN) {
+            signal(sig_nr, SIG_IGN);
+        }
     }
 }
 \f
index 2a2eef6683d9c34cbceb5abe492c98279e73e106..75d46ebccf4223876e82d54079f5e373c9833068 100644 (file)
@@ -44,6 +44,7 @@
 #include "buffer.h"
 #include "command-line.h"
 #include "compiler.h"
+#include "daemon.h"
 #include "fault.h"
 #include "flow.h"
 #include "learning-switch.h"
@@ -187,6 +188,8 @@ main(int argc, char *argv[])
         fatal(retval, "Could not listen for vlog connections");
     }
 
+    daemonize();
+
     relay_create(rconn_new(argv[optind], 1), rconn_new(argv[optind + 1], 1),
                  false);
     for (;;) {
@@ -466,6 +469,8 @@ parse_options(int argc, char *argv[])
         {"fail",        required_argument, 0, 'f'},
         {"fail-open-delay", required_argument, 0, 'd'},
         {"listen",      required_argument, 0, 'l'},
+        {"detach",      no_argument, 0, 'D'},
+        {"pidfile",     optional_argument, 0, 'P'},
         {"verbose",     optional_argument, 0, 'v'},
         {"help",        no_argument, 0, 'h'},
         {"version",     no_argument, 0, 'V'},
@@ -502,6 +507,14 @@ parse_options(int argc, char *argv[])
             }
             break;
 
+        case 'D':
+            set_detach();
+            break;
+
+        case 'P':
+            set_pidfile(optarg ? optarg : "secchan.pid");
+            break;
+
         case 'l':
             if (listen_vconn_name) {
                 fatal(0, "-l or --listen may be only specified once");
@@ -549,8 +562,11 @@ usage(void)
            "  -l, --listen=METHOD     allow management connections on METHOD\n"
            "                          (a passive OpenFlow connection method)\n"
            "\nOther options:\n"
+           "  -D, --detach            run in background as daemon\n"
+           "  -P, --pidfile[=FILE]    create pidfile (default: %s/secchan.pid)\n"
            "  -v, --verbose           set maximum verbosity level\n"
            "  -h, --help              display this help message\n"
-           "  -V, --version           display version information\n");
+           "  -V, --version           display version information\n",
+           RUNDIR);
     exit(EXIT_SUCCESS);
 }
index f8f45bc3c1430c624cd96dace97a66c941826ce1..148aa418f32e67d5c83d552ba32a128a2e4790e7 100644 (file)
@@ -38,6 +38,7 @@
 #include <string.h>
 
 #include "command-line.h"
+#include "daemon.h"
 #include "datapath.h"
 #include "fault.h"
 #include "openflow.h"
@@ -102,6 +103,8 @@ main(int argc, char *argv[])
         fatal(error, "could not listen for vlog connections");
     }
 
+    daemonize();
+
     for (;;) {
         dp_run(dp);
         dp_wait(dp);
@@ -136,6 +139,8 @@ parse_options(int argc, char *argv[])
         {"interfaces",  required_argument, 0, 'i'},
         {"datapath-id", required_argument, 0, 'd'},
         {"listen",      required_argument, 0, 'l'},
+        {"detach",      no_argument, 0, 'D'},
+        {"pidfile",     optional_argument, 0, 'P'},
         {"verbose",     optional_argument, 0, 'v'},
         {"help",        no_argument, 0, 'h'},
         {"version",     no_argument, 0, 'V'},
@@ -173,6 +178,14 @@ parse_options(int argc, char *argv[])
             printf("%s "VERSION" compiled "__DATE__" "__TIME__"\n", argv[0]);
             exit(EXIT_SUCCESS);
 
+        case 'D':
+            set_detach();
+            break;
+
+        case 'P':
+            set_pidfile(optarg ? optarg : "switch.pid");
+            break;
+
         case 'v':
             vlog_set_verbosity(optarg);
             break;
@@ -220,8 +233,11 @@ usage(void)
            "  -l, --listen=METHOD     allow management connections on METHOD\n"
            "                          (a passive OpenFlow connection method)\n"
            "\nOther options:\n"
+           "  -D, --detach            run in background as daemon\n"
+           "  -P, --pidfile[=FILE]    create pidfile (default: %s/switch.pid)\n"
            "  -v, --verbose           set maximum verbosity level\n"
            "  -h, --help              display this help message\n"
-           "  -V, --version           display version information\n");
+           "  -V, --version           display version information\n",
+        RUNDIR);
     exit(EXIT_SUCCESS);
 }