* pidof/killall5 - make omit pid list a dynamic one.
[sysvinit.git] / src / killall5.c
1 /*
2 * kilall5.c Kill all processes except processes that have the
3 * same session id, so that the shell that called us
4 * won't be killed. Typically used in shutdown scripts.
5 *
6 * pidof.c Tries to get the pid of the process[es] named.
7 *
8 * Version: 2.86 30-Jul-2004 MvS
9 *
10 * Usage: killall5 [-][signal]
11 * pidof [-s] [-o omitpid [-o omitpid]] program [program..]
12 *
13 * Authors: Miquel van Smoorenburg, miquels@cistron.nl
14 *
15 * Riku Meskanen, <mesrik@jyu.fi>
16 * - return all running pids of given program name
17 * - single shot '-s' option for backwards combatibility
18 * - omit pid '-o' option and %PPID (parent pid metavariable)
19 * - syslog() only if not a connected to controlling terminal
20 * - swapped out programs pids are caught now
21 *
22 * Werner Fink
23 * - make omit dynamic
24 * - provide '-n' to skip stat(2) syscall on network based FS
25 *
26 * This file is part of the sysvinit suite,
27 * Copyright (C) 1991-2004 Miquel van Smoorenburg.
28 *
29 * This program is free software; you can redistribute it and/or modify
30 * it under the terms of the GNU General Public License as published by
31 * the Free Software Foundation; either version 2 of the License, or
32 * (at your option) any later version.
33 *
34 * This program is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 * GNU General Public License for more details.
38 *
39 * You should have received a copy of the GNU General Public License
40 * along with this program; if not, write to the Free Software
41 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
42 */
43 #include <dirent.h>
44 #include <errno.h>
45 #include <getopt.h>
46 #include <mntent.h>
47 #include <stdarg.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <signal.h>
51 #include <string.h>
52 #include <syslog.h>
53 #include <sys/mman.h>
54 #include <sys/param.h>
55 #include <sys/stat.h>
56 #include <sys/types.h>
57 #include <sys/wait.h>
58 #include <unistd.h>
59
60 char *Version = "@(#)killall5 2.86 31-Jul-2004 miquels@cistron.nl";
61
62 #define STATNAMELEN 15
63 #define DO_NETFS 2
64 #define DO_STAT 1
65 #define NO_STAT 0
66
67 /* Info about a process. */
68 typedef struct proc {
69 char *argv0; /* Name as found out from argv[0] */
70 char *argv0base; /* `basename argv[1]` */
71 char *argv1; /* Name as found out from argv[1] */
72 char *argv1base; /* `basename argv[1]` */
73 char *statname; /* the statname without braces */
74 ino_t ino; /* Inode number */
75 dev_t dev; /* Device it is on */
76 pid_t pid; /* Process ID. */
77 pid_t sid; /* Session ID. */
78 char kernel; /* Kernel thread or zombie. */
79 char nfs; /* Name found on network FS. */
80 struct proc *next; /* Pointer to next struct. */
81 } PROC;
82
83 /* pid queue */
84
85 typedef struct pidq {
86 PROC *proc;
87 struct pidq *next;
88 } PIDQ;
89
90 typedef struct {
91 PIDQ *head;
92 PIDQ *tail;
93 PIDQ *next;
94 } PIDQ_HEAD;
95
96 typedef struct _s_omit {
97 struct _s_omit *next;
98 struct _s_omit *prev;
99 pid_t pid;
100 } OMIT;
101
102 typedef struct _s_shadow
103 {
104 struct _s_shadow *next;
105 struct _s_shadow *prev;
106 size_t nlen;
107 char * name;
108 } SHADOW;
109
110 typedef struct _s_nfs
111 {
112 struct _s_nfs *next; /* Pointer to next struct. */
113 struct _s_nfs *prev; /* Pointer to previous st. */
114 SHADOW *shadow; /* Pointer to shadows */
115 char * name;
116 size_t nlen;
117 } NFS;
118
119 /* List of processes. */
120 PROC *plist;
121
122 /* List of processes to omit. */
123 OMIT *omit;
124
125 /* List of NFS mountes partitions. */
126 NFS *nlist;
127
128 /* Did we stop all processes ? */
129 int sent_sigstop;
130
131 int scripts_too = 0;
132
133 char *progname; /* the name of the running program */
134 #ifdef __GNUC__
135 __attribute__ ((format (printf, 2, 3)))
136 #endif
137 void nsyslog(int pri, char *fmt, ...);
138
139 #if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
140 # ifndef inline
141 # define inline __inline__
142 # endif
143 # ifndef restrict
144 # define restrict __restrict__
145 # endif
146 #endif
147 #define alignof(type) ((sizeof(type)+(sizeof(void*)-1)) & ~(sizeof(void*)-1))
148
149 /*
150 * Malloc space, barf if out of memory.
151 */
152 #ifdef __GNUC__
153 static void *xmalloc(size_t) __attribute__ ((__malloc__));
154 #endif
155 static void *xmalloc(size_t bytes)
156 {
157 void *p;
158
159 if ((p = malloc(bytes)) == NULL) {
160 if (sent_sigstop) kill(-1, SIGCONT);
161 nsyslog(LOG_ERR, "out of memory");
162 exit(1);
163 }
164 return p;
165 }
166
167 #ifdef __GNUC__
168 static inline void xmemalign(void **, size_t, size_t) __attribute__ ((__nonnull__ (1)));
169 #endif
170 static inline void xmemalign(void **memptr, size_t alignment, size_t size)
171 {
172 if ((posix_memalign(memptr, alignment, size)) < 0) {
173 if (sent_sigstop) kill(-1, SIGCONT);
174 nsyslog(LOG_ERR, "out of memory");
175 exit(1);
176 }
177 }
178
179 /*
180 * See if the proc filesystem is there. Mount if needed.
181 */
182 int mount_proc(void)
183 {
184 struct stat st;
185 char *args[] = { "mount", "-t", "proc", "proc", "/proc", 0 };
186 pid_t pid, rc;
187 int wst;
188 int did_mount = 0;
189
190 /* Stat /proc/version to see if /proc is mounted. */
191 if (stat("/proc/version", &st) < 0 && errno == ENOENT) {
192
193 /* It's not there, so mount it. */
194 if ((pid = fork()) < 0) {
195 nsyslog(LOG_ERR, "cannot fork");
196 exit(1);
197 }
198 if (pid == 0) {
199 /* Try a few mount binaries. */
200 execv("/sbin/mount", args);
201 execv("/bin/mount", args);
202
203 /* Okay, I give up. */
204 nsyslog(LOG_ERR, "cannot execute mount");
205 exit(1);
206 }
207 /* Wait for child. */
208 while ((rc = wait(&wst)) != pid)
209 if (rc < 0 && errno == ECHILD)
210 break;
211 if (rc != pid || WEXITSTATUS(wst) != 0)
212 nsyslog(LOG_ERR, "mount returned non-zero exit status");
213
214 did_mount = 1;
215 }
216
217 /* See if mount succeeded. */
218 if (stat("/proc/version", &st) < 0) {
219 if (errno == ENOENT)
220 nsyslog(LOG_ERR, "/proc not mounted, failed to mount.");
221 else
222 nsyslog(LOG_ERR, "/proc unavailable.");
223 exit(1);
224 }
225
226 return did_mount;
227 }
228
229 static inline int isnetfs(const char * type)
230 {
231 static const char* netfs[] = {"nfs", "nfs4", "smbfs", "cifs", "afs", "ncpfs", (char*)0};
232 int n;
233 for (n = 0; netfs[n]; n++) {
234 if (!strcasecmp(netfs[n], type))
235 return 1;
236 }
237 return 0;
238 }
239
240 /*
241 * Remember all NFS typed partitions.
242 */
243 void init_nfs(void)
244 {
245 struct stat st;
246 struct mntent * ent;
247 FILE * mnt;
248
249 nlist = (NFS*)0;
250
251 if (stat("/proc/version", &st) < 0)
252 return;
253 if ((mnt = setmntent("/proc/mounts", "r")) == (FILE*)0)
254 return;
255
256 while ((ent = getmntent(mnt))) {
257 if (isnetfs(ent->mnt_type)) {
258 size_t nlen = strlen(ent->mnt_dir);
259 NFS *restrict p;
260 xmemalign((void*)&p, sizeof(void*), alignof(NFS)+(nlen+1));
261 p->name = ((char*)p)+alignof(NFS);
262 p->nlen = nlen;
263 p->shadow = (SHADOW*)0;
264
265 strcpy(p->name, ent->mnt_dir);
266 if (nlist)
267 nlist->prev = p;
268 p->next = nlist;
269 p->prev = (NFS*)0;
270 nlist = p;
271 }
272 }
273 endmntent(mnt);
274
275 if ((mnt = setmntent("/proc/mounts", "r")) == (FILE*)0)
276 return;
277
278 while ((ent = getmntent(mnt))) {
279 NFS *p;
280
281 for (p = nlist; p; p = p->next) {
282 SHADOW * restrict s;
283 size_t nlen;
284
285 if (strcmp(ent->mnt_dir, p->name) == 0)
286 continue;
287 if (strncmp(ent->mnt_dir, p->name, p->nlen) != 0)
288 continue;
289
290 nlen = strlen(ent->mnt_dir);
291 xmemalign((void*)&s, sizeof(void*), alignof(SHADOW)+(nlen+1));
292 s->name = ((char*)s)+alignof(SHADOW);
293 s->nlen = nlen;
294
295 strcpy(s->name, ent->mnt_dir);
296 if (p->shadow)
297 p->shadow->prev = s;
298 s->next = p->shadow;
299 s->prev = (SHADOW*)0;
300 p->shadow = s;
301 }
302 }
303 endmntent(mnt);
304 }
305
306 static void clear_shadow(SHADOW *restrict shadow)
307 {
308 SHADOW *s, *n, *l;
309
310 n = shadow;
311 l = (SHADOW*)0;
312 for (s = shadow; n; s = n) {
313 l = s->prev;
314 n = s->next;
315 if (s == shadow) {
316 if (n) n->prev = (SHADOW*)0;
317 shadow = n;
318 } else if (l) {
319 if (n) n->prev = l;
320 l->next = n;
321 }
322 free(s);
323 }
324 }
325
326 static void clear_mnt(void)
327 {
328 NFS *p, *n, *l;
329
330 n = nlist;
331 l = (NFS*)0;
332 for (p = nlist; n; p = n) {
333 l = p->prev;
334 n = p->next;
335 if (p == nlist) {
336 if (n) n->prev = (NFS*)0;
337 nlist = n;
338 } else if (l) {
339 if (n) n->prev = l;
340 l->next = n;
341 }
342 if (p->shadow)
343 clear_shadow(p->shadow);
344 free(p);
345 }
346 }
347
348 /*
349 * Check if path is ia shadow off a NFS partition.
350 */
351 static int shadow(SHADOW *restrict this, const char *restrict name, const size_t nlen)
352 {
353 SHADOW *s;
354
355 if (!this)
356 goto out;
357 for (s = this; s; s = s->next) {
358 if (nlen < s->nlen)
359 continue;
360 if (name[s->nlen] != '\0' && name[s->nlen] != '/')
361 continue;
362 if (strncmp(name, s->name, s->nlen) == 0)
363 return 1;
364 }
365 out:
366 return 0;
367 }
368
369 /*
370 * Check path is located on a network based partition.
371 */
372 int check4nfs(const char * path, char * real)
373 {
374 char buf[PATH_MAX+1];
375 const char *curr;
376 int deep = MAXSYMLINKS;
377
378 if (!nlist) return 0;
379
380 curr = path;
381 do {
382 const char *prev;
383 int len;
384
385 if ((prev = strdupa(curr)) == NULL) {
386 nsyslog(LOG_ERR, "strdupa(): %s\n", strerror(errno));
387 return 0;
388 }
389
390 errno = 0;
391 if ((len = readlink(curr, buf, PATH_MAX)) < 0)
392 break;
393 buf[len] = '\0';
394
395 if (buf[0] != '/') {
396 const char *slash;
397
398 if ((slash = strrchr(prev, '/'))) {
399 size_t off = slash - prev + 1;
400
401 if (off + len > PATH_MAX)
402 len = PATH_MAX - off;
403
404 memmove(&buf[off], &buf[0], len + 1);
405 memcpy(&buf[0], prev, off);
406 }
407 }
408 curr = &buf[0];
409
410 if (deep-- <= 0) return 0;
411
412 } while (1);
413
414 if (real) strcpy(real, curr);
415
416 if (errno == EINVAL) {
417 const size_t nlen = strlen(curr);
418 NFS *p;
419 for (p = nlist; p; p = p->next) {
420 if (nlen < p->nlen)
421 continue;
422 if (curr[p->nlen] != '\0' && curr[p->nlen] != '/')
423 continue;
424 if (!strncmp(curr, p->name, p->nlen)) {
425 if (shadow(p->shadow, curr, nlen))
426 continue;
427 return 1;
428 }
429 }
430 }
431
432 return 0;
433 }
434
435 int readarg(FILE *fp, char *buf, int sz)
436 {
437 int c = 0, f = 0;
438
439 while (f < (sz-1) && (c = fgetc(fp)) != EOF && c)
440 buf[f++] = c;
441 buf[f] = 0;
442
443 return (c == EOF && f == 0) ? c : f;
444 }
445
446 /*
447 * Read the proc filesystem.
448 * CWD must be /proc to avoid problems if / is affected by the killing (ie depend on fuse).
449 */
450 int readproc(int do_stat)
451 {
452 DIR *dir;
453 FILE *fp;
454 PROC *p, *n;
455 struct dirent *d;
456 struct stat st;
457 char path[256];
458 char buf[256];
459 char *s, *q;
460 unsigned long startcode, endcode;
461 int pid, f;
462
463 /* Open the /proc directory. */
464 if (chdir("/proc") == -1) {
465 nsyslog(LOG_ERR, "chdir /proc failed");
466 return -1;
467 }
468 if ((dir = opendir(".")) == NULL) {
469 nsyslog(LOG_ERR, "cannot opendir(/proc)");
470 return -1;
471 }
472
473 /* Free the already existing process list. */
474 n = plist;
475 for (p = plist; n; p = n) {
476 n = p->next;
477 if (p->argv0) free(p->argv0);
478 if (p->argv1) free(p->argv1);
479 if (p->statname) free(p->statname);
480 free(p);
481 }
482 plist = NULL;
483
484 /* Walk through the directory. */
485 while ((d = readdir(dir)) != NULL) {
486
487 /* See if this is a process */
488 if ((pid = atoi(d->d_name)) == 0) continue;
489
490 /* Get a PROC struct . */
491 p = (PROC *)xmalloc(sizeof(PROC));
492 memset(p, 0, sizeof(PROC));
493
494 /* Open the status file. */
495 snprintf(path, sizeof(path), "%s/stat", d->d_name);
496
497 /* Read SID & statname from it. */
498 if ((fp = fopen(path, "r")) != NULL) {
499 buf[0] = 0;
500 fgets(buf, sizeof(buf), fp);
501
502 /* See if name starts with '(' */
503 s = buf;
504 while (*s != ' ') s++;
505 s++;
506 if (*s == '(') {
507 /* Read program name. */
508 q = strrchr(buf, ')');
509 if (q == NULL) {
510 p->sid = 0;
511 nsyslog(LOG_ERR,
512 "can't get program name from /proc/%s\n",
513 path);
514 if (p->argv0) free(p->argv0);
515 if (p->argv1) free(p->argv1);
516 if (p->statname) free(p->statname);
517 free(p);
518 continue;
519 }
520 s++;
521 } else {
522 q = s;
523 while (*q != ' ') q++;
524 }
525 *q++ = 0;
526 while (*q == ' ') q++;
527 p->statname = (char *)xmalloc(strlen(s)+1);
528 strcpy(p->statname, s);
529
530 /* Get session, startcode, endcode. */
531 startcode = endcode = 0;
532 if (sscanf(q, "%*c %*d %*d %d %*d %*d %*u %*u "
533 "%*u %*u %*u %*u %*u %*d %*d "
534 "%*d %*d %*d %*d %*u %*u %*d "
535 "%*u %lu %lu",
536 &p->sid, &startcode, &endcode) != 3) {
537 p->sid = 0;
538 nsyslog(LOG_ERR, "can't read sid from %s\n",
539 path);
540 if (p->argv0) free(p->argv0);
541 if (p->argv1) free(p->argv1);
542 if (p->statname) free(p->statname);
543 free(p);
544 continue;
545 }
546 if (startcode == 0 && endcode == 0)
547 p->kernel = 1;
548 fclose(fp);
549 } else {
550 /* Process disappeared.. */
551 if (p->argv0) free(p->argv0);
552 if (p->argv1) free(p->argv1);
553 if (p->statname) free(p->statname);
554 free(p);
555 continue;
556 }
557
558 snprintf(path, sizeof(path), "%s/cmdline", d->d_name);
559 if ((fp = fopen(path, "r")) != NULL) {
560
561 /* Now read argv[0] */
562 f = readarg(fp, buf, sizeof(buf));
563
564 if (buf[0]) {
565 /* Store the name into malloced memory. */
566 p->argv0 = (char *)xmalloc(f + 1);
567 strcpy(p->argv0, buf);
568
569 /* Get a pointer to the basename. */
570 p->argv0base = strrchr(p->argv0, '/');
571 if (p->argv0base != NULL)
572 p->argv0base++;
573 else
574 p->argv0base = p->argv0;
575 }
576
577 /* And read argv[1] */
578 while ((f = readarg(fp, buf, sizeof(buf))) != EOF)
579 if (buf[0] != '-') break;
580
581 if (buf[0]) {
582 /* Store the name into malloced memory. */
583 p->argv1 = (char *)xmalloc(f + 1);
584 strcpy(p->argv1, buf);
585
586 /* Get a pointer to the basename. */
587 p->argv1base = strrchr(p->argv1, '/');
588 if (p->argv1base != NULL)
589 p->argv1base++;
590 else
591 p->argv1base = p->argv1;
592 }
593
594 fclose(fp);
595
596 } else {
597 /* Process disappeared.. */
598 if (p->argv0) free(p->argv0);
599 if (p->argv1) free(p->argv1);
600 if (p->statname) free(p->statname);
601 free(p);
602 continue;
603 }
604
605 /* Try to stat the executable. */
606 snprintf(path, sizeof(path), "/proc/%s/exe", d->d_name);
607
608 p->nfs = 0;
609
610 switch (do_stat) {
611 case DO_NETFS:
612 if ((p->nfs = check4nfs(path, buf)))
613 break;
614 case DO_STAT:
615 if (stat(path, &st) != 0)
616 break;
617 p->dev = st.st_dev;
618 p->ino = st.st_ino;
619 default:
620 break;
621 }
622
623 /* Link it into the list. */
624 p->next = plist;
625 plist = p;
626 p->pid = pid;
627 }
628 closedir(dir);
629
630 /* Done. */
631 return 0;
632 }
633
634 PIDQ_HEAD *init_pid_q(PIDQ_HEAD *q)
635 {
636 q->head = q->next = q->tail = NULL;
637 return q;
638 }
639
640 int empty_q(PIDQ_HEAD *q)
641 {
642 return (q->head == NULL);
643 }
644
645 int add_pid_to_q(PIDQ_HEAD *q, PROC *p)
646 {
647 PIDQ *tmp;
648
649 tmp = (PIDQ *)xmalloc(sizeof(PIDQ));
650
651 tmp->proc = p;
652 tmp->next = NULL;
653
654 if (empty_q(q)) {
655 q->head = tmp;
656 q->tail = tmp;
657 } else {
658 q->tail->next = tmp;
659 q->tail = tmp;
660 }
661 return 0;
662 }
663
664 PROC *get_next_from_pid_q(PIDQ_HEAD *q)
665 {
666 PROC *p;
667 PIDQ *tmp = q->head;
668
669 if (!empty_q(q)) {
670 p = q->head->proc;
671 q->head = tmp->next;
672 free(tmp);
673 return p;
674 }
675
676 return NULL;
677 }
678
679 /* Try to get the process ID of a given process. */
680 PIDQ_HEAD *pidof(char *prog)
681 {
682 PROC *p;
683 PIDQ_HEAD *q;
684 struct stat st;
685 char *s;
686 int nfs = 0;
687 int dostat = 0;
688 int foundone = 0;
689 int ok = 0;
690 char real[PATH_MAX+1];
691
692 if (! prog)
693 return NULL;
694
695 /* Try to stat the executable. */
696 if (prog[0] == '/') {
697 memset(&real[0], 0, sizeof(real));
698
699 if (check4nfs(prog, real))
700 nfs++;
701
702 if (real[0] != '\0')
703 prog = &real[0]; /* Binary located on network FS. */
704
705 if ((nfs == 0) && (stat(prog, &st) == 0))
706 dostat++; /* Binary located on a local FS. */
707 }
708
709 /* Get basename of program. */
710 if ((s = strrchr(prog, '/')) == NULL)
711 s = prog;
712 else
713 s++;
714
715 if (! *s)
716 return NULL;
717
718 q = (PIDQ_HEAD *)xmalloc(sizeof(PIDQ_HEAD));
719 q = init_pid_q(q);
720
721 /* First try to find a match based on dev/ino pair. */
722 if (dostat && !nfs) {
723 for (p = plist; p; p = p->next) {
724 if (p->nfs)
725 continue;
726 if (p->dev == st.st_dev && p->ino == st.st_ino) {
727 add_pid_to_q(q, p);
728 foundone++;
729 }
730 }
731 }
732
733 /* Second try to find a match based on full path name on
734 * network FS located binaries */
735 if (!foundone && nfs) {
736 for (p = plist; p; p = p->next) {
737 char exe [PATH_MAX+1];
738 char path[PATH_MAX+1];
739 int len;
740
741 snprintf(exe, sizeof(exe), "/proc/%d/exe", p->pid);
742 if ((len = readlink(exe, path, PATH_MAX)) < 0)
743 continue;
744 path[len] = '\0';
745 if (strcmp(prog, path) != 0)
746 continue;
747 add_pid_to_q(q, p);
748 foundone++;
749 }
750 }
751
752 /* If we didn't find a match based on dev/ino, try the name. */
753 if (!foundone) for (p = plist; p; p = p->next) {
754 ok = 0;
755
756 /* matching nonmatching
757 * proc name prog name prog name
758 * --- ----------- ------------
759 * b b, p/b, q/b
760 * p/b b, p/b q/b
761 *
762 * Algorithm: Match if:
763 * cmd = arg
764 * or cmd = base(arg)
765 * or base(cmd) = arg
766 *
767 * Specifically, do not match just because base(cmd) = base(arg)
768 * as was done in earlier versions of this program, since this
769 * allows /aaa/foo to match /bbb/foo .
770 */
771 ok |=
772 (p->argv0 && strcmp(p->argv0, prog) == 0)
773 || (p->argv0 && s != prog && strcmp(p->argv0, s) == 0)
774 || (p->argv0base && strcmp(p->argv0base, prog) == 0);
775
776 /* For scripts, compare argv[1] as well. */
777 if (
778 scripts_too && p->statname && p->argv1base
779 && !strncmp(p->statname, p->argv1base, STATNAMELEN)
780 ) {
781 ok |=
782 (p->argv1 && strcmp(p->argv1, prog) == 0)
783 || (p->argv1 && s != prog && strcmp(p->argv1, s) == 0)
784 || (p->argv1base && strcmp(p->argv1base, prog) == 0);
785 }
786
787 /*
788 * if we have a space in argv0, process probably
789 * used setproctitle so try statname.
790 */
791 if (strlen(s) <= STATNAMELEN &&
792 (p->argv0 == NULL ||
793 p->argv0[0] == 0 ||
794 strchr(p->argv0, ' '))) {
795 ok |= (strcmp(p->statname, s) == 0);
796 }
797
798 /*
799 * if we have a `-' as the first character, process
800 * probably used as a login shell
801 */
802 if (strlen(s) <= STATNAMELEN &&
803 p->argv1 == NULL &&
804 (p->argv0 != NULL &&
805 p->argv0[0] == '-')) {
806 ok |= (strcmp(p->statname, s) == 0);
807 }
808
809 if (ok) add_pid_to_q(q, p);
810 }
811
812 return q;
813 }
814
815 /* Give usage message and exit. */
816 void usage(void)
817 {
818 nsyslog(LOG_ERR, "only one argument, a signal number, allowed");
819 closelog();
820 exit(1);
821 }
822
823 /* write to syslog file if not open terminal */
824 #ifdef __GNUC__
825 __attribute__ ((format (printf, 2, 3)))
826 #endif
827 void nsyslog(int pri, char *fmt, ...)
828 {
829 va_list args;
830
831 va_start(args, fmt);
832
833 if (ttyname(0) == NULL) {
834 vsyslog(pri, fmt, args);
835 } else {
836 fprintf(stderr, "%s: ",progname);
837 vfprintf(stderr, fmt, args);
838 fprintf(stderr, "\n");
839 }
840
841 va_end(args);
842 }
843
844 #define PIDOF_SINGLE 0x01
845 #define PIDOF_OMIT 0x02
846 #define PIDOF_NETFS 0x04
847
848 /*
849 * Pidof functionality.
850 */
851 int main_pidof(int argc, char **argv)
852 {
853 PIDQ_HEAD *q;
854 PROC *p;
855 char *token, *here;
856 int f;
857 int first = 1;
858 int opt, flags = 0;
859 int chroot_check = 0;
860 struct stat st;
861 char tmp[512];
862
863 omit = (OMIT*)0;
864 nlist = (NFS*)0;
865 opterr = 0;
866
867 if ((token = getenv("PIDOF_NETFS")) && (strcmp(token,"no") != 0))
868 flags |= PIDOF_NETFS;
869
870 while ((opt = getopt(argc,argv,"hco:sxn")) != EOF) switch (opt) {
871 case '?':
872 nsyslog(LOG_ERR,"invalid options on command line!\n");
873 closelog();
874 exit(1);
875 case 'c':
876 if (geteuid() == 0) chroot_check = 1;
877 break;
878 case 'o':
879 here = optarg;
880 while ((token = strsep(&here, ",;:"))) {
881 OMIT *restrict optr;
882 pid_t opid;
883
884 if (strcmp("%PPID", token) == 0)
885 opid = getppid();
886 else
887 opid = (pid_t)atoi(token);
888
889 if (opid < 1) {
890 nsyslog(LOG_ERR,
891 "illegal omit pid value "
892 "(%s)!\n", token);
893 continue;
894 }
895 xmemalign((void*)&optr, sizeof(void*), alignof(OMIT));
896 optr->next = omit;
897 optr->prev = (OMIT*)0;
898 optr->pid = opid;
899 omit = optr;
900 }
901 flags |= PIDOF_OMIT;
902 break;
903 case 's':
904 flags |= PIDOF_SINGLE;
905 break;
906 case 'x':
907 scripts_too++;
908 break;
909 case 'n':
910 flags |= PIDOF_NETFS;
911 break;
912 default:
913 /* Nothing */
914 break;
915 }
916 argc -= optind;
917 argv += optind;
918
919 /* Check if we are in a chroot */
920 if (chroot_check) {
921 snprintf(tmp, 512, "/proc/%d/root", getpid());
922 if (stat(tmp, &st) < 0) {
923 nsyslog(LOG_ERR, "stat failed for %s!\n", tmp);
924 closelog();
925 exit(1);
926 }
927 }
928
929 if (flags & PIDOF_NETFS)
930 init_nfs(); /* Which network based FS are online? */
931
932 /* Print out process-ID's one by one. */
933 readproc((flags & PIDOF_NETFS) ? DO_NETFS : DO_STAT);
934
935 for(f = 0; f < argc; f++) {
936 if ((q = pidof(argv[f])) != NULL) {
937 pid_t spid = 0;
938 while ((p = get_next_from_pid_q(q))) {
939 if ((flags & PIDOF_OMIT) && omit) {
940 OMIT * optr;
941 for (optr = omit; optr; optr = optr->next) {
942 if (optr->pid == p->pid)
943 break;
944 }
945
946 /*
947 * On a match, continue with
948 * the for loop above.
949 */
950 if (optr)
951 continue;
952 }
953 if (flags & PIDOF_SINGLE) {
954 if (spid)
955 continue;
956 else
957 spid = 1;
958 }
959 if (chroot_check) {
960 struct stat st2;
961 snprintf(tmp, 512, "/proc/%d/root",
962 p->pid);
963 if (stat(tmp, &st2) < 0 ||
964 st.st_dev != st2.st_dev ||
965 st.st_ino != st2.st_ino) {
966 continue;
967 }
968 }
969 if (!first)
970 printf(" ");
971 printf("%d", p->pid);
972 first = 0;
973 }
974 }
975 }
976 if (!first)
977 printf("\n");
978
979 clear_mnt();
980
981 closelog();
982 return(first ? 1 : 0);
983 }
984
985 /* Main for either killall or pidof. */
986 int main(int argc, char **argv)
987 {
988 PROC *p;
989 int pid, sid = -1;
990 int sig = SIGKILL;
991 int c;
992
993 /* return non-zero if no process was killed */
994 int retval = 2;
995
996 /* Get program name. */
997 if ((progname = strrchr(argv[0], '/')) == NULL)
998 progname = argv[0];
999 else
1000 progname++;
1001
1002 /* Now connect to syslog. */
1003 openlog(progname, LOG_CONS|LOG_PID, LOG_DAEMON);
1004
1005 /* Were we called as 'pidof' ? */
1006 if (strcmp(progname, "pidof") == 0)
1007 return main_pidof(argc, argv);
1008
1009 /* Right, so we are "killall". */
1010 omit = (OMIT*)0;
1011
1012 if (argc > 1) {
1013 for (c = 1; c < argc; c++) {
1014 if (argv[c][0] == '-') (argv[c])++;
1015 if (argv[c][0] == 'o') {
1016 char * token, * here;
1017
1018 if (++c >= argc)
1019 usage();
1020
1021 here = argv[c];
1022 while ((token = strsep(&here, ",;:"))) {
1023 OMIT *restrict optr;
1024 pid_t opid = (pid_t)atoi(token);
1025
1026 if (opid < 1) {
1027 nsyslog(LOG_ERR,
1028 "illegal omit pid value "
1029 "(%s)!\n", token);
1030 continue;
1031 }
1032 xmemalign((void*)&optr, sizeof(void*), alignof(OMIT));
1033 optr->next = omit;
1034 optr->prev = (OMIT*)0;
1035 optr->pid = opid;
1036 omit = optr;
1037 }
1038 }
1039 else if ((sig = atoi(argv[1])) <= 0 || sig > 31)
1040 usage();
1041 }
1042 }
1043
1044 /* First get the /proc filesystem online. */
1045 mount_proc();
1046
1047 /*
1048 * Ignoring SIGKILL and SIGSTOP do not make sense, but
1049 * someday kill(-1, sig) might kill ourself if we don't
1050 * do this. This certainly is a valid concern for SIGTERM-
1051 * Linux 2.1 might send the calling process the signal too.
1052 */
1053 signal(SIGTERM, SIG_IGN);
1054 signal(SIGSTOP, SIG_IGN);
1055 signal(SIGKILL, SIG_IGN);
1056
1057 /* lock us into memory */
1058 mlockall(MCL_CURRENT | MCL_FUTURE);
1059
1060 /* Now stop all processes. */
1061 kill(-1, SIGSTOP);
1062 sent_sigstop = 1;
1063
1064 /* Read /proc filesystem */
1065 if (readproc(NO_STAT) < 0) {
1066 kill(-1, SIGCONT);
1067 return(1);
1068 }
1069
1070 /* Now kill all processes except init (pid 1) and our session. */
1071 sid = (int)getsid(0);
1072 pid = (int)getpid();
1073 for (p = plist; p; p = p->next) {
1074 if (p->pid == 1 || p->pid == pid || p->sid == sid || p->kernel)
1075 continue;
1076
1077 if (omit) {
1078 OMIT * optr;
1079 for (optr = omit; optr; optr = optr->next) {
1080 if (optr->pid == p->pid)
1081 break;
1082 }
1083
1084 /* On a match, continue with the for loop above. */
1085 if (optr)
1086 continue;
1087 }
1088
1089 kill(p->pid, sig);
1090 retval = 0;
1091 }
1092
1093 /* And let them continue. */
1094 kill(-1, SIGCONT);
1095
1096 /* Done. */
1097 closelog();
1098
1099 /* Force the kernel to run the scheduler */
1100 usleep(1);
1101
1102 return retval;
1103 }