killall.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2018 K. Lange
  5. *
  6. * killall - Send signals to processes matching name
  7. *
  8. * Find processes by name and send them signals.
  9. */
  10. #include <fcntl.h>
  11. #include <stdint.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <unistd.h>
  16. #include <dirent.h>
  17. #include <signal.h>
  18. #include <getopt.h>
  19. #include <errno.h>
  20. #include <sys/stat.h>
  21. #include <sys/signal.h>
  22. typedef struct process {
  23. int pid;
  24. int ppid;
  25. int tgid;
  26. char name[100];
  27. char path[200];
  28. } p_t;
  29. #define LINE_LEN 4096
  30. p_t * build_entry(struct dirent * dent) {
  31. char tmp[256];
  32. FILE * f;
  33. char line[LINE_LEN];
  34. sprintf(tmp, "/proc/%s/status", dent->d_name);
  35. f = fopen(tmp, "r");
  36. p_t * proc = malloc(sizeof(p_t));
  37. while (fgets(line, LINE_LEN, f) != NULL) {
  38. char * n = strstr(line,"\n");
  39. if (n) { *n = '\0'; }
  40. char * tab = strstr(line,"\t");
  41. if (tab) {
  42. *tab = '\0';
  43. tab++;
  44. }
  45. if (strstr(line, "Pid:") == line) {
  46. proc->pid = atoi(tab);
  47. } else if (strstr(line, "PPid:") == line) {
  48. proc->ppid = atoi(tab);
  49. } else if (strstr(line, "Tgid:") == line) {
  50. proc->tgid = atoi(tab);
  51. } else if (strstr(line, "Name:") == line) {
  52. strcpy(proc->name, tab);
  53. } else if (strstr(line, "Path:") == line) {
  54. strcpy(proc->path, tab);
  55. }
  56. }
  57. if (strstr(proc->name,"python") == proc->name) {
  58. char * name = proc->path + strlen(proc->path) - 1;
  59. while (1) {
  60. if (*name == '/') {
  61. name++;
  62. break;
  63. }
  64. if (name == proc->name) break;
  65. name--;
  66. }
  67. memcpy(proc->name, name, strlen(name)+1);
  68. }
  69. if (proc->tgid != proc->pid) {
  70. char tmp[100] = {0};
  71. sprintf(tmp, "{%s}", proc->name);
  72. memcpy(proc->name, tmp, strlen(tmp)+1);
  73. }
  74. fclose(f);
  75. return proc;
  76. }
  77. void show_usage(int argc, char * argv[]) {
  78. printf(
  79. "killall - send signal to processes with given name\n"
  80. "\n"
  81. "usage: %s [-s SIG] name\n"
  82. "\n"
  83. " -s \033[3msignal to send\033[0m\n"
  84. " -? \033[3mshow this help text\033[0m\n"
  85. "\n", argv[0]);
  86. }
  87. struct sig_def {
  88. int sig;
  89. const char * name;
  90. };
  91. struct sig_def signals[] = {
  92. {SIGHUP,"HUP"},
  93. {SIGINT,"INT"},
  94. {SIGQUIT,"QUIT"},
  95. {SIGILL,"ILL"},
  96. {SIGTRAP,"TRAP"},
  97. {SIGABRT,"ABRT"},
  98. {SIGEMT,"EMT"},
  99. {SIGFPE,"FPE"},
  100. {SIGKILL,"KILL"},
  101. {SIGBUS,"BUS"},
  102. {SIGSEGV,"SEGV"},
  103. {SIGSYS,"SYS"},
  104. {SIGPIPE,"PIPE"},
  105. {SIGALRM,"ALRM"},
  106. {SIGTERM,"TERM"},
  107. {SIGUSR1,"USR1"},
  108. {SIGUSR2,"USR2"},
  109. {SIGCHLD,"CHLD"},
  110. {SIGPWR,"PWR"},
  111. {SIGWINCH,"WINCH"},
  112. {SIGURG,"URG"},
  113. {SIGPOLL,"POLL"},
  114. {SIGSTOP,"STOP"},
  115. {SIGTSTP,"TSTP"},
  116. {SIGCONT,"CONT"},
  117. {SIGTTIN,"TTIN"},
  118. {SIGTTOUT,"TTOUT"},
  119. {SIGVTALRM,"VTALRM"},
  120. {SIGPROF,"PROF"},
  121. {SIGXCPU,"XCPU"},
  122. {SIGXFSZ,"XFSZ"},
  123. {SIGWAITING,"WAITING"},
  124. {SIGDIAF,"DIAF"},
  125. {SIGHATE,"HATE"},
  126. {SIGWINEVENT,"WINEVENT"},
  127. {SIGCAT,"CAT"},
  128. {0,NULL},
  129. };
  130. int main (int argc, char * argv[]) {
  131. int signum = SIGTERM;
  132. char c;
  133. while ((c = getopt(argc, argv, "s:?")) != -1) {
  134. switch (c) {
  135. case 's':
  136. {
  137. signum = -1;
  138. if (strlen(optarg) > 3 && strstr(optarg,"SIG") == (optarg)) {
  139. struct sig_def * s = signals;
  140. while (s->name) {
  141. if (!strcmp(optarg+3,s->name)) {
  142. signum = s->sig;
  143. break;
  144. }
  145. s++;
  146. }
  147. } else {
  148. if (optarg[0] < '0' || optarg[0] > '9') {
  149. struct sig_def * s = signals;
  150. while (s->name) {
  151. if (!strcmp(optarg,s->name)) {
  152. signum = s->sig;
  153. break;
  154. }
  155. s++;
  156. }
  157. } else {
  158. signum = atoi(optarg);
  159. }
  160. }
  161. if (signum == -1) {
  162. fprintf(stderr,"%s: %s: invalid signal specification\n",argv[0],optarg);
  163. return 1;
  164. }
  165. }
  166. break;
  167. case '?':
  168. show_usage(argc, argv);
  169. return 0;
  170. }
  171. }
  172. if (optind >= argc) {
  173. show_usage(argc, argv);
  174. return 1;
  175. }
  176. int killed_something = 0;
  177. int retval = 0;
  178. for (int i = optind; i < argc; ++i) {
  179. /* Open the directory */
  180. DIR * dirp = opendir("/proc");
  181. struct dirent * ent = readdir(dirp);
  182. while (ent != NULL) {
  183. if (ent->d_name[0] >= '0' && ent->d_name[0] <= '9') {
  184. p_t * proc = build_entry(ent);
  185. if (!strcmp(proc->name, argv[i])) {
  186. if (kill(proc->pid, signum) < 0) {
  187. fprintf(stderr, "%s(%d) %s\n", argv[i], proc->pid, strerror(errno));
  188. } else {
  189. killed_something = 1;
  190. }
  191. }
  192. free(proc);
  193. }
  194. ent = readdir(dirp);
  195. }
  196. closedir(dirp);
  197. if (!killed_something) {
  198. fprintf(stderr, "%s: no process found\n", argv[i]);
  199. retval = 1;
  200. }
  201. }
  202. return retval;
  203. }