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