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