1*60590Sbostic /*-
2*60590Sbostic * Copyright (c) 1993 The Regents of the University of California.
338015Sbostic * All rights reserved.
438015Sbostic *
538015Sbostic * This code is derived from software contributed to Berkeley by
638015Sbostic * Bill Jolitz.
738015Sbostic *
8*60590Sbostic * %sccs.include.redist.c%
938015Sbostic */
1038015Sbostic
1138015Sbostic #ifndef lint
1238015Sbostic char copyright[] =
13*60590Sbostic "@(#) Copyright (c) 1993 The Regents of the University of California.\n\
1438015Sbostic All rights reserved.\n";
1538015Sbostic #endif /* not lint */
1638015Sbostic
1738015Sbostic #ifndef lint
18*60590Sbostic static char sccsid[] = "@(#)main.c 5.2 (Berkeley) 05/29/93";
1938015Sbostic #endif /* not lint */
2038015Sbostic
2138015Sbostic #include "main.h"
2238015Sbostic #include <sys/time.h>
2338015Sbostic #include <sys/ioctl.h>
2438015Sbostic
2538015Sbostic #include <signal.h>
2638015Sbostic #include <sys/types.h>
2738015Sbostic #include <utmp.h>
2838015Sbostic #include <setjmp.h>
2938015Sbostic #include <sys/reboot.h>
3038015Sbostic #include <errno.h>
3138015Sbostic #include <sys/file.h>
3238015Sbostic #include <ttyent.h>
3338015Sbostic #include <sys/syslog.h>
3438015Sbostic #include <sys/stat.h>
3538015Sbostic
3638015Sbostic #define LINSIZ sizeof(wtmp.ut_line)
3738015Sbostic #define CMDSIZ 200 /* max string length for getty or window command*/
3838015Sbostic #define ALL p = itab; p ; p = p->next
3938015Sbostic #define EVER ;;
4038015Sbostic #define SCPYN(a, b) strncpy(a, b, sizeof(a))
4138015Sbostic #define SCMPN(a, b) strncmp(a, b, sizeof(a))
4238015Sbostic
4338015Sbostic char shell[] = "/bin/sh";
4438015Sbostic char minus[] = "-";
4538015Sbostic char runc[] = "/etc/rc";
4638015Sbostic char utmpf[] = "/etc/utmp";
4738015Sbostic char wtmpf[] = "/usr/adm/wtmp";
4838015Sbostic char ctty[] = "/dev/console";
4938015Sbostic
5038015Sbostic
5138015Sbostic struct utmp wtmp;
5238015Sbostic struct tab
5338015Sbostic {
5438015Sbostic char line[LINSIZ];
5538015Sbostic char comn[CMDSIZ];
5638015Sbostic int baud; /* outgoing baud rate */
5738015Sbostic int sock; /* socket if outgoing connected */
5838015Sbostic int fd; /* file desc if we have, else -1 */
5938015Sbostic int errfd; /* error file desc if we have, else -1 */
6038015Sbostic char xflag;
6138015Sbostic int gpid; /* pid of getty or connector */
6238015Sbostic time_t gettytime;
6338015Sbostic int gettycnt;
6438015Sbostic struct tab *next;
6538015Sbostic } *itab;
6638015Sbostic
6738015Sbostic char tty3[LINSIZ] = { "tty3" } ;
6838015Sbostic char tty2[LINSIZ] = { "tty2" } ;
6938015Sbostic int fi;
7038015Sbostic int mergflag;
7138015Sbostic char tty[20];
7238015Sbostic jmp_buf sjbuf, shutpass;
7338015Sbostic time_t time0;
7438015Sbostic
7538015Sbostic int reset();
7638015Sbostic int idle();
7738015Sbostic char *strcpy(), *strcat();
7838015Sbostic long lseek();
7938015Sbostic
8038015Sbostic struct conversation convers[MAXCONNECTS] ;
8138015Sbostic jmp_buf terminate;
8238015Sbostic
8338015Sbostic fd_set rd_fdset, wr_fdset ;
8438015Sbostic int term(), sigpipe();
8538015Sbostic int debug;
8638015Sbostic extern int errno;
8738015Sbostic struct timeval tv_2th = { 0, 500000 } ;
main(argc,argv)8838015Sbostic main (argc,argv) char *argv[]; {
8938015Sbostic int sock, msgsock, rval, rv ;
9038015Sbostic struct sockaddr_un rqsts;
9138015Sbostic int err;
9238015Sbostic struct iovec iov[4];
9338015Sbostic int constatus, rqst, resp;
9438015Sbostic int optlen ;
9538015Sbostic char *optp;
9638015Sbostic struct connectdomain *cdp;
9738015Sbostic int i,n,afd ;
9838015Sbostic struct conversation *cd ;
9938015Sbostic struct tab *p ;
10038015Sbostic
10138015Sbostic /* initialize */
10238015Sbostic n = 0;
10338015Sbostic FD_ZERO(&rd_fdset) ;
10438015Sbostic FD_ZERO(&wr_fdset) ;
10538015Sbostic signal (SIGTTOU, SIG_IGN) ;
10638015Sbostic signal (SIGTTIN, SIG_IGN) ;
10738015Sbostic signal (SIGINT, term) ;
10838015Sbostic signal (SIGTERM, term) ;
10938015Sbostic signal (SIGPIPE, sigpipe) ;
11038015Sbostic if(setjmp(terminate)) goto on_error;
11138015Sbostic openlog("connectd", LOG_CONS|LOG_ODELAY, LOG_AUTH);
11238015Sbostic /* disassociate from tty pgrp */
11338015Sbostic n = open ("/dev/tty", 2) ;
11438015Sbostic ioctl(n,TIOCNOTTY, 0) ;
11538015Sbostic close(n) ;
11638015Sbostic
11738015Sbostic /* make incoming request socket */
11838015Sbostic sock = socket (AF_UNIX, SOCK_STREAM, 0) ;
11938015Sbostic if (sock < 0) {
12038015Sbostic perror("stream socket") ;
12138015Sbostic exit(1) ;
12238015Sbostic }
12338015Sbostic rqsts.sun_family = AF_UNIX ;
12438015Sbostic strcpy (rqsts.sun_path,"/dev/connect") ;
12538015Sbostic if (bind (sock, &rqsts, sizeof (rqsts))) {
12638015Sbostic perror ("bind /dev/connect") ;
12738015Sbostic exit (1) ;
12838015Sbostic }
12938015Sbostic
13038015Sbostic /* debugging ? */
13138015Sbostic if ((argc <= 1) || strcmp(argv[1],"-d") != 0) {
13238015Sbostic if (fork()) exit(0) ;
13338015Sbostic close (0); close (1); close (2);
13438015Sbostic } else debug = 1;
13538015Sbostic
13638015Sbostic /* build tables */
13738015Sbostic itab = (struct tab *)calloc(1, sizeof(*itab));
13838015Sbostic SCPYN(itab->line, tty3);
13938015Sbostic itab->fd = -1; /* do we have a fd open */
14038015Sbostic itab->sock = -1; /* does someone else have this fd? */
14138015Sbostic itab->gpid = 0; /* does getty have this fd? */
14238015Sbostic
14338015Sbostic itab->next = (struct tab *)calloc(1, sizeof(*itab));
14438015Sbostic itab->next->fd = -1; /* do we have a fd open */
14538015Sbostic itab->next->sock = -1; /* does someone else have this fd? */
14638015Sbostic itab->next->gpid = 0; /* does getty else have this fd? */
14738015Sbostic SCPYN(itab->next->line, tty2);
14838015Sbostic p = itab ;
14938015Sbostic
15038015Sbostic /* accept connection requests on socket */
15138015Sbostic listen (sock, 5) ;
15238015Sbostic FD_SET (sock, &rd_fdset) ;
15338015Sbostic
15438015Sbostic /* add requests from other lines */
15538015Sbostic for (ALL) openline(p) ;
15638015Sbostic
15738015Sbostic /* service requests as they come in */
15838015Sbostic for (;;) {
15938015Sbostic int s, ctrl, n;
16038015Sbostic fd_set readable, writeable;
16138015Sbostic
16238015Sbostic readable = rd_fdset;
16338015Sbostic writeable = wr_fdset;
16438015Sbostic #ifdef notdef
16538015Sbostic for (i=0; i <20 ; i++) {
16638015Sbostic if (FD_ISSET(i,&readable)) fprintf(stderr, "rd%d ", i) ;
16738015Sbostic if (FD_ISSET(i,&writeable)) fprintf(stderr, "wr%d ", i) ;
16838015Sbostic }
16938015Sbostic fprintf(stderr, "?\n") ;
17038015Sbostic #endif
17138015Sbostic if ((n = select(21, &readable, &writeable,
17238015Sbostic (fd_set *)0, &tv_2th )) <= 0) {
17338015Sbostic if (n < 0 && errno != EINTR)
17438015Sbostic if (debug)
17538015Sbostic perror ("select") ;
17638015Sbostic else
17738015Sbostic syslog(LOG_WARNING, "select: %m\n");
17838015Sbostic sleep(1);
17938015Sbostic continue;
18038015Sbostic }
18138015Sbostic
18238015Sbostic /* got a request, see who it is */
18338015Sbostic fprintf(stderr, "select %d\n", n) ;
18438015Sbostic for (i=0; i <20 ; i++) {
18538015Sbostic if (FD_ISSET(i,&readable))
18638015Sbostic fprintf(stderr, "rdsel%d ", i) ;
18738015Sbostic if (FD_ISSET(i,&writeable))
18838015Sbostic fprintf(stderr, "wrsel%d ", i) ;
18938015Sbostic }
19038015Sbostic fprintf(stderr, "\n") ;
19138015Sbostic
19238015Sbostic /* have we a new connection request? */
19338015Sbostic if (FD_ISSET(sock, &readable)) {
19438015Sbostic msgsock = accept(sock, 0, 0) ;
19538015Sbostic if (msgsock == -1) {
19638015Sbostic perror ("accept") ;
19738015Sbostic continue ;
19838015Sbostic }
19938015Sbostic /*allocate a connection */
20038015Sbostic convers[msgsock].co_sock = msgsock ;
20138015Sbostic FD_SET (msgsock, &rd_fdset) ;
20238015Sbostic fprintf(stderr, "accept %d\n", msgsock) ;
20338015Sbostic }
20438015Sbostic /* have we a incoming request */
20538015Sbostic for (p = itab; p ; p = p->next)
20638015Sbostic if (FD_ISSET(p->fd, &writeable)) {
20738015Sbostic /* fork off getty after setting up line */
20838015Sbostic printf("do a getty on fd%d\n", p->fd) ;
20938015Sbostic if(p->sock >= 0) { printf("on a conn?\n") ; continue; }
21038015Sbostic i = fork ();
21138015Sbostic if (i < 0) {
21238015Sbostic perror("cd:fork") ;
21338015Sbostic exit(1);
21438015Sbostic }
21538015Sbostic if (!i) {
21638015Sbostic dup2(p->fd, 0);
21738015Sbostic dup2(p->fd, 1);
21838015Sbostic dup2(p->fd, 2);
21938015Sbostic i = getdtablesize();
22038015Sbostic for (n=3 ; n < i ; n++) close (n) ;
22138015Sbostic ioctl(0,TIOCYESTTY, 0) ;
22238015Sbostic execl("/etc/getty", "getty", "std.1200", "-", 0) ;
22338015Sbostic perror("exec");
22438015Sbostic exit(1);
22538015Sbostic } else {
22638015Sbostic p->gpid = i ;
22738015Sbostic i = wait(&n) ;
22838015Sbostic printf("cd: waitgetty %d %d\n", i, n) ;
22938015Sbostic p->gpid = 0 ;
23038015Sbostic closeline (p, 0) ;
23138015Sbostic rmut(p) ;
23238015Sbostic sleep (1) ;
23338015Sbostic openline (p) ;
23438015Sbostic }
23538015Sbostic } ;
23638015Sbostic ;
23738015Sbostic /* have we an existing socket request */
23838015Sbostic for (cd = convers; cd - convers < MAXCONNECTS ; cd++) {
23938015Sbostic cdp = &cd->co_cd ;
24038015Sbostic if (FD_ISSET(cd->co_sock, &readable)) {
24138015Sbostic fprintf(stderr, "recv %d\n", cd->co_sock) ;
24238015Sbostic /* recieve connnection request message */
24338015Sbostic rqst = rcvrequest(cd->co_sock, cd, &optp,
24438015Sbostic &optlen, &afd) ;
24538015Sbostic
24638015Sbostic /*fprintf(stderr, "rqst %d\n", rqst) ;*/
24738015Sbostic if (rqst < 0) goto end_session ;
24838015Sbostic
24938015Sbostic /*printf("cd:request %d ", rqst) ;*/
25038015Sbostic
25138015Sbostic /* process request */
25238015Sbostic switch (rqst) {
25338015Sbostic case CDNEWREQUEST:
25438015Sbostic cd->co_rqst = rqst ;
25538015Sbostic /*printf("cd_family %d, cd_address %s, cd_alen %d\n",
25638015Sbostic cdp->cd_family, cdp->cd_address, cdp->cd_alen) ;*/
25738015Sbostic /*if (optlen)
25838015Sbostic printf("option:%s\n", optp);*/
25938015Sbostic if (afd>= 0) {
26038015Sbostic cd->co_errfd = afd ;
26138015Sbostic } else cd->co_errfd = -1 ;
26238015Sbostic
26338015Sbostic cd->co_constatus = -1;
26438015Sbostic for (p = itab; p ; p = p->next)
26538015Sbostic if (p->gpid == 0 && p->fd >= 0 && p->sock < 0) break;
26638015Sbostic if (!p) exit(0); /* return error can't find a line */
26738015Sbostic fprintf(stderr, "allocate fd%d line %s\n", p->fd, p->line) ;
26838015Sbostic ioctl(p->fd, TIOCSIGNCAR, 0) ;
26938015Sbostic p->errfd = cd->co_errfd;
27038015Sbostic p->sock = cd->co_sock ;
27138015Sbostic i = fork ();
27238015Sbostic if (i < 0) {
27338015Sbostic perror("cd:fork") ;
27438015Sbostic exit(1);
27538015Sbostic }
27638015Sbostic if (!i) {
27738015Sbostic dup2(p->fd, 0);
27838015Sbostic dup2(p->fd, 1);
27938015Sbostic if (cd->co_errfd) dup2(cd->co_errfd,2);
28038015Sbostic else close(2) ;
28138015Sbostic i = getdtablesize();
28238015Sbostic for (n=3 ; n < i ; n++) close (n) ;
28338015Sbostic execl("con", "con", cdp->cd_address, 0) ;
28438015Sbostic perror("exec");
28538015Sbostic exit(1);
28638015Sbostic } else {
28738015Sbostic cd->co_pid = i ;
28838015Sbostic i = wait(&n) ;
28938015Sbostic /*printf("cd: wait %d %d\n", i, n) ;*/
29038015Sbostic if (n == 0) cd->co_constatus = n;
29138015Sbostic else {
29238015Sbostic fprintf(stderr, "cd: con fails status %d\n", n) ;
29338015Sbostic cd->co_constatus = (-1 <<16) | n ;
29438015Sbostic closeline (p, 0) ;
29538015Sbostic }
29638015Sbostic }
29738015Sbostic if (p->fd >= 0) {
29838015Sbostic fprintf(stderr, "cd: sending fd %d \n", p->fd) ;
29938015Sbostic ioctl(p->fd, TIOCCIGNCAR, 0) ;
30038015Sbostic }
30138015Sbostic optlen = 0;
30238015Sbostic
30338015Sbostic resp = CDNEWRESPONSE ;
30438015Sbostic /* send connnection response message */
30538015Sbostic err = sendrequest(cd->co_sock, resp, cd, optp, optlen, p->fd) ;
30638015Sbostic if(p->fd >= 0) closeline (p, 1) ;
30738015Sbostic if (cd->co_constatus) goto end_session ;
30838015Sbostic break ;
30938015Sbostic
31038015Sbostic case CDFINISHREQUEST:
31138015Sbostic for (p = itab; p ; p = p->next)
31238015Sbostic if (p->sock == cd->co_sock) break;
31338015Sbostic if(!p) exit(0); /* return no such connection */
31438015Sbostic p->fd = afd ;
31538015Sbostic fprintf(stderr, "cd: received fd %d \n", p->fd) ;
31638015Sbostic cd->co_constatus = -1;
31738015Sbostic ioctl(p->fd, TIOCSIGNCAR, 0) ;
31838015Sbostic i = fork ();
31938015Sbostic if (i < 0) {
32038015Sbostic perror("cd:fork") ;
32138015Sbostic exit(1);
32238015Sbostic }
32338015Sbostic if (!i) {
32438015Sbostic dup2(p->fd, 0);
32538015Sbostic dup2(p->fd, 1);
32638015Sbostic if (cd->co_errfd <= 0) dup2(cd->co_errfd,2);
32738015Sbostic else close(2) ;
32838015Sbostic i = getdtablesize();
32938015Sbostic for (n=3 ; n < i ; n++) close (n) ;
33038015Sbostic execl("con", "con", "drop" , 0) ;
33138015Sbostic perror("exec");
33238015Sbostic exit(1);
33338015Sbostic } else {
33438015Sbostic cd->co_pid = i ;
33538015Sbostic i = wait(&n) ;
33638015Sbostic fprintf(stderr,"cd: wait %d %d\n", i, n) ;
33738015Sbostic if (n == 0) cd->co_constatus = n;
33838015Sbostic else cd->co_constatus = (-1 <<16) | n ;
33938015Sbostic }
34038015Sbostic fprintf(stderr,"cd: dropped \n") ;
34138015Sbostic
34238015Sbostic cd->co_rqst = resp = CDFINISHRESPONSE ;
34338015Sbostic /* send connnection response message */
34438015Sbostic err = sendrequest(cd->co_sock, resp, cd, 0, 0, 0) ;
34538015Sbostic goto end_session;
34638015Sbostic } /* end of switch */
34738015Sbostic } ; continue; /* end of if */
34838015Sbostic
34938015Sbostic end_session:
35038015Sbostic /*fprintf(stderr, "end_session\n") ;*/
35138015Sbostic close (cd->co_errfd) ;
35238015Sbostic FD_CLR (cd->co_sock, &rd_fdset) ;
35338015Sbostic close (cd->co_sock) ;
35438015Sbostic cd->co_sock = 0 ;
35538015Sbostic if (p->fd >= 0) closeline (p, 0) ;
35638015Sbostic sleep(1) ;
35738015Sbostic openline (p) ;
35838015Sbostic } /* end of conv for */
35938015Sbostic } /*end of foerever */
36038015Sbostic on_error:
36138015Sbostic close (sock) ;
36238015Sbostic unlink ("/dev/connect") ;
36338015Sbostic }
36438015Sbostic
term()36538015Sbostic term() { struct tab *p;
36638015Sbostic
36738015Sbostic for (p = itab ; p ; p = p->next)
36838015Sbostic if (p->gpid) kill (p->gpid, SIGHUP);
36938015Sbostic longjmp (terminate);
37038015Sbostic }
37138015Sbostic
sigpipe()37238015Sbostic sigpipe() { printf("SIGPIPE\n") ; fflush (stdout) ; longjmp (terminate); }
37338015Sbostic
37438015Sbostic /*
37538015Sbostic * open and prepare line for connectd
37638015Sbostic */
37738015Sbostic openline(p) struct tab *p; {
37838015Sbostic char ttyn[32]; int n;
37938015Sbostic
38038015Sbostic /* open the bastard */
38138015Sbostic strcpy (ttyn, "/dev/");
38238015Sbostic strcat (ttyn, p->line) ;
38338015Sbostic p->fd = open (ttyn, O_RDWR|O_NDELAY) ;
38438015Sbostic
38538015Sbostic /* disassociate from our pgrp */
38638015Sbostic n = open ("/dev/tty", O_RDWR|O_NDELAY) ;
38738015Sbostic ioctl (n, TIOCNOTTY, 0) ;
38838015Sbostic close(n) ;
38938015Sbostic
39038015Sbostic /* mark 'em to be watched for carrier */
39138015Sbostic FD_SET (p->fd, &wr_fdset) ;
39238015Sbostic
39338015Sbostic /* if set in a still open state */
39438015Sbostic ioctl(p->fd, TIOCCIGNCAR, 0) ;
39538015Sbostic
39638015Sbostic if (debug) fprintf(stderr, "openline: %s: fd %d\n", p->line, p->fd) ;
39738015Sbostic }
39838015Sbostic
39938015Sbostic closeline(p, i) struct tab *p; {
40038015Sbostic
40138015Sbostic if (debug) fprintf(stderr, "closeline: %s: fd %d ", p->line, p->fd) ;
40238015Sbostic
40338015Sbostic close (p->fd) ;
40438015Sbostic FD_CLR (p->fd, &wr_fdset) ;
40538015Sbostic p->fd = -1 ;
40638015Sbostic if (i) {
40738015Sbostic if (debug) fprintf(stderr, "remove from use\n") ;
40838015Sbostic return ;
40938015Sbostic }
41038015Sbostic
41138015Sbostic if (debug) fprintf(stderr, "entirely\n") ;
41238015Sbostic if (p->gpid) kill (p->gpid, SIGKILL); /* no mercy */
41338015Sbostic p->gpid = 0 ;
41438015Sbostic
41538015Sbostic if(p->sock >= 0) close (p->sock);
41638015Sbostic p->sock = -1 ;
41738015Sbostic }
41838015Sbostic
41938015Sbostic #ifdef notdef
42038015Sbostic struct sigvec rvec = { reset, sigmask(SIGHUP), 0 };
42138015Sbostic
42238015Sbostic
main(argc,argv)42338015Sbostic main(argc, argv)
42438015Sbostic char **argv;
42538015Sbostic {
42638015Sbostic int howto, oldhowto;
42738015Sbostic
42838015Sbostic time0 = time(0);
42938015Sbostic if (argc > 1 && argv[1][0] == '-') {
43038015Sbostic char *cp;
43138015Sbostic
43238015Sbostic howto = 0;
43338015Sbostic cp = &argv[1][1];
43438015Sbostic while (*cp) switch (*cp++) {
43538015Sbostic case 'a':
43638015Sbostic howto |= RB_ASKNAME;
43738015Sbostic break;
43838015Sbostic case 's':
43938015Sbostic howto |= RB_SINGLE;
44038015Sbostic break;
44138015Sbostic }
44238015Sbostic } else {
44338015Sbostic howto = RB_SINGLE;
44438015Sbostic }
44538015Sbostic openlog("connectd", LOG_CONS|LOG_ODELAY, LOG_AUTH);
44638015Sbostic sigvec(SIGTERM, &rvec, (struct sigvec *)0);
44738015Sbostic signal(SIGTSTP, idle);
44838015Sbostic signal(SIGSTOP, SIG_IGN);
44938015Sbostic signal(SIGTTIN, SIG_IGN);
45038015Sbostic signal(SIGTTOU, SIG_IGN);
45138015Sbostic (void) setjmp(sjbuf);
45238015Sbostic for (EVER) {
45338015Sbostic oldhowto = howto;
45438015Sbostic howto = RB_SINGLE;
45538015Sbostic if (setjmp(shutpass) == 0)
45638015Sbostic shutdown();
45738015Sbostic if (oldhowto & RB_SINGLE)
45838015Sbostic single();
45938015Sbostic if (runcom(oldhowto) == 0)
46038015Sbostic continue;
46138015Sbostic merge();
46238015Sbostic multiple();
46338015Sbostic }
46438015Sbostic }
46538015Sbostic
46638015Sbostic int shutreset();
46738015Sbostic
shutdown()46838015Sbostic shutdown()
46938015Sbostic {
47038015Sbostic register i;
47138015Sbostic register struct tab *p, *p1;
47238015Sbostic
47338015Sbostic close(creat(utmpf, 0644));
47438015Sbostic signal(SIGHUP, SIG_IGN);
47538015Sbostic for (p = itab; p ; ) {
47638015Sbostic term(p);
47738015Sbostic p1 = p->next;
47838015Sbostic free(p);
47938015Sbostic p = p1;
48038015Sbostic }
48138015Sbostic itab = (struct tab *)0;
48238015Sbostic signal(SIGALRM, shutreset);
48338015Sbostic (void) kill(-1, SIGTERM); /* one chance to catch it */
48438015Sbostic sleep(5);
48538015Sbostic alarm(30);
48638015Sbostic for (i = 0; i < 5; i++)
48738015Sbostic kill(-1, SIGKILL);
48838015Sbostic while (wait((int *)0) != -1)
48938015Sbostic ;
49038015Sbostic alarm(0);
49138015Sbostic shutend();
49238015Sbostic }
49338015Sbostic
49438015Sbostic char shutfailm[] = "WARNING: Something is hung (wont die); ps axl advised\n";
49538015Sbostic
shutreset()49638015Sbostic shutreset()
49738015Sbostic {
49838015Sbostic int status;
49938015Sbostic
50038015Sbostic if (fork() == 0) {
50138015Sbostic int ct = open(ctty, 1);
50238015Sbostic write(ct, shutfailm, sizeof (shutfailm));
50338015Sbostic sleep(5);
50438015Sbostic exit(1);
50538015Sbostic }
50638015Sbostic sleep(5);
50738015Sbostic shutend();
50838015Sbostic longjmp(shutpass, 1);
50938015Sbostic }
51038015Sbostic
shutend()51138015Sbostic shutend()
51238015Sbostic {
51338015Sbostic register i, f;
51438015Sbostic
51538015Sbostic acct(0);
51638015Sbostic signal(SIGALRM, SIG_DFL);
51738015Sbostic for (i = 0; i < 10; i++)
51838015Sbostic close(i);
51938015Sbostic f = open(wtmpf, O_WRONLY|O_APPEND);
52038015Sbostic if (f >= 0) {
52138015Sbostic SCPYN(wtmp.ut_line, "~");
52238015Sbostic SCPYN(wtmp.ut_name, "shutdown");
52338015Sbostic SCPYN(wtmp.ut_host, "");
52438015Sbostic time(&wtmp.ut_time);
52538015Sbostic write(f, (char *)&wtmp, sizeof(wtmp));
52638015Sbostic close(f);
52738015Sbostic }
52838015Sbostic return (1);
52938015Sbostic }
53038015Sbostic
single()53138015Sbostic single()
53238015Sbostic {
53338015Sbostic register pid;
53438015Sbostic register xpid;
53538015Sbostic extern errno;
53638015Sbostic
53738015Sbostic do {
53838015Sbostic pid = fork();
53938015Sbostic if (pid == 0) {
54038015Sbostic signal(SIGTERM, SIG_DFL);
54138015Sbostic signal(SIGHUP, SIG_DFL);
54238015Sbostic signal(SIGALRM, SIG_DFL);
54338015Sbostic signal(SIGTSTP, SIG_IGN);
54438015Sbostic (void) open(ctty, O_RDWR);
54538015Sbostic dup2(0, 1);
54638015Sbostic dup2(0, 2);
54738015Sbostic execl(shell, minus, (char *)0);
54838015Sbostic exit(0);
54938015Sbostic }
55038015Sbostic while ((xpid = wait((int *)0)) != pid)
55138015Sbostic if (xpid == -1 && errno == ECHILD)
55238015Sbostic break;
55338015Sbostic } while (xpid == -1);
55438015Sbostic }
55538015Sbostic
runcom(oldhowto)55638015Sbostic runcom(oldhowto)
55738015Sbostic int oldhowto;
55838015Sbostic {
55938015Sbostic register pid, f;
56038015Sbostic int status;
56138015Sbostic
56238015Sbostic pid = fork();
56338015Sbostic if (pid == 0) {
56438015Sbostic (void) open("/", O_RDONLY);
56538015Sbostic dup2(0, 1);
56638015Sbostic dup2(0, 2);
56738015Sbostic if (oldhowto & RB_SINGLE)
56838015Sbostic execl(shell, shell, runc, (char *)0);
56938015Sbostic else
57038015Sbostic execl(shell, shell, runc, "autoboot", (char *)0);
57138015Sbostic exit(1);
57238015Sbostic }
57338015Sbostic while (wait(&status) != pid)
57438015Sbostic ;
57538015Sbostic if (status)
57638015Sbostic return (0);
57738015Sbostic f = open(wtmpf, O_WRONLY|O_APPEND);
57838015Sbostic if (f >= 0) {
57938015Sbostic SCPYN(wtmp.ut_line, "~");
58038015Sbostic SCPYN(wtmp.ut_name, "reboot");
58138015Sbostic SCPYN(wtmp.ut_host, "");
58238015Sbostic if (time0) {
58338015Sbostic wtmp.ut_time = time0;
58438015Sbostic time0 = 0;
58538015Sbostic } else
58638015Sbostic time(&wtmp.ut_time);
58738015Sbostic write(f, (char *)&wtmp, sizeof(wtmp));
58838015Sbostic close(f);
58938015Sbostic }
59038015Sbostic return (1);
59138015Sbostic }
59238015Sbostic
59338015Sbostic struct sigvec mvec = { merge, sigmask(SIGTERM), 0 };
59438015Sbostic /*
59538015Sbostic * Multi-user. Listen for users leaving, SIGHUP's
59638015Sbostic * which indicate ttys has changed, and SIGTERM's which
59738015Sbostic * are used to shutdown the system.
59838015Sbostic */
multiple()59938015Sbostic multiple()
60038015Sbostic {
60138015Sbostic register struct tab *p;
60238015Sbostic register pid;
60338015Sbostic int omask;
60438015Sbostic
60538015Sbostic sigvec(SIGHUP, &mvec, (struct sigvec *)0);
60638015Sbostic for (EVER) {
60738015Sbostic pid = wait((int *)0);
60838015Sbostic if (pid == -1)
60938015Sbostic return;
61038015Sbostic omask = sigblock(SIGHUP);
61138015Sbostic for (ALL) {
61238015Sbostic /* must restart window system BEFORE emulator */
61338015Sbostic if (p->wpid == pid || p->wpid == -1)
61438015Sbostic wstart(p);
61538015Sbostic if (p->pid == pid || p->pid == -1) {
61638015Sbostic /* disown the window system */
61738015Sbostic if (p->wpid)
61838015Sbostic kill(p->wpid, SIGHUP);
61938015Sbostic rmut(p);
62038015Sbostic dfork(p);
62138015Sbostic }
62238015Sbostic }
62338015Sbostic sigsetmask(omask);
62438015Sbostic }
62538015Sbostic }
62638015Sbostic
62738015Sbostic /*
62838015Sbostic * Merge current contents of ttys file
62938015Sbostic * into in-core table of configured tty lines.
63038015Sbostic * Entered as signal handler for SIGHUP.
63138015Sbostic */
63238015Sbostic #define FOUND 1
63338015Sbostic #define CHANGE 2
63438015Sbostic #define WCHANGE 4
63538015Sbostic
merge()63638015Sbostic merge()
63738015Sbostic {
63838015Sbostic register struct tab *p;
63938015Sbostic register struct ttyent *t;
64038015Sbostic register struct tab *p1;
64138015Sbostic
64238015Sbostic for (ALL)
64338015Sbostic p->xflag = 0;
64438015Sbostic setttyent();
64538015Sbostic while (t = getttyent()) {
64638015Sbostic /* is it init's responsibility?
64738015Sbostic if ((t->ty_status & TTY_ON)) continue; */
64838015Sbostic if ((t->ty_status & TTY_ON) == 0)
64938015Sbostic continue;
65038015Sbostic for (ALL) {
65138015Sbostic if (SCMPN(p->line, t->ty_name))
65238015Sbostic continue;
65338015Sbostic p->xflag |= FOUND;
65438015Sbostic if (SCMPN(p->comn, t->ty_getty)) {
65538015Sbostic p->xflag |= CHANGE;
65638015Sbostic SCPYN(p->comn, t->ty_getty);
65738015Sbostic }
65838015Sbostic if (SCMPN(p->wcmd, t->ty_window)) {
65938015Sbostic p->xflag |= WCHANGE|CHANGE;
66038015Sbostic SCPYN(p->wcmd, t->ty_window);
66138015Sbostic }
66238015Sbostic goto contin1;
66338015Sbostic }
66438015Sbostic
66538015Sbostic /*
66638015Sbostic * Make space for a new one
66738015Sbostic */
66838015Sbostic p1 = (struct tab *)calloc(1, sizeof(*p1));
66938015Sbostic if (!p1) {
67038015Sbostic syslog(LOG_ERR, "no space for '%s' !?!", t->ty_name);
67138015Sbostic goto contin1;
67238015Sbostic }
67338015Sbostic /*
67438015Sbostic * Put new terminal at the end of the linked list.
67538015Sbostic */
67638015Sbostic if (itab) {
67738015Sbostic for (p = itab; p->next ; p = p->next)
67838015Sbostic ;
67938015Sbostic p->next = p1;
68038015Sbostic } else
68138015Sbostic itab = p1;
68238015Sbostic
68338015Sbostic p = p1;
68438015Sbostic SCPYN(p->line, t->ty_name);
68538015Sbostic p->xflag |= FOUND|CHANGE;
68638015Sbostic SCPYN(p->comn, t->ty_getty);
68738015Sbostic if (strcmp(t->ty_window, "") != 0) {
68838015Sbostic p->xflag |= WCHANGE;
68938015Sbostic SCPYN(p->wcmd, t->ty_window);
69038015Sbostic }
69138015Sbostic contin1:
69238015Sbostic ;
69338015Sbostic }
69438015Sbostic endttyent();
69538015Sbostic p1 = (struct tab *)0;
69638015Sbostic for (ALL) {
69738015Sbostic if ((p->xflag&FOUND) == 0) {
69838015Sbostic term(p);
69938015Sbostic wterm(p);
70038015Sbostic if (p1)
70138015Sbostic p1->next = p->next;
70238015Sbostic else
70338015Sbostic itab = p->next;
70438015Sbostic free(p);
70538015Sbostic p = p1 ? p1 : itab;
70638015Sbostic } else {
70738015Sbostic /* window system should be started first */
70838015Sbostic if (p->xflag&WCHANGE) {
70938015Sbostic wterm(p);
71038015Sbostic wstart(p);
71138015Sbostic }
71238015Sbostic if (p->xflag&CHANGE) {
71338015Sbostic term(p);
71438015Sbostic dfork(p);
71538015Sbostic }
71638015Sbostic }
71738015Sbostic p1 = p;
71838015Sbostic }
71938015Sbostic }
72038015Sbostic
term(p)72138015Sbostic term(p)
72238015Sbostic register struct tab *p;
72338015Sbostic {
72438015Sbostic
72538015Sbostic if (p->pid != 0) {
72638015Sbostic rmut(p);
72738015Sbostic kill(p->pid, SIGKILL);
72838015Sbostic }
72938015Sbostic p->pid = 0;
73038015Sbostic /* send SIGHUP to get rid of connections */
73138015Sbostic if (p->wpid > 0)
73238015Sbostic kill(p->wpid, SIGHUP);
73338015Sbostic }
73438015Sbostic
73538015Sbostic #include <sys/ioctl.h>
73638015Sbostic
73738015Sbostic dfork(p)
73838015Sbostic struct tab *p;
73938015Sbostic {
74038015Sbostic register pid;
74138015Sbostic time_t t;
74238015Sbostic int dowait = 0;
74338015Sbostic
74438015Sbostic time(&t);
74538015Sbostic p->gettycnt++;
74638015Sbostic if ((t - p->gettytime) >= 60) {
74738015Sbostic p->gettytime = t;
74838015Sbostic p->gettycnt = 1;
74938015Sbostic } else if (p->gettycnt >= 5) {
75038015Sbostic dowait = 1;
75138015Sbostic p->gettytime = t;
75238015Sbostic p->gettycnt = 1;
75338015Sbostic }
75438015Sbostic pid = fork();
75538015Sbostic if (pid == 0) {
75638015Sbostic signal(SIGTERM, SIG_DFL);
75738015Sbostic signal(SIGHUP, SIG_IGN);
75838015Sbostic sigsetmask(0); /* since can be called from masked code */
75938015Sbostic if (dowait) {
76038015Sbostic syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line);
76138015Sbostic closelog();
76238015Sbostic sleep(30);
76338015Sbostic }
76438015Sbostic execit(p->comn, p->line);
76538015Sbostic exit(0);
76638015Sbostic }
76738015Sbostic p->pid = pid;
76838015Sbostic }
76938015Sbostic #endif
77038015Sbostic /*
77138015Sbostic * Remove utmp entry.
77238015Sbostic */
rmut(p)77338015Sbostic rmut(p)
77438015Sbostic register struct tab *p;
77538015Sbostic {
77638015Sbostic register f;
77738015Sbostic int found = 0;
77838015Sbostic static unsigned utmpsize;
77938015Sbostic static struct utmp *utmp;
78038015Sbostic register struct utmp *u;
78138015Sbostic int nutmp;
78238015Sbostic struct stat statbf;
78338015Sbostic
78438015Sbostic f = open(utmpf, O_RDWR);
78538015Sbostic if (f >= 0) {
78638015Sbostic fstat(f, &statbf);
78738015Sbostic if (utmpsize < statbf.st_size) {
78838015Sbostic utmpsize = statbf.st_size + 10 * sizeof(struct utmp);
78938015Sbostic if (utmp)
79038015Sbostic utmp = (struct utmp *)realloc(utmp, utmpsize);
79138015Sbostic else
79238015Sbostic utmp = (struct utmp *)malloc(utmpsize);
79338015Sbostic if (!utmp)
79438015Sbostic syslog(LOG_ERR, "utmp malloc failed");
79538015Sbostic }
79638015Sbostic if (statbf.st_size && utmp) {
79738015Sbostic nutmp = read(f, utmp, statbf.st_size);
79838015Sbostic nutmp /= sizeof(struct utmp);
79938015Sbostic for (u = utmp ; u < &utmp[nutmp] ; u++) {
80038015Sbostic if (SCMPN(u->ut_line, p->line) ||
80138015Sbostic u->ut_name[0]==0)
80238015Sbostic continue;
80338015Sbostic lseek(f, ((long)u)-((long)utmp), L_SET);
80438015Sbostic SCPYN(u->ut_name, "");
80538015Sbostic SCPYN(u->ut_host, "");
80638015Sbostic time(&u->ut_time);
80738015Sbostic write(f, (char *)u, sizeof(*u));
80838015Sbostic found++;
80938015Sbostic }
81038015Sbostic }
81138015Sbostic close(f);
81238015Sbostic }
81338015Sbostic if (found) {
81438015Sbostic f = open(wtmpf, O_WRONLY|O_APPEND);
81538015Sbostic if (f >= 0) {
81638015Sbostic SCPYN(wtmp.ut_line, p->line);
81738015Sbostic SCPYN(wtmp.ut_name, "");
81838015Sbostic SCPYN(wtmp.ut_host, "");
81938015Sbostic time(&wtmp.ut_time);
82038015Sbostic write(f, (char *)&wtmp, sizeof(wtmp));
82138015Sbostic close(f);
82238015Sbostic }
82338015Sbostic /*
82438015Sbostic * After a proper login force reset
82538015Sbostic * of error detection code in dfork.
82638015Sbostic */
82738015Sbostic p->gettytime = 0;
82838015Sbostic }
82938015Sbostic }
83038015Sbostic #ifdef notdef
reset()83138015Sbostic reset()
83238015Sbostic {
83338015Sbostic
83438015Sbostic longjmp(sjbuf, 1);
83538015Sbostic }
83638015Sbostic
83738015Sbostic jmp_buf idlebuf;
83838015Sbostic
idlehup()83938015Sbostic idlehup()
84038015Sbostic {
84138015Sbostic
84238015Sbostic longjmp(idlebuf, 1);
84338015Sbostic }
84438015Sbostic
idle()84538015Sbostic idle()
84638015Sbostic {
84738015Sbostic register struct tab *p;
84838015Sbostic register pid;
84938015Sbostic
85038015Sbostic signal(SIGHUP, idlehup);
85138015Sbostic for (EVER) {
85238015Sbostic if (setjmp(idlebuf))
85338015Sbostic return;
85438015Sbostic pid = wait((int *) 0);
85538015Sbostic if (pid == -1) {
85638015Sbostic sigpause(0);
85738015Sbostic continue;
85838015Sbostic }
85938015Sbostic for (ALL) {
86038015Sbostic /* if window system dies, mark it for restart */
86138015Sbostic if (p->wpid == pid)
86238015Sbostic p->wpid = -1;
86338015Sbostic if (p->pid == pid) {
86438015Sbostic rmut(p);
86538015Sbostic p->pid = -1;
86638015Sbostic }
86738015Sbostic }
86838015Sbostic }
86938015Sbostic }
87038015Sbostic
wterm(p)87138015Sbostic wterm(p)
87238015Sbostic register struct tab *p;
87338015Sbostic {
87438015Sbostic if (p->wpid != 0) {
87538015Sbostic kill(p->wpid, SIGKILL);
87638015Sbostic }
87738015Sbostic p->wpid = 0;
87838015Sbostic }
87938015Sbostic
wstart(p)88038015Sbostic wstart(p)
88138015Sbostic register struct tab *p;
88238015Sbostic {
88338015Sbostic register pid;
88438015Sbostic time_t t;
88538015Sbostic int dowait = 0;
88638015Sbostic
88738015Sbostic time(&t);
88838015Sbostic p->windcnt++;
88938015Sbostic if ((t - p->windtime) >= 60) {
89038015Sbostic p->windtime = t;
89138015Sbostic p->windcnt = 1;
89238015Sbostic } else if (p->windcnt >= 5) {
89338015Sbostic dowait = 1;
89438015Sbostic p->windtime = t;
89538015Sbostic p->windcnt = 1;
89638015Sbostic }
89738015Sbostic
89838015Sbostic pid = fork();
89938015Sbostic
90038015Sbostic if (pid == 0) {
90138015Sbostic signal(SIGTERM, SIG_DFL);
90238015Sbostic signal(SIGHUP, SIG_IGN);
90338015Sbostic sigsetmask(0); /* since can be called from masked code */
90438015Sbostic if (dowait) {
90538015Sbostic syslog(LOG_ERR, "'%s %s' failing, sleeping", p->wcmd, p->line);
90638015Sbostic closelog();
90738015Sbostic sleep(30);
90838015Sbostic }
90938015Sbostic execit(p->wcmd, p->line);
91038015Sbostic exit(0);
91138015Sbostic }
91238015Sbostic p->wpid = pid;
91338015Sbostic }
91438015Sbostic
91538015Sbostic #define NARGS 20 /* must be at least 4 */
91638015Sbostic #define ARGLEN 512 /* total size for all the argument strings */
91738015Sbostic
execit(s,arg)91838015Sbostic execit(s, arg)
91938015Sbostic char *s;
92038015Sbostic char *arg; /* last argument on line */
92138015Sbostic {
92238015Sbostic char *argv[NARGS], args[ARGLEN], *envp[1];
92338015Sbostic register char *sp = s;
92438015Sbostic register char *ap = args;
92538015Sbostic register char c;
92638015Sbostic register int i;
92738015Sbostic
92838015Sbostic /*
92938015Sbostic * First we have to set up the argument vector.
93038015Sbostic * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2").
93138015Sbostic */
93238015Sbostic for (i = 1; i < NARGS - 2; i++) {
93338015Sbostic argv[i] = ap;
93438015Sbostic for (EVER) {
93538015Sbostic if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) {
93638015Sbostic *ap = '\0';
93738015Sbostic goto done;
93838015Sbostic }
93938015Sbostic if (c == ' ') {
94038015Sbostic *ap++ = '\0';
94138015Sbostic while (*sp == ' ')
94238015Sbostic sp++;
94338015Sbostic if (*sp == '\0')
94438015Sbostic goto done;
94538015Sbostic break;
94638015Sbostic }
94738015Sbostic *ap++ = c;
94838015Sbostic }
94938015Sbostic }
95038015Sbostic done:
95138015Sbostic argv[0] = argv[1];
95238015Sbostic argv[1] = "-";
95338015Sbostic argv[i+1] = arg;
95438015Sbostic argv[i+2] = 0;
95538015Sbostic envp[0] = 0;
95638015Sbostic execve(argv[0], &argv[1], envp);
95738015Sbostic /* report failure of exec */
95838015Sbostic syslog(LOG_ERR, "%s: %m", argv[0]);
95938015Sbostic closelog();
96038015Sbostic sleep(10); /* prevent failures from eating machine */
96138015Sbostic }
96238015Sbostic #endif
963