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