1: /* 2: * Copyright (c) 1980,1986 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #ifndef lint 8: static char sccsid[] = "@(#)init.c 5.6 (Berkeley) 5/26/86"; 9: #endif not lint 10: 11: #include <signal.h> 12: #include <sys/types.h> 13: #include <utmp.h> 14: #include <setjmp.h> 15: #include <sys/reboot.h> 16: #include <errno.h> 17: #include <sys/file.h> 18: #include <ttyent.h> 19: #include <sys/syslog.h> 20: #include <sys/stat.h> 21: 22: #define LINSIZ sizeof(wtmp.ut_line) 23: #define CMDSIZ 200 /* max string length for getty or window command*/ 24: #define ALL p = itab; p ; p = p->next 25: #define EVER ;; 26: #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 27: #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 28: 29: char shell[] = "/bin/sh"; 30: char minus[] = "-"; 31: char runc[] = "/etc/rc"; 32: char utmpf[] = "/etc/utmp"; 33: char wtmpf[] = "/usr/adm/wtmp"; 34: char ctty[] = "/dev/console"; 35: 36: struct utmp wtmp; 37: struct tab 38: { 39: char line[LINSIZ]; 40: char comn[CMDSIZ]; 41: char xflag; 42: int pid; 43: int wpid; /* window system pid for SIGHUP */ 44: char wcmd[CMDSIZ]; /* command to start window system process */ 45: time_t gettytime; 46: int gettycnt; 47: time_t windtime; 48: int windcnt; 49: struct tab *next; 50: } *itab; 51: 52: int fi; 53: int mergflag; 54: char tty[20]; 55: jmp_buf sjbuf, shutpass; 56: time_t time0; 57: 58: int reset(); 59: int idle(); 60: char *strcpy(), *strcat(); 61: long lseek(); 62: 63: struct sigvec rvec = { reset, sigmask(SIGHUP), 0 }; 64: 65: 66: #ifdef vax 67: main() 68: { 69: register int r11; /* passed thru from boot */ 70: #else 71: main(argc, argv) 72: char **argv; 73: { 74: #endif 75: int howto, oldhowto; 76: 77: time0 = time(0); 78: #ifdef vax 79: howto = r11; 80: #else 81: if (argc > 1 && argv[1][0] == '-') { 82: char *cp; 83: 84: howto = 0; 85: cp = &argv[1][1]; 86: while (*cp) switch (*cp++) { 87: case 'a': 88: howto |= RB_ASKNAME; 89: break; 90: case 's': 91: howto |= RB_SINGLE; 92: break; 93: } 94: } else { 95: howto = RB_SINGLE; 96: } 97: #endif 98: openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH); 99: sigvec(SIGTERM, &rvec, (struct sigvec *)0); 100: signal(SIGTSTP, idle); 101: signal(SIGSTOP, SIG_IGN); 102: signal(SIGTTIN, SIG_IGN); 103: signal(SIGTTOU, SIG_IGN); 104: (void) setjmp(sjbuf); 105: for (EVER) { 106: oldhowto = howto; 107: howto = RB_SINGLE; 108: if (setjmp(shutpass) == 0) 109: shutdown(); 110: if (oldhowto & RB_SINGLE) 111: single(); 112: if (runcom(oldhowto) == 0) 113: continue; 114: merge(); 115: multiple(); 116: } 117: } 118: 119: int shutreset(); 120: 121: shutdown() 122: { 123: register i; 124: register struct tab *p, *p1; 125: 126: close(creat(utmpf, 0644)); 127: signal(SIGHUP, SIG_IGN); 128: for (p = itab; p ; ) { 129: term(p); 130: p1 = p->next; 131: free(p); 132: p = p1; 133: } 134: itab = (struct tab *)0; 135: signal(SIGALRM, shutreset); 136: (void) kill(-1, SIGTERM); /* one chance to catch it */ 137: sleep(5); 138: alarm(30); 139: for (i = 0; i < 5; i++) 140: kill(-1, SIGKILL); 141: while (wait((int *)0) != -1) 142: ; 143: alarm(0); 144: shutend(); 145: } 146: 147: char shutfailm[] = "WARNING: Something is hung (wont die); ps axl advised\n"; 148: 149: shutreset() 150: { 151: int status; 152: 153: if (fork() == 0) { 154: int ct = open(ctty, 1); 155: write(ct, shutfailm, sizeof (shutfailm)); 156: sleep(5); 157: exit(1); 158: } 159: sleep(5); 160: shutend(); 161: longjmp(shutpass, 1); 162: } 163: 164: shutend() 165: { 166: register i, f; 167: 168: acct(0); 169: signal(SIGALRM, SIG_DFL); 170: for (i = 0; i < 10; i++) 171: close(i); 172: f = open(wtmpf, O_WRONLY|O_APPEND); 173: if (f >= 0) { 174: SCPYN(wtmp.ut_line, "~"); 175: SCPYN(wtmp.ut_name, "shutdown"); 176: SCPYN(wtmp.ut_host, ""); 177: time(&wtmp.ut_time); 178: write(f, (char *)&wtmp, sizeof(wtmp)); 179: close(f); 180: } 181: return (1); 182: } 183: 184: single() 185: { 186: register pid; 187: register xpid; 188: extern errno; 189: 190: do { 191: pid = fork(); 192: if (pid == 0) { 193: signal(SIGTERM, SIG_DFL); 194: signal(SIGHUP, SIG_DFL); 195: signal(SIGALRM, SIG_DFL); 196: signal(SIGTSTP, SIG_IGN); 197: (void) open(ctty, O_RDWR); 198: dup2(0, 1); 199: dup2(0, 2); 200: execl(shell, minus, (char *)0); 201: exit(0); 202: } 203: while ((xpid = wait((int *)0)) != pid) 204: if (xpid == -1 && errno == ECHILD) 205: break; 206: } while (xpid == -1); 207: } 208: 209: runcom(oldhowto) 210: int oldhowto; 211: { 212: register pid, f; 213: int status; 214: 215: pid = fork(); 216: if (pid == 0) { 217: (void) open("/", O_RDONLY); 218: dup2(0, 1); 219: dup2(0, 2); 220: if (oldhowto & RB_SINGLE) 221: execl(shell, shell, runc, (char *)0); 222: else 223: execl(shell, shell, runc, "autoboot", (char *)0); 224: exit(1); 225: } 226: while (wait(&status) != pid) 227: ; 228: if (status) 229: return (0); 230: f = open(wtmpf, O_WRONLY|O_APPEND); 231: if (f >= 0) { 232: SCPYN(wtmp.ut_line, "~"); 233: SCPYN(wtmp.ut_name, "reboot"); 234: SCPYN(wtmp.ut_host, ""); 235: if (time0) { 236: wtmp.ut_time = time0; 237: time0 = 0; 238: } else 239: time(&wtmp.ut_time); 240: write(f, (char *)&wtmp, sizeof(wtmp)); 241: close(f); 242: } 243: return (1); 244: } 245: 246: struct sigvec mvec = { merge, sigmask(SIGTERM), 0 }; 247: /* 248: * Multi-user. Listen for users leaving, SIGHUP's 249: * which indicate ttys has changed, and SIGTERM's which 250: * are used to shutdown the system. 251: */ 252: multiple() 253: { 254: register struct tab *p; 255: register pid; 256: int omask; 257: 258: sigvec(SIGHUP, &mvec, (struct sigvec *)0); 259: for (EVER) { 260: pid = wait((int *)0); 261: if (pid == -1) 262: return; 263: omask = sigblock(SIGHUP); 264: for (ALL) { 265: /* must restart window system BEFORE emulator */ 266: if (p->wpid == pid || p->wpid == -1) 267: wstart(p); 268: if (p->pid == pid || p->pid == -1) { 269: /* disown the window system */ 270: if (p->wpid) 271: kill(p->wpid, SIGHUP); 272: rmut(p); 273: dfork(p); 274: } 275: } 276: sigsetmask(omask); 277: } 278: } 279: 280: /* 281: * Merge current contents of ttys file 282: * into in-core table of configured tty lines. 283: * Entered as signal handler for SIGHUP. 284: */ 285: #define FOUND 1 286: #define CHANGE 2 287: #define WCHANGE 4 288: 289: merge() 290: { 291: register struct tab *p; 292: register struct ttyent *t; 293: register struct tab *p1; 294: 295: for (ALL) 296: p->xflag = 0; 297: setttyent(); 298: while (t = getttyent()) { 299: if ((t->ty_status & TTY_ON) == 0) 300: continue; 301: for (ALL) { 302: if (SCMPN(p->line, t->ty_name)) 303: continue; 304: p->xflag |= FOUND; 305: if (SCMPN(p->comn, t->ty_getty)) { 306: p->xflag |= CHANGE; 307: SCPYN(p->comn, t->ty_getty); 308: } 309: if (SCMPN(p->wcmd, t->ty_window)) { 310: p->xflag |= WCHANGE|CHANGE; 311: SCPYN(p->wcmd, t->ty_window); 312: } 313: goto contin1; 314: } 315: 316: /* 317: * Make space for a new one 318: */ 319: p1 = (struct tab *)calloc(1, sizeof(*p1)); 320: if (!p1) { 321: syslog(LOG_ERR, "no space for '%s' !?!", t->ty_name); 322: goto contin1; 323: } 324: /* 325: * Put new terminal at the end of the linked list. 326: */ 327: if (itab) { 328: for (p = itab; p->next ; p = p->next) 329: ; 330: p->next = p1; 331: } else 332: itab = p1; 333: 334: p = p1; 335: SCPYN(p->line, t->ty_name); 336: p->xflag |= FOUND|CHANGE; 337: SCPYN(p->comn, t->ty_getty); 338: if (strcmp(t->ty_window, "") != 0) { 339: p->xflag |= WCHANGE; 340: SCPYN(p->wcmd, t->ty_window); 341: } 342: contin1: 343: ; 344: } 345: endttyent(); 346: p1 = (struct tab *)0; 347: for (ALL) { 348: if ((p->xflag&FOUND) == 0) { 349: term(p); 350: wterm(p); 351: if (p1) 352: p1->next = p->next; 353: else 354: itab = p->next; 355: free(p); 356: p = p1 ? p1 : itab; 357: } else { 358: /* window system should be started first */ 359: if (p->xflag&WCHANGE) { 360: wterm(p); 361: wstart(p); 362: } 363: if (p->xflag&CHANGE) { 364: term(p); 365: dfork(p); 366: } 367: } 368: p1 = p; 369: } 370: } 371: 372: term(p) 373: register struct tab *p; 374: { 375: 376: if (p->pid != 0) { 377: rmut(p); 378: kill(p->pid, SIGKILL); 379: } 380: p->pid = 0; 381: /* send SIGHUP to get rid of connections */ 382: if (p->wpid > 0) 383: kill(p->wpid, SIGHUP); 384: } 385: 386: #include <sys/ioctl.h> 387: 388: dfork(p) 389: struct tab *p; 390: { 391: register pid; 392: time_t t; 393: int dowait = 0; 394: 395: time(&t); 396: p->gettycnt++; 397: if ((t - p->gettytime) >= 60) { 398: p->gettytime = t; 399: p->gettycnt = 1; 400: } else if (p->gettycnt >= 5) { 401: dowait = 1; 402: p->gettytime = t; 403: p->gettycnt = 1; 404: } 405: pid = fork(); 406: if (pid == 0) { 407: signal(SIGTERM, SIG_DFL); 408: signal(SIGHUP, SIG_IGN); 409: sigsetmask(0); /* since can be called from masked code */ 410: if (dowait) { 411: syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line); 412: closelog(); 413: sleep(30); 414: } 415: execit(p->comn, p->line); 416: exit(0); 417: } 418: p->pid = pid; 419: } 420: 421: /* 422: * Remove utmp entry. 423: */ 424: rmut(p) 425: register struct tab *p; 426: { 427: register f; 428: int found = 0; 429: static unsigned utmpsize; 430: static struct utmp *utmp; 431: register struct utmp *u; 432: int nutmp; 433: struct stat statbf; 434: 435: f = open(utmpf, O_RDWR); 436: if (f >= 0) { 437: fstat(f, &statbf); 438: if (utmpsize < statbf.st_size) { 439: utmpsize = statbf.st_size + 10 * sizeof(struct utmp); 440: if (utmp) 441: utmp = (struct utmp *)realloc(utmp, utmpsize); 442: else 443: utmp = (struct utmp *)malloc(utmpsize); 444: if (!utmp) 445: syslog(LOG_ERR, "utmp malloc failed"); 446: } 447: if (statbf.st_size && utmp) { 448: nutmp = read(f, utmp, statbf.st_size); 449: nutmp /= sizeof(struct utmp); 450: for (u = utmp ; u < &utmp[nutmp] ; u++) { 451: if (SCMPN(u->ut_line, p->line) || 452: u->ut_name[0]==0) 453: continue; 454: lseek(f, ((long)u)-((long)utmp), L_SET); 455: SCPYN(u->ut_name, ""); 456: SCPYN(u->ut_host, ""); 457: time(&u->ut_time); 458: write(f, (char *)u, sizeof(*u)); 459: found++; 460: } 461: } 462: close(f); 463: } 464: if (found) { 465: f = open(wtmpf, O_WRONLY|O_APPEND); 466: if (f >= 0) { 467: SCPYN(wtmp.ut_line, p->line); 468: SCPYN(wtmp.ut_name, ""); 469: SCPYN(wtmp.ut_host, ""); 470: time(&wtmp.ut_time); 471: write(f, (char *)&wtmp, sizeof(wtmp)); 472: close(f); 473: } 474: /* 475: * After a proper login force reset 476: * of error detection code in dfork. 477: */ 478: p->gettytime = 0; 479: p->windtime = 0; 480: } 481: } 482: 483: reset() 484: { 485: 486: longjmp(sjbuf, 1); 487: } 488: 489: jmp_buf idlebuf; 490: 491: idlehup() 492: { 493: 494: longjmp(idlebuf, 1); 495: } 496: 497: idle() 498: { 499: register struct tab *p; 500: register pid; 501: 502: signal(SIGHUP, idlehup); 503: for (EVER) { 504: if (setjmp(idlebuf)) 505: return; 506: pid = wait((int *) 0); 507: if (pid == -1) { 508: sigpause(0); 509: continue; 510: } 511: for (ALL) { 512: /* if window system dies, mark it for restart */ 513: if (p->wpid == pid) 514: p->wpid = -1; 515: if (p->pid == pid) { 516: rmut(p); 517: p->pid = -1; 518: } 519: } 520: } 521: } 522: 523: wterm(p) 524: register struct tab *p; 525: { 526: if (p->wpid != 0) { 527: kill(p->wpid, SIGKILL); 528: } 529: p->wpid = 0; 530: } 531: 532: wstart(p) 533: register struct tab *p; 534: { 535: register pid; 536: time_t t; 537: int dowait = 0; 538: 539: time(&t); 540: p->windcnt++; 541: if ((t - p->windtime) >= 60) { 542: p->windtime = t; 543: p->windcnt = 1; 544: } else if (p->windcnt >= 5) { 545: dowait = 1; 546: p->windtime = t; 547: p->windcnt = 1; 548: } 549: 550: pid = fork(); 551: 552: if (pid == 0) { 553: signal(SIGTERM, SIG_DFL); 554: signal(SIGHUP, SIG_IGN); 555: sigsetmask(0); /* since can be called from masked code */ 556: if (dowait) { 557: syslog(LOG_ERR, "'%s %s' failing, sleeping", p->wcmd, p->line); 558: closelog(); 559: sleep(30); 560: } 561: execit(p->wcmd, p->line); 562: exit(0); 563: } 564: p->wpid = pid; 565: } 566: 567: #define NARGS 20 /* must be at least 4 */ 568: #define ARGLEN 512 /* total size for all the argument strings */ 569: 570: execit(s, arg) 571: char *s; 572: char *arg; /* last argument on line */ 573: { 574: char *argv[NARGS], args[ARGLEN], *envp[1]; 575: register char *sp = s; 576: register char *ap = args; 577: register char c; 578: register int i; 579: 580: /* 581: * First we have to set up the argument vector. 582: * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2"). 583: */ 584: for (i = 1; i < NARGS - 2; i++) { 585: argv[i] = ap; 586: for (EVER) { 587: if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) { 588: *ap = '\0'; 589: goto done; 590: } 591: if (c == ' ') { 592: *ap++ = '\0'; 593: while (*sp == ' ') 594: sp++; 595: if (*sp == '\0') 596: goto done; 597: break; 598: } 599: *ap++ = c; 600: } 601: } 602: done: 603: argv[0] = argv[1]; 604: argv[1] = "-"; 605: argv[i+1] = arg; 606: argv[i+2] = 0; 607: envp[0] = 0; 608: execve(argv[0], &argv[1], envp); 609: /* report failure of exec */ 610: syslog(LOG_ERR, "%s: %m", argv[0]); 611: closelog(); 612: sleep(10); /* prevent failures from eating machine */ 613: }