112682Ssam #ifndef lint 2*16452Sroot static char *sccsid = "@(#)init.c 4.13 (Berkeley) 05/07/84"; 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> 12*16452Sroot #include <ttyent.h> 131029Sbill 141029Sbill #define LINSIZ sizeof(wtmp.ut_line) 15*16452Sroot #define TTYSIZ 16 161029Sbill #define TABSIZ 100 171029Sbill #define ALL p = &itab[0]; p < &itab[TABSIZ]; p++ 181029Sbill #define EVER ;; 191029Sbill #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 201029Sbill #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 2113021Ssam #define mask(s) (1 << ((s)-1)) 221029Sbill 231029Sbill char shell[] = "/bin/sh"; 241403Sbill char getty[] = "/etc/getty"; 251029Sbill char minus[] = "-"; 261029Sbill char runc[] = "/etc/rc"; 271029Sbill char utmp[] = "/etc/utmp"; 281029Sbill char wtmpf[] = "/usr/adm/wtmp"; 291029Sbill char ctty[] = "/dev/console"; 301029Sbill char dev[] = "/dev/"; 311029Sbill 321029Sbill struct utmp wtmp; 331029Sbill struct tab 341029Sbill { 351029Sbill char line[LINSIZ]; 36*16452Sroot char comn[TTYSIZ]; 371029Sbill char xflag; 381029Sbill int pid; 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 5413021Ssam struct sigvec rvec = { reset, mask(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 8813021Ssam sigvec(SIGTERM, &rvec, (struct sigvec *)0); 892821Swnj signal(SIGTSTP, idle); 901029Sbill signal(SIGSTOP, SIG_IGN); 911029Sbill signal(SIGTTIN, SIG_IGN); 921029Sbill signal(SIGTTOU, SIG_IGN); 9313021Ssam (void) setjmp(sjbuf); 9413021Ssam for (EVER) { 951403Sbill oldhowto = howto; 961403Sbill howto = RB_SINGLE; 971429Sbill if (setjmp(shutpass) == 0) 981429Sbill shutdown(); 991403Sbill if (oldhowto & RB_SINGLE) 1001403Sbill single(); 1011403Sbill if (runcom(oldhowto) == 0) 1021403Sbill continue; 1031029Sbill merge(); 1041029Sbill multiple(); 1051029Sbill } 1061029Sbill } 1071029Sbill 1081429Sbill int shutreset(); 1091429Sbill 1101029Sbill shutdown() 1111029Sbill { 1121029Sbill register i; 1131029Sbill register struct tab *p; 1141029Sbill 1151029Sbill close(creat(utmp, 0644)); 1161029Sbill signal(SIGHUP, SIG_IGN); 11713021Ssam for (ALL) { 1181029Sbill term(p); 1191029Sbill p->line[0] = 0; 1201029Sbill } 1211429Sbill signal(SIGALRM, shutreset); 1221429Sbill alarm(30); 12313021Ssam for (i = 0; i < 5; i++) 1241029Sbill kill(-1, SIGKILL); 12513021Ssam while (wait((int *)0) != -1) 1261029Sbill ; 1271029Sbill alarm(0); 1281429Sbill shutend(); 1291429Sbill } 1301429Sbill 1311429Sbill char shutfailm[] = "WARNING: Something is hung (wont die); ps axl advised\n"; 1321429Sbill 1331429Sbill shutreset() 1341429Sbill { 1351429Sbill int status; 1361429Sbill 1371429Sbill if (fork() == 0) { 1381429Sbill int ct = open(ctty, 1); 1391429Sbill write(ct, shutfailm, sizeof (shutfailm)); 1401429Sbill sleep(5); 1411429Sbill exit(1); 1421429Sbill } 1431429Sbill sleep(5); 1441429Sbill shutend(); 1451429Sbill longjmp(shutpass, 1); 1461429Sbill } 1471429Sbill 1481429Sbill shutend() 1491429Sbill { 1502821Swnj register i, f; 1511429Sbill 1522821Swnj acct(0); 1531029Sbill signal(SIGALRM, SIG_DFL); 15413021Ssam for (i = 0; i < 10; i++) 1551029Sbill close(i); 15613021Ssam f = open(wtmpf, O_WRONLY|O_APPEND); 1572821Swnj if (f >= 0) { 1582821Swnj SCPYN(wtmp.ut_line, "~"); 1592821Swnj SCPYN(wtmp.ut_name, "shutdown"); 16012682Ssam SCPYN(wtmp.ut_host, ""); 1612821Swnj time(&wtmp.ut_time); 1622821Swnj write(f, (char *)&wtmp, sizeof(wtmp)); 1632821Swnj close(f); 1642821Swnj } 16513021Ssam return (1); 1661029Sbill } 1671029Sbill 1681029Sbill single() 1691029Sbill { 1701029Sbill register pid; 1712821Swnj register xpid; 1722821Swnj extern errno; 1731029Sbill 17413021Ssam do { 17513021Ssam pid = fork(); 17613021Ssam if (pid == 0) { 17713021Ssam signal(SIGTERM, SIG_DFL); 17813021Ssam signal(SIGHUP, SIG_DFL); 17913021Ssam signal(SIGALRM, SIG_DFL); 180*16452Sroot signal(SIGTSTP, SIG_IGN); 18113021Ssam (void) open(ctty, O_RDWR); 18213021Ssam dup2(0, 1); 18313021Ssam dup2(0, 2); 18413021Ssam execl(shell, minus, (char *)0); 18513021Ssam exit(0); 18613021Ssam } 18713021Ssam while ((xpid = wait((int *)0)) != pid) 18813021Ssam if (xpid == -1 && errno == ECHILD) 18913021Ssam break; 19013021Ssam } while (xpid == -1); 1911029Sbill } 1921029Sbill 1931403Sbill runcom(oldhowto) 1941403Sbill int oldhowto; 1951029Sbill { 1961029Sbill register pid, f; 1971403Sbill int status; 1981029Sbill 1991029Sbill pid = fork(); 20013021Ssam if (pid == 0) { 20113021Ssam (void) open("/", O_RDONLY); 20213021Ssam dup2(0, 1); 20313021Ssam dup2(0, 2); 2041403Sbill if (oldhowto & RB_SINGLE) 2051403Sbill execl(shell, shell, runc, (char *)0); 2061403Sbill else 2071403Sbill execl(shell, shell, runc, "autoboot", (char *)0); 2081403Sbill exit(1); 2091029Sbill } 21013021Ssam while (wait(&status) != pid) 2111029Sbill ; 21213021Ssam if (status) 21313021Ssam return (0); 21413021Ssam f = open(wtmpf, O_WRONLY|O_APPEND); 2151029Sbill if (f >= 0) { 2161029Sbill SCPYN(wtmp.ut_line, "~"); 2171029Sbill SCPYN(wtmp.ut_name, "reboot"); 21812682Ssam SCPYN(wtmp.ut_host, ""); 2192821Swnj if (time0) { 2202821Swnj wtmp.ut_time = time0; 2212821Swnj time0 = 0; 2222821Swnj } else 2232821Swnj time(&wtmp.ut_time); 2241029Sbill write(f, (char *)&wtmp, sizeof(wtmp)); 2251029Sbill close(f); 2261029Sbill } 22713021Ssam return (1); 2281029Sbill } 2291029Sbill 23013021Ssam struct sigvec mvec = { merge, mask(SIGTERM), 0 }; 23113021Ssam /* 23213021Ssam * Multi-user. Listen for users leaving, SIGHUP's 23313021Ssam * which indicate ttys has changed, and SIGTERM's which 23413021Ssam * are used to shutdown the system. 23513021Ssam */ 2361029Sbill multiple() 2371029Sbill { 2381029Sbill register struct tab *p; 2391029Sbill register pid; 2401029Sbill 24113021Ssam sigvec(SIGHUP, &mvec, (struct sigvec *)0); 24213021Ssam for (EVER) { 2431029Sbill pid = wait((int *)0); 24413021Ssam if (pid == -1) 2451029Sbill return; 24613021Ssam for (ALL) 24713021Ssam if (p->pid == pid || p->pid == -1) { 2481029Sbill rmut(p); 2491029Sbill dfork(p); 2501029Sbill } 2511029Sbill } 2521029Sbill } 2531029Sbill 25413021Ssam /* 25513021Ssam * Merge current contents of ttys file 25613021Ssam * into in-core table of configured tty lines. 25713021Ssam * Entered as signal handler for SIGHUP. 25813021Ssam */ 25913021Ssam #define FOUND 1 26013021Ssam #define CHANGE 2 26113021Ssam 26213021Ssam merge() 26313021Ssam { 26413021Ssam register struct tab *p; 265*16452Sroot register struct ttyent *t; 26613021Ssam 26713021Ssam for (ALL) 26813021Ssam p->xflag = 0; 269*16452Sroot setttyent(); 270*16452Sroot while (t = getttyent()) { 271*16452Sroot if ((t->ty_status & TTY_ON) == 0) 272*16452Sroot continue; 273*16452Sroot strcpy(tty, dev); 274*16452Sroot strcat(tty, t->ty_name); 275*16452Sroot if (access(tty, R_OK|W_OK) < 0) 276*16452Sroot continue; 27713021Ssam for (ALL) { 278*16452Sroot if (SCMPN(p->line, t->ty_name)) 27913021Ssam continue; 28013021Ssam p->xflag |= FOUND; 281*16452Sroot if (SCMPN(p->comn, t->ty_getty)) { 28213021Ssam p->xflag |= CHANGE; 283*16452Sroot SCPYN(p->comn, t->ty_getty); 28413021Ssam } 28513021Ssam goto contin1; 28613021Ssam } 28713021Ssam for (ALL) { 28813021Ssam if (p->line[0] != 0) 28913021Ssam continue; 290*16452Sroot SCPYN(p->line, t->ty_name); 29113021Ssam p->xflag |= FOUND|CHANGE; 292*16452Sroot SCPYN(p->comn, t->ty_getty); 29313021Ssam goto contin1; 29413021Ssam } 29513021Ssam contin1: 29613021Ssam ; 29713021Ssam } 298*16452Sroot endttyent(); 29913021Ssam for (ALL) { 30013021Ssam if ((p->xflag&FOUND) == 0) { 30113021Ssam term(p); 30213021Ssam p->line[0] = 0; 30313021Ssam } 30413021Ssam if (p->xflag&CHANGE) { 30513021Ssam term(p); 30613021Ssam dfork(p); 30713021Ssam } 30813021Ssam } 30913021Ssam } 31013021Ssam 3111029Sbill term(p) 31213021Ssam register struct tab *p; 3131029Sbill { 3141029Sbill 31513021Ssam if (p->pid != 0) { 3161029Sbill rmut(p); 3171029Sbill kill(p->pid, SIGKILL); 3181029Sbill } 3191029Sbill p->pid = 0; 3201029Sbill } 3211029Sbill 3226816Ssam #include <sys/ioctl.h> 3236816Ssam 3241029Sbill dfork(p) 32513021Ssam struct tab *p; 3261029Sbill { 3271029Sbill register pid; 3285971Sroot time_t t; 3295971Sroot int dowait = 0; 3309579Spugs extern char *sys_errlist[]; 3311029Sbill 3325971Sroot time(&t); 3335971Sroot p->gettycnt++; 3345971Sroot if ((t - p->gettytime) >= 60) { 3355971Sroot p->gettytime = t; 3365971Sroot p->gettycnt = 1; 3375971Sroot } else { 3385971Sroot if (p->gettycnt >= 5) { 3395971Sroot dowait = 1; 3405971Sroot p->gettytime = t; 3415971Sroot p->gettycnt = 1; 3425971Sroot } 3435971Sroot } 3441029Sbill pid = fork(); 34513021Ssam if (pid == 0) { 3466816Ssam int oerrno, f; 3476816Ssam extern int errno; 3486816Ssam 3496816Ssam signal(SIGTERM, SIG_DFL); 3506816Ssam signal(SIGHUP, SIG_IGN); 3519579Spugs strcpy(tty, dev); 3529579Spugs strncat(tty, p->line, LINSIZ); 3535971Sroot if (dowait) { 35413021Ssam f = open("/dev/console", O_WRONLY); 3555971Sroot write(f, "init: ", 6); 3565971Sroot write(f, tty, strlen(tty)); 3575971Sroot write(f, ": getty failing, sleeping\n\r", 27); 3585971Sroot close(f); 3595971Sroot sleep(30); 36013021Ssam if ((f = open("/dev/tty", O_RDWR)) >= 0) { 3616816Ssam ioctl(f, TIOCNOTTY, 0); 3626816Ssam close(f); 3636816Ssam } 3645971Sroot } 3651029Sbill chown(tty, 0, 0); 3661029Sbill chmod(tty, 0622); 36713021Ssam if (open(tty, O_RDWR) < 0) { 3683608Swnj int repcnt = 0; 3693608Swnj do { 3706816Ssam oerrno = errno; 3713608Swnj if (repcnt % 10 == 0) { 37213021Ssam f = open("/dev/console", O_WRONLY); 3733608Swnj write(f, "init: ", 6); 3749579Spugs write(f, tty, strlen(tty)); 3759579Spugs write(f, ": ", 2); 3769579Spugs write(f, sys_errlist[oerrno], 3779579Spugs strlen(sys_errlist[oerrno])); 3789579Spugs write(f, "\n", 1); 3793608Swnj close(f); 3806816Ssam if ((f = open("/dev/tty", 2)) >= 0) { 3816816Ssam ioctl(f, TIOCNOTTY, 0); 3826816Ssam close(f); 3836816Ssam } 3843608Swnj } 3853608Swnj repcnt++; 3863608Swnj sleep(60); 38713021Ssam } while (open(tty, O_RDWR) < 0); 3883608Swnj exit(0); /* have wrong control tty, start over */ 3893608Swnj } 3901029Sbill vhangup(); 3911029Sbill signal(SIGHUP, SIG_DFL); 39213021Ssam (void) open(tty, O_RDWR); 3931029Sbill close(0); 3941029Sbill dup(1); 3951029Sbill dup(0); 396*16452Sroot strncpy(tty, p->comn, sizeof(p->comn)); 397*16452Sroot tty[sizeof(p->comn)] = 0; 3981029Sbill execl(getty, minus, tty, (char *)0); 3991029Sbill exit(0); 4001029Sbill } 4011029Sbill p->pid = pid; 4021029Sbill } 4031029Sbill 40413021Ssam /* 40513021Ssam * Remove utmp entry. 40613021Ssam */ 4071029Sbill rmut(p) 40813021Ssam register struct tab *p; 4091029Sbill { 4101029Sbill register f; 4113608Swnj int found = 0; 4121029Sbill 41313021Ssam f = open(utmp, O_RDWR); 41413021Ssam if (f >= 0) { 41513021Ssam while (read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) { 4163608Swnj if (SCMPN(wtmp.ut_line, p->line) || wtmp.ut_name[0]==0) 4171029Sbill continue; 4181029Sbill lseek(f, -(long)sizeof(wtmp), 1); 4191029Sbill SCPYN(wtmp.ut_name, ""); 42012682Ssam SCPYN(wtmp.ut_host, ""); 4211029Sbill time(&wtmp.ut_time); 4221029Sbill write(f, (char *)&wtmp, sizeof(wtmp)); 4233608Swnj found++; 4241029Sbill } 4251029Sbill close(f); 4261029Sbill } 4273608Swnj if (found) { 42813021Ssam f = open(wtmpf, O_WRONLY|O_APPEND); 4293608Swnj if (f >= 0) { 4303608Swnj SCPYN(wtmp.ut_line, p->line); 4313608Swnj SCPYN(wtmp.ut_name, ""); 43212682Ssam SCPYN(wtmp.ut_host, ""); 4333608Swnj time(&wtmp.ut_time); 4343608Swnj write(f, (char *)&wtmp, sizeof(wtmp)); 4353608Swnj close(f); 4363608Swnj } 4371029Sbill } 4381029Sbill } 4391029Sbill 4401029Sbill reset() 4411029Sbill { 44213021Ssam 4431029Sbill longjmp(sjbuf, 1); 4441029Sbill } 4452821Swnj 44613021Ssam jmp_buf idlebuf; 44713021Ssam 44813021Ssam idlehup() 44913021Ssam { 45013021Ssam 45113021Ssam longjmp(idlebuf, 1); 45213021Ssam } 45313021Ssam 4542821Swnj idle() 4552821Swnj { 4562821Swnj register struct tab *p; 4572821Swnj register pid; 4582821Swnj 45913021Ssam signal(SIGHUP, idlehup); 4602821Swnj for (;;) { 46113021Ssam if (setjmp(idlebuf)) 46213021Ssam return; 4632821Swnj pid = wait((int *) 0); 46413021Ssam if (pid == -1) { 46513021Ssam sigpause(0); 46613021Ssam continue; 4672821Swnj } 46813021Ssam for (ALL) 46913021Ssam if (p->pid == pid) { 47013021Ssam rmut(p); 47113021Ssam p->pid = -1; 47213021Ssam } 4732821Swnj } 4742821Swnj } 475