forkpty.c raw

   1  #include <pty.h>
   2  #include <utmp.h>
   3  #include <unistd.h>
   4  #include <errno.h>
   5  #include <fcntl.h>
   6  #include <sys/wait.h>
   7  #include <pthread.h>
   8  
   9  int forkpty(int *pm, char *name, const struct termios *tio, const struct winsize *ws)
  10  {
  11  	int m, s, ec=0, p[2], cs;
  12  	pid_t pid=-1;
  13  	sigset_t set, oldset;
  14  
  15  	if (openpty(&m, &s, name, tio, ws) < 0) return -1;
  16  
  17  	sigfillset(&set);
  18  	pthread_sigmask(SIG_BLOCK, &set, &oldset);
  19  	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
  20  
  21  	if (pipe2(p, O_CLOEXEC)) {
  22  		close(s);
  23  		goto out;
  24  	}
  25  
  26  	pid = fork();
  27  	if (!pid) {
  28  		close(m);
  29  		close(p[0]);
  30  		if (login_tty(s)) {
  31  			write(p[1], &errno, sizeof errno);
  32  			_exit(127);
  33  		}
  34  		close(p[1]);
  35  		pthread_setcancelstate(cs, 0);
  36  		pthread_sigmask(SIG_SETMASK, &oldset, 0);
  37  		return 0;
  38  	}
  39  	close(s);
  40  	close(p[1]);
  41  	if (read(p[0], &ec, sizeof ec) > 0) {
  42  		int status;
  43  		waitpid(pid, &status, 0);
  44  		pid = -1;
  45  		errno = ec;
  46  	}
  47  	close(p[0]);
  48  
  49  out:
  50  	if (pid > 0) *pm = m;
  51  	else close(m);
  52  
  53  	pthread_setcancelstate(cs, 0);
  54  	pthread_sigmask(SIG_SETMASK, &oldset, 0);
  55  
  56  	return pid;
  57  }
  58