home *** CD-ROM | disk | FTP | other *** search
- /*
- * This code is in the public domain. THIS CODE IS PROVIDED ON AN AS-IS
- * BASIS. THE USER ACCEPTS ALL RISKS ASSOCIATED WITH USING THIS CODE AND
- * IS SOLELY RESPONSIBLE FOR CORRECTING ANY SOFTWARE ERRORS OR DAMAGE
- * CAUSED BY SOFTWARE ERRORS OR MISUSE.
- *
- * Written By: John F Haugh II, 12/21/90
- *
- * Modified to include suggestions made by Pat Myrto, Dan Bernstein,
- * and Axel Fischer.
- */
-
- #include <sys/types.h>
- #ifdef SYSV_IOCTL
- #include <sys/termio.h>
- #endif
- #include <sys/stat.h>
- #include <utmp.h>
- #include <string.h>
- #include <stdio.h>
- #include <signal.h>
- #include <time.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <ctype.h>
- #include <pwd.h>
-
- /*
- * BLOCKING_PTY is defined if you PTY device driver is incapable
- * of correctly handling non-blocking read requests.
- */
-
- #undef BLOCKING_PTY
-
- /*
- * MAXSESSIONS is the number of sessions which a single user can
- * manage with this program at a single time. 16 is plenty. 4 or
- * 5 might be a better idea if pty's are a scarce resource. 8
- * should be a nice compromise.
- */
-
- #define MAXSESSIONS 8
-
- int childpids[MAXSESSIONS]; /* Process ID of each session leader */
- char *labels[MAXSESSIONS]; /* Names of sessions */
- char *ports[MAXSESSIONS]; /* Names of tty's */
- int writepid; /* Process ID of PTY writing process */
- int pspid; /* Obfuscation is my life */
- int masters[MAXSESSIONS]; /* File descriptor for PTY master */
- int nsessions; /* High-water mark for session count */
- int current = -1; /* Currently active session */
- int last = -1; /* Previously active session */
- int caught = 0; /* Some signal was caught */
-
- #ifdef SYSV_IOCTL
- struct termio sanetty; /* Initial TTY modes on entry */
- struct termio rawtty; /* Modes used when session is active */
- #endif
-
- void exit ();
- void _exit ();
- char *getlogin ();
- char *getenv ();
- char *malloc ();
- char *whoami;
- struct passwd *getpwuid ();
- extern char **environ;
-
- /*
- * fix_utmp - add or remove utmp file entries
- *
- * fix_utmp creates entries for new sessions and removes entries
- * for sessions which have died.
- */
-
- void
- fix_utmp (port, pid)
- char *port;
- int pid;
- {
- char *cp;
- int fd;
- int found = 0;
- struct utmp utmp;
-
- if (strncmp (port, "/dev/", 5) == 0)
- port += 5;
-
- if ((fd = open ("/etc/utmp", O_RDWR)) == -1)
- return;
-
- while (read (fd, &utmp, sizeof utmp) == sizeof utmp) {
- if (strncmp (port, utmp.ut_line, sizeof utmp.ut_line) == 0) {
- found++;
- break;
- }
- }
- if (found)
- lseek (fd, (long) - sizeof utmp, 1);
- else if (pid == 0)
- return;
-
- if (pid) { /* Add new utmp entry */
- memset (&utmp, 0, sizeof utmp);
-
- strncpy (utmp.ut_user, whoami, sizeof utmp.ut_user);
- strncpy (utmp.ut_line, port, sizeof utmp.ut_line);
-
- if (cp = strrchr (port, '/'))
- cp++;
- else
- cp = port;
-
- if (strncmp (cp, "tty", 3) == 0)
- cp += 3;
-
- strncpy (utmp.ut_id, cp, sizeof utmp.ut_id);
-
- utmp.ut_pid = pid;
- utmp.ut_type = USER_PROCESS;
- time (&utmp.ut_time);
- } else { /* Remove utmp entry */
- utmp.ut_type = DEAD_PROCESS;
- }
- write (fd, &utmp, sizeof utmp);
- close (fd);
- }
-
- /*
- * parse - see if "s" and "pat" smell alike
- */
-
- char *
- parse (s, pat)
- char *s;
- char *pat;
- {
- int match = 0;
- int star = 0;
-
- /*
- * Match all of the characters which are identical. The '*'
- * character is used to denote the end of the unique suffix
- * for a pattern. Everything after that is optional, but
- * must be matched exactly if given.
- */
-
- while (*s && *pat) {
- if (*s == *pat && *s) {
- s++, pat++;
- continue;
- }
- if (*pat == '*') {
- star++;
- pat++;
- continue;
- }
- if ((*s == ' ' || *s == '\t') && star)
- return s;
- else
- return 0;
- }
-
- /*
- * The pattern has been used up - see if whitespace
- * follows, or if the input string is also finished.
- */
-
- if (! *pat && (*s == '\0' || *s == ' ' || *s == '\t'))
- return s;
-
- /*
- * The input string has been used up. The unique
- * prefix must have been matched.
- */
-
- if (! *s && (star || *pat == '*'))
- return s;
-
- return 0;
- }
-
- /*
- * murder - reap a single child process
- */
-
- 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++) {
-
- /*
- * Close their master sides and mark the
- * session as "available".
- */
-
- if (pid == childpids[i]) {
- childpids[i] = -1;
- if (masters[i] != -1) {
- close (masters[i]);
- if (writepid != -1)
- kill (writepid, SIGTERM);
-
- masters[i] = -1;
- }
- if (labels[i]) {
- free (labels[i]);
- labels[i] = 0;
- }
- if (ports[i]) {
- fix_utmp (ports[i], 0);
- free (ports[i]);
- ports[i] = 0;
- }
- break;
- }
- }
- if (writepid != -1 && pid == writepid)
- writepid = -1;
-
- if (pspid != -1 && pid == pspid)
- pspid = -1;
-
- signal (sig, murder);
- }
-
- /*
- * catch - catch a signal and set a flag
- */
-
- 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;
- #ifdef BLOCKING_PTY
- {
- char c; /* do reads a byte at a time */
- int cnt; /* how many bytes were read */
-
- /*
- * Ignore the SIGINT and SIGQUIT signals.
- */
-
- 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);
- }
- }
- #else
- {
- char buf[16]; /* do reads in 16 byte bursts */
- int cnt; /* how many bytes were read */
- int wanted = sizeof buf; /* how may bytes to try reading */
- int flags; /* fcntl flags */
-
- /*
- * Ignore the SIGINT and SIGQUIT signals.
- */
-
- signal (SIGINT, SIG_IGN);
- signal (SIGQUIT, SIG_IGN);
-
- flags = fcntl (fd, F_GETFL, 0);
- fcntl (fd, F_SETFL, flags|O_NDELAY);
-
- while (1) {
- if ((cnt = read (fd, buf, wanted)) == -1) {
- if (errno != EINTR)
- return -1;
-
- if (caught)
- return 0;
- else
- continue;
- }
- if (cnt == 0 && wanted != 1) {
- wanted = 1;
- fcntl (fd, F_SETFL, flags & ~O_NDELAY);
- continue;
- }
- if (cnt == 0 && wanted == 1)
- return -1;
-
- if (wanted == 1)
- flags = fcntl (fd, F_GETFL, flags|O_NDELAY);
-
- wanted = sizeof buf;
- write (1, buf, cnt);
- }
- }
- #endif
-
- /*
- * 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);
-
- /*
- * Read characters until an error is returned or ^Z is seen
- * followed by a non-^Z character.
- */
-
- while (1) {
- errno = 0;
- if ((cnt = read (0, &c, 1)) == 0)
- continue;
-
- /*
- * Some signal may have occured, so retry
- * the read.
- */
-
- if (cnt == -1) {
- if (errno == EINTR && caught)
- continue;
- else
- exit (0);
- }
-
- /*
- * Process a ^Z. If one was not seen earlier,
- * set a flag and go read another character.
- */
-
- if (c == ('z' & 037)) {
- if (! zflg++)
- continue;
- }
-
- /*
- * See if a ^Z was seen before. If so, signal
- * the master and exit.
- */
-
- else if (zflg) {
- kill (getppid (), SIGUSR1);
- exit (0);
- }
-
- /*
- * Just output the character as is.
- */
-
- zflg = 0;
- if (write (fd, &c, 1) != 1)
- break;
- }
- exit (0);
- }
-
- /*
- * usage - command line syntax
- */
-
- usage ()
- {
- fprintf (stderr, "usage: sm\n");
- exit (1);
- }
-
- /*
- * help - built-in command syntax
- */
-
- help ()
- {
- fprintf (stderr, "Valid commands are:\n");
- fprintf (stderr, "\tconnect [ # ]\t(connects to session)\n");
- fprintf (stderr, "\tcreate\t\t(sets up a new pty session)\n");
- fprintf (stderr, "\tcurrent\t\t(shows current session number)\n");
- fprintf (stderr, "\tdelete #\t(deletes session)\n");
- fprintf (stderr, "\thelp\t\tdisplay this message\n");
- fprintf (stderr, "\tjobs\t\t(shows a ps listing of current session)\n");
- fprintf (stderr, "\tquit\tor exit (terminate session manager)\n");
- fprintf (stderr, "\tset #\t\t(# is 0-15 - selets current session)\n");
- fprintf (stderr, "\ttoggle\t\t(switch to previous session)\n\n");
- fprintf (stderr, "Commands may be abbreviated to a unique prefix\n\n");
- fprintf (stderr, "Note - to exit a session back into sm so one can\n");
- fprintf (stderr, " select another session, type a ^Z and a return\n");
- fprintf (stderr, " To send ^Z to the shell, type two ^Z chars\n\n");
- }
-
- /*
- * session - create a new session on a pty
- */
-
- int
- session (prompt, init)
- char *prompt;
- int init;
- {
- char mastername[BUFSIZ];
- char slavename[BUFSIZ];
- char newprompt[32];
- char newshell[32];
- char *digits = "0123456789abcdef";
- char *letters = "pqrs";
- char *shell;
- char *arg;
- int oumask;
- int i;
- int pty;
- int ptys = 64;
- struct stat sb;
- struct passwd *pwd;
-
- /*
- * Find the number of the new session. An error will be
- * given if no sessions are available.
- */
-
- for (i = 0;i < nsessions && masters[i] != -1;i++)
- ;
-
- if (i == MAXSESSIONS) {
- printf ("out of sessions\n");
- return 0;
- }
- if (i == nsessions)
- nsessions++;
-
- /*
- * Save the previous sesssion number. This is so the
- * "toggle" command will work after a "create".
- */
-
- if (current != -1)
- last = current;
-
- current = i;
-
- /*
- * Go find the master side of a PTY to use. Masters are
- * found by trying to open them. Each PTY master is an
- * exclusive access device. If every pty is tried but no
- * available ones are found, scream.
- */
-
- 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) {
- printf ("out of ptys\n");
- return 0;
- }
-
- /*
- * Determine what the name of the slave will be. Save it
- * for later use.
- */
-
- sprintf (slavename, "/dev/tty%c%c",
- letters[pty >> 4], digits[pty & 0xf]);
-
- if (ports[i])
- free (ports[i]);
-
- ports[i] = strdup (slavename);
-
- /*
- * Let's make a child process.
- */
-
- switch (childpids[i] = fork ()) {
- case -1:
- printf ("out of processes\n");
- return 0;
- case 0:
-
- /*
- * Disassociate from the parent process group
- * and tty's.
- */
-
- close (0);
- close (1);
- for (i = 0;i < nsessions;i++)
- close (masters[i]);
-
- setpgrp ();
-
- /*
- * Reset any signals that have been upset.
- */
-
- signal (SIGINT, SIG_DFL);
- signal (SIGQUIT, SIG_DFL);
- signal (SIGCLD, SIG_DFL);
- signal (SIGHUP, SIG_DFL);
- signal (SIGUSR1, SIG_DFL);
-
- /*
- * Open the slave PTY. It will be opened as stdin.
- */
-
- if (open (slavename, O_RDWR) == -1) {
- fprintf (stderr, "can't open %s\n", slavename);
- _exit (-1);
- }
-
- /*
- * Try to change the owner of the master and slave
- * side of the PTY. This will only work if the
- * invoker has an effective UID of 0. Change the
- * mode of the slave to be the same as the parent
- * tty.
- */
-
- (void) chown (mastername, getuid (), getgid ());
- (void) chown (slavename, getuid (), getgid ());
- if (fstat (2, &sb) == 0)
- (void) chmod (slavename, sb.st_mode & 0777);
-
- /*
- * Close the last open file descriptor and make
- * the new stdout and stderr descriptors. Copy
- * the tty modes from the parent tty to the slave
- * pty.
- */
-
- close (2);
- dup (0);
- dup (0);
- #ifdef SYSV_IOCTL
- ioctl (0, TCSETAF, &sanetty);
- #endif
-
- /*
- * See if the invoker has a shell in their
- * environment and use the default value if
- * not.
- */
-
- if (! (shell = getenv ("SHELL")))
- shell = "/bin/sh";
-
- /*
- * Set the PS1 variable to "prompt " if
- * "prompt" looks reasonable.
- */
-
- if (! isalpha (*prompt))
- prompt = strrchr (slavename, '/') + 1;
-
- sprintf (newprompt, "PS1=%.16s%c ",
- prompt, getuid () ? '$':'#');
-
- for (i = 0;environ[i];i++)
- if (! strncmp (environ[i], "PS1=", 4))
- break;
-
- if (environ[i])
- environ[i] = newprompt;
-
- /*
- * See about changing current directory
- */
-
- if (init && (pwd = getpwuid (getuid ())))
- chdir (pwd->pw_dir);
-
- endpwent ();
-
- /*
- * Update the utmp file if this is a "login"
- * session.
- */
-
- if (init)
- fix_utmp (slavename, getpid ());
-
- /*
- * Undo any set-UID or set-GID bits on the
- * executable.
- */
-
- setgid (getgid ());
- setuid (getuid ());
-
- /*
- * Start off the new session.
- */
-
- if (arg = strrchr (shell, '/'))
- arg++;
- else
- arg = shell;
-
- if (init)
- sprintf (newshell, "-%s", arg), arg = newshell;
-
- execl (shell, arg, 0);
- _exit (-1);
- }
- return 1;
- }
-
- /*
- * quit - kill all active sessions
- */
-
- quit (sig)
- int sig;
- {
- int i;
-
- for (i = 0;i < nsessions;i++) {
- if (masters[i] != -1) {
- close (masters[i]);
- masters[i] = -1;
-
- if (childpids[i] != -1)
- kill (- childpids[i], SIGHUP);
- }
- }
- exit (sig);
- }
-
- /*
- * label - manipulate session labels
- *
- * label() will either create a new label (if 'sess' != -1) or
- * return the session number which matches 'name'.
- */
-
- int
- label (sess, name)
- int sess;
- char *name;
- {
- char buf[16];
- int i;
- char *cp;
-
- /*
- * Make "name" into something with no leading
- * whitespace that consists of characters in
- * [a-zA-Z0-9].
- */
-
- for (cp = name;isspace (*cp);cp++)
- ;
-
- for (i = 0;cp[i] && i < (sizeof buf - 1);i++) {
- if (isalnum (cp[i]))
- buf[i] = cp[i];
- else
- return -1;
- }
- buf[i] = '\0';
- cp = buf;
-
- /*
- * Look-up the session named "name"
- */
-
- if (sess == -1) {
-
- /*
- * See if 'name' is a label
- */
-
- for (i = 0;i < nsessions;i++)
- if (strcmp (labels[i], cp) == 0)
- return i;
-
- /*
- * Perhaps 'name' is a number?!?
- */
-
- i = strtol (name, &cp, 10);
- if (*cp)
- return -1;
- else
- return i;
- }
-
- /*
- * Add a new name, can't be a number.
- */
-
- if (*cp == '\0' || isdigit (*cp)) {
- labels[sess] = 0;
- return -1;
- }
-
- /*
- * Add a new session named "name"
- */
-
- if (labels[sess])
- free (labels[sess]);
-
- if (! (labels[sess] = malloc (strlen (cp) + 1)))
- return -1;
-
- strcpy (labels[sess], cp);
- return sess;
- }
-
- /*
- * sm - manage pty sessions
- */
-
- main (argc, argv)
- int argc;
- char **argv;
- {
- char buf[BUFSIZ];
- char *cp;
- int i;
- int pid;
- FILE *fp;
- struct passwd *pwd;
-
- /*
- * No arguments are allowed on the command line
- */
-
- if (argc > 1)
- usage ();
-
- /*
- * Set up all the file descriptors and process IDs
- */
-
- for (i = 0;i < MAXSESSIONS;i++) {
- childpids[i] = -1;
- masters[i] = -1;
- }
-
- /*
- * Get my login name
- */
-
- if (! (whoami = getlogin ())) {
- setpwent ();
- if (pwd = getpwuid (getuid ())) {
- whoami = strdup (pwd->pw_name);
- } else {
- printf ("who are you?\n");
- exit (1);
- }
- endpwent ();
- }
-
- /*
- * Get the current tty settings, and make a copy that can
- * be tinkered with. The sane values are used while getting
- * commands. The raw values are used while sessions are
- * active. New sessions are set to have the same tty values
- * as the sane values.
- */
-
- #ifdef SYSV_IOCTL
- ioctl (0, TCGETA, &sanetty);
- rawtty = sanetty;
-
- rawtty.c_oflag &= ~OPOST;
- rawtty.c_iflag &= ~(ICRNL|INLCR);
- rawtty.c_lflag = 0;
- rawtty.c_cc[VMIN] = 1;
- rawtty.c_cc[VTIME] = 1;
- #endif
-
- /*
- * SIGCLG is caught to detect when a session has died or when
- * the writer for the session has exited. SIGUSR1 is used to
- * signal that a ^Z has been seen.
- */
-
- signal (SIGCLD, murder);
- signal (SIGUSR1, catch);
-
- /*
- * The file $HOME/.smrc is read for initializing commands.
- */
-
- if (cp = getenv ("HOME")) {
- sprintf (buf, "%s/.smrc", cp);
- if (access (buf, 04) != 0 || ! (fp = fopen (buf, "r")))
- fp = stdin;
- }
-
- /*
- * This is the main loop. A line is read and executed. If
- * EOF is read, the loop is exited (except if input is the
- * .smrc file).
- */
-
- while (1) {
-
- /*
- * Keyboard signals cause an exit.
- */
-
- signal (SIGINT, quit);
- signal (SIGQUIT, quit);
-
- /*
- * Prompt for input only when it is not coming from
- * the .smrc file. A single line will be read and
- * executed. The read is retried if an interrupt
- * has been seen.
- */
-
- if (fp == stdin) {
- printf ("sm-> ");
- fflush (stdout);
- }
- while (errno = 0, fgets (buf, sizeof buf, fp) == 0) {
- if (errno == EINTR) {
- continue;
- } else if (fp != stdin) {
- fclose (fp);
- fp = stdin;
- buf[0] = '\0';
- break;
- } else {
- strcpy (buf, "quit");
- break;
- }
- }
- if (cp = strchr (buf, '\n'))
- *cp = '\0';
-
- if (! buf[0])
- continue;
-
- /*
- * Parse the command. Each command consists of a
- * verb, with some commands accepting a session ID
- * to act on. The command will be accepted if a
- * unique prefix of the command is entered.
- */
-
- if (parse (buf, "q*uit") || parse (buf, "e*xit")) {
-
- /*
- * Just give up.
- */
-
- quit (0);
- } else if (cp = parse (buf, "cr*eate")) {
- int init = 0;
-
- /*
- * Create a new session and make it current
- */
-
- while (*cp == ' ' || *cp == '\t')
- cp++;
-
- if (*cp == '-')
- init++, cp++;
-
- last = current;
-
- if (session (cp, init))
- label (current, cp);
-
- continue;
- } else if (parse (buf, "cu*rrent")) {
-
- /*
- * Give the session ID of the current session.
- */
-
- if (current != -1) {
- if (labels[current])
- printf ("current session is \"%s\"\n",
- labels[current]);
- else
- printf ("current session is %d\n",
- current);
- } else
- printf ("no current session\n");
-
- continue;
- } else if (cp = parse (buf, "s*et")) {
-
- /*
- * Set the current session ID to #
- */
-
- if (*cp) {
- if ((i = label (-1, cp)) != -1) {
- last = current;
- current = i;
- continue;
- }
- /* FALLTHROUGH */
- }
- printf ("eh?\n");
- continue;
- } else if (parse (buf, "a*ctive")) {
-
- /*
- * List the session IDs of all active sessions
- */
-
- for (i = 0;i < nsessions;i++) {
- if (masters[i] != -1) {
- if (labels[i])
- printf ("%s ", labels[i]);
- else
- printf ("%d ", i);
-
- }
- }
- putchar ('\n');
- continue;
- } else if (cp = parse (buf, "j*obs")) {
- int pids = 0;
-
- /*
- * Look for a "-" flag
- */
-
- while (isspace (*cp))
- cp++;
-
- if (*cp != '-') {
- for (pids = i = 0;i < nsessions;i++) {
- if (childpids[i] == -1)
- continue;
- else
- pids++;
-
- if (labels[i])
- printf ("%s (%d)\n", labels[i],
- childpids[i]);
- else
- printf ("#%d (%d)\n", i,
- childpids[i]);
- }
- if (! pids)
- printf ("no jobs\n");
-
- continue;
- }
-
- /*
- * Give a "ps" listing of all active sessions
- */
-
- buf[0] = '\0';
- for (i = 0;i < nsessions;i++) {
- if (childpids[i] != -1) {
- if (pids++)
- strcat (buf, ",");
-
- sprintf (buf + strlen (buf), "%d",
- childpids[i]);
- }
- }
- if (pids) {
- if (! (pspid = fork ())) {
- setgid (getgid ());
- setuid (getuid ());
- execl ("/bin/ps", "ps", "-fp", buf, 0);
- _exit (1);
- }
- while (pspid != -1)
- pause ();
- } else {
- printf ("no jobs\n");
- }
- continue;
- } else if (cp = parse (buf, "co*nnect")) {
-
- /*
- * Connect to the current or named session.
- */
-
- if (*cp) {
- if ((i = label (-1, cp)) != -1) {
- last = current;
- current = i;
- /* FALLTHROUGH */
- } else {
- printf ("eh?\n");
- continue;
- }
- }
- } else if (parse (buf, "t*oggle")) {
-
- /*
- * Toggle between the previous and current session
- */
-
- i = current;
- current = last;
- last = i;
- /* FALLTHROUGH */
- } else if (cp = parse (buf, "d*elete")) {
-
- /*
- * Delete the named session
- */
-
- if (*cp) {
- i = label (-1, cp);
- if (i >= 0 && i < MAXSESSIONS) {
- if (masters[i] != -1) {
- close (masters[i]);
- masters[i] = -1;
- if (childpids[i] != -1)
- kill (- childpids[i], SIGHUP);
-
- if (i == last)
- last == -1;
-
- if (i == current)
- current == -1;
-
- continue;
- }
- }
- /* FALLTHROUGH */
- }
- printf ("eh?\n");
- continue;
- } else if ((i = label (-1, buf)) != -1) {
- if (i >= 0 && i < MAXSESSIONS && masters[i]) {
- last = current;
- current = i;
- } else {
- printf ("eh?\n");
- continue;
- }
- } else {
-
- /*
- * The command was not recognized
- */
-
- help ();
- continue;
- }
-
- /*
- * Validate the session number. It must be in the
- * range 0 .. (MAXSESSIONS-1) to be valid. The current
- * session must also be associated with an open PTY.
- */
-
- if (current < 0 || current >= MAXSESSIONS)
- current = -1;
-
- if (current == -1 || masters[current] == -1) {
- printf ("no current session\n");
- current = -1;
- continue;
- }
-
- /*
- * Let's make a process to read from TTY and write to the
- * PTY.
- */
-
- switch (writepid = fork ()) {
- case -1:
- if (childpids[current] != -1)
- kill (childpids[current], SIGKILL);
-
- perror ("fork");
- break;
- case 0:
- writer (masters[current]);
- exit (1);
- }
-
- /*
- * Set up the raw TTY modes and start writing from the PTY to
- * the TTY.
- */
-
- #ifdef SYSV_IOCTL
- ioctl (0, TCSETAF, &rawtty);
- #endif
-
- if (reader (masters[current]) == -1) {
- close (masters[current]);
- masters[current] = -1;
- childpids[current] = -1;
- current = -1;
- if (writepid > 0)
- kill (writepid, SIGTERM);
- }
-
- /*
- * Reset the tty modes to resume the command loop.
- */
-
- #ifdef SYSV_IOCTL
- ioctl (0, TCSETA, &sanetty);
- #endif
- }
- exit (0);
- }
-