int main(int argc, char *argv[]) { if (argc == 1) { fprintf(stderr, "please supply at least one command to run\n"); return 1; } install_term_and_int_handlers(); pid_t cmds[MAX_CMDS]; int n_cmds = 0; { char **cmd_end = argv + argc; char **arg_it = argv + 1; int wait_on_command = 1; int wait_on_all_commands = 1; // TODO: parse more commands, including -h/--help with getopt if (! strcmp(*arg_it, "-f")) { ++arg_it; wait_on_all_commands = 0; } char **cmd_begin = arg_it; for (; arg_it < cmd_end; ++arg_it) { if (! strcmp(*arg_it, SEP)) { *arg_it = 0; // replace with null to terminate when passed to execvp if (wait_on_command) cmds[n_cmds++] = run_proc(cmd_begin); else run_proc(cmd_begin); cmd_begin = arg_it + 1; wait_on_command = wait_on_all_commands; } } if (cmd_begin < cmd_end) { if (wait_on_command) cmds[n_cmds++] = run_proc(cmd_begin); else run_proc(cmd_begin); wait_on_command = wait_on_all_commands; } } int error_code = wait_for_requested_commands_to_exit(n_cmds, cmds); remove_term_and_int_handlers(); alarm(WAIT_FOR_PROC_DEATH_TIMEOUT); kill(0, SIGTERM); wait_for_all_processes_to_exit(error_code); # ifndef NDEBUG fprintf(stderr, "all processes exited cleanly\n"); # endif return error_code; }
static void parse_argv(ChildProcs *child_procs, Opts *opts, int argc, char *argv[]) { child_procs->n_cmds = 1; char **args_end = argv + argc; for (char **i = argv + 1; i < args_end; ++i) { if (! strcmp(*i, SEP)) ++child_procs->n_cmds; } child_procs->cmds = calloc(child_procs->n_cmds, sizeof(Cmd)); *opts = (Opts) { .signal_everything = false }; parse_cmd_args(opts, child_procs->cmds, argv + 1, args_end); char **arg_it = child_procs->cmds->args; int cmd_idx = 0; for (; arg_it < args_end; ++arg_it) { if (! strcmp(*arg_it, SEP)) { *arg_it = 0; // replace with null to terminate when passed to execvp if (arg_it + 1 == args_end) { fprintf(stderr, "command must follow `---'\n"); exit(1); } parse_cmd_args(opts, child_procs->cmds + (++cmd_idx), arg_it + 1, args_end); Cmd *cmd = child_procs->cmds + cmd_idx; arg_it = cmd->args - 1; } } } int main(int argc, char *argv[]) { if (argc == 1) { fprintf(stderr, "please supply at least one command to run\n"); return 1; } ChildProcs child_procs; Opts opts; parse_argv(&child_procs, &opts, argc, argv); int n_watch_cmds = 0; for (int i = 0; i < child_procs.n_cmds; ++i) { if (child_procs.cmds[i].watch) ++n_watch_cmds; } // if -f hasn't been used then watch every command if (0 == n_watch_cmds) { for (int i = 0; i < child_procs.n_cmds; ++i) { if (! child_procs.cmds[i].configuring) { ++n_watch_cmds; child_procs.cmds[i].watch = true; } } } Cmd **watch_cmds = calloc(n_watch_cmds, sizeof(Cmd *)); { int watch_cmd_end = 0; for (int i = 0; i < child_procs.n_cmds; ++i) { if (child_procs.cmds[i].watch) watch_cmds[watch_cmd_end++] = child_procs.cmds + i; } } install_term_and_int_handlers(); int error_code; run_configure_cmds(child_procs.n_cmds, child_procs.cmds); if (running) { run_cmds(child_procs.n_cmds, child_procs.cmds); error_code = wait_for_requested_commands_to_exit(n_watch_cmds, watch_cmds); remove_term_and_int_handlers(); alarm(WAIT_FOR_PROC_DEATH_TIMEOUT); kill(opts.signal_everything ? -1 : 0, SIGTERM); wait_for_all_processes_to_exit(error_code); DPRINTF("all processes exited cleanly"); } free(watch_cmds); free(child_procs.cmds); return error_code; }