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 } ;
main(argc,argv)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
term()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
sigpipe()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
main(argc,argv)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
shutdown()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
shutreset()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
shutend()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
single()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
runcom(oldhowto)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 */
multiple()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
merge()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
term(p)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 */
rmut(p)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
reset()831 reset()
832 {
833
834 longjmp(sjbuf, 1);
835 }
836
837 jmp_buf idlebuf;
838
idlehup()839 idlehup()
840 {
841
842 longjmp(idlebuf, 1);
843 }
844
idle()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
wterm(p)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
wstart(p)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
execit(s,arg)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