Пример #1
0
int				pipex(t_env *env, t_ast_tree *tree)
{
	int		fd[2];

	if (pipe(fd) == -1)
		return (RESET_PUT("pipe error", NULL));
	if ((E_PID = fork()) < 0)
		return (RESET_PUT("fork error", NULL));
	if (E_PID)
	{
		if (close(fd[STDOUT_FILENO]) < 0)
			return (RESET_PUT("close error", NULL));
		if (dup2(fd[STDIN_FILENO], STDIN_FILENO) == -1)
			return (RESET_PUT("dup2 error: fd 0", NULL));
		return (EXIT_SUCCESS);
	}
	else
	{
		sig_dfl();
		if (close(fd[STDIN_FILENO]) < 0)
			return (RESET_PUT("close error fd", NULL));
		if (dup2(fd[STDOUT_FILENO], STDOUT_FILENO) == -1)
			return (RESET_PUT("dup2 error: fd 1", NULL));
		E_RET = parse_chevron(env, tree);
		exit(E_RET);
	}
}
Пример #2
0
/*
** if manage fg signal: use option WUNTRACED in waitpid and understand stat_loc
*/
static int		ft_execve(t_env *env, char **pth)
{
	if (E_PID && (E_PID = fork()) < 0)
		return (RESET_PUT("fork error", NULL));
	if (E_PID)
	{
		sig_ign();
		waitpid(E_PID, &E_RET, 0);
		return (E_RET);
	}
	else
	{
		sig_dfl();
		execve(*pth, E_ARG, E_ENV);
		ft_strdel(pth);
		exit(END_PUT("execve error: ", E_ARG[0]));
	}
}
Пример #3
0
int		ft_fork_shell(t_env *env)
{
	if (E_PID && (E_PID = fork()) < 0)
		return (RESET_PUT("fork error", NULL));
	E_BUILTIN = 0;
	if (E_PID)
	{
		if (isatty(STDIN_FILENO))
			sig_ign();
		waitpid(E_PID, &E_RET, 0);
		if (isatty(STDIN_FILENO))
			sig_init();
		return (E_RET);
	}
	else
	{
		sig_dfl();
		E_RET = exec_bin(env);
		exit(E_RET);
	}
}
Пример #4
0
int
run_job(struct exe_t *exeent)
    /* fork(), redirect outputs to a temp file, and execl() the task.
     * Return ERR if it could not fork() the first time, OK otherwise. */
{

    pid_t pid;
    cl_t *line = exeent->e_line;
    int pipe_pid_fd[2];
    int ret = 0;

    /* prepare the job execution */
    if (pipe(pipe_pid_fd) != 0) {
        error_e("pipe(pipe_pid_fd) : setting job_pid to -1");
        exeent->e_job_pid = -1;
        pipe_pid_fd[0] = pipe_pid_fd[1] = -1;
    }

#ifdef CHECKRUNJOB
    debug
        ("run_job(): first pipe created successfully : about to do first fork()");
#endif                          /* CHECKRUNJOB */

    switch (pid = fork()) {
    case -1:
        error_e("Fork error : could not exec '%s'", line->cl_shell);
        return ERR;
        break;

    case 0:
        /* child */
        {
            struct passwd *pas = NULL;
            char **jobenv = NULL;
            char **sendmailenv = NULL;
            char *curshell = NULL;
            char *curhome = NULL;
            char *content_type = NULL;
            char *encoding = NULL;
            FILE *mailf = NULL;
            int status = 0;
            int to_stdout = foreground && is_stdout(line->cl_option);
            int pipe_fd[2];
            short int mailpos = 0;      /* 'empty mail file' size */
#ifdef WITH_SELINUX
            int flask_enabled = is_selinux_enabled();
#endif

            /* // */
            debug("run_job(): child: %s, output to %s, %s, %s\n",
                  is_mail(line->cl_option) ? "mail" : "no mail",
                  to_stdout ? "stdout" : "file",
                  foreground ? "running in foreground" :
                  "running in background",
                  is_stdout(line->cl_option) ? "stdout" : "normal");
            /* // */

            errno = 0;
            pas = getpwnam(line->cl_runas);
            if (pas == NULL)
                die_e("failed to get passwd fields for user \"%s\"",
                      line->cl_runas);

            setup_user_and_env(line, pas, &sendmailenv, &jobenv, &curshell,
                               &curhome, &content_type, &encoding);

            /* close unneeded READ fd */
            xclose_check(&(pipe_pid_fd[0]), "child's pipe_pid_fd[0]");

            pipe_fd[0] = pipe_fd[1] = -1;
            if (!to_stdout && is_mail(line->cl_option)) {
                /* we create the temp file (if needed) before change_user(),
                 * as temp_file() needs root privileges */
                /* if we run in foreground, stdout and stderr point to the console.
                 * Otherwise, stdout and stderr point to /dev/null . */
                mailf = create_mail(line, NULL, content_type, encoding, jobenv);
                mailpos = ftell(mailf);
                if (pipe(pipe_fd) != 0)
                    die_e("could not pipe() (job not executed)");
            }

            become_user(line, pas, curhome);
            Free_safe(curhome);

            /* restore umask to default */
            umask(saved_umask);

            sig_dfl();

#ifdef CHECKRUNJOB
            debug
                ("run_job(): child: change_user() done -- about to do 2nd fork()");
#endif                          /* CHECKRUNJOB */

            /* now, run the job */
            switch (pid = fork()) {
            case -1:
                error_e("Fork error : could not exec '%s'", line->cl_shell);
                if (write(pipe_pid_fd[1], &pid, sizeof(pid)) < 0)
                    error_e("could not write child pid to pipe_pid_fd[1]");
                xclose_check(&(pipe_fd[0]), "child's pipe_fd[0]");
                xclose_check(&(pipe_fd[1]), "child's pipe_fd[1]");
                xclose_check(&(pipe_pid_fd[1]), "child's pipe_pid_fd[1]");
                exit(EXIT_ERR);
                break;

            case 0:
                /* grand child (child of the 2nd fork) */

                /* the grand child does not use this pipe: close remaining fd */
                xclose_check(&(pipe_pid_fd[1]), "grand child's pipe_pid_fd[1]");

                if (!to_stdout)
                    /* note : the following closes the pipe */
                    run_job_grand_child_setup_stderr_stdout(line, pipe_fd);

                foreground = 1;
                /* now, errors will be mailed to the user (or to /dev/null) */

                run_job_grand_child_setup_nice(line);

                xcloselog();

#if defined(CHECKJOBS) || defined(CHECKRUNJOB)
                /* this will force to mail a message containing at least the exact
                 * and complete command executed for each execution of all jobs */
                debug("run_job(): grand-child: Executing \"%s -c %s\"",
                      curshell, line->cl_shell);
#endif                          /* CHECKJOBS OR CHECKRUNJOB */

#ifdef WITH_SELINUX
                if (flask_enabled
                    && setexeccon(line->cl_file->cf_user_context) < 0)
                    die_e("Can't set execute context '%s' for user '%s'.",
                          line->cl_file->cf_user_context, line->cl_runas);
#else
                if (setsid() == -1) {
                    die_e("setsid(): errno %d", errno);
                }
#endif
                execle(curshell, curshell, "-c", line->cl_shell, NULL, jobenv);
                /* execle returns only on error */
                die_e("Couldn't exec shell '%s'", curshell);

                /* execution never gets here */

            default:
                /* child (parent of the 2nd fork) */

                /* close unneeded WRITE pipe and READ pipe */
                xclose_check(&(pipe_fd[1]), "child's pipe_fd[1]");

#ifdef CHECKRUNJOB
                debug("run_job(): child: pipe_fd[1] and pipe_pid_fd[0] closed"
                      " -- about to write grand-child pid to pipe");
#endif                          /* CHECKRUNJOB */

                /* give the pid of the child to the parent (main) fcron process */
                ret = write_pipe(pipe_pid_fd[1], &pid, sizeof(pid));
                if (ret != OK) {
                    if (ret == ERR)
                        error
                            ("run_job(): child: Could not write job pid to pipe");
                    else {
                        errno = ret;
                        error_e
                            ("run_job(): child: Could not write job pid to pipe");
                    }
                }

#ifdef CHECKRUNJOB
                debug("run_job(): child: grand-child pid written to pipe");
#endif                          /* CHECKRUNJOB */

                if (!is_nolog(line->cl_option))
                    explain("Job '%s' started for user %s (pid %d)",
                            line->cl_shell, line->cl_file->cf_user, pid);

                if (!to_stdout && is_mail(line->cl_option)) {
                    /* user wants a mail : we use the pipe */
                    char mailbuf[TERM_LEN];
                    FILE *pipef = fdopen(pipe_fd[0], "r");

                    if (pipef == NULL)
                        die_e("Could not fdopen() pipe_fd[0]");

                    mailbuf[sizeof(mailbuf) - 1] = '\0';
                    while (fgets(mailbuf, sizeof(mailbuf), pipef) != NULL)
                        if (fputs(mailbuf, mailf) < 0)
                            warn("fputs() failed to write to mail file for job '%s' (pid %d)", line->cl_shell, pid);
                    /* (closes also pipe_fd[0]): */
                    xfclose_check(&pipef, "child's pipef");
                }

                /* FIXME : FOLLOWING HACK USELESS ? */
                /* FIXME : HACK
                 * this is a try to fix the bug on sorcerer linux (no jobs
                 * exectued at all, and
                 * "Could not read job pid : setting it to -1: No child processes"
                 * error messages) */
                /* use a select() or similar to know when parent has read
                 * the pid (with a timeout !) */
                /* // */
                sleep(2);
                /* // */
#ifdef CHECKRUNJOB
                debug("run_job(): child: closing pipe with parent");
#endif                          /* CHECKRUNJOB */
                xclose_check(&(pipe_pid_fd[1]), "child's pipe_pid_fd[1]");

                /* we use a while because of a possible interruption by a signal */
                while ((pid = wait3(&status, 0, NULL)) > 0) {
#ifdef CHECKRUNJOB
                    debug("run_job(): child: ending job pid %d", pid);
#endif                          /* CHECKRUNJOB */
                    end_job(line, status, mailf, mailpos, sendmailenv);
                }

                /* execution never gets here */

            }

            /* execution should never gets here, but if it happened we exit with an error */
            exit(EXIT_ERR);
        }

    default:
        /* parent */

        /* close unneeded WRITE fd */
        xclose_check(&(pipe_pid_fd[1]), "parent's pipe_pid_fd[1]");

        exeent->e_ctrl_pid = pid;

#ifdef CHECKRUNJOB
        debug("run_job(): about to read grand-child pid...");
#endif                          /* CHECKRUNJOB */

        /* read the pid of the job */
        ret = read_pipe(pipe_pid_fd[0], &(exeent->e_job_pid), sizeof(pid_t));
        if (ret != OK) {
            if (ret == ERR) {
                error("Could not read job pid because of closed pipe:"
                      " setting it to -1");
            }
            else {
                errno = ret;
                error_e("Could not read job pid : setting it to -1");
            }

            exeent->e_job_pid = -1;
        }
        xclose_check(&(pipe_pid_fd[0]), "parent's pipe_pid_fd[0]");

#ifdef CHECKRUNJOB
        debug
            ("run_job(): finished reading pid of the job -- end of run_job().");
#endif                          /* CHECKRUNJOB */

    }

    return OK;

}