Example #1
0
/* ptytest tries to open a pty pair with a shell running
 * underneath the slave pty. 
 */
int main (void) {
   int master;
   int pid;
   char *name;
   fd_set ready;
   int i;
#define BUFSIZE 1024
   char buf[1024];
   struct termios ot, t;
   struct winsize ws;
   int done = 0;
   struct sigaction act;

   if ((master = get_master_pty(&name)) < 0) {
      perror("ptypair: could not open master pty");
      exit(1);
   }

   /* set up SIGWINCH handler */
   act.sa_handler = sigwinch_handler;
   sigemptyset(&(act.sa_mask));
   act.sa_flags = 0;
   if (sigaction(SIGWINCH, &act, NULL) < 0) {
      perror("ptypair: could not handle SIGWINCH ");
      exit(1);
   }

   if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0) {
      perror("ptypair: could not get window size");
      exit(1);
   }

   if ((pid = fork()) < 0) {
      perror("ptypair");
      exit(1);
   }

   if (pid == 0) { 
      int slave;  /* file descriptor for slave pty */

      /* We are in the child process */
      close(master);

      if ((slave = get_slave_pty(name)) < 0) {
         perror("ptypair: could not open slave pty");
         exit(1);
      }
      free(name);

      /* We need to make this process a session group leader, because
       * it is on a new PTY, and things like job control simply will
       * not work correctly unless there is a session group leader
       * and process group leader (which a session group leader
       * automatically is). This also disassociates us from our old
       * controlling tty. 
       */
      if (setsid() < 0) {
         perror("could not set session leader");
      }

      /* Tie us to our new controlling tty. */
      if (ioctl(slave, TIOCSCTTY, NULL)) {
         perror("could not set new controlling tty");
      }

      /* make slave pty be standard in, out, and error */
      dup2(slave, STDIN_FILENO);
      dup2(slave, STDOUT_FILENO);
      dup2(slave, STDERR_FILENO);

      /* at this point the slave pty should be standard input */
      if (slave > 2) {
         close(slave);
      }


      /* Try to restore window size; failure isn't critical */
      if (ioctl(STDOUT_FILENO, TIOCSWINSZ, &ws) < 0) {
         perror("could not restore window size");
      }

      /* now start the shell */
      execl("/bin/sh", "/bin/sh", 0);

      /* should never be reached */
      exit(1);
   }

   /* parent */
   free(name);

   /* Note that we only set termios settings for standard input;
    * the master side of a pty is NOT a tty.
    */
   tcgetattr(STDIN_FILENO, &ot);
   t = ot;
   t.c_lflag &= ~(ICANON | ISIG | ECHO | ECHOCTL | ECHOE | \
                  ECHOK | ECHOKE | ECHONL | ECHOPRT );
   t.c_iflag |= IGNBRK;
   t.c_cc[VMIN] = 1;
   t.c_cc[VTIME] = 0;
   tcsetattr(STDIN_FILENO, TCSANOW, &t);

   /* This code comes nearly verbatim from robin.c
    * If the child exits, reading master will return -1 and we exit.
    */
   do {
      FD_ZERO(&ready);
      FD_SET(STDIN_FILENO, &ready);
      FD_SET(master, &ready);
      select(master+1, &ready, NULL, NULL, NULL);

      if (propagate_sigwinch) { 
         /* signal handler has asked for SIGWINCH propagation */
         if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0) {
            perror("ptypair: could not get window size");
         }
         if (ioctl(master, TIOCSWINSZ, &ws) < 0) {
            perror("could not restore window size");
         }

         /* now do not do this again until next SIGWINCH */
         propagate_sigwinch = 0;

         /* select may have been interrupted by SIGWINCH,
          * so try again. */
         continue;
      }

      if (FD_ISSET(master, &ready)) {
         i = read(master, buf, BUFSIZE);
         if (i >= 1) {
            write(STDOUT_FILENO, buf, i);
         } else {
            done = 1;
         }
      }

      if (FD_ISSET(STDIN_FILENO, &ready)) {
         i = read(STDIN_FILENO, buf, BUFSIZE);
         if (i >= 1) {
            write(master, buf, i);
         } else {
            done = 1;
         }
      }

   } while (!done);

   /* this really doesn't matter because each time a master pty is
    * opened, the corresponding slave pty has its termios settings
    * reset
    */
   tcsetattr(STDIN_FILENO, TCSANOW, &ot);
   exit(0);
}
Example #2
0
/* ptytest tries to open a pty pair with a shell running
 * underneath the slave pty. 
 */
int main (void) {
    int master;
    int pid;
    char *name;
    struct pollfd ufds[2];
    int i;
#define BUFSIZE 1024
    char buf[1024];
    struct termios ot, t;
    struct winsize ws;
    int done = 0;
    struct sigaction act;

    if ((master = get_master_pty(&name)) < 0) {
        perror("ptypair: could not open master pty");
        exit(1);
    }

    /* set up SIGWINCH handler */
    act.sa_handler = sigwinch_handler;
    sigemptyset(&(act.sa_mask));
    act.sa_flags = 0;
    if (sigaction(SIGWINCH, &act, NULL) < 0) {
        perror("ptypair: could not handle SIGWINCH ");
        exit(1);
    }

    if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0) {
        perror("ptypair: could not get window size");
        exit(1);
    }

    if ((pid = fork()) < 0) {
        perror("ptypair");
        exit(1);
    }

    if (pid == 0) { 
        int slave;  /* file descriptor for slave pty */

        /* We are in the child process */
        close(master);

        if ((slave = get_slave_pty(name)) < 0) {
            perror("ptypair: could not open slave pty");
            exit(1);
        }
        free(name);

        /* We need to make this process a session group leader, 
         * because it is on a new PTY, and things like job control 
	 * simply will not work correctly unless there is a session 
	 * group leader and process group leader (which a session 
	 * group leader automatically is). This also disassociates 
	 * us from our old controlling tty. 
         */
        if (setsid() < 0) {
            perror("could not set session leader");
        }

        /* Tie us to our new controlling tty. */
        if (ioctl(slave, TIOCSCTTY, NULL)) {
            perror("could not set new controlling tty");
        }

        /* make slave pty be standard in, out, and error */
        dup2(slave, STDIN_FILENO);
        dup2(slave, STDOUT_FILENO);
        dup2(slave, STDERR_FILENO);

        /* at this point the slave pty should be standard input */
        if (slave > 2) {
            close(slave);
        }

        /* Try to restore window size; failure isn't critical */
        if (ioctl(STDOUT_FILENO, TIOCSWINSZ, &ws) < 0) {
            perror("could not restore window size");
        }

        /* now start the shell */
        execl("/bin/sh", "/bin/sh", 0);

        /* should never be reached */
        exit(1);
    }

    /* parent */
    free(name);

    /* Note that we only set termios settings for standard input;
     * the master side of a pty is NOT a tty.
     */
    tcgetattr(STDIN_FILENO, &ot);
    t = ot;
    t.c_lflag &= ~(ICANON | ISIG | ECHO | ECHOCTL | ECHOE | \
                   ECHOK | ECHOKE | ECHONL | ECHOPRT );
    t.c_iflag |= IGNBRK;
    t.c_cc[VMIN] = 1;
    t.c_cc[VTIME] = 0;
    tcsetattr(STDIN_FILENO, TCSANOW, &t);

    /* This code comes nearly verbatim from robin.c
     * If the child exits, reading master will return -1 and 
     * we exit.
     */
    ufds[0].fd = STDIN_FILENO;
    ufds[0].events = POLLIN;
    ufds[1].fd = master;
    ufds[1].events = POLLIN;

    do {
        int r;

        r = poll(ufds, 2, -1);
        if ((r < 0) && (errno != EINTR)) {
            done = 1;
            break;
        }

        /* First check for an opportunity to exit */
        if ((ufds[0].revents | ufds[1].revents) &
            (POLLERR | POLLHUP | POLLNVAL)) {
            done = 1;
            break;
        }

        if (propagate_sigwinch) { 
            /* signal handler has asked for SIGWINCH propagation */
            if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0) {
                perror("ptypair: could not get window size");
            }
            if (ioctl(master, TIOCSWINSZ, &ws) < 0) {
               perror("could not restore window size");
            }

            /* now do not do this again until next SIGWINCH */
            propagate_sigwinch = 0;

            /* poll may have been interrupted by SIGWINCH,
             * so try again. */
            continue;
        }

        if (ufds[1].revents & POLLIN) {
            i = read(master, buf, BUFSIZE);
            if (i >= 1) {
                write(STDOUT_FILENO, buf, i);
            } else {
                done = 1;
            }
        }

        if (ufds[0].revents & POLLIN) {
            i = read(STDIN_FILENO, buf, BUFSIZE);
            if (i >= 1) {
                write(master, buf, i);
            } else {
                done = 1;
            }
        }
    } while (!done);

    tcsetattr(STDIN_FILENO, TCSANOW, &ot);
    exit(0);
}