]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/killall/killall.c
This commit was generated by cvs2svn to compensate for changes in r165538,
[FreeBSD/FreeBSD.git] / usr.bin / killall / killall.c
1 /*-
2  * Copyright (c) 2000 Peter Wemm <peter@FreeBSD.org>
3  * Copyright (c) 2000 Paul Saab <ps@FreeBSD.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/param.h>
32 #include <sys/jail.h>
33 #include <sys/stat.h>
34 #include <sys/user.h>
35 #include <sys/sysctl.h>
36 #include <fcntl.h>
37 #include <dirent.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <pwd.h>
42 #include <signal.h>
43 #include <regex.h>
44 #include <ctype.h>
45 #include <err.h>
46 #include <errno.h>
47 #include <unistd.h>
48 #include <locale.h>
49
50 static void __dead2
51 usage(void)
52 {
53
54         fprintf(stderr, "usage: killall [-delmsvz] [-help] [-j jid]\n");
55         fprintf(stderr,
56             "               [-u user] [-t tty] [-c cmd] [-SIGNAL] [cmd]...\n");
57         fprintf(stderr, "At least one option or argument to specify processes must be given.\n");
58         exit(1);
59 }
60
61 static char *
62 upper(const char *str)
63 {
64         static char buf[80];
65         char *s;
66
67         strncpy(buf, str, sizeof(buf));
68         buf[sizeof(buf) - 1] = '\0';
69         for (s = buf; *s; s++)
70                 *s = toupper((unsigned char)*s);
71         return buf;
72 }
73
74
75 static void
76 printsig(FILE *fp)
77 {
78         const char      *const * p;
79         int             cnt;
80         int             offset = 0;
81
82         for (cnt = NSIG, p = sys_signame + 1; --cnt; ++p) {
83                 offset += fprintf(fp, "%s ", upper(*p));
84                 if (offset >= 75 && cnt > 1) {
85                         offset = 0;
86                         fprintf(fp, "\n");
87                 }
88         }
89         fprintf(fp, "\n");
90 }
91
92 static void
93 nosig(char *name)
94 {
95
96         warnx("unknown signal %s; valid signals:", name);
97         printsig(stderr);
98         exit(1);
99 }
100
101 int
102 main(int ac, char **av)
103 {
104         struct kinfo_proc *procs = NULL, *newprocs;
105         struct stat     sb;
106         struct passwd   *pw;
107         regex_t         rgx;
108         regmatch_t      pmatch;
109         int             i, j;
110         char            buf[256];
111         char            *user = NULL;
112         char            *tty = NULL;
113         char            *cmd = NULL;
114         int             vflag = 0;
115         int             sflag = 0;
116         int             dflag = 0;
117         int             eflag = 0;
118         int             jflag = 0;
119         int             mflag = 0;
120         int             zflag = 0;
121         uid_t           uid = 0;
122         dev_t           tdev = 0;
123         pid_t           mypid;
124         char            thiscmd[MAXCOMLEN + 1];
125         pid_t           thispid;
126         uid_t           thisuid;
127         dev_t           thistdev;
128         int             sig = SIGTERM;
129         const char *const *p;
130         char            *ep;
131         int             errors = 0;
132         int             jid;
133         int             mib[4];
134         size_t          miblen;
135         int             st, nprocs;
136         size_t          size;
137         int             matched;
138         int             killed = 0;
139
140         setlocale(LC_ALL, "");
141
142         av++;
143         ac--;
144
145         while (ac > 0) {
146                 if (strcmp(*av, "-l") == 0) {
147                         printsig(stdout);
148                         exit(0);
149                 }
150                 if (strcmp(*av, "-help") == 0)
151                         usage();
152                 if (**av == '-') {
153                         ++*av;
154                         switch (**av) {
155                         case 'j':
156                                 ++*av;
157                                 if (**av == '\0')
158                                         ++av;
159                                 --ac;
160                                 jflag++;
161                                 if (!*av)
162                                         errx(1, "must specify jid");
163                                 jid = strtol(*av, &ep, 10);
164                                 if (!*av || *ep)
165                                         errx(1, "illegal jid: %s", *av);
166                                 if (jail_attach(jid) == -1)
167                                         err(1, "jail_attach(): %d", jid);
168                                 break;
169                         case 'u':
170                                 ++*av;
171                                 if (**av == '\0')
172                                         ++av;
173                                 --ac;
174                                 user = *av;
175                                 break;
176                         case 't':
177                                 ++*av;
178                                 if (**av == '\0')
179                                         ++av;
180                                 --ac;
181                                 tty = *av;
182                                 break;
183                         case 'c':
184                                 ++*av;
185                                 if (**av == '\0')
186                                         ++av;
187                                 --ac;
188                                 cmd = *av;
189                                 break;
190                         case 'v':
191                                 vflag++;
192                                 break;
193                         case 's':
194                                 sflag++;
195                                 break;
196                         case 'd':
197                                 dflag++;
198                                 break;
199                         case 'e':
200                                 eflag++;
201                                 break;
202                         case 'm':
203                                 mflag++;
204                                 break;
205                         case 'z':
206                                 zflag++;
207                                 break;
208                         default:
209                                 if (isalpha((unsigned char)**av)) {
210                                         if (strncasecmp(*av, "sig", 3) == 0)
211                                                 *av += 3;
212                                         for (sig = NSIG, p = sys_signame + 1;
213                                              --sig; ++p)
214                                                 if (strcasecmp(*p, *av) == 0) {
215                                                         sig = p - sys_signame;
216                                                         break;
217                                                 }
218                                         if (!sig)
219                                                 nosig(*av);
220                                 } else if (isdigit((unsigned char)**av)) {
221                                         sig = strtol(*av, &ep, 10);
222                                         if (!*av || *ep)
223                                                 errx(1, "illegal signal number: %s", *av);
224                                         if (sig < 0 || sig >= NSIG)
225                                                 nosig(*av);
226                                 } else
227                                         nosig(*av);
228                         }
229                         ++av;
230                         --ac;
231                 } else {
232                         break;
233                 }
234         }
235
236         if (user == NULL && tty == NULL && cmd == NULL && !jflag && ac == 0)
237                 usage();
238
239         if (tty) {
240                 if (strncmp(tty, "/dev/", 5) == 0)
241                         snprintf(buf, sizeof(buf), "%s", tty);
242                 else if (strncmp(tty, "tty", 3) == 0)
243                         snprintf(buf, sizeof(buf), "/dev/%s", tty);
244                 else
245                         snprintf(buf, sizeof(buf), "/dev/tty%s", tty);
246                 if (stat(buf, &sb) < 0)
247                         err(1, "stat(%s)", buf);
248                 if (!S_ISCHR(sb.st_mode))
249                         errx(1, "%s: not a character device", buf);
250                 tdev = sb.st_rdev;
251                 if (dflag)
252                         printf("ttydev:0x%x\n", tdev);
253         }
254         if (user) {
255                 uid = strtol(user, &ep, 10);
256                 if (*user == '\0' || *ep != '\0') { /* was it a number? */
257                         pw = getpwnam(user);
258                         if (pw == NULL)
259                                 errx(1, "user %s does not exist", user);
260                         uid = pw->pw_uid;
261                         if (dflag)
262                                 printf("uid:%d\n", uid);
263                 }
264         } else {
265                 uid = getuid();
266                 if (uid != 0) {
267                         pw = getpwuid(uid);
268                         if (pw)
269                                 user = pw->pw_name;
270                         if (dflag)
271                                 printf("uid:%d\n", uid);
272                 }
273         }
274         size = 0;
275         mib[0] = CTL_KERN;
276         mib[1] = KERN_PROC;
277         mib[2] = KERN_PROC_PROC;
278         mib[3] = 0;
279         miblen = 3;
280
281         if (user) {
282                 mib[2] = eflag ? KERN_PROC_UID : KERN_PROC_RUID;
283                 mib[3] = uid;
284                 miblen = 4;
285         } else if (tty) {
286                 mib[2] = KERN_PROC_TTY;
287                 mib[3] = tdev;
288                 miblen = 4;
289         }
290
291         st = sysctl(mib, miblen, NULL, &size, NULL, 0);
292         do {
293                 size += size / 10;
294                 newprocs = realloc(procs, size);
295                 if (newprocs == 0) {
296                         if (procs)
297                                 free(procs);
298                         errx(1, "could not reallocate memory");
299                 }
300                 procs = newprocs;
301                 st = sysctl(mib, miblen, procs, &size, NULL, 0);
302         } while (st == -1 && errno == ENOMEM);
303         if (st == -1)
304                 err(1, "could not sysctl(KERN_PROC)");
305         if (size % sizeof(struct kinfo_proc) != 0) {
306                 fprintf(stderr, "proc size mismatch (%zu total, %zu chunks)\n",
307                         size, sizeof(struct kinfo_proc));
308                 fprintf(stderr, "userland out of sync with kernel, recompile libkvm etc\n");
309                 exit(1);
310         }
311         nprocs = size / sizeof(struct kinfo_proc);
312         if (dflag)
313                 printf("nprocs %d\n", nprocs);
314         mypid = getpid();
315
316         for (i = 0; i < nprocs; i++) {
317                 if ((procs[i].ki_stat & SZOMB) == SZOMB && !zflag)
318                         continue;
319                 thispid = procs[i].ki_pid;
320                 strncpy(thiscmd, procs[i].ki_comm, MAXCOMLEN);
321                 thiscmd[MAXCOMLEN] = '\0';
322                 thistdev = procs[i].ki_tdev;
323                 if (eflag)
324                         thisuid = procs[i].ki_uid;      /* effective uid */
325                 else
326                         thisuid = procs[i].ki_ruid;     /* real uid */
327
328                 if (thispid == mypid)
329                         continue;
330                 matched = 1;
331                 if (user) {
332                         if (thisuid != uid)
333                                 matched = 0;
334                 }
335                 if (tty) {
336                         if (thistdev != tdev)
337                                 matched = 0;
338                 }
339                 if (cmd) {
340                         if (mflag) {
341                                 if (regcomp(&rgx, cmd,
342                                     REG_EXTENDED|REG_NOSUB) != 0) {
343                                         mflag = 0;
344                                         warnx("%s: illegal regexp", cmd);
345                                 }
346                         }
347                         if (mflag) {
348                                 pmatch.rm_so = 0;
349                                 pmatch.rm_eo = strlen(thiscmd);
350                                 if (regexec(&rgx, thiscmd, 0, &pmatch,
351                                     REG_STARTEND) != 0)
352                                         matched = 0;
353                                 regfree(&rgx);
354                         } else {
355                                 if (strncmp(thiscmd, cmd, MAXCOMLEN) != 0)
356                                         matched = 0;
357                         }
358                 }
359                 if (jflag && thispid == getpid())
360                         matched = 0;
361                 if (matched == 0)
362                         continue;
363                 if (ac > 0)
364                         matched = 0;
365                 for (j = 0; j < ac; j++) {
366                         if (mflag) {
367                                 if (regcomp(&rgx, av[j],
368                                     REG_EXTENDED|REG_NOSUB) != 0) {
369                                         mflag = 0;
370                                         warnx("%s: illegal regexp", av[j]);
371                                 }
372                         }
373                         if (mflag) {
374                                 pmatch.rm_so = 0;
375                                 pmatch.rm_eo = strlen(thiscmd);
376                                 if (regexec(&rgx, thiscmd, 0, &pmatch,
377                                     REG_STARTEND) == 0)
378                                         matched = 1;
379                                 regfree(&rgx);
380                         } else {
381                                 if (strcmp(thiscmd, av[j]) == 0)
382                                         matched = 1;
383                         }
384                         if (matched)
385                                 break;
386                 }
387                 if (matched == 0)
388                         continue;
389                 if (dflag)
390                         printf("sig:%d, cmd:%s, pid:%d, dev:0x%x uid:%d\n", sig,
391                             thiscmd, thispid, thistdev, thisuid);
392
393                 if (vflag || sflag)
394                         printf("kill -%s %d\n", upper(sys_signame[sig]),
395                             thispid);
396
397                 killed++;
398                 if (!dflag && !sflag) {
399                         if (kill(thispid, sig) < 0 /* && errno != ESRCH */ ) {
400                                 warn("warning: kill -%s %d",
401                                     upper(sys_signame[sig]), thispid);
402                                 errors = 1;
403                         }
404                 }
405         }
406         if (killed == 0) {
407                 fprintf(stderr, "No matching processes %swere found\n",
408                     getuid() != 0 ? "belonging to you " : "");
409                 errors = 1;
410         }
411         exit(errors);
412 }