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