PageRenderTime 54ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

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

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