/* Copyright 1989 Silicon Graphics, Inc. All Rights Reserved. */ /* Copyright (c) 1984 AT&T */ /* All Rights Reserved */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */ /* The copyright notice above does not evidence any */ /* actual or intended publication of such source code. */ #ident "$Revision: 1.27 $" /* * Go through the process table and kill all valid processes that * are not Process 0 (sched) or Process 1 (init) or that do not * have the current process group leader id. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern char *_sys_signames[]; /* * killall - Usage: killall [-v][-g][-k secs][-signame|[-]signal] [procname ...] */ #define MAXNAMES 1000 char dbgdir[] = _PATH_PROCFSPI; int nname = 0; /* # of names */ struct n { char *name; int found; int pid; } names[MAXNAMES]; int Debug = 0; int Verbose = 0; int Spgrp = 0; int Usesig = 0; int Slowkill = 0; static int cksigname(char *); static void Usage(void); static int killname(int); static int chksigno(char *); static int cksigname(char *); char cmd_label[] = "UX:killall"; struct kamsg { int flag; char *cmsg; char *dmsg; }; struct kamsg kausage[] = { { SGINL_USAGE, _SGI_DMMX_usage_killall, "killall [-v] [-g] [-k seconds] [-signame|[-]signal] [name ...]" }, { SGINL_USAGESPC, _SGI_DMMX_usage_killall_v, "-v = verbose" }, { SGINL_USAGESPC, _SGI_DMMX_usage_killall_g, "-g = send signal to process's group" }, { SGINL_USAGESPC, _SGI_DMMX_usage_killall_signal, "signal = send sig # 'signal' to process" }, { SGINL_USAGESPC, _SGI_DMMX_usage_killall_signame, "-signame = send signal 'signame' to process" }, { SGINL_USAGESPC, _SGI_DMMX_usage_killall_l, "-l = list signal names" }, { 0, 0, 0 }, }; static const cap_value_t kcaps[] = {CAP_KILL, CAP_MAC_WRITE}; static int kcaps_sz = (int) (sizeof (kcaps) / sizeof (kcaps[0])); static const cap_value_t ocaps[] = {CAP_MAC_READ}; static int ocaps_sz = (int) (sizeof (ocaps) / sizeof (ocaps[0])); /* * some message prints */ static void Usage(void) { register struct kamsg *ump; for(ump = kausage; ump->cmsg; ump++) { _sgi_nl_usage(ump->flag, cmd_label, gettxt(ump->cmsg, ump->dmsg)); } exit(-1); /* NOTREACHED */ } static void err_stat(char *s) { _sgi_nl_error(SGINL_SYSERR, cmd_label, gettxt(_SGI_DMMX_cannotstat, "Cannot stat %s"), s); } static void err_open(char *s) { _sgi_nl_error(SGINL_SYSERR, cmd_label, gettxt(_SGI_DMMX_CannotOpen, "Cannot open %s"), s); } static void err_ioctl(void) { _sgi_nl_error(SGINL_SYSERR, cmd_label, gettxt(_SGI_DMMX_Cannot_PIOCPSINFO, "Cannot ioctl() PIOCPSINFO")); } static void info_kill(int pid, char *name) { _sgi_ffmtmsg(stdout, 0, cmd_label, MM_INFO, gettxt(_SGI_DMMX_killall_info, "killing pid %d <%s> "), pid, name); } /* * main entry */ int main(int argc, char *argv[]) { register int sig, pgrp; cap_t ocap; const cap_value_t cap_shutdown = CAP_SHUTDOWN; /* * intnl support */ (void)setlocale(LC_ALL, ""); (void)setcat("uxsgicore"); (void)setlabel(cmd_label); if (argc == 1) { /* simple - kill all procs outside our pgrp with a SIGKILL */ sig = 9; } else { argc--; argv++; while (argv[0][0] == '-') { if (strcmp(argv[0], "-k") == 0) { if (argc <= 0) Usage(); Slowkill = atoi(argv[1]) * 100; argc--; argv++; } else if (strcmp(argv[0], "-d") == 0) Debug++; else if (strcmp(argv[0], "-g") == 0) Spgrp++; else if (strcmp(argv[0], "-v") == 0) Verbose++; else if ((sig = cksigname(&argv[0][1])) >= 0) Usesig++; else if ((sig = chksigno(&argv[0][1])) >= 0) Usesig++; else { _sgi_nl_error(SGINL_NOSYSERR, cmd_label, gettxt(_SGI_DMMX_invalid_arg, "invalid argument %s"), argv[0]); Usage(); /* not reached */ } argc--; argv++; if (argc <= 0) Usage(); } /* look for signal # - only if entirely a number and within * range consider it a signo - else a program name */ if (!Usesig) { if ((sig = chksigno(&argv[0][0])) >= 0) { argc--; argv++; } else { sig = 9; } } while (argc--) { if (Debug) _sgi_ffmtmsg(stdout, 0, cmd_label, MM_INFO, gettxt(_SGI_DMMX_add_name, "adding name <%s>"), *argv); names[nname].found = 0; names[nname++].name = *argv++; } } if (nname) { /* do by name */ if (Slowkill) { int rc; int t; int d; int i; rc = killname(Usesig?sig:SIGTERM); for (d = t = 0; t < Slowkill; t += d) { sginap(d); ocap = cap_acquire(kcaps_sz, kcaps); for (i = 0; i < nname; i++) if (names[i].found && !kill(names[i].pid,0)) break; else names[i].found = 0; cap_surrender(ocap); if (i == nname) exit(0); d += 10; } ocap = cap_acquire(kcaps_sz, kcaps); for (i = 0; i < nname; i++) if (names[i].found) { kill(names[i].pid,SIGKILL); sginap(0); } cap_surrender(ocap); exit(rc); } exit(killname(sig)); } if ((pgrp = getpgrp()) == -1) { _sgi_nl_error(SGINL_SYSERR, cmd_label, gettxt(_SGI_DMMX_cannot_getpgrp, "cannot getpgrp()")); exit(1); } ocap = cap_acquire(1, &cap_shutdown); if (uadmin(A_KILLALL, pgrp, sig) != 0) { if (errno == EPERM) _sgi_nl_error(SGINL_NOSYSERR, cmd_label, gettxt(_SGI_DMMX_MustBeSU, "Must be super-user")); else _sgi_nl_error(SGINL_SYSERR, cmd_label, gettxt(_SGI_DMMX_cannot_kill, "Cannot kill"), ""); cap_surrender(ocap); exit(1); } cap_surrender(ocap); return(0); } /* * killname - send signal to all processes with name in name array */ static int killname(int sig) { struct prpsinfo psinfo; int rv, rval = 0; int dids = 0; char pname[50]; int pdlen, j; DIR *dirp; struct dirent *dentp; int procfd; /* filedescriptor for /proc/pinfo/nnnnn */ struct ustat ustatb; struct stat statb; dev_t procdev; cap_t ocap; if (stat(dbgdir, &statb) < 0) { err_stat(dbgdir); exit(1); } procdev = statb.st_dev; if (stat("/", &statb) < 0) { err_stat("/"); exit(1); } if ((procdev == statb.st_dev) || (ustat(procdev, &ustatb) < 0)) { _sgi_nl_error(SGINL_NOSYSERR, cmd_label, gettxt(_SGI_DMMX_not_mounted, "%s is not mounted"), dbgdir); exit(1); } if ((dirp = opendir(dbgdir)) == NULL) { err_open(dbgdir); exit(1); } sprintf(pname, "%s%c", dbgdir, '/'); pdlen = strlen(pname); /* for each active process --- */ while (dentp = readdir(dirp)) { if (dentp->d_name[0] == '.') /* skip . and .. */ continue; (void) strcpy(pname + pdlen, dentp->d_name); retry: ocap = cap_acquire(ocaps_sz, ocaps); if ((procfd = open(pname, O_RDONLY)) == -1) { cap_surrender(ocap); continue; } cap_surrender(ocap); /* * Get the psinfo structure for the process and close quickly. */ if (ioctl(procfd, PIOCPSINFO, (char *) &psinfo) == -1) { int saverr = errno; (void) close(procfd); if (saverr == EACCES) continue; if (saverr == EAGAIN) goto retry; if (saverr != ENOENT) { errno = saverr; err_ioctl(); } continue; } (void) close(procfd); if ((psinfo.pr_state == 0) || (psinfo.pr_zomb)) continue; if (Debug) _sgi_ffmtmsg(stdout, 0, cmd_label, MM_INFO, gettxt(_SGI_DMMX_check_for, "checking for <%s> or <%s>"), psinfo.pr_fname, psinfo.pr_psargs); for (j = 0; j < nname; j++) { int namelen = strlen(names[j].name); if ((strcmp(names[j].name, psinfo.pr_fname) == 0) || ((strncmp(names[j].name, psinfo.pr_psargs, namelen) == 0) && (psinfo.pr_psargs[namelen] == '\0' || psinfo.pr_psargs[namelen] == ' '))) { dids++; names[j].found++; if (Debug || Verbose) info_kill(psinfo.pr_pid, psinfo.pr_fname); if (Spgrp) { ocap = cap_acquire(kcaps_sz, kcaps); rv = kill(-psinfo.pr_pid, sig); cap_surrender(ocap); names[j].pid = -psinfo.pr_pid; } else { ocap = cap_acquire(kcaps_sz, kcaps); rv = kill(psinfo.pr_pid, sig); cap_surrender(ocap); names[j].pid = psinfo.pr_pid; } if (rv < 0) rval = -1; if (Verbose || Debug) { if (rv < 0) { _sgi_nl_error(SGINL_SYSERR2, cmd_label, gettxt(_SGI_DMMX_killall_failed, "killing failed")); } } } } } /* * Report on any names not found if verbose */ if (Debug || Verbose) { for (j = 0; j < nname; j++) { if (names[j].found == 0) _sgi_nl_error(SGINL_NOSYSERR, cmd_label, gettxt(_SGI_DMMX_killall_pnotfnd, "process <%s> not found"), names[j].name); } } /* return error if ANY failures OR nothing done */ if (dids == 0) rval = -1; return(rval); } static int chksigno(char *s) { register char *sp = s; register char c; register int sig; while ((c = *sp++) != '\0') { if (!isdigit(c)) return(-1); } sig = atoi(s); if (sig < 0 || sig > NSIG) { _sgi_nl_error(SGINL_NOSYSERR, cmd_label, gettxt(_SGI_DMMX_bad_signalnbr, "bad signal # %s"), s); Usage(); /* no return */ } return(sig); } static int cksigname(char *name) { register int i; if (*name == 'l') { int printed = 0; /* * Print an abbreviated list of signal names. */ for (i = 1; i < NSIG; i++) { if (_sys_signames[i]) printed += printf("%s ", _sys_signames[i]); if (printed > 60) { putchar('\n'); printed = 0; } } putchar('\n'); exit(0); return(0); } else { for (i = 1; i < NSIG; i++) { if (_sys_signames[i] && !strcmp(name, _sys_signames[i])) { return(i); } } return(-1); } }