home *** CD-ROM | disk | FTP | other *** search
- /*
- * This code is in the public domain.
- *
- * Written By: John F Haugh II, 12/21/90
- */
-
- #include <sys/types.h>
- #include <sys/termio.h>
- #include <stdio.h>
- #include <signal.h>
- #include <time.h>
- #include <fcntl.h>
- #include <errno.h>
-
- #define MAXSESSIONS 16
-
- int childpids[MAXSESSIONS];
- int writepid;
- int masters[MAXSESSIONS];
- int nsessions;
- int current = -1;
- int caught = 0;
-
- struct termio sanetty;
- struct termio rawtty;
-
- void exit ();
- void _exit ();
- char *getlogin ();
- char *getenv ();
- struct passwd *getpwnam ();
-
- void
- murder (sig)
- int sig;
- {
- int pid;
- int i;
-
- pid = wait ((int *) 0);
-
- /*
- * See what children have died recently.
- */
-
- for (i = 0;pid != -1 && i < nsessions;i++) {
- if (pid == childpids[i]) {
- childpids[i] = -1;
- close (masters[i]);
- masters[i] = -1;
- }
- }
- signal (sig, murder);
- }
-
- void
- catch (sig)
- int sig;
- {
- caught = 1;
- signal (sig, catch);
- }
-
- /*
- * reader - read characters from the pty and write to the screen
- */
-
- int
- reader (fd)
- int fd;
- {
- char c;
- int cnt;
-
- signal (SIGINT, SIG_IGN);
- signal (SIGQUIT, SIG_IGN);
-
- while (1) {
- if ((cnt = read (fd, &c, 1)) == -1) {
- if (errno != EINTR)
- return -1;
-
- if (caught)
- return 0;
- else
- continue;
- }
- if (cnt == 0)
- return -1;
-
- write (1, &c, 1);
- }
- }
-
- /*
- * writer - write characters read from the keyboard down the pty
- */
-
- writer (fd)
- int fd;
- {
- char c;
- int cnt;
- int zflg = 0;
-
- signal (SIGINT, SIG_IGN);
- signal (SIGQUIT, SIG_IGN);
- signal (SIGHUP, _exit);
-
- while (1) {
- errno = 0;
- if ((cnt = read (0, &c, 1)) == 0)
- continue;
-
- if (cnt == -1) {
- if (errno == EINTR && caught)
- continue;
- else
- exit (0);
- }
- if (c == ('z' & 037)) {
- if (! zflg++)
- continue;
- } else if (zflg) {
- kill (getppid (), SIGUSR1);
- exit (0);
- }
- zflg = 0;
- if (write (fd, &c, 1) != 1)
- break;
- }
- exit (0);
- }
-
- usage ()
- {
- fprintf (stderr, "usage: ptymgr\n");
- exit (1);
- }
-
- session ()
- {
- char mastername[BUFSIZ];
- char slavename[BUFSIZ];
- char *digits = "0123456789abcdef";
- char *letters = "pqrs";
- char *shell;
- int i;
- int pty;
- int ptys = 64;
-
- for (i = 0;i < nsessions && masters[i] != -1;i++)
- ;
-
- if (i == MAXSESSIONS)
- return -1;
-
- if (i == nsessions)
- nsessions++;
-
- current = i;
-
- for (pty = 0;pty < ptys;pty++) {
- sprintf (mastername, "/dev/pty%c%c",
- letters[pty >> 4], digits[pty & 0xf]);
- if ((masters[i] = open (mastername, O_RDWR)) != -1)
- break;
- }
- if (masters[i] == -1) {
- fprintf (stderr, "Can't find a pty\n");
- return -1;
- }
-
- /*
- * Let's make a child process ...
- */
-
- switch (childpids[i] = fork ()) {
- case -1:
- perror ("fork");
- exit (1);
- case 0:
- close (0);
- close (1);
- for (i = 0;i < nsessions;i++)
- close (masters[i]);
-
- setpgrp ();
-
- signal (SIGINT, SIG_DFL);
- signal (SIGQUIT, SIG_DFL);
- signal (SIGCLD, SIG_DFL);
- signal (SIGHUP, SIG_DFL);
- signal (SIGUSR1, SIG_DFL);
-
- sprintf (slavename, "/dev/tty%c%c",
- letters[pty >> 4], digits[pty & 0xf]);
-
- if (open (slavename, O_RDWR) == -1) {
- fprintf (stderr, "can't open %s\n", slavename);
- _exit (-1);
- }
- close (2);
- dup (0);
- dup (0);
- ioctl (0, TCSETAF, &sanetty);
-
- if (! (shell = getenv ("SHELL")))
- shell = "/bin/sh";
-
- execl (shell, strrchr (shell, '/') + 1, 0);
- _exit (-1);
- }
- }
-
- main (argc, argv)
- int argc;
- char **argv;
- {
- char buf[BUFSIZ];
- char *cp;
- int i;
- int pid;
-
- for (i = 0;i < MAXSESSIONS;i++) {
- childpids[i] = -1;
- masters[i] = -1;
- }
- ioctl (0, TCGETA, &sanetty);
- rawtty = sanetty;
-
- /*
- * Let's have our own little process group
- */
-
- setpgrp ();
-
- rawtty.c_oflag &= ~OPOST;
- rawtty.c_lflag = 0;
- rawtty.c_cc[VMIN] = 1;
- rawtty.c_cc[VTIME] = 1;
-
- signal (SIGCLD, murder);
- signal (SIGUSR1, catch);
-
- while (1) {
- printf ("pty-> ");
- fflush (stdout);
-
- while (errno = 0, gets (buf) == 0) {
- if (errno == EINTR)
- continue;
- else
- exit (0);
- }
- if (! buf[0])
- continue;
-
- /*
- * Get the command
- */
-
- if (strcmp (buf, "quit") == 0 || strcmp (buf, "exit") == 0) {
- exit (0);
- } else if (strcmp (buf, "create") == 0) {
- session ();
- continue;
- } else if (strcmp (buf, "current") == 0) {
- printf ("current session is %d\n", current);
- continue;
- } else if (strncmp (buf, "set", 3) == 0) {
- i = strtol (buf + 3, &cp, 10);
- if (buf[3] != '\0' && *cp == '\0')
- current = i;
- else
- printf ("eh?\n");
- continue;
- } else if (strcmp (buf, "active") == 0) {
- for (i = 0;i < nsessions;i++)
- if (masters[i] != -1)
- printf ("%d ", i);
-
- putchar ('\n');
- continue;
- } else if (strcmp (buf, "jobs") == 0) {
- int pids = 0;
-
- strcpy (buf, "ps -fp ");
- for (i = 0;i < nsessions;i++) {
- if (childpids[i] != -1) {
- if (pids++)
- strcat (buf, ",");
-
- sprintf (buf + strlen (buf), "%d",
- childpids[i]);
- }
- }
- if (pids)
- system (buf);
- continue;
- } else if (strncmp (buf, "connect", 7) != 0) {
- printf ("eh?\n");
- continue;
- }
- i = strtol (buf + 2, &cp, 10);
- if (*cp == '\0' && buf[2]) {
- if (masters[i] != -1)
- current = i;
- else
- current = -1;
- }
- if (current == -1) {
- printf ("no current session\n");
- continue;
- }
-
- /*
- * Let's make a process to read from the child ...
- */
-
- switch (writepid = fork ()) {
- case -1:
- kill (childpids[current], SIGKILL);
- perror ("fork");
- break;
- case 0:
- writer (masters[current]);
- exit (1);
- }
- ioctl (0, TCSETAF, &rawtty);
-
- if (reader (masters[current]) == -1) {
- close (masters[current]);
- masters[current] = -1;
- childpids[current] = -1;
- current = -1;
- if (writepid > 0)
- kill (writepid, SIGTERM);
- }
- ioctl (0, TCSETA, &sanetty);
- }
- exit (0);
- }
-