home *** CD-ROM | disk | FTP | other *** search
/ ftp.urbanrage.com / 2015-02-07.ftp.urbanrage.com.tar / ftp.urbanrage.com / pub / c / pity.c < prev    next >
C/C++ Source or Header  |  2014-11-25  |  3KB  |  114 lines

  1. /*
  2.  * pity - provide a pseudo tty to child process
  3.  * to compile gcc -o pity pity.c -lutil
  4.  */
  5.  
  6. #include <pty.h>
  7. #include <errno.h>
  8. #include <unistd.h>
  9. #include <stdlib.h>
  10. #include <stdio.h>
  11. #include <fcntl.h>
  12. #include <termios.h>
  13. #include <sys/ioctl.h>
  14. #include <sys/types.h>
  15. #include <sys/wait.h>
  16.  
  17. static inline void report_error(int err, char* errmsg) {
  18.     perror(errmsg);
  19.     exit(err);
  20. }
  21.  
  22. int main(int argc, char* argv[]) {
  23.     int master;
  24.     int slave;
  25.     int pid;
  26.     int child;
  27.     int err;
  28.     int n;
  29.     int flags;
  30.     FILE* fp;
  31.     char* buff[128];
  32.     struct termios term_info;
  33.     struct termios term_slave;
  34.     struct termios term_restore;
  35.     struct winsize wsize;
  36.  
  37.     /* get terminal info and save it for later use */
  38.     err = tcgetattr(fileno(stdin), &term_info);
  39.     if (err < 0) {
  40.         report_error(err, "couldn't get terminal attributes");
  41.     }
  42.     term_restore = term_info;
  43.     term_slave = term_info;
  44.     err = ioctl(fileno(stdout), TIOCGWINSZ, &wsize);
  45.     if (err < 0) {
  46.         report_error(err, "couldn't get window size");
  47.     }
  48.  
  49.     pid = forkpty(&master, NULL, &term_slave, &wsize);
  50.     if (pid < 0) {
  51.         report_error(pid, "couldn't forkpty");
  52.     }
  53.  
  54.     if (pid == 0) {
  55.         /* I'm the child */
  56.         err = execvp(argv[1], argv+1);
  57.         report_error(err, "couldn't exec");
  58.     }
  59.  
  60.     /* work that happens in the master */
  61.     term_info.c_lflag &= ~ICANON;
  62.     err = tcsetattr(fileno(stdin), TCSANOW, &term_info);
  63.     if (err < 0) {
  64.         report_error(err, "couldn't set terminal attributes");
  65.     }
  66.  
  67.     /* turn off blocking on stdin */
  68.     flags = fcntl(fileno(stdin), F_GETFL, 0);
  69.     flags |= O_NONBLOCK;
  70.     err = fcntl(fileno(stdin), F_SETFL, flags);
  71.     if (err < 0) {
  72.         report_error(err, "failed to set stdin nonblock");
  73.     }
  74.  
  75.     /* turn off blocking on pty */
  76.     flags = fcntl(master, F_GETFL, 0);
  77.     flags |= O_NONBLOCK;
  78.     err = fcntl(master, F_SETFL, flags);
  79.     if (err < 0) {
  80.         perror("failed to set pty nonblock");
  81.     }
  82.     for(;;) {
  83.         child = waitpid(pid, NULL, WNOHANG);
  84.         if (child == pid) {
  85.             break;
  86.         }
  87.         n = read(fileno(stdin), buff, sizeof(buff));
  88.         if (n > 0) {
  89.             write(master, buff, n);
  90.         } else {
  91.             if (n < 0) {
  92.                 if (errno != EAGAIN) {
  93.                     break;
  94.                 }
  95.             }
  96.         }
  97.         n = read(master, buff, sizeof(buff));
  98.         if (n > 0) {
  99.             write(fileno(stderr), buff, n);
  100.         } else {
  101.             if (n < 0) {
  102.                 if (errno != EAGAIN) {
  103.                     break;
  104.                 }
  105.             }
  106.         }
  107.     }
  108.     err = tcsetattr(fileno(stdin), TCSANOW, &term_restore);
  109.     if (err < 0) {
  110.         report_error(err, "couldn't restore terminal attributes");
  111.     }
  112.     exit(0);
  113. }
  114.