/usr/src/suites/install/libbe/src/utils/C/multi_driver.c
C | 355 lines | 222 code | 55 blank | 78 comment | 42 complexity | 366dd9d7fca4193f8930eec643f566e0 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
- /*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
- /*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
- /*
- * The program is a wrapper to fork a process to execute a command user
- * gives, and it also provides an user interface to the process it forked
- * if the process would asked user input interaction(e.g., yes or no), it
- * simulates the activity to input the interactives.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <ctype.h>
- #include <limits.h>
- #include <signal.h>
- #include <netinet/in.h>
- #include <inttypes.h>
- #define MAX_PRC_NUM 1024
- typedef struct exec_prc {
- pid_t pid;
- char *exec_cmd;
- char stdout_file[PATH_MAX];
- int stdout_fd;
- char stderr_file[PATH_MAX];
- int stderr_fd;
- int child_ret;
- } exec_prc_t;
- static exec_prc_t prc_array[MAX_PRC_NUM];
- static void
- usage() {
- (void) printf("USAGE:\n\t");
- (void) printf(" prog -i <process number> -p <cmd in p1>.\n\t");
- (void) printf(" prog -p <cmd in p1> -s <signal> -d <data input>\n");
- (void) printf("E.G.\n\t");
- (void) printf(" prog -i 2 -p ls -p pwd\n\t");
- (void) printf(" prog -p <application> -s 2: send SIGINT to daemon\n\t");
- (void) printf(" prog -p <application> -d aaaaa: send aaaaa to app");
- (void) printf(" in case to test input conditions\n");
- }
- /*
- * This function do work as cleaner, free memory, remove unused file
- */
- static void
- cleanup() {
- int i = 0;
- for (i = 0; i < MAX_PRC_NUM; i++) {
- if (prc_array[i].exec_cmd) {
- free(prc_array[i].exec_cmd);
- prc_array[i].exec_cmd = NULL;
- (void) unlink(prc_array[i].stdout_file);
- (void) unlink(prc_array[i].stderr_file);
- }
- }
- }
- /*
- * This function dump stdout and stderr of child process to stdout
- */
- static int
- dumpfile(int i) {
- char divider[] = "======";
- char *out = "stdout";
- char *err = "stderr";
- char *s_d = "========";
- char line[256];
- FILE *o_fd = NULL, *e_fd = NULL;
- (void) memset(line, 0, sizeof (line));
- if (!prc_array[i].exec_cmd)
- return (-1);
- (void) printf("Process %d: %s\n", i+1, prc_array[i].exec_cmd);
- (void) printf("Ret code: %d\n", (prc_array[i].child_ret/256)%128);
- (void) printf("%s %s %s\n", divider, out, divider);
- if ((o_fd = fopen(prc_array[i].stdout_file, "r")) == NULL) {
- perror("Could not find out file");
- exit(-1);
- }
- while (!feof(o_fd)) {
- (void) memset(line, 0, sizeof (line));
- (void) fgets(line, sizeof (line), o_fd);
- (void) printf("%s", line);
- }
- (void) fclose(o_fd);
- (void) printf("\n%s%s%s\n", divider, s_d, divider);
- (void) printf("%s %s %s\n", divider, err, divider);
- if ((e_fd = fopen(prc_array[i].stderr_file, "r")) == NULL) {
- perror("Could not find err file");
- exit(-1);
- }
- while (!feof(e_fd)) {
- (void) memset(line, 0, sizeof (line));
- (void) fgets(line, sizeof (line), e_fd);
- (void) printf("%s", line);
- }
- (void) fclose(e_fd);
- (void) printf("\n%s%s%s\n\n", divider, s_d, divider);
- return (0);
- }
- int
- main(int argc, char *argv[]) {
- int i = 0, c = 0, t = 0;
- unsigned int prc_num = 0;
- char *tmp_dir = "/tmp";
- char tmp_out_tp[20];
- char tmp_err_tp[20];
- unsigned int tx_sig = 0, tx_sig_sign = 0;
- unsigned int tx_data_sign = 0;
- /* Presume the longest input from user is 256 */
- char tx_data[20][256];
- (void) memset(tmp_out_tp, 0, sizeof (tmp_out_tp));
- (void) memset(tmp_err_tp, 0, sizeof (tmp_err_tp));
- for (t = 0; t < 20; t++) {
- (void) memset(tx_data[t], 0, sizeof (tx_data[t]));
- }
- if (argc <= 3) {
- usage();
- exit(-1);
- }
- (void) memset(prc_array, 0, sizeof (prc_array));
- while ((c = getopt(argc, argv, "i:p:s:d:")) != -1) {
- switch (c) {
- case 'i':
- prc_num = atoi(optarg);
- break;
- case 'p':
- /* Copy command to different process cmd buffer */
- prc_array[i].exec_cmd = (char *) \
- malloc(strlen(optarg)+1);
- (void) memset(prc_array[i].exec_cmd, 0, \
- strlen(optarg)+1);
- (void) strncpy(prc_array[i].exec_cmd, optarg, \
- strlen(optarg)+1);
- /*
- * Generate temporay file for stdout and stderr
- * in child processes.
- */
- (void) memset(tmp_out_tp, 0, sizeof (tmp_out_tp));
- (void) memset(tmp_err_tp, 0, sizeof (tmp_err_tp));
- (void) snprintf(tmp_out_tp, sizeof (tmp_out_tp), \
- "%s/p%d_out_XXXXXX", tmp_dir, i);
- (void) snprintf(tmp_err_tp, sizeof (tmp_err_tp), \
- "%s/p%d_err_XXXXXX", tmp_dir, i);
- prc_array[i].stdout_fd = mkstemp(tmp_out_tp);
- (void) sprintf(prc_array[i].stdout_file, "%s", \
- tmp_out_tp);
- prc_array[i].stderr_fd = mkstemp(tmp_err_tp);
- (void) sprintf(prc_array[i].stderr_file, "%s", \
- tmp_err_tp);
- i++;
- break;
- case 's':
- /* Check the signal user want to input */
- tx_sig_sign = 1;
- tx_sig = atoi(optarg);
- break;
- case 'd':
- /* Check the character user want to input */
- (void) snprintf(tx_data[tx_data_sign], \
- sizeof (tx_data[tx_data_sign]), \
- "%s\n", optarg);
- tx_data_sign += 1;
- break;
- default:
- usage();
- exit(-1);
- }
- }
- /* Default fork one child process number */
- if (prc_num == 0) {
- prc_num = 1;
- }
- /* Only could send signal to one process */
- if (tx_sig_sign != 0 && prc_num >= 2) {
- usage();
- exit(-1);
- }
- /* Only could send signal to one process */
- if (tx_data_sign != 0 && prc_num >= 2) {
- usage();
- exit(-1);
- }
- /* Create pipe so that parent could input data to child process */
- int ret, t_pipe[2];
- ret = pipe(t_pipe);
- for (i = 0; i < prc_num && prc_array[i].exec_cmd; i++) {
- if ((prc_array[i].pid = fork()) == 0) {
- /* If no available command, just exit */
- if (! prc_array[i].exec_cmd) {
- (void) printf("process %d exit\n", i);
- exit(0);
- }
- char *arg[256];
- int j = 0;
- /*
- * Close write pipe. Here parent doesn't
- * need to check child status
- */
- (void) close(t_pipe[0]);
- /* Redirect stdin to pipe read socket */
- (void) dup2(t_pipe[1], 0);
- /* Redirect stdout and stderr */
- (void) dup2(prc_array[i].stdout_fd, 1);
- (void) dup2(prc_array[i].stderr_fd, 2);
- /* Analyze command in child process */
- char *token = strtok(prc_array[i].exec_cmd, " ");
- while (token != NULL) {
- arg[j] = (char *)malloc(PATH_MAX);
- (void) memset(arg[j], 0, PATH_MAX);
- (void) sprintf(arg[j], "%s", token);
- /* Get next token: */
- token = strtok(NULL, " ");
- j++;
- }
- arg[j] = (char *)0;
- /* Run execv to replace current process context */
- ret = execvp(arg[0], arg);
- #ifdef DEBUG
- if (ret != 0) {
- perror("Exec error");
- }
- #endif
- exit(ret);
- } else {
- /* Close read socket */
- (void) close(t_pipe[1]);
- if (tx_data_sign != 0) {
- /*
- * Send signal to child process after 5 second, this is
- * an estimated value, because parent could not get
- * the status of child right now since stdout/stderr
- * is redirected to stdout_fd/stderr_fd.
- */
- (void) sleep(3);
- for (i = 0; i < tx_data_sign; i++) {
- (void) sleep(1);
- /* Write user input data to child process */
- ret = write(t_pipe[0], \
- tx_data[i], strlen(tx_data[i]));
- if (ret < 0) {
- perror("Write to child error");
- exit(ret);
- }
- }
- /* Close pipe */
- (void) close(t_pipe[1]);
- }
- /* Send signal if needed. */
- if (tx_sig_sign != 0) {
- /* Send signal to child process after 1 second */
- (void) sleep(1);
- /* Only support signal send one child process */
- (void) kill(prc_array[0].pid, tx_sig);
- }
- }
- }
- /*
- * Wait these child process exit and clean up the
- * running environments, i.e., tidy the output from
- * stdout and stderr in child process; unlink temporary
- * files; free the alloc buffer, etc.
- */
- for (i = 0; i < prc_num; i++) {
- if (prc_array[i].pid != 0) {
- (void) waitpid(prc_array[i].pid, \
- &(prc_array[i].child_ret), \
- WEXITED);
- }
- /* read temporary output into one report file */
- (void) dumpfile(i);
- }
- /* clean up running environment */
- cleanup();
- ret = 0;
- for (i = 0; i < prc_num; i++) {
- ret |= (prc_array[i].child_ret/256)%128;
- }
- return (ret);
- }