112682Ssam #ifndef lint 2*17582Ssam static char *sccsid = "@(#)init.c 4.14 (Berkeley) 12/23/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> 1216452Sroot #include <ttyent.h> 131029Sbill 141029Sbill #define LINSIZ sizeof(wtmp.ut_line) 1516452Sroot #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]; 3616452Sroot 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); 18016452Sroot 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; 26516452Sroot register struct ttyent *t; 26613021Ssam 26713021Ssam for (ALL) 26813021Ssam p->xflag = 0; 26916452Sroot setttyent(); 27016452Sroot while (t = getttyent()) { 27116452Sroot if ((t->ty_status & TTY_ON) == 0) 27216452Sroot continue; 27316452Sroot strcpy(tty, dev); 27416452Sroot strcat(tty, t->ty_name); 27516452Sroot if (access(tty, R_OK|W_OK) < 0) 27616452Sroot continue; 27713021Ssam for (ALL) { 27816452Sroot if (SCMPN(p->line, t->ty_name)) 27913021Ssam continue; 28013021Ssam p->xflag |= FOUND; 28116452Sroot if (SCMPN(p->comn, t->ty_getty)) { 28213021Ssam p->xflag |= CHANGE; 28316452Sroot SCPYN(p->comn, t->ty_getty); 28413021Ssam } 28513021Ssam goto contin1; 28613021Ssam } 28713021Ssam for (ALL) { 28813021Ssam if (p->line[0] != 0) 28913021Ssam continue; 29016452Sroot SCPYN(p->line, t->ty_name); 29113021Ssam p->xflag |= FOUND|CHANGE; 29216452Sroot SCPYN(p->comn, t->ty_getty); 29313021Ssam goto contin1; 29413021Ssam } 29513021Ssam contin1: 29613021Ssam ; 29713021Ssam } 29816452Sroot 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); 367*17582Ssam /* 368*17582Ssam * Give port selectors an opportunity 369*17582Ssam * to see DTR transition. 370*17582Ssam */ 371*17582Ssam sleep(1); 37213021Ssam if (open(tty, O_RDWR) < 0) { 3733608Swnj int repcnt = 0; 3743608Swnj do { 3756816Ssam oerrno = errno; 3763608Swnj if (repcnt % 10 == 0) { 37713021Ssam f = open("/dev/console", O_WRONLY); 3783608Swnj write(f, "init: ", 6); 3799579Spugs write(f, tty, strlen(tty)); 3809579Spugs write(f, ": ", 2); 3819579Spugs write(f, sys_errlist[oerrno], 3829579Spugs strlen(sys_errlist[oerrno])); 3839579Spugs write(f, "\n", 1); 3843608Swnj close(f); 3856816Ssam if ((f = open("/dev/tty", 2)) >= 0) { 3866816Ssam ioctl(f, TIOCNOTTY, 0); 3876816Ssam close(f); 3886816Ssam } 3893608Swnj } 3903608Swnj repcnt++; 3913608Swnj sleep(60); 39213021Ssam } while (open(tty, O_RDWR) < 0); 3933608Swnj exit(0); /* have wrong control tty, start over */ 3943608Swnj } 3951029Sbill vhangup(); 3961029Sbill signal(SIGHUP, SIG_DFL); 39713021Ssam (void) open(tty, O_RDWR); 3981029Sbill close(0); 3991029Sbill dup(1); 4001029Sbill dup(0); 40116452Sroot strncpy(tty, p->comn, sizeof(p->comn)); 40216452Sroot tty[sizeof(p->comn)] = 0; 4031029Sbill execl(getty, minus, tty, (char *)0); 4041029Sbill exit(0); 4051029Sbill } 4061029Sbill p->pid = pid; 4071029Sbill } 4081029Sbill 40913021Ssam /* 41013021Ssam * Remove utmp entry. 41113021Ssam */ 4121029Sbill rmut(p) 41313021Ssam register struct tab *p; 4141029Sbill { 4151029Sbill register f; 4163608Swnj int found = 0; 4171029Sbill 41813021Ssam f = open(utmp, O_RDWR); 41913021Ssam if (f >= 0) { 42013021Ssam while (read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) { 4213608Swnj if (SCMPN(wtmp.ut_line, p->line) || wtmp.ut_name[0]==0) 4221029Sbill continue; 4231029Sbill lseek(f, -(long)sizeof(wtmp), 1); 4241029Sbill SCPYN(wtmp.ut_name, ""); 42512682Ssam SCPYN(wtmp.ut_host, ""); 4261029Sbill time(&wtmp.ut_time); 4271029Sbill write(f, (char *)&wtmp, sizeof(wtmp)); 4283608Swnj found++; 4291029Sbill } 4301029Sbill close(f); 4311029Sbill } 4323608Swnj if (found) { 43313021Ssam f = open(wtmpf, O_WRONLY|O_APPEND); 4343608Swnj if (f >= 0) { 4353608Swnj SCPYN(wtmp.ut_line, p->line); 4363608Swnj SCPYN(wtmp.ut_name, ""); 43712682Ssam SCPYN(wtmp.ut_host, ""); 4383608Swnj time(&wtmp.ut_time); 4393608Swnj write(f, (char *)&wtmp, sizeof(wtmp)); 4403608Swnj close(f); 4413608Swnj } 442*17582Ssam /* 443*17582Ssam * After a proper login force reset 444*17582Ssam * of error detection code in dfork. 445*17582Ssam */ 446*17582Ssam p->gettytime = 0; 4471029Sbill } 4481029Sbill } 4491029Sbill 4501029Sbill reset() 4511029Sbill { 45213021Ssam 4531029Sbill longjmp(sjbuf, 1); 4541029Sbill } 4552821Swnj 45613021Ssam jmp_buf idlebuf; 45713021Ssam 45813021Ssam idlehup() 45913021Ssam { 46013021Ssam 46113021Ssam longjmp(idlebuf, 1); 46213021Ssam } 46313021Ssam 4642821Swnj idle() 4652821Swnj { 4662821Swnj register struct tab *p; 4672821Swnj register pid; 4682821Swnj 46913021Ssam signal(SIGHUP, idlehup); 4702821Swnj for (;;) { 47113021Ssam if (setjmp(idlebuf)) 47213021Ssam return; 4732821Swnj pid = wait((int *) 0); 47413021Ssam if (pid == -1) { 47513021Ssam sigpause(0); 47613021Ssam continue; 4772821Swnj } 47813021Ssam for (ALL) 47913021Ssam if (p->pid == pid) { 48013021Ssam rmut(p); 48113021Ssam p->pid = -1; 48213021Ssam } 4832821Swnj } 4842821Swnj } 485