home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2395 / sm.c
C/C++ Source or Header  |  1990-12-28  |  6KB  |  344 lines

  1. /*
  2.  * This code is in the public domain.
  3.  *
  4.  * Written By: John F Haugh II, 12/21/90
  5.  */
  6.  
  7. #include <sys/types.h>
  8. #include <sys/termio.h>
  9. #include <stdio.h>
  10. #include <signal.h>
  11. #include <time.h>
  12. #include <fcntl.h>
  13. #include <errno.h>
  14.  
  15. #define    MAXSESSIONS    16
  16.  
  17. int    childpids[MAXSESSIONS];
  18. int    writepid;
  19. int    masters[MAXSESSIONS];
  20. int    nsessions;
  21. int    current = -1;
  22. int    caught = 0;
  23.  
  24. struct    termio    sanetty;
  25. struct    termio    rawtty;
  26.  
  27. void    exit ();
  28. void    _exit ();
  29. char    *getlogin ();
  30. char    *getenv ();
  31. struct    passwd    *getpwnam ();
  32.  
  33. void
  34. murder (sig)
  35. int    sig;
  36. {
  37.     int    pid;
  38.     int    i;
  39.  
  40.     pid = wait ((int *) 0);
  41.  
  42.     /*
  43.      * See what children have died recently.
  44.      */
  45.  
  46.     for (i = 0;pid != -1 && i < nsessions;i++) {
  47.         if (pid == childpids[i]) {
  48.             childpids[i] = -1;
  49.             close (masters[i]);
  50.             masters[i] = -1;
  51.         }
  52.     }
  53.     signal (sig, murder);
  54. }
  55.  
  56. void
  57. catch (sig)
  58. int    sig;
  59. {
  60.     caught = 1;
  61.     signal (sig, catch);
  62. }
  63.  
  64. /*
  65.  * reader - read characters from the pty and write to the screen
  66.  */
  67.  
  68. int
  69. reader (fd)
  70. int    fd;
  71. {
  72.     char    c;
  73.     int    cnt;
  74.  
  75.     signal (SIGINT, SIG_IGN);
  76.     signal (SIGQUIT, SIG_IGN);
  77.  
  78.     while (1) {
  79.         if ((cnt = read (fd, &c, 1)) == -1) {
  80.             if (errno != EINTR)
  81.                 return -1;
  82.  
  83.             if (caught)
  84.                 return 0;
  85.             else
  86.                 continue;
  87.         }
  88.         if (cnt == 0)
  89.             return -1;
  90.  
  91.         write (1, &c, 1);
  92.     }
  93. }
  94.  
  95. /*
  96.  * writer - write characters read from the keyboard down the pty
  97.  */
  98.  
  99. writer (fd)
  100. int    fd;
  101. {
  102.     char    c;
  103.     int    cnt;
  104.     int    zflg = 0;
  105.  
  106.     signal (SIGINT, SIG_IGN);
  107.     signal (SIGQUIT, SIG_IGN);
  108.     signal (SIGHUP, _exit);
  109.  
  110.     while (1) {
  111.         errno = 0;
  112.         if ((cnt = read (0, &c, 1)) == 0)
  113.             continue;
  114.  
  115.         if (cnt == -1) {
  116.             if (errno == EINTR && caught)
  117.                 continue;
  118.             else
  119.                 exit (0);
  120.         }
  121.         if (c == ('z' & 037)) {
  122.             if (! zflg++)
  123.                 continue;
  124.         } else if (zflg) {
  125.             kill (getppid (), SIGUSR1);
  126.             exit (0);
  127.         }
  128.         zflg = 0;
  129.         if (write (fd, &c, 1) != 1)
  130.             break;
  131.     }
  132.     exit (0);
  133. }
  134.  
  135. usage ()
  136. {
  137.     fprintf (stderr, "usage: ptymgr\n");
  138.     exit (1);
  139. }
  140.  
  141. session ()
  142. {
  143.     char    mastername[BUFSIZ];
  144.     char    slavename[BUFSIZ];
  145.     char    *digits = "0123456789abcdef";
  146.     char    *letters = "pqrs";
  147.     char    *shell;
  148.     int    i;
  149.     int    pty;
  150.     int    ptys = 64;
  151.  
  152.     for (i = 0;i < nsessions && masters[i] != -1;i++)
  153.         ;
  154.  
  155.     if (i == MAXSESSIONS)
  156.         return -1;
  157.  
  158.     if (i == nsessions)
  159.         nsessions++;
  160.  
  161.     current = i;
  162.  
  163.     for (pty = 0;pty < ptys;pty++) {
  164.         sprintf (mastername, "/dev/pty%c%c",
  165.             letters[pty >> 4], digits[pty & 0xf]);
  166.         if ((masters[i] = open (mastername, O_RDWR)) != -1)
  167.             break;
  168.     }
  169.     if (masters[i] == -1) {
  170.         fprintf (stderr, "Can't find a pty\n");
  171.         return -1;
  172.     }
  173.  
  174.     /*
  175.      * Let's make a child process ...
  176.      */
  177.  
  178.     switch (childpids[i] = fork ()) {
  179.         case -1:
  180.             perror ("fork");
  181.             exit (1);
  182.         case 0:
  183.             close (0);
  184.             close (1);
  185.             for (i = 0;i < nsessions;i++)
  186.                 close (masters[i]);
  187.  
  188.             setpgrp ();
  189.  
  190.             signal (SIGINT, SIG_DFL);
  191.             signal (SIGQUIT, SIG_DFL);
  192.             signal (SIGCLD, SIG_DFL);
  193.             signal (SIGHUP, SIG_DFL);
  194.             signal (SIGUSR1, SIG_DFL);
  195.  
  196.             sprintf (slavename, "/dev/tty%c%c",
  197.                 letters[pty >> 4], digits[pty & 0xf]);
  198.  
  199.             if (open (slavename, O_RDWR) == -1) {
  200.                 fprintf (stderr, "can't open %s\n", slavename);
  201.                 _exit (-1);
  202.             }
  203.             close (2);
  204.             dup (0);
  205.             dup (0);
  206.             ioctl (0, TCSETAF, &sanetty);
  207.  
  208.             if (! (shell = getenv ("SHELL")))
  209.                 shell = "/bin/sh";
  210.  
  211.             execl (shell, strrchr (shell, '/') + 1, 0);
  212.             _exit (-1);
  213.     }
  214. }
  215.  
  216. main (argc, argv)
  217. int    argc;
  218. char    **argv;
  219. {
  220.     char    buf[BUFSIZ];
  221.     char    *cp;
  222.     int    i;
  223.     int    pid;
  224.  
  225.     for (i = 0;i < MAXSESSIONS;i++) {
  226.         childpids[i] = -1;
  227.         masters[i] = -1;
  228.     }
  229.     ioctl (0, TCGETA, &sanetty);
  230.     rawtty = sanetty;
  231.  
  232.     /*
  233.      * Let's have our own little process group
  234.      */
  235.  
  236.     setpgrp ();
  237.  
  238.     rawtty.c_oflag &= ~OPOST;
  239.     rawtty.c_lflag = 0;
  240.     rawtty.c_cc[VMIN] = 1;
  241.     rawtty.c_cc[VTIME] = 1;
  242.  
  243.     signal (SIGCLD, murder);
  244.     signal (SIGUSR1, catch);
  245.  
  246.     while (1) {
  247.         printf ("pty-> ");
  248.         fflush (stdout);
  249.  
  250.         while (errno = 0, gets (buf) == 0) {
  251.             if (errno == EINTR)
  252.                 continue;
  253.             else
  254.                 exit (0);
  255.         }
  256.         if (! buf[0])
  257.             continue;
  258.  
  259.         /*
  260.          * Get the command
  261.          */
  262.  
  263.         if (strcmp (buf, "quit") == 0 || strcmp (buf, "exit") == 0) {
  264.             exit (0);
  265.         } else if (strcmp (buf, "create") == 0) {
  266.             session ();
  267.             continue;
  268.         } else if (strcmp (buf, "current") == 0) {
  269.             printf ("current session is %d\n", current);
  270.             continue;
  271.         } else if (strncmp (buf, "set", 3) == 0) {
  272.             i = strtol (buf + 3, &cp, 10);
  273.             if (buf[3] != '\0' && *cp == '\0')
  274.                 current = i;
  275.             else
  276.                 printf ("eh?\n");
  277.             continue;
  278.         } else if (strcmp (buf, "active") == 0) {
  279.             for (i = 0;i < nsessions;i++)
  280.                 if (masters[i] != -1)
  281.                     printf ("%d ", i);
  282.  
  283.             putchar ('\n');
  284.             continue;
  285.         } else if (strcmp (buf, "jobs") == 0) {
  286.             int    pids = 0;
  287.  
  288.             strcpy (buf, "ps -fp ");
  289.             for (i = 0;i < nsessions;i++) {
  290.                 if (childpids[i] != -1) {
  291.                     if (pids++)
  292.                         strcat (buf, ",");
  293.  
  294.                     sprintf (buf + strlen (buf), "%d",
  295.                         childpids[i]);
  296.                 }
  297.             }
  298.             if (pids)
  299.                 system (buf);
  300.             continue;
  301.         } else if (strncmp (buf, "connect", 7) != 0) {
  302.             printf ("eh?\n");
  303.             continue;
  304.         }
  305.         i = strtol (buf + 2, &cp, 10);
  306.         if (*cp == '\0' && buf[2]) {
  307.             if (masters[i] != -1)
  308.                 current = i;
  309.             else
  310.                 current = -1;
  311.         }
  312.         if (current == -1) {
  313.             printf ("no current session\n");
  314.             continue;
  315.         }
  316.  
  317.         /*
  318.          * Let's make a process to read from the child ...
  319.          */
  320.  
  321.         switch (writepid = fork ()) {
  322.             case -1:
  323.                 kill (childpids[current], SIGKILL);
  324.                 perror ("fork");
  325.                 break;
  326.             case 0:
  327.                 writer (masters[current]);
  328.                 exit (1);
  329.         }
  330.         ioctl (0, TCSETAF, &rawtty);
  331.  
  332.         if (reader (masters[current]) == -1) {
  333.             close (masters[current]);
  334.             masters[current] = -1;
  335.             childpids[current] = -1;
  336.             current = -1;
  337.             if (writepid > 0)
  338.                 kill (writepid, SIGTERM);
  339.         }
  340.         ioctl (0, TCSETA, &sanetty);
  341.     }
  342.     exit (0);
  343. }
  344.