]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - usr.bin/killall/killall.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.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                                 }
161                                 jflag++;
162                                 if (*av == NULL)
163                                         errx(1, "must specify jid");
164                                 jid = strtol(*av, &ep, 10);
165                                 if (!*av || *ep)
166                                         errx(1, "illegal jid: %s", *av);
167                                 if (jail_attach(jid) == -1)
168                                         err(1, "jail_attach(): %d", jid);
169                                 break;
170                         case 'u':
171                                 ++*av;
172                                 if (**av == '\0') {
173                                         ++av;
174                                         --ac;
175                                 }
176                                 if (*av == NULL)
177                                         errx(1, "must specify user");
178                                 user = *av;
179                                 break;
180                         case 't':
181                                 ++*av;
182                                 if (**av == '\0') {
183                                         ++av;
184                                         --ac;
185                                 }
186                                 if (*av == NULL)
187                                         errx(1, "must specify tty");
188                                 tty = *av;
189                                 break;
190                         case 'c':
191                                 ++*av;
192                                 if (**av == '\0') {
193                                         ++av;
194                                         --ac;
195                                 }
196                                 if (*av == NULL)
197                                         errx(1, "must specify procname");
198                                 cmd = *av;
199                                 break;
200                         case 'v':
201                                 vflag++;
202                                 break;
203                         case 's':
204                                 sflag++;
205                                 break;
206                         case 'd':
207                                 dflag++;
208                                 break;
209                         case 'e':
210                                 eflag++;
211                                 break;
212                         case 'm':
213                                 mflag++;
214                                 break;
215                         case 'z':
216                                 zflag++;
217                                 break;
218                         default:
219                                 if (isalpha((unsigned char)**av)) {
220                                         if (strncasecmp(*av, "sig", 3) == 0)
221                                                 *av += 3;
222                                         for (sig = NSIG, p = sys_signame + 1;
223                                              --sig; ++p)
224                                                 if (strcasecmp(*p, *av) == 0) {
225                                                         sig = p - sys_signame;
226                                                         break;
227                                                 }
228                                         if (!sig)
229                                                 nosig(*av);
230                                 } else if (isdigit((unsigned char)**av)) {
231                                         sig = strtol(*av, &ep, 10);
232                                         if (!*av || *ep)
233                                                 errx(1, "illegal signal number: %s", *av);
234                                         if (sig < 0 || sig >= NSIG)
235                                                 nosig(*av);
236                                 } else
237                                         nosig(*av);
238                         }
239                         ++av;
240                         --ac;
241                 } else {
242                         break;
243                 }
244         }
245
246         if (user == NULL && tty == NULL && cmd == NULL && !jflag && ac == 0)
247                 usage();
248
249         if (tty) {
250                 if (strncmp(tty, "/dev/", 5) == 0)
251                         snprintf(buf, sizeof(buf), "%s", tty);
252                 else if (strncmp(tty, "tty", 3) == 0)
253                         snprintf(buf, sizeof(buf), "/dev/%s", tty);
254                 else
255                         snprintf(buf, sizeof(buf), "/dev/tty%s", tty);
256                 if (stat(buf, &sb) < 0)
257                         err(1, "stat(%s)", buf);
258                 if (!S_ISCHR(sb.st_mode))
259                         errx(1, "%s: not a character device", buf);
260                 tdev = sb.st_rdev;
261                 if (dflag)
262                         printf("ttydev:0x%x\n", tdev);
263         }
264         if (user) {
265                 uid = strtol(user, &ep, 10);
266                 if (*user == '\0' || *ep != '\0') { /* was it a number? */
267                         pw = getpwnam(user);
268                         if (pw == NULL)
269                                 errx(1, "user %s does not exist", user);
270                         uid = pw->pw_uid;
271                         if (dflag)
272                                 printf("uid:%d\n", uid);
273                 }
274         } else {
275                 uid = getuid();
276                 if (uid != 0) {
277                         pw = getpwuid(uid);
278                         if (pw)
279                                 user = pw->pw_name;
280                         if (dflag)
281                                 printf("uid:%d\n", uid);
282                 }
283         }
284         size = 0;
285         mib[0] = CTL_KERN;
286         mib[1] = KERN_PROC;
287         mib[2] = KERN_PROC_PROC;
288         mib[3] = 0;
289         miblen = 3;
290
291         if (user) {
292                 mib[2] = eflag ? KERN_PROC_UID : KERN_PROC_RUID;
293                 mib[3] = uid;
294                 miblen = 4;
295         } else if (tty) {
296                 mib[2] = KERN_PROC_TTY;
297                 mib[3] = tdev;
298                 miblen = 4;
299         }
300
301         st = sysctl(mib, miblen, NULL, &size, NULL, 0);
302         do {
303                 size += size / 10;
304                 newprocs = realloc(procs, size);
305                 if (newprocs == 0) {
306                         if (procs)
307                                 free(procs);
308                         errx(1, "could not reallocate memory");
309                 }
310                 procs = newprocs;
311                 st = sysctl(mib, miblen, procs, &size, NULL, 0);
312         } while (st == -1 && errno == ENOMEM);
313         if (st == -1)
314                 err(1, "could not sysctl(KERN_PROC)");
315         if (size % sizeof(struct kinfo_proc) != 0) {
316                 fprintf(stderr, "proc size mismatch (%zu total, %zu chunks)\n",
317                         size, sizeof(struct kinfo_proc));
318                 fprintf(stderr, "userland out of sync with kernel, recompile libkvm etc\n");
319                 exit(1);
320         }
321         nprocs = size / sizeof(struct kinfo_proc);
322         if (dflag)
323                 printf("nprocs %d\n", nprocs);
324         mypid = getpid();
325
326         for (i = 0; i < nprocs; i++) {
327                 if ((procs[i].ki_stat & SZOMB) == SZOMB && !zflag)
328                         continue;
329                 thispid = procs[i].ki_pid;
330                 strncpy(thiscmd, procs[i].ki_comm, MAXCOMLEN);
331                 thiscmd[MAXCOMLEN] = '\0';
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 }