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