diff options
Diffstat (limited to 'usr.bin/killall/killall.c')
| -rw-r--r-- | usr.bin/killall/killall.c | 437 |
1 files changed, 437 insertions, 0 deletions
diff --git a/usr.bin/killall/killall.c b/usr.bin/killall/killall.c new file mode 100644 index 000000000000..8f1b4bad80f2 --- /dev/null +++ b/usr.bin/killall/killall.c @@ -0,0 +1,437 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2000 Peter Wemm <peter@FreeBSD.org> + * Copyright (c) 2000 Paul Saab <ps@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/jail.h> +#include <sys/stat.h> +#include <sys/uio.h> +#include <sys/user.h> +#include <sys/sysctl.h> +#include <fcntl.h> +#include <dirent.h> +#include <jail.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <pwd.h> +#include <signal.h> +#include <regex.h> +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <unistd.h> +#include <locale.h> + +static void __dead2 +usage(void) +{ + + fprintf(stderr, "usage: killall [-delmsqvz] [-help] [-I] [-j jail]\n"); + fprintf(stderr, + " [-u user] [-t tty] [-c cmd] [-SIGNAL] [cmd]...\n"); + fprintf(stderr, "At least one option or argument to specify processes must be given.\n"); + exit(1); +} + + +static void +printsig(FILE *fp) +{ + const char *const * p; + int cnt; + int offset = 0; + + for (cnt = NSIG, p = sys_signame + 1; --cnt; ++p) { + offset += fprintf(fp, "%s ", *p); + if (offset >= 75 && cnt > 1) { + offset = 0; + fprintf(fp, "\n"); + } + } + fprintf(fp, "\n"); +} + +static void +nosig(char *name) +{ + + warnx("unknown signal %s; valid signals:", name); + printsig(stderr); + exit(1); +} + +int +main(int ac, char **av) +{ + char **saved_av; + struct kinfo_proc *procs, *newprocs; + struct stat sb; + struct passwd *pw; + regex_t rgx; + regmatch_t pmatch; + int i, j, ch; + char buf[256]; + char first; + char *user = NULL; + char *tty = NULL; + char *cmd = NULL; + int qflag = 0; + int vflag = 0; + int sflag = 0; + int dflag = 0; + int eflag = 0; + int Iflag = 0; + int jflag = 0; + int mflag = 0; + int zflag = 0; + uid_t uid = 0; + dev_t tdev = 0; + pid_t mypid; + char thiscmd[MAXCOMLEN + 1]; + pid_t thispid; + uid_t thisuid; + dev_t thistdev; + int sig = SIGTERM; + const char *const *p; + char *ep; + int errors = 0; + int jid; + int mib[4]; + size_t miblen; + int st, nprocs; + size_t size; + int matched; + int killed = 0; + + setlocale(LC_ALL, ""); + + av++; + ac--; + + while (ac > 0) { + if (strcmp(*av, "-l") == 0) { + printsig(stdout); + exit(0); + } + if (strcmp(*av, "-help") == 0) + usage(); + if (**av == '-') { + ++*av; + switch (**av) { + case 'j': + ++*av; + if (**av == '\0') { + ++av; + --ac; + } + jflag++; + if (*av == NULL) + errx(1, "must specify jail"); + jid = jail_getid(*av); + if (jid < 0) + errx(1, "%s", jail_errmsg); + if (jail_attach(jid) == -1) + err(1, "jail_attach(%d)", jid); + break; + case 'u': + ++*av; + if (**av == '\0') { + ++av; + --ac; + } + if (*av == NULL) + errx(1, "must specify user"); + user = *av; + break; + case 't': + ++*av; + if (**av == '\0') { + ++av; + --ac; + } + if (*av == NULL) + errx(1, "must specify tty"); + tty = *av; + break; + case 'c': + ++*av; + if (**av == '\0') { + ++av; + --ac; + } + if (*av == NULL) + errx(1, "must specify procname"); + cmd = *av; + break; + case 'q': + qflag++; + break; + case 'v': + vflag++; + break; + case 's': + sflag++; + break; + case 'd': + dflag++; + break; + case 'e': + eflag++; + break; + case 'm': + mflag++; + break; + case 'z': + zflag++; + break; + default: + saved_av = av; + if (isalpha((unsigned char)**av)) { + if (strncasecmp(*av, "SIG", 3) == 0) + *av += 3; + for (sig = NSIG, p = sys_signame + 1; + --sig; ++p) + if (strcasecmp(*p, *av) == 0) { + sig = p - sys_signame; + break; + } + if (!sig) { + if (**saved_av == 'I') { + av = saved_av; + Iflag = 1; + break; + } else + nosig(*av); + } + } else if (isdigit((unsigned char)**av)) { + sig = strtol(*av, &ep, 10); + if (!*av || *ep) + errx(1, "illegal signal number: %s", *av); + if (sig < 0 || sig >= NSIG) + nosig(*av); + } else + nosig(*av); + } + ++av; + --ac; + } else { + break; + } + } + + if (user == NULL && tty == NULL && cmd == NULL && !jflag && ac == 0) + usage(); + + if (tty) { + if (strncmp(tty, "/dev/", 5) == 0) + snprintf(buf, sizeof(buf), "%s", tty); + else if (strncmp(tty, "tty", 3) == 0 || + strncmp(tty, "pts/", 4) == 0) + snprintf(buf, sizeof(buf), "/dev/%s", tty); + else + snprintf(buf, sizeof(buf), "/dev/tty%s", tty); + if (stat(buf, &sb) < 0) + err(1, "stat(%s)", buf); + if (!S_ISCHR(sb.st_mode)) + errx(1, "%s: not a character device", buf); + tdev = sb.st_rdev; + if (dflag) + printf("ttydev:0x%jx\n", (uintmax_t)tdev); + } + if (user) { + uid = strtol(user, &ep, 10); + if (*user == '\0' || *ep != '\0') { /* was it a number? */ + pw = getpwnam(user); + if (pw == NULL) + errx(1, "user %s does not exist", user); + uid = pw->pw_uid; + if (dflag) + printf("uid:%d\n", uid); + } + } else { + uid = getuid(); + if (uid != 0) { + pw = getpwuid(uid); + if (pw) + user = pw->pw_name; + if (dflag) + printf("uid:%d\n", uid); + } + } + size = 0; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + + if (user) { + mib[2] = eflag ? KERN_PROC_UID : KERN_PROC_RUID; + mib[3] = uid; + miblen = 4; + } else if (tty) { + mib[2] = KERN_PROC_TTY; + mib[3] = tdev; + miblen = 4; + } else { + mib[2] = KERN_PROC_PROC; + mib[3] = 0; + miblen = 3; + } + + procs = NULL; + st = sysctl(mib, miblen, NULL, &size, NULL, 0); + do { + size += size / 10; + newprocs = realloc(procs, size); + if (newprocs == NULL) { + free(procs); + err(1, "could not reallocate memory"); + } + procs = newprocs; + st = sysctl(mib, miblen, procs, &size, NULL, 0); + } while (st == -1 && errno == ENOMEM); + if (st == -1) + err(1, "could not sysctl(KERN_PROC)"); + if (size % sizeof(struct kinfo_proc) != 0) { + fprintf(stderr, "proc size mismatch (%zu total, %zu chunks)\n", + size, sizeof(struct kinfo_proc)); + fprintf(stderr, "userland out of sync with kernel\n"); + exit(1); + } + nprocs = size / sizeof(struct kinfo_proc); + if (dflag) + printf("nprocs %d\n", nprocs); + mypid = getpid(); + + for (i = 0; i < nprocs; i++) { + if (procs[i].ki_stat == SZOMB && !zflag) + continue; + thispid = procs[i].ki_pid; + strlcpy(thiscmd, procs[i].ki_comm, sizeof(thiscmd)); + thistdev = procs[i].ki_tdev; + if (eflag) + thisuid = procs[i].ki_uid; /* effective uid */ + else + thisuid = procs[i].ki_ruid; /* real uid */ + + if (thispid == mypid) + continue; + matched = 1; + if (user) { + if (thisuid != uid) + matched = 0; + } + if (tty) { + if (thistdev != tdev) + matched = 0; + } + if (cmd) { + if (mflag) { + if (regcomp(&rgx, cmd, + REG_EXTENDED|REG_NOSUB) != 0) { + mflag = 0; + warnx("%s: illegal regexp", cmd); + } + } + if (mflag) { + pmatch.rm_so = 0; + pmatch.rm_eo = strlen(thiscmd); + if (regexec(&rgx, thiscmd, 0, &pmatch, + REG_STARTEND) != 0) + matched = 0; + regfree(&rgx); + } else { + if (strncmp(thiscmd, cmd, MAXCOMLEN) != 0) + matched = 0; + } + } + if (jflag && thispid == getpid()) + matched = 0; + if (matched == 0) + continue; + if (ac > 0) + matched = 0; + for (j = 0; j < ac; j++) { + if (mflag) { + if (regcomp(&rgx, av[j], + REG_EXTENDED|REG_NOSUB) != 0) { + mflag = 0; + warnx("%s: illegal regexp", av[j]); + } + } + if (mflag) { + pmatch.rm_so = 0; + pmatch.rm_eo = strlen(thiscmd); + if (regexec(&rgx, thiscmd, 0, &pmatch, + REG_STARTEND) == 0) + matched = 1; + regfree(&rgx); + } else { + if (strcmp(thiscmd, av[j]) == 0) + matched = 1; + } + if (matched) + break; + } + if (matched != 0 && Iflag) { + printf("Send signal %d to %s (pid %d uid %d)? ", + sig, thiscmd, thispid, thisuid); + fflush(stdout); + first = ch = getchar(); + while (ch != '\n' && ch != EOF) + ch = getchar(); + if (first != 'y' && first != 'Y') + matched = 0; + } + if (matched == 0) + continue; + if (dflag) + printf("sig:%d, cmd:%s, pid:%d, dev:0x%jx uid:%d\n", + sig, thiscmd, thispid, (uintmax_t)thistdev, + thisuid); + + if (vflag || sflag) + printf("kill -%s %d\n", sys_signame[sig], thispid); + + killed++; + if (!dflag && !sflag) { + if (kill(thispid, sig) < 0 /* && errno != ESRCH */ ) { + warn("warning: kill -%s %d", + sys_signame[sig], thispid); + errors = 1; + } + } + } + if (killed == 0) { + if (!qflag) + fprintf(stderr, "No matching processes %swere found\n", + getuid() != 0 ? "belonging to you " : ""); + errors = 1; + } + exit(errors); +} |
