PageRenderTime 50ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/usr.bin/killall/killall.c

https://github.com/blacklion/GEOM-Events
C | 409 lines | 362 code | 21 blank | 26 comment | 141 complexity | 31ba1d5ac04c4b8d313b808168174990 MD5 | raw file
  1. /*-
  2. * Copyright (c) 2000 Peter Wemm <peter@FreeBSD.org>
  3. * Copyright (c) 2000 Paul Saab <ps@FreeBSD.org>
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  16. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  21. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  22. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  23. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  24. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  25. * SUCH DAMAGE.
  26. */
  27. #include <sys/cdefs.h>
  28. __FBSDID("$FreeBSD$");
  29. #include <sys/param.h>
  30. #include <sys/jail.h>
  31. #include <sys/stat.h>
  32. #include <sys/uio.h>
  33. #include <sys/user.h>
  34. #include <sys/sysctl.h>
  35. #include <fcntl.h>
  36. #include <dirent.h>
  37. #include <jail.h>
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41. #include <pwd.h>
  42. #include <signal.h>
  43. #include <regex.h>
  44. #include <ctype.h>
  45. #include <err.h>
  46. #include <errno.h>
  47. #include <unistd.h>
  48. #include <locale.h>
  49. static void __dead2
  50. usage(void)
  51. {
  52. fprintf(stderr, "usage: killall [-delmsvz] [-help] [-j jail]\n");
  53. fprintf(stderr,
  54. " [-u user] [-t tty] [-c cmd] [-SIGNAL] [cmd]...\n");
  55. fprintf(stderr, "At least one option or argument to specify processes must be given.\n");
  56. exit(1);
  57. }
  58. static void
  59. printsig(FILE *fp)
  60. {
  61. const char *const * p;
  62. int cnt;
  63. int offset = 0;
  64. for (cnt = NSIG, p = sys_signame + 1; --cnt; ++p) {
  65. offset += fprintf(fp, "%s ", *p);
  66. if (offset >= 75 && cnt > 1) {
  67. offset = 0;
  68. fprintf(fp, "\n");
  69. }
  70. }
  71. fprintf(fp, "\n");
  72. }
  73. static void
  74. nosig(char *name)
  75. {
  76. warnx("unknown signal %s; valid signals:", name);
  77. printsig(stderr);
  78. exit(1);
  79. }
  80. int
  81. main(int ac, char **av)
  82. {
  83. struct kinfo_proc *procs = NULL, *newprocs;
  84. struct stat sb;
  85. struct passwd *pw;
  86. regex_t rgx;
  87. regmatch_t pmatch;
  88. int i, j;
  89. char buf[256];
  90. char *user = NULL;
  91. char *tty = NULL;
  92. char *cmd = NULL;
  93. int vflag = 0;
  94. int sflag = 0;
  95. int dflag = 0;
  96. int eflag = 0;
  97. int jflag = 0;
  98. int mflag = 0;
  99. int zflag = 0;
  100. uid_t uid = 0;
  101. dev_t tdev = 0;
  102. pid_t mypid;
  103. char thiscmd[MAXCOMLEN + 1];
  104. pid_t thispid;
  105. uid_t thisuid;
  106. dev_t thistdev;
  107. int sig = SIGTERM;
  108. const char *const *p;
  109. char *ep;
  110. int errors = 0;
  111. int jid;
  112. int mib[4];
  113. size_t miblen;
  114. int st, nprocs;
  115. size_t size;
  116. int matched;
  117. int killed = 0;
  118. setlocale(LC_ALL, "");
  119. av++;
  120. ac--;
  121. while (ac > 0) {
  122. if (strcmp(*av, "-l") == 0) {
  123. printsig(stdout);
  124. exit(0);
  125. }
  126. if (strcmp(*av, "-help") == 0)
  127. usage();
  128. if (**av == '-') {
  129. ++*av;
  130. switch (**av) {
  131. case 'j':
  132. ++*av;
  133. if (**av == '\0') {
  134. ++av;
  135. --ac;
  136. }
  137. jflag++;
  138. if (*av == NULL)
  139. errx(1, "must specify jail");
  140. jid = jail_getid(*av);
  141. if (jid < 0)
  142. errx(1, "%s", jail_errmsg);
  143. if (jail_attach(jid) == -1)
  144. err(1, "jail_attach(%d)", jid);
  145. break;
  146. case 'u':
  147. ++*av;
  148. if (**av == '\0') {
  149. ++av;
  150. --ac;
  151. }
  152. if (*av == NULL)
  153. errx(1, "must specify user");
  154. user = *av;
  155. break;
  156. case 't':
  157. ++*av;
  158. if (**av == '\0') {
  159. ++av;
  160. --ac;
  161. }
  162. if (*av == NULL)
  163. errx(1, "must specify tty");
  164. tty = *av;
  165. break;
  166. case 'c':
  167. ++*av;
  168. if (**av == '\0') {
  169. ++av;
  170. --ac;
  171. }
  172. if (*av == NULL)
  173. errx(1, "must specify procname");
  174. cmd = *av;
  175. break;
  176. case 'v':
  177. vflag++;
  178. break;
  179. case 's':
  180. sflag++;
  181. break;
  182. case 'd':
  183. dflag++;
  184. break;
  185. case 'e':
  186. eflag++;
  187. break;
  188. case 'm':
  189. mflag++;
  190. break;
  191. case 'z':
  192. zflag++;
  193. break;
  194. default:
  195. if (isalpha((unsigned char)**av)) {
  196. if (strncasecmp(*av, "SIG", 3) == 0)
  197. *av += 3;
  198. for (sig = NSIG, p = sys_signame + 1;
  199. --sig; ++p)
  200. if (strcasecmp(*p, *av) == 0) {
  201. sig = p - sys_signame;
  202. break;
  203. }
  204. if (!sig)
  205. nosig(*av);
  206. } else if (isdigit((unsigned char)**av)) {
  207. sig = strtol(*av, &ep, 10);
  208. if (!*av || *ep)
  209. errx(1, "illegal signal number: %s", *av);
  210. if (sig < 0 || sig >= NSIG)
  211. nosig(*av);
  212. } else
  213. nosig(*av);
  214. }
  215. ++av;
  216. --ac;
  217. } else {
  218. break;
  219. }
  220. }
  221. if (user == NULL && tty == NULL && cmd == NULL && !jflag && ac == 0)
  222. usage();
  223. if (tty) {
  224. if (strncmp(tty, "/dev/", 5) == 0)
  225. snprintf(buf, sizeof(buf), "%s", tty);
  226. else if (strncmp(tty, "tty", 3) == 0)
  227. snprintf(buf, sizeof(buf), "/dev/%s", tty);
  228. else
  229. snprintf(buf, sizeof(buf), "/dev/tty%s", tty);
  230. if (stat(buf, &sb) < 0)
  231. err(1, "stat(%s)", buf);
  232. if (!S_ISCHR(sb.st_mode))
  233. errx(1, "%s: not a character device", buf);
  234. tdev = sb.st_rdev;
  235. if (dflag)
  236. printf("ttydev:0x%x\n", tdev);
  237. }
  238. if (user) {
  239. uid = strtol(user, &ep, 10);
  240. if (*user == '\0' || *ep != '\0') { /* was it a number? */
  241. pw = getpwnam(user);
  242. if (pw == NULL)
  243. errx(1, "user %s does not exist", user);
  244. uid = pw->pw_uid;
  245. if (dflag)
  246. printf("uid:%d\n", uid);
  247. }
  248. } else {
  249. uid = getuid();
  250. if (uid != 0) {
  251. pw = getpwuid(uid);
  252. if (pw)
  253. user = pw->pw_name;
  254. if (dflag)
  255. printf("uid:%d\n", uid);
  256. }
  257. }
  258. size = 0;
  259. mib[0] = CTL_KERN;
  260. mib[1] = KERN_PROC;
  261. mib[2] = KERN_PROC_PROC;
  262. mib[3] = 0;
  263. miblen = 3;
  264. if (user) {
  265. mib[2] = eflag ? KERN_PROC_UID : KERN_PROC_RUID;
  266. mib[3] = uid;
  267. miblen = 4;
  268. } else if (tty) {
  269. mib[2] = KERN_PROC_TTY;
  270. mib[3] = tdev;
  271. miblen = 4;
  272. }
  273. st = sysctl(mib, miblen, NULL, &size, NULL, 0);
  274. do {
  275. size += size / 10;
  276. newprocs = realloc(procs, size);
  277. if (newprocs == 0) {
  278. if (procs)
  279. free(procs);
  280. errx(1, "could not reallocate memory");
  281. }
  282. procs = newprocs;
  283. st = sysctl(mib, miblen, procs, &size, NULL, 0);
  284. } while (st == -1 && errno == ENOMEM);
  285. if (st == -1)
  286. err(1, "could not sysctl(KERN_PROC)");
  287. if (size % sizeof(struct kinfo_proc) != 0) {
  288. fprintf(stderr, "proc size mismatch (%zu total, %zu chunks)\n",
  289. size, sizeof(struct kinfo_proc));
  290. fprintf(stderr, "userland out of sync with kernel, recompile libkvm etc\n");
  291. exit(1);
  292. }
  293. nprocs = size / sizeof(struct kinfo_proc);
  294. if (dflag)
  295. printf("nprocs %d\n", nprocs);
  296. mypid = getpid();
  297. for (i = 0; i < nprocs; i++) {
  298. if ((procs[i].ki_stat & SZOMB) == SZOMB && !zflag)
  299. continue;
  300. thispid = procs[i].ki_pid;
  301. strlcpy(thiscmd, procs[i].ki_comm, sizeof(thiscmd));
  302. thistdev = procs[i].ki_tdev;
  303. if (eflag)
  304. thisuid = procs[i].ki_uid; /* effective uid */
  305. else
  306. thisuid = procs[i].ki_ruid; /* real uid */
  307. if (thispid == mypid)
  308. continue;
  309. matched = 1;
  310. if (user) {
  311. if (thisuid != uid)
  312. matched = 0;
  313. }
  314. if (tty) {
  315. if (thistdev != tdev)
  316. matched = 0;
  317. }
  318. if (cmd) {
  319. if (mflag) {
  320. if (regcomp(&rgx, cmd,
  321. REG_EXTENDED|REG_NOSUB) != 0) {
  322. mflag = 0;
  323. warnx("%s: illegal regexp", cmd);
  324. }
  325. }
  326. if (mflag) {
  327. pmatch.rm_so = 0;
  328. pmatch.rm_eo = strlen(thiscmd);
  329. if (regexec(&rgx, thiscmd, 0, &pmatch,
  330. REG_STARTEND) != 0)
  331. matched = 0;
  332. regfree(&rgx);
  333. } else {
  334. if (strncmp(thiscmd, cmd, MAXCOMLEN) != 0)
  335. matched = 0;
  336. }
  337. }
  338. if (jflag && thispid == getpid())
  339. matched = 0;
  340. if (matched == 0)
  341. continue;
  342. if (ac > 0)
  343. matched = 0;
  344. for (j = 0; j < ac; j++) {
  345. if (mflag) {
  346. if (regcomp(&rgx, av[j],
  347. REG_EXTENDED|REG_NOSUB) != 0) {
  348. mflag = 0;
  349. warnx("%s: illegal regexp", av[j]);
  350. }
  351. }
  352. if (mflag) {
  353. pmatch.rm_so = 0;
  354. pmatch.rm_eo = strlen(thiscmd);
  355. if (regexec(&rgx, thiscmd, 0, &pmatch,
  356. REG_STARTEND) == 0)
  357. matched = 1;
  358. regfree(&rgx);
  359. } else {
  360. if (strcmp(thiscmd, av[j]) == 0)
  361. matched = 1;
  362. }
  363. if (matched)
  364. break;
  365. }
  366. if (matched == 0)
  367. continue;
  368. if (dflag)
  369. printf("sig:%d, cmd:%s, pid:%d, dev:0x%x uid:%d\n", sig,
  370. thiscmd, thispid, thistdev, thisuid);
  371. if (vflag || sflag)
  372. printf("kill -%s %d\n", sys_signame[sig], thispid);
  373. killed++;
  374. if (!dflag && !sflag) {
  375. if (kill(thispid, sig) < 0 /* && errno != ESRCH */ ) {
  376. warn("warning: kill -%s %d",
  377. sys_signame[sig], thispid);
  378. errors = 1;
  379. }
  380. }
  381. }
  382. if (killed == 0) {
  383. fprintf(stderr, "No matching processes %swere found\n",
  384. getuid() != 0 ? "belonging to you " : "");
  385. errors = 1;
  386. }
  387. exit(errors);
  388. }