Esempio n. 1
0
/****** uti/pty/fork_pty() *****************************************************
*  NAME
*     fork_pty() -- Opens a pty, forks and redirects the std handles
*
*  SYNOPSIS
*     pid_t fork_pty(int *ptrfdm, int *fd_pipe_err, dstring *err_msg)
*
*  FUNCTION
*     Opens a pty, forks and redirects stdin, stdout and stderr of the child
*     to the pty.
*
*  INPUTS
*     int *ptrfdm      - Receives the file descriptor of the master side of
*                        the pty.
*     int *fd_pipe_err - A int[2] array that receives the file descriptors
*                        of a pipe to separately redirect stderr.
*                        To achieve the same behaviour like rlogin/rsh, this
*                        is normally disabled, compile with
*                        -DUSE_PTY_AND_PIPE_ERR to enable this feature.
*     dstring *err_msg - Receives an error string in case of error.
*
*  RESULT
*     pid_t - -1 in case of error,
*              0 in the child process,
*              or the pid of the child process in the parent process.
*
*  NOTES
*     MT-NOTE: fork_pty() is not MT safe
*
*  SEE ALSO
*     pty/fork_no_pty
*******************************************************************************/
pid_t fork_pty(int *ptrfdm, int *fd_pipe_err, dstring *err_msg)
{
    pid_t pid;
    int   fdm, fds;
    char  pts_name[20];
    int   old_euid;

    /*
     * We run this either as root with euid="sge admin user" or as an unprivileged
     * user.  If we are root with euid="sge admin user", we must change our
     * euid back to root for this function.
     */
    old_euid = geteuid();
    if (getuid() == SGE_SUPERUSER_UID) {
        seteuid(SGE_SUPERUSER_UID);
    }
    if ((fdm = ptym_open(pts_name)) < 0) {
        sge_dstring_sprintf(err_msg, "can't open master pty \"%s\": %d, %s",
                            pts_name, errno, strerror(errno));
        return -1;
    }
#if defined(USE_PTY_AND_PIPE_ERR)
    if (pipe(fd_pipe_err) == -1) {
        sge_dstring_sprintf(err_msg, "can't create pipe for stderr: %d, %s",
                            errno, strerror(errno));
        return -1;
    }
#endif
    if ((pid = fork()) < 0) {
        return -1;
    } else if (pid == 0) {     /* child */
        if ((g_newpgrp = setsid()) < 0) {
            sge_dstring_sprintf(err_msg, "setsid() error: %d, %s",
                                errno, strerror(errno));
            return -1;
        }

        /* Open pty slave */
        if ((fds = ptys_open(fdm, pts_name)) < 0) {
            seteuid(old_euid);
            sge_dstring_sprintf(err_msg, "can't open slave pty: %d", fds);
            return -1;
        }
        seteuid(old_euid);
        close(fdm);
        fdm = -1;   /* all done with master in child */

#if   defined(TIOCSCTTY) && !defined(CIBAUD)
        /* 44BSD way to acquire controlling terminal */
        /* !CIBAUD to avoid doing this under SunOS */
        if (ioctl(fds, TIOCSCTTY, (char *) 0) < 0) {
            sge_dstring_sprintf(err_msg, "TIOCSCTTY error: %d, %s",
                                errno, strerror(errno));
            return -1;
        }
#endif
        /* slave becomes stdin/stdout/stderr of child */
        if ((dup2(fds, STDIN_FILENO)) != STDIN_FILENO) {
            sge_dstring_sprintf(err_msg, "dup2 to stdin error: %d, %s",
                                errno, strerror(errno));
            return -1;
        }
        if ((dup2(fds, STDOUT_FILENO)) != STDOUT_FILENO) {
            sge_dstring_sprintf(err_msg, "dup2 to stdout error: %d, %s",
                                errno, strerror(errno));
            return -1;
        }
#if defined(USE_PTY_AND_PIPE_ERR)
        close(fd_pipe_err[0]);
        fd_pipe_err[0] = -1;
        if ((dup2(fd_pipe_err[1], STDERR_FILENO)) != STDERR_FILENO) {
            sge_dstring_sprintf(err_msg, "dup2 to stderr error: %d, %s",
                                errno, strerror(errno));
            return -1;
        }
        close(fd_pipe_err[1]);
        fd_pipe_err[1] = -1;
#else
        if ((dup2(fds, STDERR_FILENO)) != STDERR_FILENO) {
            sge_dstring_sprintf(err_msg, "dup2 to stderr error: %d, %s",
                                errno, strerror(errno));
            return -1;
        }
#endif

        if (fds > STDERR_FILENO) {
            close(fds);
            fds = -1;
        }
        return 0;      /* child returns 0 just like fork() */
    } else {          /* parent */
        *ptrfdm = fdm; /* return fd of master */
        close(fd_pipe_err[1]);
        fd_pipe_err[1] = -1;
        seteuid(old_euid);
        return pid;    /* parent returns pid of child */
    }
}
Esempio n. 2
0
pid_t pty_fork(int *ptrfdm, char *slave_name, int slave_namesz, const struct termios *slave_termios, const struct winsize *slave_winsize)
{
	int		fdm, fds;
	pid_t	pid;
	char 	pts_name[20];

	if ((fdm = ptym_open(pts_name, sizeof(pts_name))) < 0)
		err_sys("can't open master pty: %s, error %d", pts_name, fdm);
	
	if (slave_name != NULL) {
		/*
		 * Return name of slave. Null terminate to handle case
		 * where strlen(pts_name) > slave_namesz.
		 */
		strncpy(slave_name, pts_name, slave_namesz);
		slave_name[slave_namesz - 1] = '\0';
	}

	if ((pid = fork()) < 0) {
		return -1;
	} else if (pid == 0) {			/* child */
		if (setsid() < 0)
			err_sys("setsid error");
		
		/*
		 * System V acquires controlling terminal on open().
		 */
		if ((fds = ptys_open(pts_name)) < 0)
			err_sys("can't open slave pty");
		close(fdm);					/* all done with master in child */

	#if defined(TIOCSCTTY)
		/*
		 * TIOCSCTTY is the BSD way to acquire a controlling terminal.
		 */
		if (ioctl(fds, TIOCSCTTY, (char *)0) < 0)
			err_sys("TIOCSCTTY error");
	#endif 
	
		/*
		 * Set slave's termios and window size.
		 */
		if (slave_termios != NULL) {
			if (tcsetattr(fds, TCSANOW, slave_termios) < 0)
				err_sys("tcsetattr error on slave pty");
		}
		if (slave_winsize != NULL) {
			if (ioctl(fds, TIOCSWINSZ, slave_winsize) < 0)
				err_sys("TIOCSWINSZ error on slave pty");
		}
	
		/*
		 * Slave becomes stdin/stdout/stderr of child.
		 */
		if (dup2(fds, STDIN_FILENO) != STDIN_FILENO)
			err_sys("dup2 error to stdin");
		if (dup2(fds, STDOUT_FILENO) != STDOUT_FILENO)
			err_sys("dup2 error to stdout");
		if (dup2(fds, STDERR_FILENO) != STDERR_FILENO)
			err_sys("dup2 error to stderr");
		if (fds != STDIN_FILENO && fds != STDOUT_FILENO && fds != STDERR_FILENO)
			close(fds);
		return 0;					/* child return 0 just like fork() */
		} else {					/* parent */
			*ptrfdm = fdm;			/* return fd of master */
			return pid;				/* parent returns pid of child */
		}
	}
Esempio n. 3
0
pid_t
exec_pty(const char *path, char *const argv[], char *const envp[],
      const char *dirpath, int channels[3], const char *pts_name, int fdm)
{
	int pipe2[2];
	pid_t childpid;
	char *full_path;

	/*
	 * We use pfind() to check that the program exists and is an executable.
	 * If not pass the error up.  Also execve() wants a full path.
	 */ 
	full_path = pfind(path);
	if (full_path == NULL) {
		fprintf(stderr, "Unable to find full path for \"%s\"\n", (path) ? path : "");
		return -1;
	}

	/*
	 *  Make sure we can create our pipes before forking.
	 */ 
	if (channels != NULL) {
		if (pipe(pipe2) < 0) { 
			fprintf(stderr, "%s(%d): returning due to error: %s\n", __FUNCTION__, __LINE__, strerror(errno));
			free(full_path);
			return -1;
		}
	}

	childpid = fork();

	if (childpid < 0) {
		fprintf(stderr, "%s(%d): returning due to error: %s\n", __FUNCTION__, __LINE__, strerror(errno));
		free(full_path);
		return -1;
	} else if (childpid == 0) { /* child */

		chdir(dirpath);

		if (channels != NULL) {
			int fds;

			fds = ptys_open(fdm, pts_name);
			if (fds < 0) {
				fprintf(stderr, "%s(%d): returning due to error: %s\n", __FUNCTION__, __LINE__, strerror(errno));
				return -1;
			}

			/* Close the read end of pipe2 */
			if (close(pipe2[0]) == -1)
				perror("close(pipe2[0]))");

			/* close the master, no need in the child */
			close(fdm);

			set_noecho(fds);
			/* redirections */
			dup2(fds, STDIN_FILENO);   /* dup stdin */
			dup2(fds, STDOUT_FILENO);  /* dup stdout */
			dup2(pipe2[1], STDERR_FILENO);  /* dup stderr */
			close(fds);  /* done with fds. */
		}

		/* Close all the fd's in the child */
		{
			int fdlimit = sysconf(_SC_OPEN_MAX);
			int fd = 3;

			while (fd < fdlimit)
				close(fd++);
		}

		if (envp[0] == NULL) {
			execv(full_path, argv);
		} else {
			execve(full_path, argv, envp);
		}

		_exit(127);

	} else if (childpid != 0) { /* parent */

		set_noecho(fdm);
		if (channels != NULL) {
			/* close the write end of pipe1 */
			if (close(pipe2[1]) == -1)
				perror("close(pipe2[1])");
 
			channels[0] = fdm; /* Input Stream. */
			channels[1] = fdm; /* Output Stream.  */
			channels[2] = pipe2[0]; /* stderr Stream.  */
			/*channels[2] = fdm;  Input Stream.  */
		}

		free(full_path);
		return childpid;
	}

	free(full_path);
	return -1;                  /*NOT REACHED */
}
Esempio n. 4
0
pid_t
pty_fork2(int *ptrfdm, char *slave_name)
{
	int		fdm, fds;
	pid_t	pid;
	char	pts_name[20];

	if ( (fdm = ptym_open(pts_name)) < 0)
	{
	    msg("can't open master pty");
	    return ERRO;
	}

	strcpy(slave_name, pts_name);	/* return name of slave */
        /*/printf("\npty_fork2: %d %s", fdm, pts_name); */

	if ( (pid = fork()) < 0)
	{
	    msg("Can not fork");
	    return ERRO;
	}

	else if (pid == 0) {		/* child */
		/*/ sleep(30); */
		if (setsid() < 0)
		{
		   msg("setsid error");
		   exit(1);
		}

		/* SVR4 acquires controlling terminal on open() */
		if ( (fds = ptys_open(fdm, pts_name)) < 0)
		{
		    msg("can't open slave pty");
		    exit(1);
		}
		close(fdm);		/* all done with master in child */

#ifdef	LINUX
				/* 44BSD way to acquire controlling terminal */
    		if (ioctl(fds, TIOCSCTTY, (char *) 0) < 0)
    		{
		    msg("TIOCSCTTY error");
	  	    return ERRO;
   		}
#endif
		if (tty_copy(fds) == ERRO)
		   exit(1);
				/* slave becomes stdin/stdout/stderr of child */
		if (dup2(fds, STDOUT_FILENO) != STDOUT_FILENO ||
		    dup2(fds, STDERR_FILENO) != STDERR_FILENO ||
		    dup2(fds, STDIN_FILENO) != STDIN_FILENO )
		{
		    msg("dup2 error to slave");
		    exit(1);
		}
		if (fds > STDERR_FILENO)
		   close(fds);
		return 0;		/* child returns 0 just like fork() */

	} else {					/* parent */
		*ptrfdm = fdm;	/* return fd of master */
		return(pid);	/* parent returns pid of child */
	}
}