/* 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 "timeval.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]); time_init(); 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); } }