PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/usr/src/suites/install/libbe/src/utils/C/multi_driver.c

https://bitbucket.org/illumos/illumos-stc
C | 355 lines | 222 code | 55 blank | 78 comment | 42 complexity | 366dd9d7fca4193f8930eec643f566e0 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  1. /*
  2. * CDDL HEADER START
  3. *
  4. * The contents of this file are subject to the terms of the
  5. * Common Development and Distribution License (the "License").
  6. * You may not use this file except in compliance with the License.
  7. *
  8. * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  9. * or http://www.opensolaris.org/os/licensing.
  10. * See the License for the specific language governing permissions
  11. * and limitations under the License.
  12. *
  13. * When distributing Covered Code, include this CDDL HEADER in each
  14. * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15. * If applicable, add the following below this CDDL HEADER, with the
  16. * fields enclosed by brackets "[]" replaced with your own identifying
  17. * information: Portions Copyright [yyyy] [name of copyright owner]
  18. *
  19. * CDDL HEADER END
  20. */
  21. /*
  22. * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
  23. * Use is subject to license terms.
  24. */
  25. /*
  26. * The program is a wrapper to fork a process to execute a command user
  27. * gives, and it also provides an user interface to the process it forked
  28. * if the process would asked user input interaction(e.g., yes or no), it
  29. * simulates the activity to input the interactives.
  30. */
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <unistd.h>
  34. #include <string.h>
  35. #include <sys/types.h>
  36. #include <sys/wait.h>
  37. #include <ctype.h>
  38. #include <limits.h>
  39. #include <signal.h>
  40. #include <netinet/in.h>
  41. #include <inttypes.h>
  42. #define MAX_PRC_NUM 1024
  43. typedef struct exec_prc {
  44. pid_t pid;
  45. char *exec_cmd;
  46. char stdout_file[PATH_MAX];
  47. int stdout_fd;
  48. char stderr_file[PATH_MAX];
  49. int stderr_fd;
  50. int child_ret;
  51. } exec_prc_t;
  52. static exec_prc_t prc_array[MAX_PRC_NUM];
  53. static void
  54. usage() {
  55. (void) printf("USAGE:\n\t");
  56. (void) printf(" prog -i <process number> -p <cmd in p1>.\n\t");
  57. (void) printf(" prog -p <cmd in p1> -s <signal> -d <data input>\n");
  58. (void) printf("E.G.\n\t");
  59. (void) printf(" prog -i 2 -p ls -p pwd\n\t");
  60. (void) printf(" prog -p <application> -s 2: send SIGINT to daemon\n\t");
  61. (void) printf(" prog -p <application> -d aaaaa: send aaaaa to app");
  62. (void) printf(" in case to test input conditions\n");
  63. }
  64. /*
  65. * This function do work as cleaner, free memory, remove unused file
  66. */
  67. static void
  68. cleanup() {
  69. int i = 0;
  70. for (i = 0; i < MAX_PRC_NUM; i++) {
  71. if (prc_array[i].exec_cmd) {
  72. free(prc_array[i].exec_cmd);
  73. prc_array[i].exec_cmd = NULL;
  74. (void) unlink(prc_array[i].stdout_file);
  75. (void) unlink(prc_array[i].stderr_file);
  76. }
  77. }
  78. }
  79. /*
  80. * This function dump stdout and stderr of child process to stdout
  81. */
  82. static int
  83. dumpfile(int i) {
  84. char divider[] = "======";
  85. char *out = "stdout";
  86. char *err = "stderr";
  87. char *s_d = "========";
  88. char line[256];
  89. FILE *o_fd = NULL, *e_fd = NULL;
  90. (void) memset(line, 0, sizeof (line));
  91. if (!prc_array[i].exec_cmd)
  92. return (-1);
  93. (void) printf("Process %d: %s\n", i+1, prc_array[i].exec_cmd);
  94. (void) printf("Ret code: %d\n", (prc_array[i].child_ret/256)%128);
  95. (void) printf("%s %s %s\n", divider, out, divider);
  96. if ((o_fd = fopen(prc_array[i].stdout_file, "r")) == NULL) {
  97. perror("Could not find out file");
  98. exit(-1);
  99. }
  100. while (!feof(o_fd)) {
  101. (void) memset(line, 0, sizeof (line));
  102. (void) fgets(line, sizeof (line), o_fd);
  103. (void) printf("%s", line);
  104. }
  105. (void) fclose(o_fd);
  106. (void) printf("\n%s%s%s\n", divider, s_d, divider);
  107. (void) printf("%s %s %s\n", divider, err, divider);
  108. if ((e_fd = fopen(prc_array[i].stderr_file, "r")) == NULL) {
  109. perror("Could not find err file");
  110. exit(-1);
  111. }
  112. while (!feof(e_fd)) {
  113. (void) memset(line, 0, sizeof (line));
  114. (void) fgets(line, sizeof (line), e_fd);
  115. (void) printf("%s", line);
  116. }
  117. (void) fclose(e_fd);
  118. (void) printf("\n%s%s%s\n\n", divider, s_d, divider);
  119. return (0);
  120. }
  121. int
  122. main(int argc, char *argv[]) {
  123. int i = 0, c = 0, t = 0;
  124. unsigned int prc_num = 0;
  125. char *tmp_dir = "/tmp";
  126. char tmp_out_tp[20];
  127. char tmp_err_tp[20];
  128. unsigned int tx_sig = 0, tx_sig_sign = 0;
  129. unsigned int tx_data_sign = 0;
  130. /* Presume the longest input from user is 256 */
  131. char tx_data[20][256];
  132. (void) memset(tmp_out_tp, 0, sizeof (tmp_out_tp));
  133. (void) memset(tmp_err_tp, 0, sizeof (tmp_err_tp));
  134. for (t = 0; t < 20; t++) {
  135. (void) memset(tx_data[t], 0, sizeof (tx_data[t]));
  136. }
  137. if (argc <= 3) {
  138. usage();
  139. exit(-1);
  140. }
  141. (void) memset(prc_array, 0, sizeof (prc_array));
  142. while ((c = getopt(argc, argv, "i:p:s:d:")) != -1) {
  143. switch (c) {
  144. case 'i':
  145. prc_num = atoi(optarg);
  146. break;
  147. case 'p':
  148. /* Copy command to different process cmd buffer */
  149. prc_array[i].exec_cmd = (char *) \
  150. malloc(strlen(optarg)+1);
  151. (void) memset(prc_array[i].exec_cmd, 0, \
  152. strlen(optarg)+1);
  153. (void) strncpy(prc_array[i].exec_cmd, optarg, \
  154. strlen(optarg)+1);
  155. /*
  156. * Generate temporay file for stdout and stderr
  157. * in child processes.
  158. */
  159. (void) memset(tmp_out_tp, 0, sizeof (tmp_out_tp));
  160. (void) memset(tmp_err_tp, 0, sizeof (tmp_err_tp));
  161. (void) snprintf(tmp_out_tp, sizeof (tmp_out_tp), \
  162. "%s/p%d_out_XXXXXX", tmp_dir, i);
  163. (void) snprintf(tmp_err_tp, sizeof (tmp_err_tp), \
  164. "%s/p%d_err_XXXXXX", tmp_dir, i);
  165. prc_array[i].stdout_fd = mkstemp(tmp_out_tp);
  166. (void) sprintf(prc_array[i].stdout_file, "%s", \
  167. tmp_out_tp);
  168. prc_array[i].stderr_fd = mkstemp(tmp_err_tp);
  169. (void) sprintf(prc_array[i].stderr_file, "%s", \
  170. tmp_err_tp);
  171. i++;
  172. break;
  173. case 's':
  174. /* Check the signal user want to input */
  175. tx_sig_sign = 1;
  176. tx_sig = atoi(optarg);
  177. break;
  178. case 'd':
  179. /* Check the character user want to input */
  180. (void) snprintf(tx_data[tx_data_sign], \
  181. sizeof (tx_data[tx_data_sign]), \
  182. "%s\n", optarg);
  183. tx_data_sign += 1;
  184. break;
  185. default:
  186. usage();
  187. exit(-1);
  188. }
  189. }
  190. /* Default fork one child process number */
  191. if (prc_num == 0) {
  192. prc_num = 1;
  193. }
  194. /* Only could send signal to one process */
  195. if (tx_sig_sign != 0 && prc_num >= 2) {
  196. usage();
  197. exit(-1);
  198. }
  199. /* Only could send signal to one process */
  200. if (tx_data_sign != 0 && prc_num >= 2) {
  201. usage();
  202. exit(-1);
  203. }
  204. /* Create pipe so that parent could input data to child process */
  205. int ret, t_pipe[2];
  206. ret = pipe(t_pipe);
  207. for (i = 0; i < prc_num && prc_array[i].exec_cmd; i++) {
  208. if ((prc_array[i].pid = fork()) == 0) {
  209. /* If no available command, just exit */
  210. if (! prc_array[i].exec_cmd) {
  211. (void) printf("process %d exit\n", i);
  212. exit(0);
  213. }
  214. char *arg[256];
  215. int j = 0;
  216. /*
  217. * Close write pipe. Here parent doesn't
  218. * need to check child status
  219. */
  220. (void) close(t_pipe[0]);
  221. /* Redirect stdin to pipe read socket */
  222. (void) dup2(t_pipe[1], 0);
  223. /* Redirect stdout and stderr */
  224. (void) dup2(prc_array[i].stdout_fd, 1);
  225. (void) dup2(prc_array[i].stderr_fd, 2);
  226. /* Analyze command in child process */
  227. char *token = strtok(prc_array[i].exec_cmd, " ");
  228. while (token != NULL) {
  229. arg[j] = (char *)malloc(PATH_MAX);
  230. (void) memset(arg[j], 0, PATH_MAX);
  231. (void) sprintf(arg[j], "%s", token);
  232. /* Get next token: */
  233. token = strtok(NULL, " ");
  234. j++;
  235. }
  236. arg[j] = (char *)0;
  237. /* Run execv to replace current process context */
  238. ret = execvp(arg[0], arg);
  239. #ifdef DEBUG
  240. if (ret != 0) {
  241. perror("Exec error");
  242. }
  243. #endif
  244. exit(ret);
  245. } else {
  246. /* Close read socket */
  247. (void) close(t_pipe[1]);
  248. if (tx_data_sign != 0) {
  249. /*
  250. * Send signal to child process after 5 second, this is
  251. * an estimated value, because parent could not get
  252. * the status of child right now since stdout/stderr
  253. * is redirected to stdout_fd/stderr_fd.
  254. */
  255. (void) sleep(3);
  256. for (i = 0; i < tx_data_sign; i++) {
  257. (void) sleep(1);
  258. /* Write user input data to child process */
  259. ret = write(t_pipe[0], \
  260. tx_data[i], strlen(tx_data[i]));
  261. if (ret < 0) {
  262. perror("Write to child error");
  263. exit(ret);
  264. }
  265. }
  266. /* Close pipe */
  267. (void) close(t_pipe[1]);
  268. }
  269. /* Send signal if needed. */
  270. if (tx_sig_sign != 0) {
  271. /* Send signal to child process after 1 second */
  272. (void) sleep(1);
  273. /* Only support signal send one child process */
  274. (void) kill(prc_array[0].pid, tx_sig);
  275. }
  276. }
  277. }
  278. /*
  279. * Wait these child process exit and clean up the
  280. * running environments, i.e., tidy the output from
  281. * stdout and stderr in child process; unlink temporary
  282. * files; free the alloc buffer, etc.
  283. */
  284. for (i = 0; i < prc_num; i++) {
  285. if (prc_array[i].pid != 0) {
  286. (void) waitpid(prc_array[i].pid, \
  287. &(prc_array[i].child_ret), \
  288. WEXITED);
  289. }
  290. /* read temporary output into one report file */
  291. (void) dumpfile(i);
  292. }
  293. /* clean up running environment */
  294. cleanup();
  295. ret = 0;
  296. for (i = 0; i < prc_num; i++) {
  297. ret |= (prc_array[i].child_ret/256)%128;
  298. }
  299. return (ret);
  300. }