--- /dev/null
+.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)
--- /dev/null
+/* 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);
+ }
+}