fstest_monitor.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. /*
  2. * Copyright (C) 2007 Nokia Corporation.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * version 2 as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful, but
  9. * WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. * General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program; if not, write to the Free Software
  15. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  16. * 02110-1301 USA
  17. *
  18. * Author: Adrian Hunter
  19. */
  20. #include <sys/types.h>
  21. #include <sys/wait.h>
  22. #include <unistd.h>
  23. #include <stdio.h>
  24. #include <signal.h>
  25. #include <string.h>
  26. #include <stdlib.h>
  27. #include <ctype.h>
  28. #include <errno.h>
  29. struct child_info {
  30. struct child_info *next;
  31. pid_t pid;
  32. int terminated;
  33. int killed;
  34. int gone;
  35. };
  36. struct child_info *children = 0;
  37. static void kill_children(void)
  38. {
  39. struct child_info *child;
  40. child = children;
  41. while (child) {
  42. if (!child->gone) {
  43. if (!child->terminated) {
  44. child->terminated = 1;
  45. kill(child->pid, SIGTERM);
  46. } /*else if (!child->killed) {
  47. child->killed = 1;
  48. kill(child->pid, SIGKILL);
  49. }*/
  50. }
  51. child = child->next;
  52. }
  53. }
  54. static void add_child(pid_t child_pid)
  55. {
  56. struct child_info *child;
  57. size_t sz;
  58. sz = sizeof(struct child_info);
  59. child = (struct child_info *) malloc(sz);
  60. memset(child, 0, sz);
  61. child->pid = child_pid;
  62. child->next = children;
  63. children = child;
  64. }
  65. static void mark_child_gone(pid_t child_pid)
  66. {
  67. struct child_info *child;
  68. child = children;
  69. while (child) {
  70. if (child->pid == child_pid) {
  71. child->gone = 1;
  72. break;
  73. }
  74. child = child->next;
  75. }
  76. }
  77. static int have_children(void)
  78. {
  79. struct child_info *child;
  80. child = children;
  81. while (child) {
  82. if (!child->gone)
  83. return 1;
  84. child = child->next;
  85. }
  86. return 0;
  87. }
  88. static int parse_command_line(char *cmdline, int *pargc, char ***pargv)
  89. {
  90. char **tmp;
  91. char *p, *v, *q;
  92. size_t sz;
  93. int argc = 0;
  94. int state = 0;
  95. char *argv[1024];
  96. if (!cmdline)
  97. return 1;
  98. q = v = (char *) malloc(strlen(cmdline) + 1024);
  99. if (!v)
  100. return 1;
  101. p = cmdline;
  102. for (;;) {
  103. char c = *p++;
  104. if (!c) {
  105. *v++ = 0;
  106. break;
  107. }
  108. switch (state) {
  109. case 0: /* Between args */
  110. if (isspace(c))
  111. break;
  112. argv[argc++] = v;
  113. if (c == '"') {
  114. state = 2;
  115. break;
  116. } else if (c == '\'') {
  117. state = 3;
  118. break;
  119. }
  120. state = 1;
  121. /* fall-through */
  122. case 1: /* Not quoted */
  123. if (c == '\\') {
  124. if (*p)
  125. *v++ = *p;
  126. } else if (isspace(c)) {
  127. *v++ = 0;
  128. state = 0;
  129. } else
  130. *v++ = c;
  131. break;
  132. case 2: /* Double quoted */
  133. if (c == '\\' && *p == '"') {
  134. *v++ = '"';
  135. ++p;
  136. } else if (c == '"') {
  137. *v++ = 0;
  138. state = 0;
  139. } else
  140. *v++ = c;
  141. break;
  142. case 3: /* Single quoted */
  143. if (c == '\'') {
  144. *v++ = 0;
  145. state = 0;
  146. } else
  147. *v++ = c;
  148. break;
  149. }
  150. }
  151. argv[argc] = 0;
  152. sz = sizeof(char *) * (argc + 1);
  153. tmp = (char **) malloc(sz);
  154. if (!tmp) {
  155. free(q);
  156. return 1;
  157. }
  158. if (argc == 0)
  159. free(q);
  160. memcpy(tmp, argv, sz);
  161. *pargc = argc;
  162. *pargv = tmp;
  163. return 0;
  164. }
  165. static void signal_handler(int signum)
  166. {
  167. (void)signum;
  168. kill_children();
  169. }
  170. int result = 0;
  171. int alarm_gone_off = 0;
  172. static void alarm_handler(int signum)
  173. {
  174. (void)signum;
  175. if (!result)
  176. alarm_gone_off = 1;
  177. kill_children();
  178. }
  179. int main(int argc, char *argv[], char **env)
  180. {
  181. int p;
  182. pid_t child_pid;
  183. int status;
  184. int duration = 0;
  185. p = 1;
  186. if (argc > 1) {
  187. if (strncmp(argv[p], "--help", 6) == 0 ||
  188. strncmp(argv[p], "-h", 2) == 0) {
  189. printf( "Usage is: "
  190. "fstest_monitor options programs...\n"
  191. " Options are:\n"
  192. " -h, --help "
  193. "This help message\n"
  194. " -d, --duration arg "
  195. "Stop after arg seconds\n"
  196. "\n"
  197. "Run programs and wait for them."
  198. " If duration is specified,\n"
  199. "kill all programs"
  200. " after that number of seconds have elapsed.\n"
  201. "Example: "
  202. "fstest_monitor \"/bin/ls -l\" /bin/date\n"
  203. );
  204. return 1;
  205. }
  206. if (strncmp(argv[p], "--duration", 10) == 0 ||
  207. strncmp(argv[p], "-d", 2) == 0) {
  208. char *s;
  209. if (p+1 < argc && !isdigit(argv[p][strlen(argv[p])-1]))
  210. ++p;
  211. s = argv[p];
  212. while (*s && !isdigit(*s))
  213. ++s;
  214. duration = atoi(s);
  215. ++p;
  216. }
  217. }
  218. signal(SIGTERM, signal_handler);
  219. signal(SIGINT, signal_handler);
  220. for (; p < argc; ++p) {
  221. child_pid = fork();
  222. if (child_pid) {
  223. /* Parent */
  224. if (child_pid == (pid_t) -1) {
  225. kill_children();
  226. result = 1;
  227. break;
  228. }
  229. add_child(child_pid);
  230. } else {
  231. /* Child */
  232. int cargc;
  233. char **cargv;
  234. if (parse_command_line(argv[p], &cargc, &cargv))
  235. return 1;
  236. execve(cargv[0], cargv, env);
  237. return 1;
  238. }
  239. }
  240. if (!result && duration > 0) {
  241. signal(SIGALRM, alarm_handler);
  242. alarm(duration);
  243. }
  244. while (have_children()) {
  245. status = 0;
  246. child_pid = wait(&status);
  247. if (child_pid == (pid_t) -1) {
  248. if (errno == EINTR)
  249. continue;
  250. kill_children();
  251. return 1;
  252. }
  253. mark_child_gone(child_pid);
  254. if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
  255. result = 1;
  256. kill_children();
  257. }
  258. }
  259. if (alarm_gone_off)
  260. return 0;
  261. return result;
  262. }