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