home *** CD-ROM | disk | FTP | other *** search
- /* Copyright 1990, Daniel J. Bernstein. All rights reserved. */
-
- #include "config.h"
- #include <sys/types.h>
- #include <sys/time.h>
- #include <stdio.h>
- #include <strings.h>
- #include "pty.h"
- #include "sigler.h"
- #include "sig.h"
- #include "file.h"
- #include "sock.h"
- #include "err.h"
- #include "misc.h"
-
- /* General XXX: In failure cases, sig.* isn't always removed. */
-
- static char *glfnsty;
-
- static int masterpid;
-
- static int flagmaster = 1;
- static int flagcont = 0;
- static int pi[2];
-
- static void deatherrp(i,s)
- int i;
- char *s;
- {
- int e = errno;
-
- (void) kill(masterpid,SIGTERM);
- /* XXX: should wait while flagmaster */
- (void) tty_modifymodes(fdtty,&tmotty,&tmochartty);
- fatalerrp(i,s,e);
- }
-
- static void finish(i)
- sig_num i;
- {
- if (i == SIGTERM)
- {
- flagmaster = 0;
- (void) write(pi[1],".",1);
- }
- else
- (void) write(pi[1],",",1);
- }
-
- /*ARGSUSED*/
- static void sig_usr2(i)
- sig_num i;
- {
- if (flagsession)
- {
- char fnsess[20];
- int fdsess;
- int newuid = uid;
- char newsuid[10];
-
- /* XXX: We should have some error recovery here! */
-
- /* We can make quite a few assumptions, because we only get USR2 */
- /* forwarded from the master. */
-
- (void) sprintf(fnsess,"sess.%s",glfnsty + sizeof(DEVSTY) - 3);
- if ((fdsess = open(fnsess,O_RDONLY,0600)) != -1)
- {
- (void) read(fdsess,(char *) &newuid,sizeof(int));
- (void) sprintf(newsuid,"%d",newuid);
-
- (void) chdir("..");
- (void) chdir(newsuid);
-
- uid = newuid;
- (void) setreuid(uid,euid);
- (void) close(fdsess);
- }
- }
- }
-
- /*ARGSUSED*/
- static void sig_cont(i)
- sig_num i;
- {
- flagcont = 1;
- (void) write(pi[1]," ",1);
- }
-
- void sigler(fnsty,master)
- char *fnsty;
- int master;
- {
- char ch;
- char path[100];
- int fd = -1;
- char *ttyn;
- char fntty[TTYNAMELEN];
-
- glfnsty = fnsty;
- masterpid = master;
- /* pid = getpid() is already true */
- (void) sprintf(path,"sig.%s",fnsty + sizeof(DEVSTY) - 3);
- (void) unlink(path);
-
- (void) close(fdmty);
- (void) close(fdsty);
- if (fdre != -1) (void) close(fdre);
-
- if (pipe(pi) == -1) /* clumsy, but stops several races */
- /* This is absolutely impossible. fdmty and fdsty must have been open */
- /* before this, and we just closed them, so there must be two fds */
- /* available for the pipe. */
- deatherrp(10,"pty: fatal: cannot open internal pipe");
- (void) fcntl(pi[1],F_SETFL,FNDELAY);
-
- sig_ignore(SIGCHLD);
- sig_ignore(SIGXCPU);
- sig_ignore(SIGXFSZ);
- sig_ignore(SIGPROF);
- sig_ignore(SIGVTALRM);
-
- sig_default(SIGEMT); /* XXX: really dump? */
- sig_default(SIGIOT);
- sig_default(SIGILL);
- sig_default(SIGSEGV);
-
- sig_default(SIGTTOU);
- sig_default(SIGTTIN);
- sig_default(SIGTSTP);
- sig_default(SIGSTOP);
-
- sig_sethandler(SIGTERM,finish); sig_handle(SIGTERM);
- sig_sethandler(SIGINT,finish); sig_handle(SIGINT);
- sig_sethandler(SIGQUIT,finish); sig_handle(SIGQUIT);
- sig_sethandler(SIGHUP,finish); sig_handle(SIGHUP);
- sig_sethandler(SIGUSR1,finish); sig_handle(SIGUSR1); /* disconnect */
-
- sig_sethandler(SIGCONT,sig_cont); sig_handle(SIGCONT);
-
- sig_sethandler(SIGUSR2,sig_usr2); sig_handle(SIGUSR2);
-
- for (;;)
- {
- if (flagcont)
- {
- flagcont = 0;
- if (tty_modifymodes(fdtty,&tmochartty,&tmotty) == -1)
- ; /* XXX: impossible, but what if it happens? */
- (void) kill(masterpid,SIGUSR1); /* not CONT---see master.c's sig_cont() */
- }
- #ifdef NO_FDPASSING
- if (flagmaster == 2)
- {
- static fd_set rfds;
- static fd_set wfds;
- static int r;
- static int w;
- static char foobuf[OUTBUFSIZE];
- int fdnum;
- static char *s;
-
- fdnum = fd; if (fdin > fdnum) fdnum = fdin;
- if (pi[0] > fdnum) fdnum = pi[0]; fdnum++;
-
- FD_ZERO(&rfds);
- FD_ZERO(&wfds);
- FD_SET(fd,&rfds);
- FD_SET(fdin,&rfds);
- FD_SET(pi[0],&rfds);
-
- r = select(fdnum,&rfds,&wfds,(fd_set *) 0,(struct timeval *) 0);
- if (r > 0)
- {
- if (FD_ISSET(fd,&rfds))
- {
- if ((r = read(fd,foobuf,OUTBUFSIZE)) == -1)
- deatherrp(11,"pty: fatal: socket read error");
- s = foobuf;
- /* XXX: r can't be zero, but what if it is? */
- while (r)
- {
- if ((w = write(fdout,s,r)) == -1)
- deatherrp(14,"pty: fatal: output write error");
- r -= w; s += w;
- }
- }
- if (FD_ISSET(fdin,&rfds))
- {
- if ((r = read(fdin,foobuf,OUTBUFSIZE)) == -1)
- deatherrp(13,"pty: fatal: input read error");
- s = foobuf;
- /* XXX: What if r is zero? Can't pass EOF, grrrr */
- while (r)
- {
- if ((w = write(fd,s,r)) == -1)
- deatherrp(12,"pty: fatal: socket write error");
- r -= w; s += w;
- }
- }
- if (FD_ISSET(pi[0],&rfds))
- (void) read(pi[0],&ch,1);
- }
- }
- else
- (void) read(pi[0],&ch,1);
- #else
- (void) read(pi[0],&ch,1);
- #endif
- if ((ch == '.') || (ch == ','))
- {
- if (fd != -1)
- (void) close(fd);
- if (flagmaster)
- {
- if (kill(masterpid,SIGTERM) == -1)
- flagmaster = 0; /* XXX */
-
- if (fdpass != -1)
- (void) write(fdpass,".",1);
-
- while (flagmaster)
- ;
- while (ch != '.')
- (void) read(pi[0],&ch,1);
- }
-
- /* We don't test at this point whether the killing signal was a HUP. */
- /* This means that hanging up on a reconnecting sigler won't stop */
- /* the reconnect; instead, the new session will be instantly hung */
- /* up. The USR1 used for a manual disconnect could be HUP for this */
- /* reason. */
- if (flagsession
- &&((fd = open(path,O_RDONLY)) != -1)
- &&(read(fd,fnsty,sizeof(DEVSTY) - 1) > 0))
- {
- warnerr2("pty: reconnecting to %s\r\n",fnsty);
- (void) close(fd);
- (void) unlink(path);
- if ((fd = pty_writesock(fnsty)) == -1)
- warnerr2("pty: reconnect failed: cannot talk to %s\r\n",fnsty);
- else
- {
- if ((pty_getch(fd,&ch) != -1) && (ch == 'p'))
- if (pty_putgetint(fd,'p',&masterpid) != -1)
- do
- {
- #ifdef NO_FDPASSING
- if (fdtty != -1)
- {
- if (!(ttyn = real_ttyname(fdtty))) break;
- /* XXX: Should we NXCL here? */
- (void) strncpy(fntty,ttyn,TTYNAMELEN - 1);
- if (pty_sendstr(fd,'s',fntty) == -1) break;
- if (flagverbose)
- warnerr2("pty: sent parent tty %s\r\n",fntty);
- }
- #else
- if (fdtty != -1)
- {
- if (!(ttyn = real_ttyname(fdtty))) break;
- /* XXX: Should we NXCL here? */
- (void) strncpy(fntty,ttyn,TTYNAMELEN - 1);
- if (pty_sendstr(fd,'s',fntty) == -1) break;
- if (flagverbose)
- warnerr2("pty: sent parent tty %s\r\n",fntty);
- /* We shouldn't have to send the parent tty name, */
- /* but passing the fd alone doesn't set the control */
- /* terminal of the receiver (grrrr), and a detached */
- /* process effectively has no pgrp. Aargh. */
- }
-
- if (fdpass == -1)
- {
- if (pty_sendfd(fd,'0',&fdin) == -1) break;
- if (pty_sendfd(fd,'1',&fdout) == -1) break;
- }
- else
- if (pty_sendfd(fd,'f',&fdpass) == -1) break;
- if (fdtty != -1)
- if (pty_sendfd(fd,'t',&fdtty) == -1) break;
- #endif
- if (pty_sendint(fd,'p',&pid) == -1) break;
- if (pty_sendint(fd,'g',&pgrp) == -1) break;
- if (pty_sendint(fd,'j',&flagjobctrl) == -1) break;
- if (fdtty != -1)
- {
- if (pty_sendtty(fd,'c',&tmochartty) == -1) break;
- if (pty_sendtty(fd,'n',&tmotty) == -1) break;
- }
- if (pty_putch(fd," ") == -1) break;
- #ifdef NO_FDPASSING
- flagmaster = 2; /* Success, but pain coming up. */
- #else
- flagmaster = 1; /* Successfully reconnected! */
- #endif
- }
- while(0);
- if (flagmaster < 2)
- {
- (void) close(fd);
- fd = -1;
- }
- }
- if (flagmaster)
- {
- /* remake path for new pty */
- (void) sprintf(path,"sig.%s",fnsty + sizeof(DEVSTY) - 3);
- (void) unlink(path);
- warnerr2("pty: successfully reconnected to %s\r\n",fnsty);
- }
- else
- warnerr2("pty: reconnect to %s failed\r\n",fnsty);
- }
- if (!flagmaster)
- {
- if (tty_modifymodes(fdtty,&tmotty,&tmochartty) == -1)
- warnerr2("%s","pty: can't restore tty modes\n"); /*XXX*/
- fatal(0);
- /*NOTREACHED*/
- }
- }
- }
- }
-