New utility ofp-kill.
authorBen Pfaff <blp@nicira.com>
Wed, 23 Jul 2008 20:09:25 +0000 (13:09 -0700)
committerBen Pfaff <blp@nicira.com>
Wed, 23 Jul 2008 20:12:23 +0000 (13:12 -0700)
Needed for controller discovery in upcoming revision of ofp-switch-setup.

utilities/Makefile.am
utilities/ofp-kill.8.in [new file with mode: 0644]
utilities/ofp-kill.c [new file with mode: 0644]

index d9a8b28dbeaf222852305506167fb6c89c0dd421..0d682fee4d3e8136a4a406ae7a97f889e65bfefc 100644 (file)
@@ -1,14 +1,15 @@
 include ../Make.vars
 
-bin_PROGRAMS = vlogconf dpctl ofp-discover
+bin_PROGRAMS = vlogconf dpctl ofp-discover ofp-kill
 bin_SCRIPTS = ofp-pki
 noinst_SCRIPTS = ofp-pki-cgi
 
-EXTRA_DIST = ofp-pki.in ofp-pki-cgi.in ofp-pki.8.in ofp-discover.8.in
-DISTCLEANFILES = ofp-pki ofp-pki-cgi ofp-pki.8 ofp-discover.8
+EXTRA_DIST = ofp-pki.in ofp-pki-cgi.in ofp-pki.8.in ofp-discover.8.in  \
+ofp-kill.8.in
+DISTCLEANFILES = ofp-pki ofp-pki-cgi ofp-pki.8 ofp-discover.8 ofp-kill.8
 
 dist_man_MANS = vlogconf.8 dpctl.8
-man_MANS = ofp-pki.8 ofp-discover.8
+man_MANS = ofp-pki.8 ofp-discover.8 ofp-kill.8
 
 dpctl_SOURCES = dpctl.c
 dpctl_LDADD = ../lib/libopenflow.a $(FAULT_LIBS) $(SSL_LIBS)
@@ -19,6 +20,9 @@ vlogconf_LDADD = ../lib/libopenflow.a
 ofp_discover_SOURCES = ofp-discover.c
 ofp_discover_LDADD = ../lib/libopenflow.a
 
+ofp_kill_SOURCES = ofp-kill.c
+ofp_kill_LDADD = ../lib/libopenflow.a
+
 pkidir = $(pkgdatadir)/pki
 
 ofp-pki: ofp-pki.in Makefile
@@ -31,3 +35,5 @@ ofp-pki.8: ofp-pki.8.in Makefile
        ($(do_subst) && $(ro_man)) < $(srcdir)/ofp-pki.8.in > ofp-pki.8
 ofp-discover.8: ofp-discover.8.in Makefile
        ($(do_subst) && $(ro_man)) < $(srcdir)/ofp-discover.8.in > ofp-discover.8
+ofp-kill.8: ofp-kill.8.in Makefile
+       ($(do_subst) && $(ro_man)) < $(srcdir)/ofp-kill.8.in > ofp-kill.8
diff --git a/utilities/ofp-kill.8.in b/utilities/ofp-kill.8.in
new file mode 100644 (file)
index 0000000..122ff54
--- /dev/null
@@ -0,0 +1,65 @@
+.TH ofp\-kill 8 "May 2008" "OpenFlow" "OpenFlow Manual"
+
+.SH NAME
+ofp\-kill \- kills processes given their pidfiles
+
+.SH SYNOPSIS
+.B ofp\-kill
+[\fIoptions\fR] \fIpidfile\fR [\fIpidfile\fR...]
+
+.SH DESCRIPTION
+The \fBofp\-kill\fR program reads each \fIpidfile\fR specified on the
+command line and sends a signal to the program associated with it, if
+any.  It reads one line of text from \fIpidfile\fR, which must contain
+the PID of the process to kill as a text string.  It then uses
+\fBfcntl\fR(2) to verify that a process with the PID from the file
+owns a lock on \fIpidfile\fR before it sends the signal.
+
+A \fIpidfile\fR whose name begins with \fB/\fR is used literally.
+Otherwise, \fB@rundir@/\fR is prefixed.
+
+This program exists for use by \fBofp\-switch\-setup\fR, which cannot
+easily implement its functionality since Perl has no portable
+interface to \fBfcntl\fR-based file locking.
+
+.SH OPTIONS
+.TP
+\fB-s \fInumber\fR|\fIname\fR, \fB\-\^\-signal=\fInumber\fR|\fIname\fR
+Sets the signal to be sent to each process.  Signals may be given by
+number (e.g. \fB1\fR) or by name (e.g. \fBHUP\fR or \fBSIGHUP\fR).
+By default, \fBSIGTERM\fR is sent.
+
+.TP
+\fB-f\fR, \fB\-\^\-force\fR
+Causes \fBofp\-kill\fR to ignore all errors without printing a message
+to \fBstderr\fR, and to exit with return code 0.
+
+.TP
+.BR \-h ", " \-\^\-help
+Prints a brief help message to the console.
+
+.TP
+.BR \-V ", " \-\^\-version
+Prints version information to the console.
+
+.SH "EXIT CODE"
+
+Without \fB-f\fR or \fB\-\^\-force\fR, \fBofp\-kill\fR exits with
+status 0 if at least one \fIpidfile\fR was given and the process
+represented by every \fIpidfile\fR was signaled successfully,
+otherwise with status 1.
+
+With \fB-f\fR or \fB\-\^\-force\fR, \fBofp\-kill\fR always exits with
+status 0.
+
+.SH BUGS
+
+There is a race between verifying the lock on \fIpidfile\fR and
+actually killing the process.
+
+\fBofp\-kill\fR does not wait for the signaled processes to die before
+exiting.
+
+.SH "SEE ALSO"
+
+.BR ofp\-switch\-setup (8)
diff --git a/utilities/ofp-kill.c b/utilities/ofp-kill.c
new file mode 100644 (file)
index 0000000..9647f46
--- /dev/null
@@ -0,0 +1,258 @@
+/* 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 <config.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include "command-line.h"
+#include "daemon.h"
+#include "util.h"
+
+/* -s, --signal: signal to send. */
+static int sig_nr = SIGTERM;
+
+/* -f, --force: ignore errors. */
+static bool force;
+
+static void cond_error(int err_no, const char *, ...) PRINTF_FORMAT(2, 3);
+static bool kill_pidfile(const char *pidfile, FILE *);
+
+static void parse_options(int argc, char *argv[]);
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+    bool ok = true;
+    int i;
+
+    set_program_name(argv[0]);
+    parse_options(argc, argv);
+
+    argc -= optind;
+    argv += optind;
+    if (argc < 1) {
+        if (!force) {
+            fatal(0, "need at least one non-option argument; "
+                  "use --help for usage");
+        }
+    }
+
+    for (i = 0; i < argc; i++) {
+        char *pidfile;
+        FILE *file;
+
+        pidfile = make_pidfile_name(argv[i]);
+        file = fopen(pidfile, "r");
+        if (!file) {
+            ok = false;
+            cond_error(errno, "%s: open", pidfile);
+        } else {
+            ok = kill_pidfile(argv[i], file) && ok;
+            fclose(file);
+        }
+        free(pidfile);
+    }
+
+    return ok || force ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+static bool
+kill_pidfile(const char *pidfile, FILE *file)
+{
+    char line[128];
+    struct flock lck;
+
+    lck.l_type = F_WRLCK;
+    lck.l_whence = SEEK_SET;
+    lck.l_start = 0;
+    lck.l_len = 0;
+    if (fcntl(fileno(file), F_GETLK, &lck)) {
+        cond_error(errno, "%s: fcntl", pidfile); 
+        return false;
+    }
+
+    if (!fgets(line, sizeof line, file)) {
+        cond_error(errno, "%s: read", pidfile);
+        return false;
+    }
+
+    if (lck.l_pid != strtoul(line, NULL, 10)) {
+        cond_error(errno, "l_pid (%ld) != %s pid (%s)",
+                   (long int) lck.l_pid, pidfile, line);
+        return false;
+    }
+
+    if (kill(lck.l_pid, sig_nr) < 0) {
+        cond_error(errno, "%s: kill(%ld)", pidfile, (long int) lck.l_pid);
+        return false;
+    }
+
+    return true;
+}
+
+static void
+parse_options(int argc, char *argv[])
+{
+    static struct option long_options[] = {
+        {"signal",      required_argument, 0, 's'},
+        {"force",       no_argument, 0, 'f'},
+        {"help",        no_argument, 0, 'h'},
+        {"version",     no_argument, 0, 'V'},
+        {0, 0, 0, 0},
+    };
+    char *short_options = long_options_to_short_options(long_options);
+
+    for (;;) {
+        int c;
+
+        c = getopt_long(argc, argv, short_options, long_options, NULL);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+        case 's':
+            if (atoi(optarg) || !strcmp(optarg, "0")) {
+                sig_nr = atoi(optarg);
+            } else {
+                struct signal_name {
+                    const char *name;
+                    int number;
+                };
+
+                static const struct signal_name signals[] = {
+#define SIGNAL(NAME) { #NAME, NAME }
+                    SIGNAL(SIGABRT),
+                    SIGNAL(SIGALRM),
+                    SIGNAL(SIGBUS),
+                    SIGNAL(SIGCHLD),
+                    SIGNAL(SIGCONT),
+                    SIGNAL(SIGFPE),
+                    SIGNAL(SIGHUP),
+                    SIGNAL(SIGILL),
+                    SIGNAL(SIGINT),
+                    SIGNAL(SIGKILL),
+                    SIGNAL(SIGPIPE),
+                    SIGNAL(SIGQUIT),
+                    SIGNAL(SIGSEGV),
+                    SIGNAL(SIGSTOP),
+                    SIGNAL(SIGTERM),
+                    SIGNAL(SIGTSTP),
+                    SIGNAL(SIGTTIN),
+                    SIGNAL(SIGTTOU),
+                    SIGNAL(SIGUSR1),
+                    SIGNAL(SIGUSR2),
+#ifdef SIGPOLL
+                    SIGNAL(SIGPOLL),
+#endif
+                    SIGNAL(SIGPROF),
+                    SIGNAL(SIGSYS),
+                    SIGNAL(SIGTRAP),
+                    SIGNAL(SIGURG),
+                    SIGNAL(SIGVTALRM),
+                    SIGNAL(SIGXCPU),
+                    SIGNAL(SIGXFSZ),
+#undef SIGNAL
+                };
+                int i;
+
+                for (i = 0; i < ARRAY_SIZE(signals); i++) {
+                    const struct signal_name *s = &signals[i];
+                    if (!strcmp(optarg, s->name)
+                        || !strcmp(optarg, s->name + 3)) {
+                        sig_nr = s->number;
+                        goto got_name;
+                    }
+                }
+                fatal(0, "unknown signal \"%s\"", optarg);
+            got_name: ;
+            }
+            break;
+
+        case 'f':
+            force = true;
+            break;
+
+        case 'h':
+            usage();
+
+        case 'V':
+            printf("%s "VERSION" compiled "__DATE__" "__TIME__"\n", argv[0]);
+            exit(EXIT_SUCCESS);
+
+        case '?':
+            exit(EXIT_FAILURE);
+
+        default:
+            abort();
+        }
+    }
+    free(short_options);
+}
+
+static void
+usage(void)
+{
+    printf("%s: kills a program using a pidfile\n"
+           "usage: %s [OPTIONS] PIDFILE [PIDFILE...]\n"
+           "where each PIDFILE is a pidfile created by an OpenFlow daemon.\n"
+           "\nOptions:\n"
+           "  -s, --signal=NUMBER|NAME  signal to send (default: TERM)\n"
+           "  -f, --force             ignore errors\n"
+           "  -h, --help              display this help message\n"
+           "  -V, --version           display version information\n",
+           program_name, program_name);
+    exit(EXIT_SUCCESS);
+}
+
+static void
+cond_error(int err_no, const char *format, ...)
+{
+    if (!force) {
+        va_list args;
+
+        fprintf(stderr, "%s: ", program_name);
+        va_start(args, format);
+        vfprintf(stderr, format, args);
+        va_end(args);
+        if (err_no != 0)
+            fprintf(stderr, " (%s)", strerror(err_no));
+        putc('\n', stderr);
+    }
+}