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