From: Ben Pfaff Date: Fri, 13 Jun 2008 18:29:39 +0000 (-0700) Subject: Add --detach and --pidfile options to daemons. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fe867d8d718db8f1fa6c40813c30dac700b82909;p=openvswitch Add --detach and --pidfile options to daemons. --- diff --git a/Make.vars b/Make.vars index 538cde32..ceef15b7 100644 --- 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 diff --git a/controller/controller.c b/controller/controller.c index 0cc42589..b59d76b5 100644 --- a/controller/controller.c +++ b/controller/controller.c @@ -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); } diff --git a/include/Makefile.am b/include/Makefile.am index f6ee667d..6a839f2b 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -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 index 00000000..208cee9c --- /dev/null +++ b/include/daemon.h @@ -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 */ diff --git a/include/fatal-signal.h b/include/fatal-signal.h index a3a9c542..39d86fd5 100644 --- a/include/fatal-signal.h +++ b/include/fatal-signal.h @@ -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. * diff --git a/include/vlog.h b/include/vlog.h index 2e389f7b..1988e5e8 100644 --- a/include/vlog.h +++ b/include/vlog.h @@ -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) \ diff --git a/lib/Makefile.am b/lib/Makefile.am index 0ffc3fdc..bd86fa1a 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -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 index 00000000..e3c2b13e --- /dev/null +++ b/lib/daemon.c @@ -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 +#include +#include +#include +#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()); + } +} + diff --git a/lib/fatal-signal.c b/lib/fatal-signal.c index 0fc75cc2..43b27a39 100644 --- a/lib/fatal-signal.c +++ b/lib/fatal-signal.c @@ -123,6 +123,7 @@ fatal_signal_unblock() 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]); + } + } +} + +/* 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); + } } } diff --git a/secchan/secchan.c b/secchan/secchan.c index 2a2eef66..75d46ebc 100644 --- a/secchan/secchan.c +++ b/secchan/secchan.c @@ -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); } diff --git a/switch/switch.c b/switch/switch.c index f8f45bc3..148aa418 100644 --- a/switch/switch.c +++ b/switch/switch.c @@ -38,6 +38,7 @@ #include #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); }