xref: /original-bsd/contrib/connectd/cd/main.c (revision 23c6a147)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Bill Jolitz.
7  *
8  * Redistribution and use in source and binary forms are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by the University of California, Berkeley.  The name of the
14  * University may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  */
20 
21 #ifndef lint
22 char copyright[] =
23 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
24  All rights reserved.\n";
25 #endif /* not lint */
26 
27 #ifndef lint
28 static char sccsid[] = "@(#)main.c	5.1 (Berkeley) 05/16/89";
29 #endif /* not lint */
30 
31 #include "main.h"
32 #include <sys/time.h>
33 #include <sys/ioctl.h>
34 
35 #include <signal.h>
36 #include <sys/types.h>
37 #include <utmp.h>
38 #include <setjmp.h>
39 #include <sys/reboot.h>
40 #include <errno.h>
41 #include <sys/file.h>
42 #include <ttyent.h>
43 #include <sys/syslog.h>
44 #include <sys/stat.h>
45 
46 #define	LINSIZ	sizeof(wtmp.ut_line)
47 #define	CMDSIZ	200	/* max string length for getty or window command*/
48 #define	ALL	p = itab; p ; p = p->next
49 #define	EVER	;;
50 #define SCPYN(a, b)	strncpy(a, b, sizeof(a))
51 #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
52 
53 char	shell[]	= "/bin/sh";
54 char	minus[]	= "-";
55 char	runc[]	= "/etc/rc";
56 char	utmpf[]	= "/etc/utmp";
57 char	wtmpf[]	= "/usr/adm/wtmp";
58 char	ctty[]	= "/dev/console";
59 
60 
61 struct utmp wtmp;
62 struct	tab
63 {
64 	char	line[LINSIZ];
65 	char	comn[CMDSIZ];
66 	int		baud;		/* outgoing baud rate */
67 	int		sock;		/* socket if outgoing connected */
68 	int		fd;		/* file desc if we have, else -1 */
69 	int		errfd;		/* error file desc if we have, else -1 */
70 	char	xflag;
71 	int		gpid;		/* pid of getty or connector */
72 	time_t	gettytime;
73 	int	gettycnt;
74 	struct	tab *next;
75 } *itab;
76 
77 char	tty3[LINSIZ] = { "tty3" } ;
78 char	tty2[LINSIZ] = { "tty2" } ;
79 int	fi;
80 int	mergflag;
81 char	tty[20];
82 jmp_buf	sjbuf, shutpass;
83 time_t	time0;
84 
85 int	reset();
86 int	idle();
87 char	*strcpy(), *strcat();
88 long	lseek();
89 
90 struct conversation  convers[MAXCONNECTS] ;
91 jmp_buf terminate;
92 
93 fd_set rd_fdset, wr_fdset ;
94 int term(), sigpipe();
95 int debug;
96 extern int errno;
97 struct timeval tv_2th = { 0, 500000 } ;
98 main (argc,argv) char *argv[]; {
99 	int sock, msgsock, rval, rv ;
100 	struct sockaddr_un rqsts;
101 	int err;
102 	struct iovec iov[4];
103 	int constatus, rqst, resp;
104 	int optlen ;
105 	char *optp;
106 	struct connectdomain *cdp;
107 	int i,n,afd ;
108 	struct conversation *cd ;
109 	struct tab *p ;
110 
111 	/* initialize */
112 	n = 0;
113 	FD_ZERO(&rd_fdset) ;
114 	FD_ZERO(&wr_fdset) ;
115 	signal (SIGTTOU, SIG_IGN) ;
116 	signal (SIGTTIN, SIG_IGN) ;
117 	signal (SIGINT, term) ;
118 	signal (SIGTERM, term) ;
119 	signal (SIGPIPE, sigpipe) ;
120 	if(setjmp(terminate)) goto on_error;
121 	openlog("connectd", LOG_CONS|LOG_ODELAY, LOG_AUTH);
122 	/* disassociate from tty pgrp */
123 	n = open ("/dev/tty", 2) ;
124 	ioctl(n,TIOCNOTTY, 0) ;
125 	close(n) ;
126 
127 	/* make incoming request socket */
128 	sock = socket (AF_UNIX, SOCK_STREAM, 0) ;
129 	if (sock < 0) {
130 		perror("stream socket") ;
131 		exit(1) ;
132 	}
133 	rqsts.sun_family = AF_UNIX ;
134 	strcpy (rqsts.sun_path,"/dev/connect") ;
135 	if (bind (sock, &rqsts, sizeof (rqsts))) {
136 		perror ("bind /dev/connect") ;
137 		exit (1) ;
138 	}
139 
140 	/* debugging ? */
141 	if ((argc <= 1) || strcmp(argv[1],"-d") != 0) {
142 		if (fork()) exit(0) ;
143 		close (0); close (1); close (2);
144 	} else debug = 1;
145 
146 	/* build tables */
147 	itab = (struct tab *)calloc(1, sizeof(*itab));
148 	SCPYN(itab->line, tty3);
149 	itab->fd = -1;	/* do we have a fd open */
150 	itab->sock = -1; /* does someone else have this fd? */
151 	itab->gpid = 0; /* does getty have this fd? */
152 
153 	itab->next = (struct tab *)calloc(1, sizeof(*itab));
154 	itab->next->fd = -1;	/* do we have a fd open */
155 	itab->next->sock = -1; /* does someone else have this fd? */
156 	itab->next->gpid = 0; /* does getty else have this fd? */
157 	SCPYN(itab->next->line, tty2);
158 	p = itab ;
159 
160 	/* accept connection requests on socket */
161 	listen (sock, 5) ;
162 	FD_SET (sock, &rd_fdset) ;
163 
164 	/* add requests from other lines */
165 	for (ALL) openline(p) ;
166 
167 	/* service requests as they come in */
168 	for (;;) {
169 	    int s, ctrl, n;
170 	    fd_set readable, writeable;
171 
172 	    readable = rd_fdset;
173 	    writeable = wr_fdset;
174 #ifdef notdef
175 for (i=0; i <20 ; i++) {
176 if (FD_ISSET(i,&readable)) fprintf(stderr, "rd%d ", i) ;
177 if (FD_ISSET(i,&writeable)) fprintf(stderr, "wr%d ", i) ;
178 }
179 fprintf(stderr, "?\n") ;
180 #endif
181 	    if ((n = select(21, &readable, &writeable,
182 		(fd_set *)0, &tv_2th )) <= 0) {
183 		    if (n < 0 && errno != EINTR)
184 				if (debug)
185 					perror ("select") ;
186 				else
187 					syslog(LOG_WARNING, "select: %m\n");
188 		    sleep(1);
189 		    continue;
190 	    }
191 
192 		/* got a request, see who it is */
193 fprintf(stderr, "select %d\n", n) ;
194 for (i=0; i <20 ; i++) {
195 if (FD_ISSET(i,&readable))
196 fprintf(stderr, "rdsel%d ", i) ;
197 if (FD_ISSET(i,&writeable))
198 fprintf(stderr, "wrsel%d ", i) ;
199 }
200 fprintf(stderr, "\n") ;
201 
202 		/* have we a new connection request? */
203 	    if (FD_ISSET(sock, &readable)) {
204 		msgsock = accept(sock, 0, 0) ;
205 		if (msgsock == -1) {
206 			perror ("accept") ;
207 			continue ;
208 		}
209 /*allocate a connection */
210 		convers[msgsock].co_sock = msgsock ;
211 		FD_SET (msgsock, &rd_fdset) ;
212 fprintf(stderr, "accept %d\n", msgsock) ;
213 	    }
214 		/* have we a incoming request */
215 for (p = itab; p ; p = p->next)
216 	    if (FD_ISSET(p->fd, &writeable)) {
217 		/* fork off getty after setting up line */
218 printf("do a getty on fd%d\n", p->fd) ;
219 if(p->sock >= 0) {  printf("on a conn?\n") ; continue; }
220 			i = fork ();
221 			if (i < 0) {
222 				perror("cd:fork") ;
223 				exit(1);
224 			}
225 			if (!i) {
226 				dup2(p->fd, 0);
227 				dup2(p->fd, 1);
228 				dup2(p->fd, 2);
229 				i = getdtablesize();
230 				for (n=3 ; n < i ; n++) close (n) ;
231 ioctl(0,TIOCYESTTY, 0) ;
232 			execl("/etc/getty", "getty", "std.1200", "-", 0) ;
233 				perror("exec");
234 				exit(1);
235 			} else {
236 p->gpid = i ;
237 				i = wait(&n) ;
238 printf("cd: waitgetty %d %d\n", i, n) ;
239 p->gpid = 0 ;
240 	closeline (p, 0) ;
241 rmut(p) ;
242 	sleep (1) ;
243 	openline (p) ;
244 			}
245 	    } ;
246 		;
247 		/* have we an existing socket request */
248 	    for (cd = convers; cd - convers < MAXCONNECTS ; cd++) {
249 		cdp = &cd->co_cd ;
250 	    	if (FD_ISSET(cd->co_sock, &readable)) {
251 fprintf(stderr, "recv %d\n", cd->co_sock) ;
252 			/* recieve connnection request message */
253 			rqst = rcvrequest(cd->co_sock, cd, &optp,
254 					&optlen, &afd) ;
255 
256 /*fprintf(stderr, "rqst %d\n", rqst) ;*/
257 			if (rqst < 0) goto end_session ;
258 
259 /*printf("cd:request %d ", rqst) ;*/
260 
261 			/* process request */
262 			switch (rqst) {
263 		case CDNEWREQUEST:
264 				cd->co_rqst = rqst ;
265 /*printf("cd_family %d, cd_address %s, cd_alen %d\n",
266 	cdp->cd_family, cdp->cd_address, cdp->cd_alen) ;*/
267 /*if (optlen)
268 	printf("option:%s\n", optp);*/
269 			if (afd>= 0) {
270 				cd->co_errfd = afd ;
271 			} else cd->co_errfd = -1 ;
272 
273 			cd->co_constatus = -1;
274 for (p = itab; p ; p = p->next)
275 	if (p->gpid == 0 && p->fd >= 0 && p->sock < 0) break;
276 if (!p) exit(0); /* return error can't find a line */
277 fprintf(stderr, "allocate fd%d line %s\n", p->fd, p->line) ;
278 ioctl(p->fd, TIOCSIGNCAR, 0) ;
279 p->errfd = cd->co_errfd;
280 p->sock = cd->co_sock ;
281 			i = fork ();
282 			if (i < 0) {
283 				perror("cd:fork") ;
284 				exit(1);
285 			}
286 			if (!i) {
287 				dup2(p->fd, 0);
288 				dup2(p->fd, 1);
289 				if (cd->co_errfd) dup2(cd->co_errfd,2);
290 				else close(2) ;
291 				i = getdtablesize();
292 				for (n=3 ; n < i ; n++) close (n) ;
293 				execl("con", "con", cdp->cd_address, 0) ;
294 				perror("exec");
295 				exit(1);
296 			} else {
297 				cd->co_pid = i ;
298 				i = wait(&n) ;
299 /*printf("cd: wait %d %d\n", i, n) ;*/
300 				if (n == 0) cd->co_constatus = n;
301 				else	{
302 	fprintf(stderr, "cd: con fails status %d\n", n) ;
303 					cd->co_constatus = (-1 <<16) | n ;
304 					closeline (p, 0) ;
305 				}
306 			}
307 if (p->fd >= 0) {
308 	fprintf(stderr, "cd: sending fd %d \n", p->fd) ;
309 	ioctl(p->fd, TIOCCIGNCAR, 0) ;
310 }
311 optlen = 0;
312 
313 			resp = CDNEWRESPONSE ;
314 		/* send connnection response message */
315 		err = sendrequest(cd->co_sock, resp, cd, optp, optlen, p->fd) ;
316 		if(p->fd >= 0) closeline (p, 1) ;
317 		if (cd->co_constatus) goto end_session ;
318 		break ;
319 
320 	case CDFINISHREQUEST:
321 for (p = itab; p ; p = p->next)
322 	if (p->sock == cd->co_sock) break;
323 if(!p) exit(0); /* return no such connection */
324 		p->fd = afd ;
325 fprintf(stderr, "cd: received fd %d \n", p->fd) ;
326 			cd->co_constatus = -1;
327 ioctl(p->fd, TIOCSIGNCAR, 0) ;
328 			i = fork ();
329 			if (i < 0) {
330 				perror("cd:fork") ;
331 				exit(1);
332 			}
333 			if (!i) {
334 				dup2(p->fd, 0);
335 				dup2(p->fd, 1);
336 				if (cd->co_errfd <= 0) dup2(cd->co_errfd,2);
337 				else close(2) ;
338 				i = getdtablesize();
339 				for (n=3 ; n < i ; n++) close (n) ;
340 				execl("con", "con", "drop" , 0) ;
341 				perror("exec");
342 				exit(1);
343 			} else {
344 				cd->co_pid = i ;
345 				i = wait(&n) ;
346 fprintf(stderr,"cd: wait %d %d\n", i, n) ;
347 				if (n == 0) cd->co_constatus = n;
348 				else	cd->co_constatus = (-1 <<16) | n ;
349 			}
350 fprintf(stderr,"cd: dropped \n") ;
351 
352 		cd->co_rqst = resp = CDFINISHRESPONSE ;
353 		/* send connnection response message */
354 		err = sendrequest(cd->co_sock, resp, cd, 0, 0, 0) ;
355 		goto end_session;
356 		} 	/* end of switch */
357 		} ;  continue; 	/* end of if */
358 
359 	end_session:
360 /*fprintf(stderr, "end_session\n") ;*/
361 		close (cd->co_errfd) ;
362 		FD_CLR (cd->co_sock, &rd_fdset) ;
363 		close (cd->co_sock) ;
364 		cd->co_sock = 0 ;
365 		if (p->fd >= 0) closeline (p, 0) ;
366 		sleep(1) ;
367 		openline (p) ;
368 	} /* end of conv for */
369 	}	/*end of foerever */
370 on_error:
371 	close (sock) ;
372 	unlink ("/dev/connect") ;
373 }
374 
375 term() { struct tab *p;
376 
377 	for (p = itab ; p ; p = p->next)
378 		if (p->gpid) kill (p->gpid, SIGHUP);
379 	longjmp (terminate);
380 }
381 
382 sigpipe() { printf("SIGPIPE\n") ; fflush (stdout) ; longjmp (terminate); }
383 
384 /*
385  * open and prepare line for connectd
386  */
387 openline(p) struct tab *p; {
388 	char ttyn[32]; int n;
389 
390 	/* open the bastard */
391 	strcpy (ttyn, "/dev/");
392 	strcat (ttyn, p->line) ;
393 	p->fd = open (ttyn, O_RDWR|O_NDELAY) ;
394 
395 	/* disassociate from our pgrp */
396 	n = open ("/dev/tty", O_RDWR|O_NDELAY) ;
397 	ioctl (n, TIOCNOTTY, 0) ;
398 	close(n) ;
399 
400 	/* mark 'em to be watched for carrier */
401 	FD_SET (p->fd, &wr_fdset) ;
402 
403 	/* if set in a still open state */
404 	ioctl(p->fd, TIOCCIGNCAR, 0) ;
405 
406 	if (debug) fprintf(stderr, "openline: %s: fd %d\n", p->line,  p->fd) ;
407 }
408 
409 closeline(p, i) struct tab *p; {
410 
411 	if (debug) fprintf(stderr, "closeline: %s: fd %d ", p->line,  p->fd) ;
412 
413 	close (p->fd) ;
414 	FD_CLR (p->fd, &wr_fdset) ;
415 	p->fd = -1 ;
416 	if (i) {
417 		if (debug) fprintf(stderr, "remove from use\n") ;
418 		return ;
419 	}
420 
421 	if (debug) fprintf(stderr, "entirely\n") ;
422 	if (p->gpid) kill (p->gpid, SIGKILL); /* no mercy */
423 	p->gpid = 0 ;
424 
425 	if(p->sock >= 0) close (p->sock);
426 	p->sock = -1 ;
427 }
428 
429 #ifdef notdef
430 struct	sigvec rvec = { reset, sigmask(SIGHUP), 0 };
431 
432 
433 main(argc, argv)
434 	char **argv;
435 {
436 	int howto, oldhowto;
437 
438 	time0 = time(0);
439 	if (argc > 1 && argv[1][0] == '-') {
440 		char *cp;
441 
442 		howto = 0;
443 		cp = &argv[1][1];
444 		while (*cp) switch (*cp++) {
445 		case 'a':
446 			howto |= RB_ASKNAME;
447 			break;
448 		case 's':
449 			howto |= RB_SINGLE;
450 			break;
451 		}
452 	} else {
453 		howto = RB_SINGLE;
454 	}
455 	openlog("connectd", LOG_CONS|LOG_ODELAY, LOG_AUTH);
456 	sigvec(SIGTERM, &rvec, (struct sigvec *)0);
457 	signal(SIGTSTP, idle);
458 	signal(SIGSTOP, SIG_IGN);
459 	signal(SIGTTIN, SIG_IGN);
460 	signal(SIGTTOU, SIG_IGN);
461 	(void) setjmp(sjbuf);
462 	for (EVER) {
463 		oldhowto = howto;
464 		howto = RB_SINGLE;
465 		if (setjmp(shutpass) == 0)
466 			shutdown();
467 		if (oldhowto & RB_SINGLE)
468 			single();
469 		if (runcom(oldhowto) == 0)
470 			continue;
471 		merge();
472 		multiple();
473 	}
474 }
475 
476 int	shutreset();
477 
478 shutdown()
479 {
480 	register i;
481 	register struct tab *p, *p1;
482 
483 	close(creat(utmpf, 0644));
484 	signal(SIGHUP, SIG_IGN);
485 	for (p = itab; p ; ) {
486 		term(p);
487 		p1 = p->next;
488 		free(p);
489 		p = p1;
490 	}
491 	itab = (struct tab *)0;
492 	signal(SIGALRM, shutreset);
493 	(void) kill(-1, SIGTERM);	/* one chance to catch it */
494 	sleep(5);
495 	alarm(30);
496 	for (i = 0; i < 5; i++)
497 		kill(-1, SIGKILL);
498 	while (wait((int *)0) != -1)
499 		;
500 	alarm(0);
501 	shutend();
502 }
503 
504 char shutfailm[] = "WARNING: Something is hung (wont die); ps axl advised\n";
505 
506 shutreset()
507 {
508 	int status;
509 
510 	if (fork() == 0) {
511 		int ct = open(ctty, 1);
512 		write(ct, shutfailm, sizeof (shutfailm));
513 		sleep(5);
514 		exit(1);
515 	}
516 	sleep(5);
517 	shutend();
518 	longjmp(shutpass, 1);
519 }
520 
521 shutend()
522 {
523 	register i, f;
524 
525 	acct(0);
526 	signal(SIGALRM, SIG_DFL);
527 	for (i = 0; i < 10; i++)
528 		close(i);
529 	f = open(wtmpf, O_WRONLY|O_APPEND);
530 	if (f >= 0) {
531 		SCPYN(wtmp.ut_line, "~");
532 		SCPYN(wtmp.ut_name, "shutdown");
533 		SCPYN(wtmp.ut_host, "");
534 		time(&wtmp.ut_time);
535 		write(f, (char *)&wtmp, sizeof(wtmp));
536 		close(f);
537 	}
538 	return (1);
539 }
540 
541 single()
542 {
543 	register pid;
544 	register xpid;
545 	extern	errno;
546 
547 	do {
548 		pid = fork();
549 		if (pid == 0) {
550 			signal(SIGTERM, SIG_DFL);
551 			signal(SIGHUP, SIG_DFL);
552 			signal(SIGALRM, SIG_DFL);
553 			signal(SIGTSTP, SIG_IGN);
554 			(void) open(ctty, O_RDWR);
555 			dup2(0, 1);
556 			dup2(0, 2);
557 			execl(shell, minus, (char *)0);
558 			exit(0);
559 		}
560 		while ((xpid = wait((int *)0)) != pid)
561 			if (xpid == -1 && errno == ECHILD)
562 				break;
563 	} while (xpid == -1);
564 }
565 
566 runcom(oldhowto)
567 	int oldhowto;
568 {
569 	register pid, f;
570 	int status;
571 
572 	pid = fork();
573 	if (pid == 0) {
574 		(void) open("/", O_RDONLY);
575 		dup2(0, 1);
576 		dup2(0, 2);
577 		if (oldhowto & RB_SINGLE)
578 			execl(shell, shell, runc, (char *)0);
579 		else
580 			execl(shell, shell, runc, "autoboot", (char *)0);
581 		exit(1);
582 	}
583 	while (wait(&status) != pid)
584 		;
585 	if (status)
586 		return (0);
587 	f = open(wtmpf, O_WRONLY|O_APPEND);
588 	if (f >= 0) {
589 		SCPYN(wtmp.ut_line, "~");
590 		SCPYN(wtmp.ut_name, "reboot");
591 		SCPYN(wtmp.ut_host, "");
592 		if (time0) {
593 			wtmp.ut_time = time0;
594 			time0 = 0;
595 		} else
596 			time(&wtmp.ut_time);
597 		write(f, (char *)&wtmp, sizeof(wtmp));
598 		close(f);
599 	}
600 	return (1);
601 }
602 
603 struct	sigvec	mvec = { merge, sigmask(SIGTERM), 0 };
604 /*
605  * Multi-user.  Listen for users leaving, SIGHUP's
606  * which indicate ttys has changed, and SIGTERM's which
607  * are used to shutdown the system.
608  */
609 multiple()
610 {
611 	register struct tab *p;
612 	register pid;
613 	int omask;
614 
615 	sigvec(SIGHUP, &mvec, (struct sigvec *)0);
616 	for (EVER) {
617 		pid = wait((int *)0);
618 		if (pid == -1)
619 			return;
620 		omask = sigblock(SIGHUP);
621 		for (ALL) {
622 			/* must restart window system BEFORE emulator */
623 			if (p->wpid == pid || p->wpid == -1)
624 				wstart(p);
625 			if (p->pid == pid || p->pid == -1) {
626 				/* disown the window system */
627 				if (p->wpid)
628 					kill(p->wpid, SIGHUP);
629 				rmut(p);
630 				dfork(p);
631 			}
632 		}
633 		sigsetmask(omask);
634 	}
635 }
636 
637 /*
638  * Merge current contents of ttys file
639  * into in-core table of configured tty lines.
640  * Entered as signal handler for SIGHUP.
641  */
642 #define	FOUND	1
643 #define	CHANGE	2
644 #define WCHANGE 4
645 
646 merge()
647 {
648 	register struct tab *p;
649 	register struct ttyent *t;
650 	register struct tab *p1;
651 
652 	for (ALL)
653 		p->xflag = 0;
654 	setttyent();
655 	while (t = getttyent()) {
656 		/* is it init's responsibility?
657 		if ((t->ty_status & TTY_ON)) continue; */
658 		if ((t->ty_status & TTY_ON) == 0)
659 			continue;
660 		for (ALL) {
661 			if (SCMPN(p->line, t->ty_name))
662 				continue;
663 			p->xflag |= FOUND;
664 			if (SCMPN(p->comn, t->ty_getty)) {
665 				p->xflag |= CHANGE;
666 				SCPYN(p->comn, t->ty_getty);
667 			}
668 			if (SCMPN(p->wcmd, t->ty_window)) {
669 				p->xflag |= WCHANGE|CHANGE;
670 				SCPYN(p->wcmd, t->ty_window);
671 			}
672 			goto contin1;
673 		}
674 
675 		/*
676 		 * Make space for a new one
677 		 */
678 		p1 = (struct tab *)calloc(1, sizeof(*p1));
679 		if (!p1) {
680 			syslog(LOG_ERR, "no space for '%s' !?!", t->ty_name);
681 			goto contin1;
682 		}
683 		/*
684 		 * Put new terminal at the end of the linked list.
685 		 */
686 		if (itab) {
687 			for (p = itab; p->next ; p = p->next)
688 				;
689 			p->next = p1;
690 		} else
691 			itab = p1;
692 
693 		p = p1;
694 		SCPYN(p->line, t->ty_name);
695 		p->xflag |= FOUND|CHANGE;
696 		SCPYN(p->comn, t->ty_getty);
697 		if (strcmp(t->ty_window, "") != 0) {
698 			p->xflag |= WCHANGE;
699 			SCPYN(p->wcmd, t->ty_window);
700 		}
701 	contin1:
702 		;
703 	}
704 	endttyent();
705 	p1 = (struct tab *)0;
706 	for (ALL) {
707 		if ((p->xflag&FOUND) == 0) {
708 			term(p);
709 			wterm(p);
710 			if (p1)
711 				p1->next = p->next;
712 			else
713 				itab = p->next;
714 			free(p);
715 			p = p1 ? p1 : itab;
716 		} else {
717 			/* window system should be started first */
718 			if (p->xflag&WCHANGE) {
719 				wterm(p);
720 				wstart(p);
721 			}
722 			if (p->xflag&CHANGE) {
723 				term(p);
724 				dfork(p);
725 			}
726 		}
727 		p1 = p;
728 	}
729 }
730 
731 term(p)
732 	register struct tab *p;
733 {
734 
735 	if (p->pid != 0) {
736 		rmut(p);
737 		kill(p->pid, SIGKILL);
738 	}
739 	p->pid = 0;
740 	/* send SIGHUP to get rid of connections */
741 	if (p->wpid > 0)
742 		kill(p->wpid, SIGHUP);
743 }
744 
745 #include <sys/ioctl.h>
746 
747 dfork(p)
748 	struct tab *p;
749 {
750 	register pid;
751 	time_t t;
752 	int dowait = 0;
753 
754 	time(&t);
755 	p->gettycnt++;
756 	if ((t - p->gettytime) >= 60) {
757 		p->gettytime = t;
758 		p->gettycnt = 1;
759 	} else if (p->gettycnt >= 5) {
760 		dowait = 1;
761 		p->gettytime = t;
762 		p->gettycnt = 1;
763 	}
764 	pid = fork();
765 	if (pid == 0) {
766 		signal(SIGTERM, SIG_DFL);
767 		signal(SIGHUP, SIG_IGN);
768 		sigsetmask(0);	/* since can be called from masked code */
769 		if (dowait) {
770 			syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line);
771 			closelog();
772 			sleep(30);
773 		}
774 		execit(p->comn, p->line);
775 		exit(0);
776 	}
777 	p->pid = pid;
778 }
779 #endif
780 /*
781  * Remove utmp entry.
782  */
783 rmut(p)
784 	register struct tab *p;
785 {
786 	register f;
787 	int found = 0;
788 	static unsigned utmpsize;
789 	static struct utmp *utmp;
790 	register struct utmp *u;
791 	int nutmp;
792 	struct stat statbf;
793 
794 	f = open(utmpf, O_RDWR);
795 	if (f >= 0) {
796 		fstat(f, &statbf);
797 		if (utmpsize < statbf.st_size) {
798 			utmpsize = statbf.st_size + 10 * sizeof(struct utmp);
799 			if (utmp)
800 				utmp = (struct utmp *)realloc(utmp, utmpsize);
801 			else
802 				utmp = (struct utmp *)malloc(utmpsize);
803 			if (!utmp)
804 				syslog(LOG_ERR, "utmp malloc failed");
805 		}
806 		if (statbf.st_size && utmp) {
807 			nutmp = read(f, utmp, statbf.st_size);
808 			nutmp /= sizeof(struct utmp);
809 			for (u = utmp ; u < &utmp[nutmp] ; u++) {
810 				if (SCMPN(u->ut_line, p->line) ||
811 				    u->ut_name[0]==0)
812 					continue;
813 				lseek(f, ((long)u)-((long)utmp), L_SET);
814 				SCPYN(u->ut_name, "");
815 				SCPYN(u->ut_host, "");
816 				time(&u->ut_time);
817 				write(f, (char *)u, sizeof(*u));
818 				found++;
819 			}
820 		}
821 		close(f);
822 	}
823 	if (found) {
824 		f = open(wtmpf, O_WRONLY|O_APPEND);
825 		if (f >= 0) {
826 			SCPYN(wtmp.ut_line, p->line);
827 			SCPYN(wtmp.ut_name, "");
828 			SCPYN(wtmp.ut_host, "");
829 			time(&wtmp.ut_time);
830 			write(f, (char *)&wtmp, sizeof(wtmp));
831 			close(f);
832 		}
833 		/*
834 		 * After a proper login force reset
835 		 * of error detection code in dfork.
836 		 */
837 		p->gettytime = 0;
838 	}
839 }
840 #ifdef notdef
841 reset()
842 {
843 
844 	longjmp(sjbuf, 1);
845 }
846 
847 jmp_buf	idlebuf;
848 
849 idlehup()
850 {
851 
852 	longjmp(idlebuf, 1);
853 }
854 
855 idle()
856 {
857 	register struct tab *p;
858 	register pid;
859 
860 	signal(SIGHUP, idlehup);
861 	for (EVER) {
862 		if (setjmp(idlebuf))
863 			return;
864 		pid = wait((int *) 0);
865 		if (pid == -1) {
866 			sigpause(0);
867 			continue;
868 		}
869 		for (ALL) {
870 			/* if window system dies, mark it for restart */
871 			if (p->wpid == pid)
872 				p->wpid = -1;
873 			if (p->pid == pid) {
874 				rmut(p);
875 				p->pid = -1;
876 			}
877 		}
878 	}
879 }
880 
881 wterm(p)
882 	register struct tab *p;
883 {
884 	if (p->wpid != 0) {
885 		kill(p->wpid, SIGKILL);
886 	}
887 	p->wpid = 0;
888 }
889 
890 wstart(p)
891 	register struct tab *p;
892 {
893 	register pid;
894 	time_t t;
895 	int dowait = 0;
896 
897 	time(&t);
898 	p->windcnt++;
899 	if ((t - p->windtime) >= 60) {
900 		p->windtime = t;
901 		p->windcnt = 1;
902 	} else if (p->windcnt >= 5) {
903 		dowait = 1;
904 		p->windtime = t;
905 		p->windcnt = 1;
906 	}
907 
908 	pid = fork();
909 
910 	if (pid == 0) {
911 		signal(SIGTERM, SIG_DFL);
912 		signal(SIGHUP,  SIG_IGN);
913 		sigsetmask(0);	/* since can be called from masked code */
914 		if (dowait) {
915 			syslog(LOG_ERR, "'%s %s' failing, sleeping", p->wcmd, p->line);
916 			closelog();
917 			sleep(30);
918 		}
919 		execit(p->wcmd, p->line);
920 		exit(0);
921 	}
922 	p->wpid = pid;
923 }
924 
925 #define NARGS	20	/* must be at least 4 */
926 #define ARGLEN	512	/* total size for all the argument strings */
927 
928 execit(s, arg)
929 	char *s;
930 	char *arg;	/* last argument on line */
931 {
932 	char *argv[NARGS], args[ARGLEN], *envp[1];
933 	register char *sp = s;
934 	register char *ap = args;
935 	register char c;
936 	register int i;
937 
938 	/*
939 	 * First we have to set up the argument vector.
940 	 * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2").
941 	 */
942 	for (i = 1; i < NARGS - 2; i++) {
943 		argv[i] = ap;
944 		for (EVER) {
945 			if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) {
946 				*ap = '\0';
947 				goto done;
948 			}
949 			if (c == ' ') {
950 				*ap++ = '\0';
951 				while (*sp == ' ')
952 					sp++;
953 				if (*sp == '\0')
954 					goto done;
955 				break;
956 			}
957 			*ap++ = c;
958 		}
959 	}
960 done:
961 	argv[0] = argv[1];
962 	argv[1] = "-";
963 	argv[i+1] = arg;
964 	argv[i+2] = 0;
965 	envp[0] = 0;
966 	execve(argv[0], &argv[1], envp);
967 	/* report failure of exec */
968 	syslog(LOG_ERR, "%s: %m", argv[0]);
969 	closelog();
970 	sleep(10);	/* prevent failures from eating machine */
971 }
972 #endif
973