112682Ssam #ifndef lint 2*18542Sralph static char *sccsid = "@(#)init.c 4.15 (Berkeley) 04/01/85"; 312682Ssam #endif 412682Ssam 51029Sbill #include <signal.h> 61029Sbill #include <sys/types.h> 71029Sbill #include <utmp.h> 81029Sbill #include <setjmp.h> 91403Sbill #include <sys/reboot.h> 102821Swnj #include <errno.h> 1113021Ssam #include <sys/file.h> 1216452Sroot #include <ttyent.h> 13*18542Sralph #include <syslog.h> 141029Sbill 151029Sbill #define LINSIZ sizeof(wtmp.ut_line) 16*18542Sralph #define CMDSIZ 70 /* max string length for getty or window command*/ 171029Sbill #define TABSIZ 100 181029Sbill #define ALL p = &itab[0]; p < &itab[TABSIZ]; p++ 191029Sbill #define EVER ;; 201029Sbill #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 211029Sbill #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 221029Sbill 231029Sbill char shell[] = "/bin/sh"; 241029Sbill char minus[] = "-"; 251029Sbill char runc[] = "/etc/rc"; 261029Sbill char utmp[] = "/etc/utmp"; 271029Sbill char wtmpf[] = "/usr/adm/wtmp"; 281029Sbill char ctty[] = "/dev/console"; 291029Sbill 301029Sbill struct utmp wtmp; 311029Sbill struct tab 321029Sbill { 331029Sbill char line[LINSIZ]; 34*18542Sralph char comn[CMDSIZ]; 351029Sbill char xflag; 361029Sbill int pid; 37*18542Sralph int wpid; /* window system pid for SIGHUP */ 38*18542Sralph char wcmd[CMDSIZ]; /* command to start window system process */ 395971Sroot time_t gettytime; 405971Sroot int gettycnt; 411029Sbill } itab[TABSIZ]; 421029Sbill 431029Sbill int fi; 441029Sbill int mergflag; 451029Sbill char tty[20]; 461429Sbill jmp_buf sjbuf, shutpass; 472821Swnj time_t time0; 481029Sbill 491029Sbill int reset(); 502821Swnj int idle(); 511029Sbill char *strcpy(), *strcat(); 521029Sbill long lseek(); 531029Sbill 54*18542Sralph struct sigvec rvec = { reset, sigmask(SIGHUP), 0 }; 5513021Ssam 5613021Ssam #ifdef vax 571029Sbill main() 581029Sbill { 591403Sbill register int r11; /* passed thru from boot */ 6013021Ssam #else 619869Spugs main(argc, argv) 629869Spugs char **argv; 639869Spugs { 6413021Ssam #endif 651403Sbill int howto, oldhowto; 661403Sbill 672821Swnj time0 = time(0); 6813021Ssam #ifdef vax 691403Sbill howto = r11; 7013021Ssam #else 719869Spugs if (argc > 1 && argv[1][0] == '-') { 729869Spugs char *cp; 739869Spugs 749869Spugs howto = 0; 759869Spugs cp = &argv[1][1]; 769869Spugs while (*cp) switch (*cp++) { 779869Spugs case 'a': 789869Spugs howto |= RB_ASKNAME; 799869Spugs break; 809869Spugs case 's': 819869Spugs howto |= RB_SINGLE; 829869Spugs break; 839869Spugs } 849869Spugs } else { 859869Spugs howto = RB_SINGLE; 869869Spugs } 8713021Ssam #endif 88*18542Sralph openlog("init", LOG_CONS|LOG_ODELAY, 0); 8913021Ssam sigvec(SIGTERM, &rvec, (struct sigvec *)0); 902821Swnj signal(SIGTSTP, idle); 911029Sbill signal(SIGSTOP, SIG_IGN); 921029Sbill signal(SIGTTIN, SIG_IGN); 931029Sbill signal(SIGTTOU, SIG_IGN); 9413021Ssam (void) setjmp(sjbuf); 9513021Ssam for (EVER) { 961403Sbill oldhowto = howto; 971403Sbill howto = RB_SINGLE; 981429Sbill if (setjmp(shutpass) == 0) 991429Sbill shutdown(); 1001403Sbill if (oldhowto & RB_SINGLE) 1011403Sbill single(); 1021403Sbill if (runcom(oldhowto) == 0) 1031403Sbill continue; 1041029Sbill merge(); 1051029Sbill multiple(); 1061029Sbill } 1071029Sbill } 1081029Sbill 1091429Sbill int shutreset(); 1101429Sbill 1111029Sbill shutdown() 1121029Sbill { 1131029Sbill register i; 1141029Sbill register struct tab *p; 1151029Sbill 1161029Sbill close(creat(utmp, 0644)); 1171029Sbill signal(SIGHUP, SIG_IGN); 11813021Ssam for (ALL) { 1191029Sbill term(p); 1201029Sbill p->line[0] = 0; 1211029Sbill } 1221429Sbill signal(SIGALRM, shutreset); 1231429Sbill alarm(30); 12413021Ssam for (i = 0; i < 5; i++) 1251029Sbill kill(-1, SIGKILL); 12613021Ssam while (wait((int *)0) != -1) 1271029Sbill ; 1281029Sbill alarm(0); 1291429Sbill shutend(); 1301429Sbill } 1311429Sbill 1321429Sbill char shutfailm[] = "WARNING: Something is hung (wont die); ps axl advised\n"; 1331429Sbill 1341429Sbill shutreset() 1351429Sbill { 1361429Sbill int status; 1371429Sbill 1381429Sbill if (fork() == 0) { 1391429Sbill int ct = open(ctty, 1); 1401429Sbill write(ct, shutfailm, sizeof (shutfailm)); 1411429Sbill sleep(5); 1421429Sbill exit(1); 1431429Sbill } 1441429Sbill sleep(5); 1451429Sbill shutend(); 1461429Sbill longjmp(shutpass, 1); 1471429Sbill } 1481429Sbill 1491429Sbill shutend() 1501429Sbill { 1512821Swnj register i, f; 1521429Sbill 1532821Swnj acct(0); 1541029Sbill signal(SIGALRM, SIG_DFL); 15513021Ssam for (i = 0; i < 10; i++) 1561029Sbill close(i); 15713021Ssam f = open(wtmpf, O_WRONLY|O_APPEND); 1582821Swnj if (f >= 0) { 1592821Swnj SCPYN(wtmp.ut_line, "~"); 1602821Swnj SCPYN(wtmp.ut_name, "shutdown"); 16112682Ssam SCPYN(wtmp.ut_host, ""); 1622821Swnj time(&wtmp.ut_time); 1632821Swnj write(f, (char *)&wtmp, sizeof(wtmp)); 1642821Swnj close(f); 1652821Swnj } 16613021Ssam return (1); 1671029Sbill } 1681029Sbill 1691029Sbill single() 1701029Sbill { 1711029Sbill register pid; 1722821Swnj register xpid; 1732821Swnj extern errno; 1741029Sbill 17513021Ssam do { 17613021Ssam pid = fork(); 17713021Ssam if (pid == 0) { 17813021Ssam signal(SIGTERM, SIG_DFL); 17913021Ssam signal(SIGHUP, SIG_DFL); 18013021Ssam signal(SIGALRM, SIG_DFL); 18116452Sroot signal(SIGTSTP, SIG_IGN); 18213021Ssam (void) open(ctty, O_RDWR); 18313021Ssam dup2(0, 1); 18413021Ssam dup2(0, 2); 18513021Ssam execl(shell, minus, (char *)0); 18613021Ssam exit(0); 18713021Ssam } 18813021Ssam while ((xpid = wait((int *)0)) != pid) 18913021Ssam if (xpid == -1 && errno == ECHILD) 19013021Ssam break; 19113021Ssam } while (xpid == -1); 1921029Sbill } 1931029Sbill 1941403Sbill runcom(oldhowto) 1951403Sbill int oldhowto; 1961029Sbill { 1971029Sbill register pid, f; 1981403Sbill int status; 1991029Sbill 2001029Sbill pid = fork(); 20113021Ssam if (pid == 0) { 20213021Ssam (void) open("/", O_RDONLY); 20313021Ssam dup2(0, 1); 20413021Ssam dup2(0, 2); 2051403Sbill if (oldhowto & RB_SINGLE) 2061403Sbill execl(shell, shell, runc, (char *)0); 2071403Sbill else 2081403Sbill execl(shell, shell, runc, "autoboot", (char *)0); 2091403Sbill exit(1); 2101029Sbill } 21113021Ssam while (wait(&status) != pid) 2121029Sbill ; 21313021Ssam if (status) 21413021Ssam return (0); 21513021Ssam f = open(wtmpf, O_WRONLY|O_APPEND); 2161029Sbill if (f >= 0) { 2171029Sbill SCPYN(wtmp.ut_line, "~"); 2181029Sbill SCPYN(wtmp.ut_name, "reboot"); 21912682Ssam SCPYN(wtmp.ut_host, ""); 2202821Swnj if (time0) { 2212821Swnj wtmp.ut_time = time0; 2222821Swnj time0 = 0; 2232821Swnj } else 2242821Swnj time(&wtmp.ut_time); 2251029Sbill write(f, (char *)&wtmp, sizeof(wtmp)); 2261029Sbill close(f); 2271029Sbill } 22813021Ssam return (1); 2291029Sbill } 2301029Sbill 231*18542Sralph struct sigvec mvec = { merge, sigmask(SIGTERM), 0 }; 23213021Ssam /* 23313021Ssam * Multi-user. Listen for users leaving, SIGHUP's 23413021Ssam * which indicate ttys has changed, and SIGTERM's which 23513021Ssam * are used to shutdown the system. 23613021Ssam */ 2371029Sbill multiple() 2381029Sbill { 2391029Sbill register struct tab *p; 2401029Sbill register pid; 2411029Sbill 24213021Ssam sigvec(SIGHUP, &mvec, (struct sigvec *)0); 24313021Ssam for (EVER) { 2441029Sbill pid = wait((int *)0); 24513021Ssam if (pid == -1) 2461029Sbill return; 247*18542Sralph for (ALL) { 248*18542Sralph /* must restart window system BEFORE emulator */ 249*18542Sralph if (p->wpid == pid || p->wpid == -1) 250*18542Sralph wstart(p); 25113021Ssam if (p->pid == pid || p->pid == -1) { 252*18542Sralph /* disown the window system */ 253*18542Sralph if (p->wpid) 254*18542Sralph kill(p->wpid, SIGHUP); 2551029Sbill rmut(p); 2561029Sbill dfork(p); 2571029Sbill } 258*18542Sralph } 2591029Sbill } 2601029Sbill } 2611029Sbill 26213021Ssam /* 26313021Ssam * Merge current contents of ttys file 26413021Ssam * into in-core table of configured tty lines. 26513021Ssam * Entered as signal handler for SIGHUP. 26613021Ssam */ 26713021Ssam #define FOUND 1 26813021Ssam #define CHANGE 2 269*18542Sralph #define WCHANGE 4 27013021Ssam 27113021Ssam merge() 27213021Ssam { 27313021Ssam register struct tab *p; 27416452Sroot register struct ttyent *t; 27513021Ssam 27613021Ssam for (ALL) 27713021Ssam p->xflag = 0; 27816452Sroot setttyent(); 27916452Sroot while (t = getttyent()) { 28016452Sroot if ((t->ty_status & TTY_ON) == 0) 28116452Sroot continue; 28213021Ssam for (ALL) { 28316452Sroot if (SCMPN(p->line, t->ty_name)) 28413021Ssam continue; 28513021Ssam p->xflag |= FOUND; 28616452Sroot if (SCMPN(p->comn, t->ty_getty)) { 28713021Ssam p->xflag |= CHANGE; 28816452Sroot SCPYN(p->comn, t->ty_getty); 28913021Ssam } 290*18542Sralph if (SCMPN(p->wcmd, t->ty_window)) { 291*18542Sralph p->xflag |= WCHANGE|CHANGE; 292*18542Sralph SCPYN(p->wcmd, t->ty_window); 293*18542Sralph } 29413021Ssam goto contin1; 29513021Ssam } 296*18542Sralph 29713021Ssam for (ALL) { 29813021Ssam if (p->line[0] != 0) 29913021Ssam continue; 30016452Sroot SCPYN(p->line, t->ty_name); 30113021Ssam p->xflag |= FOUND|CHANGE; 30216452Sroot SCPYN(p->comn, t->ty_getty); 303*18542Sralph if (strcmp(t->ty_window, "") != 0) { 304*18542Sralph p->xflag |= WCHANGE; 305*18542Sralph SCPYN(p->wcmd, t->ty_window); 306*18542Sralph } 30713021Ssam goto contin1; 30813021Ssam } 30913021Ssam contin1: 31013021Ssam ; 31113021Ssam } 31216452Sroot endttyent(); 31313021Ssam for (ALL) { 31413021Ssam if ((p->xflag&FOUND) == 0) { 31513021Ssam term(p); 31613021Ssam p->line[0] = 0; 317*18542Sralph wterm(p); 31813021Ssam } 319*18542Sralph /* window system should be started first */ 320*18542Sralph if (p->xflag&WCHANGE) { 321*18542Sralph wterm(p); 322*18542Sralph wstart(p); 323*18542Sralph } 32413021Ssam if (p->xflag&CHANGE) { 32513021Ssam term(p); 32613021Ssam dfork(p); 32713021Ssam } 32813021Ssam } 32913021Ssam } 33013021Ssam 3311029Sbill term(p) 33213021Ssam register struct tab *p; 3331029Sbill { 3341029Sbill 33513021Ssam if (p->pid != 0) { 3361029Sbill rmut(p); 3371029Sbill kill(p->pid, SIGKILL); 3381029Sbill } 3391029Sbill p->pid = 0; 340*18542Sralph /* send SIGHUP to get rid of connections */ 341*18542Sralph if (p->wpid > 0) 342*18542Sralph kill(p->wpid, SIGHUP); 3431029Sbill } 3441029Sbill 3456816Ssam #include <sys/ioctl.h> 3466816Ssam 3471029Sbill dfork(p) 34813021Ssam struct tab *p; 3491029Sbill { 3501029Sbill register pid; 3515971Sroot time_t t; 3525971Sroot int dowait = 0; 3531029Sbill 3545971Sroot time(&t); 3555971Sroot p->gettycnt++; 3565971Sroot if ((t - p->gettytime) >= 60) { 3575971Sroot p->gettytime = t; 3585971Sroot p->gettycnt = 1; 359*18542Sralph } else if (p->gettycnt >= 5) { 360*18542Sralph dowait = 1; 361*18542Sralph p->gettytime = t; 362*18542Sralph p->gettycnt = 1; 3635971Sroot } 3641029Sbill pid = fork(); 36513021Ssam if (pid == 0) { 3666816Ssam signal(SIGTERM, SIG_DFL); 3676816Ssam signal(SIGHUP, SIG_IGN); 3685971Sroot if (dowait) { 369*18542Sralph syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line); 370*18542Sralph closelog(); 3715971Sroot sleep(30); 3725971Sroot } 373*18542Sralph execit(p->comn, p->line); 3741029Sbill exit(0); 3751029Sbill } 3761029Sbill p->pid = pid; 3771029Sbill } 3781029Sbill 37913021Ssam /* 38013021Ssam * Remove utmp entry. 38113021Ssam */ 3821029Sbill rmut(p) 38313021Ssam register struct tab *p; 3841029Sbill { 3851029Sbill register f; 3863608Swnj int found = 0; 3871029Sbill 38813021Ssam f = open(utmp, O_RDWR); 38913021Ssam if (f >= 0) { 39013021Ssam while (read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) { 3913608Swnj if (SCMPN(wtmp.ut_line, p->line) || wtmp.ut_name[0]==0) 3921029Sbill continue; 3931029Sbill lseek(f, -(long)sizeof(wtmp), 1); 3941029Sbill SCPYN(wtmp.ut_name, ""); 39512682Ssam SCPYN(wtmp.ut_host, ""); 3961029Sbill time(&wtmp.ut_time); 3971029Sbill write(f, (char *)&wtmp, sizeof(wtmp)); 3983608Swnj found++; 3991029Sbill } 4001029Sbill close(f); 4011029Sbill } 4023608Swnj if (found) { 40313021Ssam f = open(wtmpf, O_WRONLY|O_APPEND); 4043608Swnj if (f >= 0) { 4053608Swnj SCPYN(wtmp.ut_line, p->line); 4063608Swnj SCPYN(wtmp.ut_name, ""); 40712682Ssam SCPYN(wtmp.ut_host, ""); 4083608Swnj time(&wtmp.ut_time); 4093608Swnj write(f, (char *)&wtmp, sizeof(wtmp)); 4103608Swnj close(f); 4113608Swnj } 41217582Ssam /* 41317582Ssam * After a proper login force reset 41417582Ssam * of error detection code in dfork. 41517582Ssam */ 41617582Ssam p->gettytime = 0; 4171029Sbill } 4181029Sbill } 4191029Sbill 4201029Sbill reset() 4211029Sbill { 42213021Ssam 4231029Sbill longjmp(sjbuf, 1); 4241029Sbill } 4252821Swnj 42613021Ssam jmp_buf idlebuf; 42713021Ssam 42813021Ssam idlehup() 42913021Ssam { 43013021Ssam 43113021Ssam longjmp(idlebuf, 1); 43213021Ssam } 43313021Ssam 4342821Swnj idle() 4352821Swnj { 4362821Swnj register struct tab *p; 4372821Swnj register pid; 4382821Swnj 43913021Ssam signal(SIGHUP, idlehup); 440*18542Sralph for (EVER) { 44113021Ssam if (setjmp(idlebuf)) 44213021Ssam return; 4432821Swnj pid = wait((int *) 0); 44413021Ssam if (pid == -1) { 44513021Ssam sigpause(0); 44613021Ssam continue; 4472821Swnj } 448*18542Sralph for (ALL) { 449*18542Sralph /* if window system dies, mark it for restart */ 450*18542Sralph if (p->wpid == pid) 451*18542Sralph p->wpid = -1; 45213021Ssam if (p->pid == pid) { 45313021Ssam rmut(p); 45413021Ssam p->pid = -1; 45513021Ssam } 456*18542Sralph } 4572821Swnj } 4582821Swnj } 459*18542Sralph 460*18542Sralph wterm(p) 461*18542Sralph register struct tab *p; 462*18542Sralph { 463*18542Sralph if (p->wpid != 0) { 464*18542Sralph kill(p->wpid, SIGKILL); 465*18542Sralph } 466*18542Sralph p->wpid = 0; 467*18542Sralph } 468*18542Sralph 469*18542Sralph wstart(p) 470*18542Sralph register struct tab *p; 471*18542Sralph { 472*18542Sralph int npid = fork(); 473*18542Sralph 474*18542Sralph if (npid == 0) { 475*18542Sralph /* 476*18542Sralph signal(SIGTERM, SIG_DFL); 477*18542Sralph signal(SIGHUP, SIG_DFL); 478*18542Sralph signal(SIGALRM, SIG_DFL); 479*18542Sralph signal(SIGTSTP, SIG_IGN); 480*18542Sralph */ 481*18542Sralph execit(p->wcmd, p->line); 482*18542Sralph exit(0); 483*18542Sralph } 484*18542Sralph p->wpid = npid; 485*18542Sralph } 486*18542Sralph 487*18542Sralph #define NARGS 20 /* must be at lease 4 */ 488*18542Sralph #define ARGLEN 512 /* total size for all the argument strings */ 489*18542Sralph 490*18542Sralph execit(s, arg) 491*18542Sralph char *s; 492*18542Sralph char *arg; /* last argument on line */ 493*18542Sralph { 494*18542Sralph char *argv[NARGS], args[ARGLEN], *envp[1]; 495*18542Sralph register char *sp = s; 496*18542Sralph register char *ap = args; 497*18542Sralph register char c; 498*18542Sralph register int i; 499*18542Sralph 500*18542Sralph /* 501*18542Sralph * First we have to set up the argument vector. 502*18542Sralph * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2"). 503*18542Sralph */ 504*18542Sralph for (i = 1; i < NARGS - 2; i++) { 505*18542Sralph argv[i] = ap; 506*18542Sralph for (EVER) { 507*18542Sralph if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) { 508*18542Sralph *ap = '\0'; 509*18542Sralph goto done; 510*18542Sralph } 511*18542Sralph if (c == ' ') { 512*18542Sralph *ap++ = '\0'; 513*18542Sralph while (*sp == ' ') 514*18542Sralph sp++; 515*18542Sralph if (*sp == '\0') 516*18542Sralph goto done; 517*18542Sralph break; 518*18542Sralph } 519*18542Sralph *ap++ = c; 520*18542Sralph } 521*18542Sralph } 522*18542Sralph done: 523*18542Sralph argv[0] = argv[1]; 524*18542Sralph argv[1] = "-"; 525*18542Sralph argv[i+1] = arg; 526*18542Sralph argv[i+2] = 0; 527*18542Sralph envp[0] = 0; 528*18542Sralph execve(argv[0], &argv[1], envp); 529*18542Sralph /* report failure of exec */ 530*18542Sralph syslog(LOG_ERR, "%s: %m", argv[0]); 531*18542Sralph closelog(); 532*18542Sralph sleep(10); /* prevent failures from eating machine */ 533*18542Sralph } 534