xref: /csrg-svn/contrib/connectd/cd/main.c (revision 60590)
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