Example #1
0
/** 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);
	}
}
Example #2
0
File: pty.c Project: myra/kmscon
/*
 * 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;
}
Example #3
0
File: lemon.c Project: Ndunmo/lemon
int start(command_options *commands) {
    pid_t child = fork();

    if (child == 0) {
        return exec_child(commands);
    } else {
        return hold_child(child, commands);
    }
}
Example #4
0
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;
}
Example #5
0
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;
}
Example #7
0
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;
}
Example #8
0
/** 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);
}
Example #9
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);
}