/** run_command(Command* cmd) ** Take a filled-out Command struct and run the command as specified. */ void run_command (Command* cmd) { //Fork cmd->pid = fork(); if(cmd->pid) { //Parent - add to background process list or wait if (cmd->background) { //Add to running background processes list add_background(cmd->pid); } else { wait_status(cmd->pid, 0); } } else { //Child //Input redirection (file or dev/null for background) if (cmd->background && !cmd->redirectIn) { dup2(open("/dev/null", O_RDONLY), 0); } else if (cmd->redirectIn) { dup2(fileno(cmd->redirectIn), STDIN_FILENO); fclose(cmd->redirectIn); } //Output redirection if (cmd->redirectOut) { dup2(fileno(cmd->redirectOut), STDOUT_FILENO); fclose(cmd->redirectOut); } //Reset normal signal handling signal(SIGINT, SIG_DFL); //Exec the child exec_child(cmd); } }
/* * This is functionally equivalent to forkpty(3). We do it manually to obtain * a little bit more control of the process, and as a bonus avoid linking to * the libutil library in glibc. */ static int pty_spawn(struct kmscon_pty *pty, int master, unsigned short width, unsigned short height) { pid_t pid; struct winsize ws; memset(&ws, 0, sizeof(ws)); ws.ws_col = width; ws.ws_row = height; log_debug("forking child"); pid = fork(); switch (pid) { case -1: log_err("cannot fork: %m"); return -errno; case 0: setup_child(master, &ws); exec_child(pty->fd); exit(EXIT_FAILURE); default: pty->fd = master; pty->child = pid; break; } return 0; }
int start(command_options *commands) { pid_t child = fork(); if (child == 0) { return exec_child(commands); } else { return hold_child(child, commands); } }
static errno_t sdap_fork_child(struct tevent_context *ev, struct sdap_child *child) { int pipefd_to_child[2]; int pipefd_from_child[2]; pid_t pid; int ret; errno_t err; ret = pipe(pipefd_from_child); if (ret == -1) { err = errno; DEBUG(1, ("pipe failed [%d][%s].\n", err, strerror(err))); return err; } ret = pipe(pipefd_to_child); if (ret == -1) { err = errno; DEBUG(1, ("pipe failed [%d][%s].\n", err, strerror(err))); return err; } pid = fork(); if (pid == 0) { /* child */ err = exec_child(child, pipefd_to_child, pipefd_from_child, LDAP_CHILD, ldap_child_debug_fd); if (err != EOK) { DEBUG(1, ("Could not exec LDAP child: [%d][%s].\n", err, strerror(err))); return err; } } else if (pid > 0) { /* parent */ child->pid = pid; child->read_from_child_fd = pipefd_from_child[0]; close(pipefd_from_child[1]); child->write_to_child_fd = pipefd_to_child[1]; close(pipefd_to_child[0]); fd_nonblocking(child->read_from_child_fd); fd_nonblocking(child->write_to_child_fd); ret = child_handler_setup(ev, pid, NULL, NULL); if (ret != EOK) { return ret; } } else { /* error */ err = errno; DEBUG(1, ("fork failed [%d][%s].\n", err, strerror(err))); return err; } return EOK; }
int main (int argc, char* argv[]) { if (argc < 2) { fprintf(stderr, "usage: %s COMMAND [ ARGS ... ]\n", argv[0]); return 255; } child_pid = fork(); if (child_pid == -1) { perror("fork error"); return 255; } else if (child_pid == 0) { return exec_child(argc, argv); } else { return main_loop(); } }
int execute(char **args) { if(args==NULL || args[0]==NULL) return 1; int i,len; i=0; len=num_bultin(); for(i=0;i<len;i++) { if(!strcmp(args[0],builtin_name[i])) return (*builtin_function[i])(args); } int background=is_background(args); int status=exec_child(args,background); return status; }
int main(int argc, char **argv) { int maxjobs = -1; int curjobs = 0; double maxload = -1; int argsatonce = 1; int opt; char **command = calloc(sizeof(char*), argc); char **arguments = NULL; int argidx = 0; int arglen = 0; int cidx = 0; int returncode = 0; int replace_cb = 0; int stdout_fd = 1; int stderr_fd = 2; char *t; while ((argv[optind] && strcmp(argv[optind], "--") != 0) && (opt = getopt(argc, argv, "+hij:l:n:")) != -1) { switch (opt) { case 'h': usage(); break; case 'i': replace_cb = 1; break; case 'j': errno = 0; maxjobs = strtoul(optarg, &t, 0); if (errno != 0 || (t-optarg) != strlen(optarg)) { fprintf(stderr, "option '%s' is not a number\n", optarg); exit(2); } break; case 'l': errno = 0; maxload = strtod(optarg, &t); if (errno != 0 || (t-optarg) != strlen(optarg)) { fprintf(stderr, "option '%s' is not a number\n", optarg); exit(2); } break; case 'n': errno = 0; argsatonce = strtoul(optarg, &t, 0); if (errno != 0 || argsatonce < 1 || (t-optarg) != strlen(optarg)) { fprintf(stderr, "option '%s' is not a positive number\n", optarg); exit(2); } break; default: /* ’?’ */ usage(); break; } } if (replace_cb && argsatonce > 1) { fprintf(stderr, "options -i and -n are incomaptible\n"); exit(2); } if (maxjobs < 0) { #ifdef _SC_NPROCESSORS_ONLN maxjobs = sysconf(_SC_NPROCESSORS_ONLN); #else #warning Cannot autodetect number of CPUS on this system: _SC_NPROCESSORS_ONLN not defined. maxjobs = 1; #endif } while (optind < argc) { if (strcmp(argv[optind], "--") == 0) { int i; optind++; arglen = argc - optind; arguments = calloc(sizeof(char *), arglen); if (! arguments) { exit(1); } for (i = 0; i < arglen; i++) { arguments[i] = strdup(argv[optind + i]); } optind += i; } else { command[cidx] = strdup(argv[optind]); cidx++; } optind++; } if (argsatonce > 1 && ! command[0]) { fprintf(stderr, "option -n cannot be used without a command\n"); exit(2); } pipe_child_stdout = create_pipe_child(&stdout_fd, 1); pipe_child_stderr = create_pipe_child(&stderr_fd, 2); if ((pipe_child_stdout < 0) || (pipe_child_stderr < 0)) exit(1); while (argidx < arglen) { double load; getloadavg(&load, 1); if ((maxjobs == 0 || curjobs < maxjobs) && (maxload < 0 || load < maxload)) { if (argsatonce > arglen - argidx) argsatonce = arglen - argidx; exec_child(command, arguments + argidx, replace_cb, argsatonce, stdout_fd, stderr_fd); argidx += argsatonce; curjobs++; } if (maxjobs == 0 || curjobs == maxjobs) { returncode |= wait_for_child(0); curjobs--; } if (maxload > 0 && load >= maxload) { int r; sleep(1); /* XXX We should have a better * heurestic than this */ r = wait_for_child(WNOHANG); if (r > 0) returncode |= r; if (r != -1) curjobs--; } } while (curjobs > 0) { returncode |= wait_for_child(0); curjobs--; } if (pipe_child_stdout) { kill(pipe_child_stdout, SIGKILL); wait_for_child(0); } if (pipe_child_stderr) { kill(pipe_child_stderr, SIGKILL); wait_for_child(0); } return returncode; }
/** run_pipe_commands (Command* cmd1, Command* cmd2) ** Take two commands and run them, piped together. */ void run_pipe_commands (Command* cmd1, Command* cmd2) { int fds[2]; //Make pipe between commands - 0 is read end, 1 is write end pipe(fds); //Fork first command cmd1->pid = fork(); if(!cmd1->pid) { //Child //Do input redirection if (cmd1->redirectIn) { dup2(fileno(cmd1->redirectIn), STDIN_FILENO); fclose(cmd2->redirectIn); } //Set stdout to write end of pipe dup2(fds[1] , 1); //Close files close(fds[0]); close(fds[1]); //Exec exec_child(cmd1); } //Fork second command cmd2->pid = fork(); if(!cmd2->pid) { //Child //Do output redirection if (cmd2->redirectOut) { dup2(fileno(cmd2->redirectOut), STDOUT_FILENO); fclose(cmd2->redirectOut); } //Set stdin to read end of pipe dup2(fds[0], 0); close(fds[0]); close(fds[1]); //Exec exec_child(cmd2); } //Close files close(fds[0]); close(fds[1]); int status[2]; //Wait on first process - if it fails, terminate the second if (wait_status(cmd1->pid, 0) == 1) { //Error occured - terminate kill(cmd2->pid, SIGINT); //Not a background command so we need to reap cmd2. //Don't want to display a message so don't use that command. waitpid(cmd2->pid, NULL, 0); } //Wait on second process waitpid(cmd2->pid, &status[1], 0); }
static bool client_exec_script(struct master_service_connection *conn) { ARRAY_TYPE(const_string) envs; const char *const *args; string_t *input; void *buf; size_t prev_size, scanpos; bool header_complete = FALSE, noreply = FALSE; ssize_t ret; int status; pid_t pid; net_set_nonblock(conn->fd, FALSE); input = t_buffer_create(IO_BLOCK_SIZE); /* Input contains: VERSION .. <lf> [alarm=<secs> <lf>] "noreply" | "-" (or anything really) <lf> arg 1 <lf> arg 2 <lf> ... <lf> DATA This is quite a horrible protocol. If alarm is specified, it MUST be before "noreply". If "noreply" isn't given, something other string (typically "-") must be given which is eaten away. */ alarm(SCRIPT_READ_TIMEOUT_SECS); scanpos = 1; while (!header_complete) { const unsigned char *pos, *end; prev_size = input->used; buf = buffer_append_space_unsafe(input, IO_BLOCK_SIZE); /* peek in socket input buffer */ ret = recv(conn->fd, buf, IO_BLOCK_SIZE, MSG_PEEK); if (ret <= 0) { buffer_set_used_size(input, prev_size); if (strchr(str_c(input), '\n') != NULL) script_verify_version(t_strcut(str_c(input), '\n')); if (ret < 0) i_fatal("recv(MSG_PEEK) failed: %m"); i_fatal("recv(MSG_PEEK) failed: disconnected"); } /* scan for final \n\n */ pos = CONST_PTR_OFFSET(input->data, scanpos); end = CONST_PTR_OFFSET(input->data, prev_size + ret); for (; pos < end; pos++) { if (pos[-1] == '\n' && pos[0] == '\n') { header_complete = TRUE; pos++; break; } } scanpos = pos - (const unsigned char *)input->data; /* read data for real (up to and including \n\n) */ ret = recv(conn->fd, buf, scanpos-prev_size, 0); if (prev_size+ret != scanpos) { if (ret < 0) i_fatal("recv() failed: %m"); if (ret == 0) i_fatal("recv() failed: disconnected"); i_fatal("recv() failed: size of definitive recv() differs from peek"); } buffer_set_used_size(input, scanpos); } alarm(0); /* drop the last two LFs */ buffer_set_used_size(input, scanpos-2); args = t_strsplit(str_c(input), "\n"); script_verify_version(*args); args++; t_array_init(&envs, 16); if (*args != NULL) { const char *p; if (str_begins(*args, "alarm=")) { unsigned int seconds; if (str_to_uint(*args + 6, &seconds) < 0) i_fatal("invalid alarm option"); alarm(seconds); args++; } while (str_begins(*args, "env_")) { const char *envname, *env; env = t_str_tabunescape(*args+4); p = strchr(env, '='); if (p == NULL) i_fatal("invalid environment variable"); envname = t_strdup_until(*args+4, p); if (str_array_find(accepted_envs, envname)) array_append(&envs, &env, 1); args++; } if (strcmp(*args, "noreply") == 0) { noreply = TRUE; } if (**args == '\0') i_fatal("empty options"); args++; } array_append_zero(&envs); if (noreply) { /* no need to fork and check exit status */ exec_child(conn, args, array_idx(&envs, 0)); i_unreached(); } if ((pid = fork()) == (pid_t)-1) { i_error("fork() failed: %m"); return FALSE; } if (pid == 0) { /* child */ exec_child(conn, args, array_idx(&envs, 0)); i_unreached(); } /* parent */ /* check script exit status */ if (waitpid(pid, &status, 0) < 0) { i_error("waitpid() failed: %m"); return FALSE; } else if (WIFEXITED(status)) { ret = WEXITSTATUS(status); if (ret != 0) { i_error("Script terminated abnormally, exit status %d", (int)ret); return FALSE; } } else if (WIFSIGNALED(status)) { i_error("Script terminated abnormally, signal %d", WTERMSIG(status)); return FALSE; } else if (WIFSTOPPED(status)) { i_fatal("Script stopped, signal %d", WSTOPSIG(status)); return FALSE; } else { i_fatal("Script terminated abnormally, return status %d", status); return FALSE; } return TRUE; }
static int program_client_local_connect (struct program_client *pclient) { struct program_client_local *slclient = (struct program_client_local *) pclient; int fd[2] = { -1, -1 }; struct program_client_extra_fd *efds = NULL; int *parent_extra_fds = NULL, *child_extra_fds = NULL; unsigned int xfd_count = 0, i; /* create normal I/O fd */ if ( pclient->input != NULL || pclient->output != NULL || pclient->output_seekable ) { if ( socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0 ) { i_error("socketpair() failed: %m"); return -1; } } /* create pipes for additional output through side-channel fds */ if ( array_is_created(&pclient->extra_fds) ) { int extra_fd[2]; efds = array_get_modifiable(&pclient->extra_fds, &xfd_count); if ( xfd_count > 0 ) { parent_extra_fds = t_malloc(sizeof(int) * xfd_count); child_extra_fds = t_malloc(sizeof(int) * xfd_count * 2 + 1); for ( i = 0; i < xfd_count; i++ ) { if ( pipe(extra_fd) < 0 ) { i_error("pipe() failed: %m"); return -1; } parent_extra_fds[i] = extra_fd[0]; child_extra_fds[i*2+0] = extra_fd[1]; child_extra_fds[i*2+1] = efds[i].child_fd; } child_extra_fds[xfd_count*2] = -1; } } /* fork child */ if ( (slclient->pid = fork()) == (pid_t)-1 ) { i_error("fork() failed: %m"); /* clean up */ if ( fd[0] >= 0 && close(fd[0]) < 0 ) { i_error("close(pipe_fd[0]) failed: %m"); } if ( fd[1] >= 0 && close(fd[1]) < 0 ) { i_error("close(pipe_fd[1]) failed: %m"); } for ( i = 0; i < xfd_count; i++ ) { if ( close(child_extra_fds[i*2]) < 0 ) { i_error("close(extra_fd[1]) failed: %m"); } if ( close(parent_extra_fds[i]) < 0 ) { i_error("close(extra_fd[0]) failed: %m"); } } return -1; } if ( slclient->pid == 0 ) { unsigned int count; const char *const *envs = NULL; /* child */ if ( fd[1] >= 0 && close(fd[1]) < 0 ) { i_error("close(pipe_fd[1]) failed: %m"); } for ( i = 0; i < xfd_count; i++ ) { if ( close(parent_extra_fds[i]) < 0 ) i_error("close(extra_fd[0]) failed: %m"); } /* drop privileges if we have any */ if ( getuid() == 0 ) { uid_t uid; gid_t gid; /* switch back to root */ if (seteuid(0) < 0) i_fatal("seteuid(0) failed: %m"); /* drop gids first */ gid = getgid(); if ( gid == 0 || gid != pclient->set.gid ) { if ( pclient->set.gid != 0 ) gid = pclient->set.gid; else gid = getegid(); } if ( setgroups(1, &gid) < 0 ) i_fatal("setgroups(%d) failed: %m", gid); if ( gid != 0 && setgid(gid) < 0 ) i_fatal("setgid(%d) failed: %m", gid); /* drop uid */ if ( pclient->set.uid != 0 ) uid = pclient->set.uid; else uid = geteuid(); if ( uid != 0 && setuid(uid) < 0 ) i_fatal("setuid(%d) failed: %m", uid); } i_assert(pclient->set.uid == 0 || getuid() != 0); i_assert(pclient->set.gid == 0 || getgid() != 0); if ( array_is_created(&pclient->envs) ) envs = array_get(&pclient->envs, &count); exec_child(pclient->path, pclient->args, envs, ( pclient->input != NULL ? fd[0] : -1 ), ( pclient->output != NULL || pclient->output_seekable ? fd[0] : -1 ), child_extra_fds, pclient->set.drop_stderr); i_unreached(); } /* parent */ if ( fd[0] >= 0 && close(fd[0]) < 0 ) i_error("close(pipe_fd[0]) failed: %m"); if ( fd[1] >= 0 ) { net_set_nonblock(fd[1], TRUE); pclient->fd_in = ( pclient->output != NULL || pclient->output_seekable ? fd[1] : -1 ); pclient->fd_out = ( pclient->input != NULL ? fd[1] : -1 ); } for ( i = 0; i < xfd_count; i++ ) { if ( close(child_extra_fds[i*2]) < 0 ) i_error("close(extra_fd[1]) failed: %m"); net_set_nonblock(parent_extra_fds[i], TRUE); efds[i].parent_fd = parent_extra_fds[i]; } program_client_init_streams(pclient); return program_client_connected(pclient); }