From a1255475a43a74f2c4719fbb4714feb4bc75b473 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Wed, 23 Jul 2008 13:09:25 -0700 Subject: [PATCH] New utility ofp-kill. Needed for controller discovery in upcoming revision of ofp-switch-setup. --- utilities/Makefile.am | 14 ++- utilities/ofp-kill.8.in | 65 ++++++++++ utilities/ofp-kill.c | 258 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 333 insertions(+), 4 deletions(-) create mode 100644 utilities/ofp-kill.8.in create mode 100644 utilities/ofp-kill.c diff --git a/utilities/Makefile.am b/utilities/Makefile.am index d9a8b28d..0d682fee 100644 --- a/utilities/Makefile.am +++ b/utilities/Makefile.am @@ -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 index 00000000..122ff541 --- /dev/null +++ b/utilities/ofp-kill.8.in @@ -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 index 00000000..9647f466 --- /dev/null +++ b/utilities/ofp-kill.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#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); + } +} -- 2.30.2