]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - usr.bin/killall/killall.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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/uio.h>
35 #include <sys/user.h>
36 #include <sys/sysctl.h>
37 #include <fcntl.h>
38 #include <dirent.h>
39 #include <jail.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <pwd.h>
44 #include <signal.h>
45 #include <regex.h>
46 #include <ctype.h>
47 #include <err.h>
48 #include <errno.h>
49 #include <unistd.h>
50 #include <locale.h>
51
52 static void __dead2
53 usage(void)
54 {
55
56         fprintf(stderr, "usage: killall [-delmsvz] [-help] [-j jail]\n");
57         fprintf(stderr,
58             "               [-u user] [-t tty] [-c cmd] [-SIGNAL] [cmd]...\n");
59         fprintf(stderr, "At least one option or argument to specify processes must be given.\n");
60         exit(1);
61 }
62
63 static char *
64 upper(const char *str)
65 {
66         static char buf[80];
67         char *s;
68
69         strlcpy(buf, str, sizeof(buf));
70         for (s = buf; *s; s++)
71                 *s = toupper((unsigned char)*s);
72         return buf;
73 }
74
75
76 static void
77 printsig(FILE *fp)
78 {
79         const char      *const * p;
80         int             cnt;
81         int             offset = 0;
82
83         for (cnt = NSIG, p = sys_signame + 1; --cnt; ++p) {
84                 offset += fprintf(fp, "%s ", upper(*p));
85                 if (offset >= 75 && cnt > 1) {
86                         offset = 0;
87                         fprintf(fp, "\n");
88                 }
89         }
90         fprintf(fp, "\n");
91 }
92
93 static void
94 nosig(char *name)
95 {
96
97         warnx("unknown signal %s; valid signals:", name);
98         printsig(stderr);
99         exit(1);
100 }
101
102 int
103 main(int ac, char **av)
104 {
105         struct kinfo_proc *procs = NULL, *newprocs;
106         struct stat     sb;
107         struct passwd   *pw;
108         regex_t         rgx;
109         regmatch_t      pmatch;
110         int             i, j;
111         char            buf[256];
112         char            *user = NULL;
113         char            *tty = NULL;
114         char            *cmd = NULL;
115         int             vflag = 0;
116         int             sflag = 0;
117         int             dflag = 0;
118         int             eflag = 0;
119         int             jflag = 0;
120         int             mflag = 0;
121         int             zflag = 0;
122         uid_t           uid = 0;
123         dev_t           tdev = 0;
124         pid_t           mypid;
125         char            thiscmd[MAXCOMLEN + 1];
126         pid_t           thispid;
127         uid_t           thisuid;
128         dev_t           thistdev;
129         int             sig = SIGTERM;
130         const char *const *p;
131         char            *ep;
132         int             errors = 0;
133         int             jid;
134         int             mib[4];
135         size_t          miblen;
136         int             st, nprocs;
137         size_t          size;
138         int             matched;
139         int             killed = 0;
140
141         setlocale(LC_ALL, "");
142
143         av++;
144         ac--;
145
146         while (ac > 0) {
147                 if (strcmp(*av, "-l") == 0) {
148                         printsig(stdout);
149                         exit(0);
150                 }
151                 if (strcmp(*av, "-help") == 0)
152                         usage();
153                 if (**av == '-') {
154                         ++*av;
155                         switch (**av) {
156                         case 'j':
157                                 ++*av;
158                                 if (**av == '\0') {
159                                         ++av;
160                                         --ac;
161                                 }
162                                 jflag++;
163                                 if (*av == NULL)
164                                         errx(1, "must specify jail");
165                                 jid = jail_getid(*av);
166                                 if (jid < 0)
167                                         errx(1, "%s", jail_errmsg);
168                                 if (jail_attach(jid) == -1)
169                                         err(1, "jail_attach(%d)", jid);
170                                 break;
171                         case 'u':
172                                 ++*av;
173                                 if (**av == '\0') {
174                                         ++av;
175                                         --ac;
176                                 }
177                                 if (*av == NULL)
178                                         errx(1, "must specify user");
179                                 user = *av;
180                                 break;
181                         case 't':
182                                 ++*av;
183                                 if (**av == '\0') {
184                                         ++av;
185                                         --ac;
186                                 }
187                                 if (*av == NULL)
188                                         errx(1, "must specify tty");
189                                 tty = *av;
190                                 break;
191                         case 'c':
192                                 ++*av;
193                                 if (**av == '\0') {
194                                         ++av;
195                                         --ac;
196                                 }
197                                 if (*av == NULL)
198                                         errx(1, "must specify procname");
199                                 cmd = *av;
200                                 break;
201                         case 'v':
202                                 vflag++;
203                                 break;
204                         case 's':
205                                 sflag++;
206                                 break;
207                         case 'd':
208                                 dflag++;
209                                 break;
210                         case 'e':
211                                 eflag++;
212                                 break;
213                         case 'm':
214                                 mflag++;
215                                 break;
216                         case 'z':
217                                 zflag++;
218                                 break;
219                         default:
220                                 if (isalpha((unsigned char)**av)) {
221                                         if (strncasecmp(*av, "sig", 3) == 0)
222                                                 *av += 3;
223                                         for (sig = NSIG, p = sys_signame + 1;
224                                              --sig; ++p)
225                                                 if (strcasecmp(*p, *av) == 0) {
226                                                         sig = p - sys_signame;
227                                                         break;
228                                                 }
229                                         if (!sig)
230                                                 nosig(*av);
231                                 } else if (isdigit((unsigned char)**av)) {
232                                         sig = strtol(*av, &ep, 10);
233                                         if (!*av || *ep)
234                                                 errx(1, "illegal signal number: %s", *av);
235                                         if (sig < 0 || sig >= NSIG)
236                                                 nosig(*av);
237                                 } else
238                                         nosig(*av);
239                         }
240                         ++av;
241                         --ac;
242                 } else {
243                         break;
244                 }
245         }
246
247         if (user == NULL && tty == NULL && cmd == NULL && !jflag && ac == 0)
248                 usage();
249
250         if (tty) {
251                 if (strncmp(tty, "/dev/", 5) == 0)
252                         snprintf(buf, sizeof(buf), "%s", tty);
253                 else if (strncmp(tty, "tty", 3) == 0)
254                         snprintf(buf, sizeof(buf), "/dev/%s", tty);
255                 else
256                         snprintf(buf, sizeof(buf), "/dev/tty%s", tty);
257                 if (stat(buf, &sb) < 0)
258                         err(1, "stat(%s)", buf);
259                 if (!S_ISCHR(sb.st_mode))
260                         errx(1, "%s: not a character device", buf);
261                 tdev = sb.st_rdev;
262                 if (dflag)
263                         printf("ttydev:0x%x\n", tdev);
264         }
265         if (user) {
266                 uid = strtol(user, &ep, 10);
267                 if (*user == '\0' || *ep != '\0') { /* was it a number? */
268                         pw = getpwnam(user);
269                         if (pw == NULL)
270                                 errx(1, "user %s does not exist", user);
271                         uid = pw->pw_uid;
272                         if (dflag)
273                                 printf("uid:%d\n", uid);
274                 }
275         } else {
276                 uid = getuid();
277                 if (uid != 0) {
278                         pw = getpwuid(uid);
279                         if (pw)
280                                 user = pw->pw_name;
281                         if (dflag)
282                                 printf("uid:%d\n", uid);
283                 }
284         }
285         size = 0;
286         mib[0] = CTL_KERN;
287         mib[1] = KERN_PROC;
288         mib[2] = KERN_PROC_PROC;
289         mib[3] = 0;
290         miblen = 3;
291
292         if (user) {
293                 mib[2] = eflag ? KERN_PROC_UID : KERN_PROC_RUID;
294                 mib[3] = uid;
295                 miblen = 4;
296         } else if (tty) {
297                 mib[2] = KERN_PROC_TTY;
298                 mib[3] = tdev;
299                 miblen = 4;
300         }
301
302         st = sysctl(mib, miblen, NULL, &size, NULL, 0);
303         do {
304                 size += size / 10;
305                 newprocs = realloc(procs, size);
306                 if (newprocs == 0) {
307                         if (procs)
308                                 free(procs);
309                         errx(1, "could not reallocate memory");
310                 }
311                 procs = newprocs;
312                 st = sysctl(mib, miblen, procs, &size, NULL, 0);
313         } while (st == -1 && errno == ENOMEM);
314         if (st == -1)
315                 err(1, "could not sysctl(KERN_PROC)");
316         if (size % sizeof(struct kinfo_proc) != 0) {
317                 fprintf(stderr, "proc size mismatch (%zu total, %zu chunks)\n",
318                         size, sizeof(struct kinfo_proc));
319                 fprintf(stderr, "userland out of sync with kernel, recompile libkvm etc\n");
320                 exit(1);
321         }
322         nprocs = size / sizeof(struct kinfo_proc);
323         if (dflag)
324                 printf("nprocs %d\n", nprocs);
325         mypid = getpid();
326
327         for (i = 0; i < nprocs; i++) {
328                 if ((procs[i].ki_stat & SZOMB) == SZOMB && !zflag)
329                         continue;
330                 thispid = procs[i].ki_pid;
331                 strlcpy(thiscmd, procs[i].ki_comm, sizeof(thiscmd));
332                 thistdev = procs[i].ki_tdev;
333                 if (eflag)
334                         thisuid = procs[i].ki_uid;      /* effective uid */
335                 else
336                         thisuid = procs[i].ki_ruid;     /* real uid */
337
338                 if (thispid == mypid)
339                         continue;
340                 matched = 1;
341                 if (user) {
342                         if (thisuid != uid)
343                                 matched = 0;
344                 }
345                 if (tty) {
346                         if (thistdev != tdev)
347                                 matched = 0;
348                 }
349                 if (cmd) {
350                         if (mflag) {
351                                 if (regcomp(&rgx, cmd,
352                                     REG_EXTENDED|REG_NOSUB) != 0) {
353                                         mflag = 0;
354                                         warnx("%s: illegal regexp", cmd);
355                                 }
356                         }
357                         if (mflag) {
358                                 pmatch.rm_so = 0;
359                                 pmatch.rm_eo = strlen(thiscmd);
360                                 if (regexec(&rgx, thiscmd, 0, &pmatch,
361                                     REG_STARTEND) != 0)
362                                         matched = 0;
363                                 regfree(&rgx);
364                         } else {
365                                 if (strncmp(thiscmd, cmd, MAXCOMLEN) != 0)
366                                         matched = 0;
367                         }
368                 }
369                 if (jflag && thispid == getpid())
370                         matched = 0;
371                 if (matched == 0)
372                         continue;
373                 if (ac > 0)
374                         matched = 0;
375                 for (j = 0; j < ac; j++) {
376                         if (mflag) {
377                                 if (regcomp(&rgx, av[j],
378                                     REG_EXTENDED|REG_NOSUB) != 0) {
379                                         mflag = 0;
380                                         warnx("%s: illegal regexp", av[j]);
381                                 }
382                         }
383                         if (mflag) {
384                                 pmatch.rm_so = 0;
385                                 pmatch.rm_eo = strlen(thiscmd);
386                                 if (regexec(&rgx, thiscmd, 0, &pmatch,
387                                     REG_STARTEND) == 0)
388                                         matched = 1;
389                                 regfree(&rgx);
390                         } else {
391                                 if (strcmp(thiscmd, av[j]) == 0)
392                                         matched = 1;
393                         }
394                         if (matched)
395                                 break;
396                 }
397                 if (matched == 0)
398                         continue;
399                 if (dflag)
400                         printf("sig:%d, cmd:%s, pid:%d, dev:0x%x uid:%d\n", sig,
401                             thiscmd, thispid, thistdev, thisuid);
402
403                 if (vflag || sflag)
404                         printf("kill -%s %d\n", upper(sys_signame[sig]),
405                             thispid);
406
407                 killed++;
408                 if (!dflag && !sflag) {
409                         if (kill(thispid, sig) < 0 /* && errno != ESRCH */ ) {
410                                 warn("warning: kill -%s %d",
411                                     upper(sys_signame[sig]), thispid);
412                                 errors = 1;
413                         }
414                 }
415         }
416         if (killed == 0) {
417                 fprintf(stderr, "No matching processes %swere found\n",
418                     getuid() != 0 ? "belonging to you " : "");
419                 errors = 1;
420         }
421         exit(errors);
422 }