home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mgr / sparcmgr / demo3.zoo / demo / misc / getpty.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-08-24  |  9.3 KB  |  509 lines

  1. /*                        Copyright (c) 1987 Bellcore
  2.  *                            All Rights Reserved
  3.  *       Permission is granted to copy or use this program, EXCEPT that it
  4.  *       may not be sold for profit, the copyright notice must be reproduced
  5.  *       on copies, and credit should be given to Bellcore where it is due.
  6.  *       BELLCORE MAKES NO WARRANTY AND ACCEPTS NO LIABILITY FOR THIS PROGRAM.
  7.  */
  8. #ifndef lint
  9. static char rcsid[] = "$Header: getpty.c,v 4.2 88/06/22 14:37:33 bianchi Exp $";
  10. #endif
  11. #include <sys/types.h>
  12. #include <sys/wait.h>
  13.  
  14. #include <sys/file.h>
  15. #include <sys/signal.h>
  16. #include <sgtty.h>
  17. #include <stdio.h>
  18.  
  19. #include <errno.h>
  20. #include <pwd.h>
  21.  
  22. /*
  23. **    size of input and output buffers
  24. */
  25. #define BFRSIZE        1024
  26.  
  27. extern    int errno;
  28. extern  int done();
  29. int    lostpeer();
  30. int shellid;
  31. int    rem;
  32. int verboseflag = 0;
  33. int    defflags, tabflag;
  34. char    deferase, defkill;
  35. struct    tchars deftc;
  36. struct    ltchars defltc;
  37. struct    tchars notc =    { -1, -1, -1, -1, -1, -1 };
  38. struct    ltchars noltc =    { -1, -1, -1, -1, -1, -1 };
  39.  
  40. /*
  41. ** flags to signal that massage routines have more data ready to go
  42. **    these flags are necessary so that massage routines can buffer
  43. **    data if necessary
  44. */
  45. int more_out = 0;
  46. int more_in = 0;
  47. getpty(cmd)
  48.     char **cmd;
  49. {
  50.     int exit();
  51.     struct sgttyb sb;
  52.     char pibuf[BFRSIZE], fibuf[BFRSIZE], *pbp, *fbp;
  53.     int pcc = 0, fcc = 0;
  54.     int cc;
  55.  
  56.     signal(SIGPIPE, lostpeer);
  57.         shellid = get_command(cmd,&rem);
  58.         if (rem < 0)
  59.                 return(-1);
  60.  
  61.     ioctl(0, TIOCGETP, (char *)&sb);
  62.     defflags = sb.sg_flags;
  63.     tabflag = defflags & TBDELAY;
  64.     defflags &= ECHO | CRMOD;
  65.     deferase = sb.sg_erase;
  66.     defkill = sb.sg_kill;
  67.     ioctl(0, TIOCGETC, (char *)&deftc);
  68.     notc.t_startc = deftc.t_startc;
  69.     notc.t_stopc = deftc.t_stopc;
  70.     ioctl(0, TIOCGLTC, (char *)&defltc);
  71.     signal(SIGINT, exit);
  72.     signal(SIGHUP, exit);
  73.     signal(SIGQUIT, exit);
  74.     mode(1);
  75.     signal(SIGINT, SIG_IGN);
  76.     signal(SIGCHLD, done);
  77.     for (;;)
  78.     {
  79.         int ibits = 0, obits = 0;
  80.  
  81.         if (fcc)
  82.             obits |= (1<<rem);
  83.         else
  84.             ibits |= (1<<0);
  85.         if (pcc >= 0)
  86.             if (pcc)
  87.                 obits |= (1<<1);
  88.             else
  89.                 ibits |= (1<<rem);
  90.         if (fcc < 0 && pcc < 0)
  91.             break;
  92.         select(16, &ibits, &obits, 0, 0, 0);
  93.         if (ibits == 0 && obits == 0) {
  94.             sleep(5);
  95.             continue;
  96.         }
  97.         if ((fcc == 0) && more_in)
  98.         {
  99.             fbp = fibuf;
  100.             fcc = inmassage(fibuf,-2);
  101.         }
  102.         else
  103.         {
  104.             if (ibits & (1<<0)) {
  105.                 fcc = read(0, fibuf, sizeof (fibuf));
  106.                 if (fcc < 0 && errno == EWOULDBLOCK)
  107.                     fcc = 0;
  108.                 else {
  109.                     if (fcc <= 0)
  110.                         break;
  111.                     fbp = fibuf;
  112.                     fcc = inmassage(fibuf,fcc);
  113.                 }
  114.             }
  115.         }
  116.         if ((pcc == 0) && more_out)
  117.         {
  118.             pbp = pibuf;
  119.             pcc = outmassage(pibuf,-2);
  120.         }
  121.         else
  122.         {
  123.             if (ibits & (1<<rem)) {
  124.                 pcc = read(rem, pibuf, sizeof (pibuf));
  125.                 pbp = pibuf;
  126.                 if (pcc < 0 && errno == EWOULDBLOCK)
  127.                     pcc = 0;
  128.                 else if (pcc <= 0)
  129.                     pcc = -1;
  130.                 pcc = outmassage(pibuf,pcc);
  131.             }
  132.         }
  133.         if ((obits & (1<<1)) && pcc > 0) {
  134.             cc = write(1, pbp, pcc);
  135.             if (cc > 0) {
  136.                 pcc -= cc;
  137.                 pbp += cc;
  138.             }
  139.         }
  140.         if ((obits & (1<<rem)) && fcc > 0) {
  141.             cc = write(rem, fbp, fcc);
  142.             if (cc > 0) {
  143.                 fcc -= cc;
  144.                 fbp += cc;
  145.             }
  146.         }
  147.     }
  148.     fprintf(stderr,"Closed connection.\r\n");
  149.     done();
  150.     /* this point should never be reached !!! */
  151.     return(-2);
  152. }
  153.  
  154. done()
  155. {
  156.  
  157.     mode(0);
  158.     if (shellid > 0 && kill(shellid, SIGKILL) >= 0)
  159.         wait((int *)0);
  160.     cleanup();
  161. }
  162.  
  163.  
  164. /*
  165.  * writer: write to remote: 0 -> line.
  166.  */
  167. writer()
  168. {
  169.     int c;
  170.     while (read(0,&c,1) != 0)
  171.     {
  172.         if (write(rem, &c, 1) == 0) {
  173.             fprintf(stderr,"line gone\r\n");
  174.             return(0);
  175.         }
  176.     }
  177. }
  178.  
  179. /*
  180.  * reader: read from remote: line -> 1
  181.  */
  182. reader()
  183. {
  184.     char rb[BUFSIZ];
  185.     register int cnt;
  186.  
  187.     for (;;) {
  188.         cnt = read(rem, rb, sizeof (rb));
  189.         if (cnt == 0)
  190.             break;
  191.         if (cnt < 0) {
  192.             if (errno == EINTR)
  193.                 continue;
  194.             break;
  195.         }
  196.         write(1, rb, cnt);
  197.     }
  198. }
  199.  
  200. mode(f)
  201. {
  202.     struct tchars *tc;
  203.     struct ltchars *ltc;
  204.     struct sgttyb sb;
  205.  
  206.     ioctl(0, TIOCGETP, (char *)&sb);
  207.     switch (f) {
  208.  
  209.     case 0:
  210.         sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
  211.         sb.sg_flags |= defflags|tabflag;
  212.         tc = &deftc;
  213.         ltc = &defltc;
  214.         sb.sg_kill = defkill;
  215.         sb.sg_erase = deferase;
  216.         break;
  217.  
  218.     case 1:
  219.         sb.sg_flags |=  RAW;
  220. /*
  221.         sb.sg_flags |= (eight ? RAW : CBREAK);
  222. */
  223.         sb.sg_flags &= ~defflags;
  224.         /* preserve tab delays, but turn off XTABS */
  225.         if ((sb.sg_flags & TBDELAY) == XTABS)
  226.             sb.sg_flags &= ~TBDELAY;
  227.         tc = ¬c;
  228.         ltc = &noltc;
  229.         sb.sg_kill = sb.sg_erase = -1;
  230.         break;
  231.  
  232.     default:
  233.         return;
  234.     }
  235.     ioctl(0, TIOCSLTC, (char *)ltc);
  236.     ioctl(0, TIOCSETC, (char *)tc);
  237.     ioctl(0, TIOCSETN, (char *)&sb);
  238. }
  239.  
  240.  
  241. lostpeer()
  242. {
  243.     signal(SIGPIPE, SIG_IGN);
  244.     fprintf(stderr,"\007Connection closed.\r\n");
  245.     done();
  246. }
  247.  
  248.  
  249. #define SHELL        "/bin/sh"
  250.  
  251. #ifdef SYSV
  252. #define index        strchr
  253. #endif
  254.  
  255. static char *line = "/dev/ptypX";
  256. static int  pty_index=5;    /* better hit rate than 0 */
  257. extern char **environ;
  258.  
  259. /* place to save tty modes */
  260.  
  261. int t_ldisc;
  262. struct sgttyb t_sgttyb;
  263. struct tchars t_tchars;
  264. struct ltchars t_ltchars;
  265. int t_lflags;
  266. /*    get a pty line */
  267.  
  268. int
  269. getapty()
  270.    {
  271.    register int i;
  272.    int fd;
  273.    char list[20];
  274.  
  275.    strcpy(list,"0123456789abcdef");
  276.    line[5] = 'p';
  277. /*
  278.    for(line[8]='p';line[8]!='r';line[8]='q')
  279. */
  280.    for(line[8]='p';line[8]!='r';line[8]++)
  281.       for (i=1;i<=16;i++) {
  282.          line[9]=list[(pty_index+i)%16];
  283.      if (verboseflag)
  284.      {
  285.         printf("trying %s\n",line);
  286.      }
  287.          if ((fd = open(line,2)) >= 0) {
  288.             /* pty_index = (pty_index+i)%16; */
  289.         if (verboseflag)
  290.         {
  291.         printf("   GOT %s\n",line);
  292.         }
  293.             line[5] = 't';
  294.             return(fd);
  295.             }
  296.          }
  297.    return(-1);
  298.    }
  299.       
  300. int getatty()
  301.    {
  302.    int fd;
  303.    line[5]='t';
  304.    fd=open(line,2);
  305.    if (fd<0) {
  306.       sleep(3);
  307.       return (open(line,2));
  308.       }
  309.    return(fd);
  310.    }
  311.  
  312. char *
  313. last_tty()
  314.    {
  315.    return(line);
  316.    }
  317.  
  318. /******************************************************************************/
  319. /* start a command */
  320.  
  321. get_command(argv,file)
  322. char **argv;
  323. int *file;
  324.    {
  325.    register int i;                /* counter */
  326.    int fd;                    /* file desc */
  327.    int tty;                    /* fd of /dev/tty */
  328.    int pid;                    /* pid of shell */
  329.    int group;                    /* process group id */
  330.    int tty_slots;                /* # of tty slots */
  331.    char *name, *get_path();
  332.    char *getenv();
  333.    char *shell = getenv("SHELL");
  334.    char *arg[2];
  335. #define MAXNAME 256
  336.    char who[MAXNAME];
  337.  
  338.    if (argv == (char **) 0 ) {
  339.       argv = arg;
  340.       *argv = shell?shell:SHELL;
  341.       *(argv+1) = (char *) 0;
  342.       }
  343.    name = get_path(argv[0]);
  344.  
  345.    if (name == (char *) 0 || *name == '\0')
  346.       return(-2);
  347.  
  348. #ifdef DEBUG
  349.    dprintf(stderr,"EXECING: ");
  350.    for(i=0;argv[i]!='\0';i++)
  351.       dprintf(stderr,"%s ",argv[i]);
  352.    dprintf("\n");
  353. #endif
  354.  
  355.    if ((*file=getapty()) < 0)
  356.       return(-1);
  357.    ioctl(*file,TIOCREMOTE,0);    /* I dunno */
  358.  
  359.    ioctl(0,TIOCGETD,&t_ldisc);
  360.    ioctl(0,TIOCGETP,&t_sgttyb);
  361.    ioctl(0,TIOCGETC,&t_tchars);
  362.    ioctl(0,TIOCGLTC,&t_ltchars);
  363.    ioctl(0,TIOCLGET,&t_lflags);
  364.  
  365.    if ((pid=fork()) != 0) {
  366.       return(pid);
  367.       }
  368.  
  369.    /* void association with controlling terminal */
  370.  
  371. #ifdef TIOCNOTTY
  372.    tty = open("/dev/tty",0);
  373.    ioctl(tty,TIOCNOTTY,0);
  374.    close(tty);
  375. #endif
  376.  
  377.    if ((fd=getatty())<0) {
  378.     char permsg[256];
  379.       sprintf(permsg,"Slave side of p-tty %s won't open",line);
  380.       perror(permsg);
  381.       sleep(5);
  382.       exit(1);
  383.       }
  384.  
  385.  
  386.    group=getpid();
  387.  
  388. #ifndef SYSV
  389.    tty_slots = getdtablesize();
  390. #else
  391.    tty_slots = 20;
  392. #endif
  393.  
  394.    for(i=0;i<tty_slots;i++) if (i != fd) close(i);
  395.  
  396.    /* set the uid stuff up */
  397.  
  398.    if (geteuid() < 2) {
  399.       int uid = getuid();
  400.       fchmod(fd,0622);
  401.       fchown(fd,uid,-1);
  402.       setreuid(uid,uid);
  403.  
  404.       uid = getgid();
  405.       fchown(fd,-1,uid);
  406.       setregid(uid,uid);
  407.       }
  408.  
  409.    dup(fd), dup(fd), dup(fd);
  410.    close(fd);
  411.  
  412.    setpgrp(group,group);
  413.    ioctl(0,TIOCSPGRP,&group);
  414.  
  415.    t_ldisc=NTTYDISC;
  416.    t_sgttyb.sg_flags = ECHO|CRMOD|EVENP|ODDP;
  417.  
  418.    ioctl(0,TIOCSETD,&t_ldisc);
  419.    ioctl(0,TIOCSETP,&t_sgttyb);
  420.    ioctl(0,TIOCSETC,&t_tchars);
  421.    ioctl(0,TIOCSLTC,&t_ltchars);
  422.    ioctl(0,TIOCLSET,&t_lflags);
  423.  
  424.    /* add a utmp entry */
  425.  
  426. /*
  427. #ifdef WHO
  428.    sprintf(who,"%s%c",HOST,line[9]);
  429.    add_utmp(0,who);
  430. #endif
  431. */
  432.  
  433.    /* start the command */
  434.  
  435. #ifdef DEBUG
  436.    dprintf(stderr,"execing %s (%s ...)\r\n",name,*argv);
  437.    fflush(stderr);
  438. #endif
  439.  
  440. /*
  441.    do_env("TERM=",TERMNAME);
  442.    do_env("TERMCAP=","");
  443. */
  444.  
  445.    execve(name,argv,environ);
  446.    _exit(1);
  447.    }
  448.  
  449. /* get a complete path name from command */
  450.  
  451. static char path[512];
  452. static char start[512];
  453.  
  454. char *
  455. get_path(name)
  456. char *name;
  457.    {
  458.    char *getenv(), *index();
  459.    register char c, *next, *list;
  460.  
  461. #ifdef DEBUG
  462.    dprintf(stderr,"looking for command: %s\n",name);
  463. #endif
  464.  
  465.    if (index("/.",*name))
  466.       if (access(name,X_OK)==0)
  467.          return(name);
  468.       else
  469.          return((char *)0);
  470.  
  471.    strcpy(start,getenv("PATH"));
  472.    for(list=start;next=index(list,':');list=next+1) {
  473.       *next = '\0';
  474.       sprintf(path,"%s/%s",list,name);
  475. #ifdef DEBUG
  476.       dprintf(stderr," X? %s\n",path);
  477. #endif
  478.       if (access(path,X_OK) == 0)
  479.          return(path);
  480.       }
  481.  
  482.    sprintf(path,"%s/%s",list,name);
  483. #ifdef DEBUG
  484.    dprintf(stderr,"X? %s\n",path);
  485. #endif
  486.    if (list && access(path,X_OK) == 0) {
  487.       return(path);
  488.       }
  489.    else {
  490.       return((char *) 0);
  491.       }
  492.    }
  493.  
  494. /* change an environment variable */
  495.  
  496. do_env(name,value)
  497. char *name, *value;
  498.    {
  499.    register int i;
  500.    int n = strlen(name);
  501.    
  502.    for(i=0;environ[i] != (char *) 0;i++)
  503.       if (strncmp(environ[i],name,n) == 0) {
  504.          strcpy(environ[i]+n,value);
  505.          break;
  506.          }
  507.    }
  508.  
  509.