PageRenderTime 63ms CodeModel.GetById 34ms RepoModel.GetById 0ms app.codeStats 0ms

/usr/src/suites/storage/fwflash/src/utils/C/multi_driver.c

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