]>
git.wh0rd.org - sysvinit.git/blob - src/killall5.c
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.
6 * pidof.c Tries to get the pid of the process[es] named.
8 * Version: 2.86 30-Jul-2004 MvS
10 * Usage: killall5 [-][signal]
11 * pidof [-s] [-o omitpid [-o omitpid]] program [program..]
13 * Authors: Miquel van Smoorenburg, miquels@cistron.nl
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
24 * - provide '-n' to skip stat(2) syscall on network based FS
26 * This file is part of the sysvinit suite,
27 * Copyright (C) 1991-2004 Miquel van Smoorenburg.
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.
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.
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
55 #include <sys/param.h>
57 #include <sys/types.h>
61 char *Version
= "@(#)killall5 2.86 31-Jul-2004 miquels@cistron.nl";
65 # define PATH_MAX MAXPATHLEN
67 # define PATH_MAX 2048
71 #define STATNAMELEN 15
76 /* Info about a process. */
78 char *pathname
; /* full path to executable */
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. */
87 pid_t sid
; /* Session ID. */
88 char kernel
; /* Kernel thread or zombie. */
89 char nfs
; /* Name found on network FS. */
90 struct proc
*next
; /* Pointer to next struct. */
106 typedef struct _s_omit
{
107 struct _s_omit
*next
;
108 struct _s_omit
*prev
;
112 typedef struct _s_shadow
114 struct _s_shadow
*next
;
115 struct _s_shadow
*prev
;
120 typedef struct _s_nfs
122 struct _s_nfs
*next
; /* Pointer to next struct. */
123 struct _s_nfs
*prev
; /* Pointer to previous st. */
124 SHADOW
*shadow
; /* Pointer to shadows */
129 /* List of processes. */
132 /* List of processes to omit. */
135 /* List of NFS mountes partitions. */
138 /* Did we stop all processes ? */
143 char *progname
; /* the name of the running program */
145 __attribute__ ((format (printf
, 2, 3)))
147 void nsyslog(int pri
, char *fmt
, ...);
149 #if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
151 # define inline __inline__
154 # define restrict __restrict__
157 #define alignof(type) ((sizeof(type)+(sizeof(void*)-1)) & ~(sizeof(void*)-1))
160 * Malloc space, barf if out of memory.
163 static void *xmalloc(size_t) __attribute__ ((__malloc__
));
165 static void *xmalloc(size_t bytes
)
169 if ((p
= malloc(bytes
)) == NULL
) {
170 if (sent_sigstop
) kill(-1, SIGCONT
);
171 nsyslog(LOG_ERR
, "out of memory");
178 static inline void xmemalign(void **, size_t, size_t) __attribute__ ((__nonnull__ (1)));
180 static inline void xmemalign(void **memptr
, size_t alignment
, size_t size
)
182 if ((posix_memalign(memptr
, alignment
, size
)) < 0) {
183 if (sent_sigstop
) kill(-1, SIGCONT
);
184 nsyslog(LOG_ERR
, "out of memory");
190 * See if the proc filesystem is there. Mount if needed.
195 char *args
[] = { "mount", "-t", "proc", "proc", "/proc", 0 };
200 /* Stat /proc/version to see if /proc is mounted. */
201 if (stat("/proc/version", &st
) < 0 && errno
== ENOENT
) {
203 /* It's not there, so mount it. */
204 if ((pid
= fork()) < 0) {
205 nsyslog(LOG_ERR
, "cannot fork");
209 /* Try a few mount binaries. */
210 execv("/bin/mount", args
);
211 execv("/sbin/mount", args
);
213 /* Okay, I give up. */
214 nsyslog(LOG_ERR
, "cannot execute mount");
217 /* Wait for child. */
218 while ((rc
= wait(&wst
)) != pid
)
219 if (rc
< 0 && errno
== ECHILD
)
221 if (rc
!= pid
|| WEXITSTATUS(wst
) != 0)
222 nsyslog(LOG_ERR
, "mount returned non-zero exit status");
227 /* See if mount succeeded. */
228 if (stat("/proc/version", &st
) < 0) {
230 nsyslog(LOG_ERR
, "/proc not mounted, failed to mount.");
232 nsyslog(LOG_ERR
, "/proc unavailable.");
239 static inline int isnetfs(const char * type
)
241 static const char* netfs
[] = {"nfs", "nfs4", "smbfs", "cifs", "afs", "ncpfs", (char*)0};
243 for (n
= 0; netfs
[n
]; n
++) {
244 if (!strcasecmp(netfs
[n
], type
))
251 * Remember all NFS typed partitions.
261 if (stat("/proc/version", &st
) < 0)
263 if ((mnt
= setmntent("/proc/mounts", "r")) == (FILE*)0)
266 while ((ent
= getmntent(mnt
))) {
267 if (isnetfs(ent
->mnt_type
)) {
268 size_t nlen
= strlen(ent
->mnt_dir
);
270 xmemalign((void*)&p
, sizeof(void*), alignof(NFS
)+(nlen
+1));
271 p
->name
= ((char*)p
)+alignof(NFS
);
273 p
->shadow
= (SHADOW
*)0;
275 strcpy(p
->name
, ent
->mnt_dir
);
285 if ((mnt
= setmntent("/proc/mounts", "r")) == (FILE*)0)
288 while ((ent
= getmntent(mnt
))) {
291 for (p
= nlist
; p
; p
= p
->next
) {
295 if (strcmp(ent
->mnt_dir
, p
->name
) == 0)
297 if (strncmp(ent
->mnt_dir
, p
->name
, p
->nlen
) != 0)
300 nlen
= strlen(ent
->mnt_dir
);
301 xmemalign((void*)&s
, sizeof(void*), alignof(SHADOW
)+(nlen
+1));
302 s
->name
= ((char*)s
)+alignof(SHADOW
);
305 strcpy(s
->name
, ent
->mnt_dir
);
309 s
->prev
= (SHADOW
*)0;
316 static void clear_shadow(SHADOW
*restrict shadow
)
322 for (s
= shadow
; n
; s
= n
) {
326 if (n
) n
->prev
= (SHADOW
*)0;
336 static void clear_mnt(void)
342 for (p
= nlist
; n
; p
= n
) {
346 if (n
) n
->prev
= (NFS
*)0;
353 clear_shadow(p
->shadow
);
359 * Check if path is a shadow off a NFS partition.
361 static int shadow(SHADOW
*restrict
this, const char *restrict name
, const size_t nlen
)
367 for (s
= this; s
; s
= s
->next
) {
370 if (name
[s
->nlen
] != '\0' && name
[s
->nlen
] != '/')
372 if (strncmp(name
, s
->name
, s
->nlen
) == 0)
380 * Get the maximal number of symlinks to follow. Use sysconf() on
381 * Hurd where the hardcoded value MAXSYMLINKS is not available.
383 static int maxsymlinks(void)
385 int v
= sysconf(_SC_SYMLOOP_MAX
);
394 * Check path is located on a network based partition.
396 int check4nfs(const char * path
, char * real
)
398 char buf
[PATH_MAX
+1];
400 int deep
= maxsymlinks();
402 if (!nlist
) return 0;
409 if ((prev
= strdupa(curr
)) == NULL
) {
410 nsyslog(LOG_ERR
, "strdupa(): %s\n", strerror(errno
));
415 if ((len
= readlink(curr
, buf
, PATH_MAX
)) < 0)
422 if ((slash
= strrchr(prev
, '/'))) {
423 size_t off
= slash
- prev
+ 1;
425 if (off
+ len
> PATH_MAX
)
426 len
= PATH_MAX
- off
;
428 memmove(&buf
[off
], &buf
[0], len
+ 1);
429 memcpy(&buf
[0], prev
, off
);
434 if (deep
-- <= 0) return 0;
438 if (real
) strcpy(real
, curr
);
440 if (errno
== EINVAL
) {
441 const size_t nlen
= strlen(curr
);
443 for (p
= nlist
; p
; p
= p
->next
) {
446 if (curr
[p
->nlen
] != '\0' && curr
[p
->nlen
] != '/')
448 if (!strncmp(curr
, p
->name
, p
->nlen
)) {
449 if (shadow(p
->shadow
, curr
, nlen
))
459 int readarg(FILE *fp
, char *buf
, int sz
)
463 while (f
< (sz
-1) && (c
= fgetc(fp
)) != EOF
&& c
)
467 return (c
== EOF
&& f
== 0) ? c
: f
;
471 * Read the proc filesystem.
472 * CWD must be /proc to avoid problems if / is affected by the killing (ie depend on fuse).
474 int readproc(int do_stat
)
481 char path
[PATH_MAX
+1];
482 char buf
[PATH_MAX
+1];
484 unsigned long startcode
, endcode
;
488 /* Open the /proc directory. */
489 if (chdir("/proc") == -1) {
490 nsyslog(LOG_ERR
, "chdir /proc failed");
493 if ((dir
= opendir(".")) == NULL
) {
494 nsyslog(LOG_ERR
, "cannot opendir(/proc)");
498 /* Free the already existing process list. */
500 for (p
= plist
; n
; p
= n
) {
502 if (p
->argv0
) free(p
->argv0
);
503 if (p
->argv1
) free(p
->argv1
);
504 if (p
->statname
) free(p
->statname
);
510 /* Walk through the directory. */
511 while ((d
= readdir(dir
)) != NULL
) {
513 /* See if this is a process */
514 if ((pid
= atoi(d
->d_name
)) == 0) continue;
516 /* Get a PROC struct . */
517 p
= (PROC
*)xmalloc(sizeof(PROC
));
518 memset(p
, 0, sizeof(PROC
));
520 /* Open the status file. */
521 snprintf(path
, sizeof(path
), "%s/stat", d
->d_name
);
523 /* Read SID & statname from it. */
524 if ((fp
= fopen(path
, "r")) != NULL
) {
527 len
= fread(buf
, sizeof(char), sizeof(buf
)-1, fp
);
530 if (buf
[0] == '\0') {
532 "can't read from %s\n", path
);
538 /* See if name starts with '(' */
540 while (*s
&& *s
!= ' ') s
++;
543 /* Read program name. */
544 q
= strrchr(buf
, ')');
548 "can't get program name from /proc/%s\n",
551 if (p
->argv0
) free(p
->argv0
);
552 if (p
->argv1
) free(p
->argv1
);
553 if (p
->statname
) free(p
->statname
);
561 while (*q
&& *q
!= ' ') q
++;
564 while (*q
== ' ') q
++;
565 p
->statname
= (char *)xmalloc(strlen(s
)+1);
566 strcpy(p
->statname
, s
);
568 /* Get session, startcode, endcode. */
569 startcode
= endcode
= 0;
570 if (sscanf(q
, "%*c %*d %*d %d %*d %*d %*u %*u "
571 "%*u %*u %*u %*u %*u %*d %*d "
572 "%*d %*d %*d %*d %*u %*u %*d "
574 &p
->sid
, &startcode
, &endcode
) != 3) {
576 nsyslog(LOG_ERR
, "can't read sid from %s\n",
579 if (p
->argv0
) free(p
->argv0
);
580 if (p
->argv1
) free(p
->argv1
);
581 if (p
->statname
) free(p
->statname
);
586 if (startcode
== 0 && endcode
== 0)
590 /* Process disappeared.. */
591 if (p
->argv0
) free(p
->argv0
);
592 if (p
->argv1
) free(p
->argv1
);
593 if (p
->statname
) free(p
->statname
);
599 snprintf(path
, sizeof(path
), "%s/cmdline", d
->d_name
);
600 if ((fp
= fopen(path
, "r")) != NULL
) {
602 /* Now read argv[0] */
603 f
= readarg(fp
, buf
, sizeof(buf
));
606 /* Store the name into malloced memory. */
607 p
->argv0
= (char *)xmalloc(f
+ 1);
608 strcpy(p
->argv0
, buf
);
610 /* Get a pointer to the basename. */
611 p
->argv0base
= strrchr(p
->argv0
, '/');
612 if (p
->argv0base
!= NULL
)
615 p
->argv0base
= p
->argv0
;
618 /* And read argv[1] */
619 while ((f
= readarg(fp
, buf
, sizeof(buf
))) != EOF
)
620 if (buf
[0] != '-') break;
623 /* Store the name into malloced memory. */
624 p
->argv1
= (char *)xmalloc(f
+ 1);
625 strcpy(p
->argv1
, buf
);
627 /* Get a pointer to the basename. */
628 p
->argv1base
= strrchr(p
->argv1
, '/');
629 if (p
->argv1base
!= NULL
)
632 p
->argv1base
= p
->argv1
;
638 /* Process disappeared.. */
639 if (p
->argv0
) free(p
->argv0
);
640 if (p
->argv1
) free(p
->argv1
);
641 if (p
->statname
) free(p
->statname
);
647 /* Try to stat the executable. */
648 snprintf(path
, sizeof(path
), "/proc/%s/exe", d
->d_name
);
654 if ((p
->nfs
= check4nfs(path
, buf
)))
657 if (stat(path
, &st
) != 0) {
660 len
= readlink(path
, buf
, PATH_MAX
);
665 ptr
= strstr(buf
, " (deleted)");
669 len
-= strlen(" (deleted)");
671 if (stat(buf
, &st
) != 0)
675 p
->pathname
= (char *)xmalloc(len
+ 1);
676 memcpy(p
->pathname
, buf
, len
);
677 p
->pathname
[len
] = '\0';
689 len
= readlink(path
, buf
, PATH_MAX
);
691 p
->pathname
= (char *)xmalloc(len
+ 1);
692 memcpy(p
->pathname
, buf
, len
);
693 p
->pathname
[len
] = '\0';
698 /* Link it into the list. */
709 PIDQ_HEAD
*init_pid_q(PIDQ_HEAD
*q
)
711 q
->head
= q
->next
= q
->tail
= NULL
;
715 int empty_q(PIDQ_HEAD
*q
)
717 return (q
->head
== NULL
);
720 int add_pid_to_q(PIDQ_HEAD
*q
, PROC
*p
)
724 tmp
= (PIDQ
*)xmalloc(sizeof(PIDQ
));
739 PROC
*get_next_from_pid_q(PIDQ_HEAD
*q
)
754 /* Try to get the process ID of a given process. */
755 PIDQ_HEAD
*pidof(char *prog
)
765 const int root
= (getuid() == 0);
766 char real
[PATH_MAX
+1];
771 /* Try to stat the executable. */
772 if (prog
[0] == '/') {
773 memset(&real
[0], 0, sizeof(real
));
775 if (check4nfs(prog
, real
))
779 prog
= &real
[0]; /* Binary located on network FS. */
781 if ((nfs
== 0) && (stat(prog
, &st
) == 0))
782 dostat
++; /* Binary located on a local FS. */
785 /* Get basename of program. */
786 if ((s
= strrchr(prog
, '/')) == NULL
)
794 q
= (PIDQ_HEAD
*)xmalloc(sizeof(PIDQ_HEAD
));
797 /* First try to find a match based on dev/ino pair. */
798 if (dostat
&& !nfs
) {
799 for (p
= plist
; p
; p
= p
->next
) {
802 if (p
->dev
== st
.st_dev
&& p
->ino
== st
.st_ino
) {
809 /* Second try to find a match based on full path name on
810 * network FS located binaries */
811 if (!foundone
&& nfs
) {
812 for (p
= plist
; p
; p
= p
->next
) {
817 if (strcmp(prog
, p
->pathname
) != 0)
824 /* If we didn't find a match based on dev/ino, try the name. */
825 if (!foundone
) for (p
= plist
; p
; p
= p
->next
) {
826 if (prog
[0] == '/') {
832 if (strcmp(prog
, p
->pathname
)) {
833 int len
= strlen(prog
);
834 if (strncmp(prog
, p
->pathname
, len
))
840 if (strcmp(" (deleted)", p
->pathname
+ len
))
854 /* matching nonmatching
855 * proc name prog name prog name
856 * --- ----------- ------------
860 * Algorithm: Match if:
865 * Specifically, do not match just because base(cmd) = base(arg)
866 * as was done in earlier versions of this program, since this
867 * allows /aaa/foo to match /bbb/foo .
870 (p
->argv0
&& strcmp(p
->argv0
, prog
) == 0)
871 || (p
->argv0
&& s
!= prog
&& strcmp(p
->argv0
, s
) == 0)
872 || (p
->argv0base
&& strcmp(p
->argv0base
, prog
) == 0);
874 /* For scripts, compare argv[1] as well. */
876 scripts_too
&& p
->statname
&& p
->argv1base
877 && !strncmp(p
->statname
, p
->argv1base
, STATNAMELEN
)
880 (p
->argv1
&& strcmp(p
->argv1
, prog
) == 0)
881 || (p
->argv1
&& s
!= prog
&& strcmp(p
->argv1
, s
) == 0)
882 || (p
->argv1base
&& strcmp(p
->argv1base
, prog
) == 0);
886 * if we have a space in argv0, process probably
887 * used setproctitle so try statname.
889 if (strlen(s
) <= STATNAMELEN
&&
892 strchr(p
->argv0
, ' '))) {
893 ok
|= (strcmp(p
->statname
, s
) == 0);
897 * if we have a `-' as the first character, process
898 * probably used as a login shell
900 if (strlen(s
) <= STATNAMELEN
&&
903 p
->argv0
[0] == '-')) {
904 ok
|= (strcmp(p
->statname
, s
) == 0);
907 if (ok
) add_pid_to_q(q
, p
);
913 /* Give usage message and exit. */
916 nsyslog(LOG_ERR
, "only one argument, a signal number, allowed");
921 /* write to syslog file if not open terminal */
923 __attribute__ ((format (printf
, 2, 3)))
925 void nsyslog(int pri
, char *fmt
, ...)
931 if (ttyname(0) == NULL
) {
932 vsyslog(pri
, fmt
, args
);
934 fprintf(stderr
, "%s: ",progname
);
935 vfprintf(stderr
, fmt
, args
);
936 fprintf(stderr
, "\n");
942 #define PIDOF_SINGLE 0x01
943 #define PIDOF_OMIT 0x02
944 #define PIDOF_NETFS 0x04
947 * Pidof functionality.
949 int main_pidof(int argc
, char **argv
)
957 int chroot_check
= 0;
965 if ((token
= getenv("PIDOF_NETFS")) && (strcmp(token
,"no") != 0))
966 flags
|= PIDOF_NETFS
;
968 while ((opt
= getopt(argc
,argv
,"hco:sxn")) != EOF
) switch (opt
) {
970 nsyslog(LOG_ERR
,"invalid options on command line!\n");
974 if (geteuid() == 0) chroot_check
= 1;
978 while ((token
= strsep(&here
, ",;:"))) {
982 if (strcmp("%PPID", token
) == 0)
985 opid
= (pid_t
)atoi(token
);
989 "illegal omit pid value "
993 xmemalign((void*)&optr
, sizeof(void*), alignof(OMIT
));
995 optr
->prev
= (OMIT
*)0;
1002 flags
|= PIDOF_SINGLE
;
1008 flags
|= PIDOF_NETFS
;
1017 /* Check if we are in a chroot */
1019 snprintf(tmp
, 512, "/proc/%d/root", getpid());
1020 if (stat(tmp
, &st
) < 0) {
1021 nsyslog(LOG_ERR
, "stat failed for %s!\n", tmp
);
1027 if (flags
& PIDOF_NETFS
)
1028 init_nfs(); /* Which network based FS are online? */
1030 /* Print out process-ID's one by one. */
1031 readproc((flags
& PIDOF_NETFS
) ? DO_NETFS
: DO_STAT
);
1033 for(f
= 0; f
< argc
; f
++) {
1034 if ((q
= pidof(argv
[f
])) != NULL
) {
1036 while ((p
= get_next_from_pid_q(q
))) {
1037 if ((flags
& PIDOF_OMIT
) && omit
) {
1039 for (optr
= omit
; optr
; optr
= optr
->next
) {
1040 if (optr
->pid
== p
->pid
)
1045 * On a match, continue with
1046 * the for loop above.
1051 if (flags
& PIDOF_SINGLE
) {
1059 snprintf(tmp
, 512, "/proc/%d/root",
1061 if (stat(tmp
, &st2
) < 0 ||
1062 st
.st_dev
!= st2
.st_dev
||
1063 st
.st_ino
!= st2
.st_ino
) {
1069 printf("%d", p
->pid
);
1080 return(first
? 1 : 0);
1083 /* Main for either killall or pidof. */
1084 int main(int argc
, char **argv
)
1091 /* return non-zero if no process was killed */
1094 /* Get program name. */
1095 if ((progname
= strrchr(argv
[0], '/')) == NULL
)
1100 /* Now connect to syslog. */
1101 openlog(progname
, LOG_CONS
|LOG_PID
, LOG_DAEMON
);
1103 /* Were we called as 'pidof' ? */
1104 if (strcmp(progname
, "pidof") == 0)
1105 return main_pidof(argc
, argv
);
1107 /* Right, so we are "killall". */
1111 for (c
= 1; c
< argc
; c
++) {
1112 if (argv
[c
][0] == '-') (argv
[c
])++;
1113 if (argv
[c
][0] == 'o') {
1114 char * token
, * here
;
1120 while ((token
= strsep(&here
, ",;:"))) {
1121 OMIT
*restrict optr
;
1122 pid_t opid
= (pid_t
)atoi(token
);
1126 "illegal omit pid value "
1130 xmemalign((void*)&optr
, sizeof(void*), alignof(OMIT
));
1132 optr
->prev
= (OMIT
*)0;
1137 else if ((sig
= atoi(argv
[1])) <= 0 || sig
> 31)
1142 /* First get the /proc filesystem online. */
1146 * Ignoring SIGKILL and SIGSTOP do not make sense, but
1147 * someday kill(-1, sig) might kill ourself if we don't
1148 * do this. This certainly is a valid concern for SIGTERM-
1149 * Linux 2.1 might send the calling process the signal too.
1151 signal(SIGTERM
, SIG_IGN
);
1152 signal(SIGSTOP
, SIG_IGN
);
1153 signal(SIGKILL
, SIG_IGN
);
1155 /* lock us into memory */
1156 mlockall(MCL_CURRENT
| MCL_FUTURE
);
1158 /* Now stop all processes. */
1162 /* Read /proc filesystem */
1163 if (readproc(NO_STAT
) < 0) {
1168 /* Now kill all processes except init (pid 1) and our session. */
1169 sid
= (int)getsid(0);
1170 pid
= (int)getpid();
1171 for (p
= plist
; p
; p
= p
->next
) {
1172 if (p
->pid
== 1 || p
->pid
== pid
|| p
->sid
== sid
|| p
->kernel
)
1177 for (optr
= omit
; optr
; optr
= optr
->next
) {
1178 if (optr
->pid
== p
->pid
)
1182 /* On a match, continue with the for loop above. */
1191 /* And let them continue. */
1197 /* Force the kernel to run the scheduler */