1/* kill.c - a program to send signals to processes
2 *
3 * Copyright 2012 Daniel Walter <d.walter@0x90.at>
4 *
5 * See http://opengroup.org/onlinepubs/9699919799/utilities/kill.html
6 *
7 * killall5.c - Send signal to all processes outside current session.
8 *
9 * Copyright 2014 Ranjan Kumar <ranjankumar.bth@gmail.com>
10 * Copyright 2014 Kyungwan Han <asura321@gamil.com>
11 *
12 * No Standard
13
14USE_KILL(NEWTOY(kill, "?ls: ", TOYFLAG_BIN))
15USE_KILLALL5(NEWTOY(killall5, "?o*ls: [!lo][!ls]", TOYFLAG_SBIN))
16
17config KILL
18  bool "kill"
19  default y
20  help
21    usage: kill [-l [SIGNAL] | -s SIGNAL | -SIGNAL] pid...
22
23    Send signal to process(es).
24
25    -l	List signal name(s) and number(s)
26    -s	Send SIGNAL (default SIGTERM)
27
28config KILLALL5
29  bool "killall5"
30  default y
31  depends on KILL
32  help
33    usage: killall5 [-l [SIGNAL]] [-SIGNAL|-s SIGNAL] [-o PID]...
34
35    Send a signal to all processes outside current session.
36
37    -l     List signal name(s) and number(s)
38    -o PID Omit PID
39    -s     send SIGNAL (default SIGTERM)
40*/
41
42// This has to match the filename:
43#define FOR_kill
44#include "toys.h"
45
46GLOBALS(
47  char *signame;
48  struct arg_list *olist;
49)
50
51// But kill's flags are a subset of killall5's
52
53#define CLEANUP_kill
54#define FOR_killall5
55#include "generated/flags.h"
56
57void kill_main(void)
58{
59  int signum;
60  char *tmp, **args = toys.optargs;
61  pid_t pid;
62
63  // list signal(s)
64  if (toys.optflags & FLAG_l) {
65    if (*args) {
66      int signum = sig_to_num(*args);
67      char *s = NULL;
68
69      if (signum>=0) s = num_to_sig(signum&127);
70      puts(s ? s : "UNKNOWN");
71    } else sig_to_num(NULL);
72    return;
73  }
74
75  // signal must come before pids, so "kill -9 -1" isn't confusing.
76
77  if (!TT.signame && *args && **args=='-') TT.signame=*(args++)+1;
78  if (TT.signame) {
79    char *arg;
80    int i = strtol(TT.signame, &arg, 10);
81    if (!*arg) arg = num_to_sig(i);
82    else arg = TT.signame;
83
84    if (!arg || -1 == (signum = sig_to_num(arg)))
85      error_exit("Unknown signal '%s'", arg);
86  } else signum = SIGTERM;
87
88  // is it killall5?
89  if (CFG_KILLALL5 && toys.which->name[4]=='a') {
90    DIR *dp;
91    struct dirent *entry;
92    int pid, sid;
93    long *olist = 0, ocount = 0;
94
95    // parse omit list
96    if (toys.optflags & FLAG_o) {
97      struct arg_list *ptr;
98
99      for (ptr = TT.olist; ptr; ptr = ptr->next) ocount++;
100      olist = xmalloc(ocount*sizeof(long));
101      ocount = 0;
102      for (ptr = TT.olist; ptr; ptr=ptr->next)
103        olist[ocount++] = atolx(ptr->arg);
104    }
105
106    sid = getsid(pid = getpid());
107
108    if (!(dp = opendir("/proc"))) perror_exit("/proc");
109    while ((entry = readdir(dp))) {
110      int count, procpid, procsid;
111
112      if (!(procpid = atoi(entry->d_name))) continue;
113
114      snprintf(toybuf, sizeof(toybuf), "/proc/%d/stat", procpid);
115      if (!readfile(toybuf, toybuf, sizeof(toybuf))) continue;
116      if (sscanf(toybuf, "%*d %*s %*c %*d %*d %d", &procsid) != 1) continue;
117      if (pid == procpid || sid == procsid || procpid == 1) continue;
118
119      // Check for kernel threads.
120      snprintf(toybuf, sizeof(toybuf), "/proc/%d/cmdline", procpid);
121      if (!readfile(toybuf, toybuf, sizeof(toybuf)) || !*toybuf) continue;
122
123      // Check with omit list.
124      for (count = 0; count < ocount; count++)
125        if (procpid == olist[count]) break;
126      if (count != ocount) continue;
127
128      kill(procpid, signum);
129    }
130    if (CFG_TOYBOX_FREE) {
131      closedir(dp);
132      free(olist);
133    }
134
135  // is it kill?
136  } else {
137
138    // "<1" in optstr wouldn't cover this because "-SIGNAL"
139    if (!*args) help_exit("missing argument");
140
141    while (*args) {
142      char *arg = *(args++);
143
144      pid = strtol(arg, &tmp, 10);
145      if (*tmp || kill(pid, signum) < 0) error_msg("unknown pid '%s'", arg);
146    }
147  }
148}
149
150void killall5_main(void)
151{
152  kill_main();
153}
154