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