121135Sdist /* 228801Skarels * Copyright (c) 1980,1986 Regents of the University of California. 321135Sdist * All rights reserved. The Berkeley software License Agreement 421135Sdist * specifies the terms and conditions for redistribution. 521135Sdist */ 621135Sdist 712682Ssam #ifndef lint 8*42407Smarc static char sccsid[] = "@(#)init.c 5.15 (Berkeley) 05/27/90"; 921135Sdist #endif not lint 1012682Ssam 111029Sbill #include <sys/types.h> 1237284Sbostic #include <sys/file.h> 1337284Sbostic #include <sys/signal.h> 1437284Sbostic #include <sys/reboot.h> 1537284Sbostic #include <sys/syslog.h> 1637284Sbostic #include <sys/stat.h> 17*42407Smarc #include <sys/ioctl.h> 181029Sbill #include <setjmp.h> 1935606Sbostic #include <utmp.h> 202821Swnj #include <errno.h> 2116452Sroot #include <ttyent.h> 2237284Sbostic #include "pathnames.h" 231029Sbill 2424494Skarels #define CMDSIZ 200 /* max string length for getty or window command*/ 2523147Sbloom #define ALL p = itab; p ; p = p->next 261029Sbill #define EVER ;; 271029Sbill #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 281029Sbill #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 291029Sbill 3037284Sbostic char shell[] = _PATH_BSHELL; 311029Sbill char minus[] = "-"; 3237284Sbostic char runc[] = _PATH_RC; 3337284Sbostic char ctty[] = _PATH_CONSOLE; 341029Sbill 351029Sbill struct tab 361029Sbill { 3735670Sbostic char line[UT_LINESIZE]; 3818542Sralph char comn[CMDSIZ]; 391029Sbill char xflag; 401029Sbill int pid; 4118542Sralph int wpid; /* window system pid for SIGHUP */ 4218542Sralph char wcmd[CMDSIZ]; /* command to start window system process */ 435971Sroot time_t gettytime; 445971Sroot int gettycnt; 4522181Skarels time_t windtime; 4622181Skarels int windcnt; 4723147Sbloom struct tab *next; 4823147Sbloom } *itab; 491029Sbill 501029Sbill int fi; 511029Sbill int mergflag; 521029Sbill char tty[20]; 531429Sbill jmp_buf sjbuf, shutpass; 541029Sbill 551029Sbill char *strcpy(), *strcat(); 561029Sbill long lseek(); 57*42407Smarc void idle(), merge(), reset(); 581029Sbill 5918542Sralph struct sigvec rvec = { reset, sigmask(SIGHUP), 0 }; 6013021Ssam 6129836Ssam #if defined(vax) || defined(tahoe) 621029Sbill main() 631029Sbill { 6429836Ssam #if defined(tahoe) 6529836Ssam register int r12; /* make sure r11 gets bootflags */ 6629836Ssam #endif 671403Sbill register int r11; /* passed thru from boot */ 6813021Ssam #else 699869Spugs main(argc, argv) 709869Spugs char **argv; 719869Spugs { 7213021Ssam #endif 73*42407Smarc int howto, oldhowto, started; 741403Sbill 7529836Ssam #if defined(vax) || defined(tahoe) 761403Sbill howto = r11; 7713021Ssam #else 78*42407Smarc howto = 0; 799869Spugs if (argc > 1 && argv[1][0] == '-') { 809869Spugs char *cp; 819869Spugs 829869Spugs cp = &argv[1][1]; 839869Spugs while (*cp) switch (*cp++) { 849869Spugs case 'a': 859869Spugs howto |= RB_ASKNAME; 869869Spugs break; 879869Spugs case 's': 889869Spugs howto |= RB_SINGLE; 899869Spugs break; 909869Spugs } 919869Spugs } else { 929869Spugs howto = RB_SINGLE; 939869Spugs } 9413021Ssam #endif 95*42407Smarc if (getuid() != 0) 96*42407Smarc exit(1); 9724854Seric openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH); 98*42407Smarc if (setsid() < 0) 99*42407Smarc syslog(LOG_ERR, "setsid failed (initial) %m"); 10013021Ssam sigvec(SIGTERM, &rvec, (struct sigvec *)0); 1012821Swnj signal(SIGTSTP, idle); 1021029Sbill signal(SIGSTOP, SIG_IGN); 1031029Sbill signal(SIGTTIN, SIG_IGN); 1041029Sbill signal(SIGTTOU, SIG_IGN); 10513021Ssam (void) setjmp(sjbuf); 106*42407Smarc for (started = 0; ; ) { 1071403Sbill oldhowto = howto; 1081403Sbill howto = RB_SINGLE; 109*42407Smarc if (started && setjmp(shutpass) == 0) 1101429Sbill shutdown(); 111*42407Smarc started = 1; 1121403Sbill if (oldhowto & RB_SINGLE) 1131403Sbill single(); 1141403Sbill if (runcom(oldhowto) == 0) 1151403Sbill continue; 1161029Sbill merge(); 1171029Sbill multiple(); 1181029Sbill } 1191029Sbill } 1201029Sbill 121*42407Smarc void shutreset(); 1221429Sbill 1231029Sbill shutdown() 1241029Sbill { 1251029Sbill register i; 12623147Sbloom register struct tab *p, *p1; 1271029Sbill 1281029Sbill signal(SIGHUP, SIG_IGN); 12923147Sbloom for (p = itab; p ; ) { 1301029Sbill term(p); 13123147Sbloom p1 = p->next; 13223147Sbloom free(p); 13323147Sbloom p = p1; 1341029Sbill } 13523147Sbloom itab = (struct tab *)0; 1361429Sbill signal(SIGALRM, shutreset); 13728801Skarels (void) kill(-1, SIGTERM); /* one chance to catch it */ 13828801Skarels sleep(5); 1391429Sbill alarm(30); 14013021Ssam for (i = 0; i < 5; i++) 1411029Sbill kill(-1, SIGKILL); 14213021Ssam while (wait((int *)0) != -1) 1431029Sbill ; 1441029Sbill alarm(0); 1451429Sbill shutend(); 1461429Sbill } 1471429Sbill 148*42407Smarc char shutfailm[] = "init: WARNING: something is hung (won't die); ps axl advised\n"; 1491429Sbill 150*42407Smarc void 1511429Sbill shutreset() 1521429Sbill { 1531429Sbill int status; 1541429Sbill 1551429Sbill if (fork() == 0) { 1561429Sbill int ct = open(ctty, 1); 1571429Sbill write(ct, shutfailm, sizeof (shutfailm)); 1581429Sbill sleep(5); 1591429Sbill exit(1); 1601429Sbill } 1611429Sbill sleep(5); 1621429Sbill shutend(); 1631429Sbill longjmp(shutpass, 1); 1641429Sbill } 1651429Sbill 1661429Sbill shutend() 1671429Sbill { 1682821Swnj register i, f; 1691429Sbill 1702821Swnj acct(0); 1711029Sbill signal(SIGALRM, SIG_DFL); 17213021Ssam for (i = 0; i < 10; i++) 1731029Sbill close(i); 17435606Sbostic logwtmp("~", "shutdown", ""); 1751029Sbill } 1761029Sbill 1771029Sbill single() 1781029Sbill { 1791029Sbill register pid; 1802821Swnj register xpid; 18135606Sbostic extern int errno; 1821029Sbill 18313021Ssam do { 18413021Ssam pid = fork(); 18513021Ssam if (pid == 0) { 18613021Ssam signal(SIGTERM, SIG_DFL); 18713021Ssam signal(SIGHUP, SIG_DFL); 18813021Ssam signal(SIGALRM, SIG_DFL); 18916452Sroot signal(SIGTSTP, SIG_IGN); 190*42407Smarc if (setsid() < 0) 191*42407Smarc syslog(LOG_ERR, "setsid failed (single): %m"); 19213021Ssam (void) open(ctty, O_RDWR); 193*42407Smarc if (ioctl(0, TIOCSCTTY, 0) < 0) 194*42407Smarc syslog(LOG_ERR, "TIOCSCTTY failed: %m"); 19513021Ssam dup2(0, 1); 19613021Ssam dup2(0, 2); 19713021Ssam execl(shell, minus, (char *)0); 19830516Sbostic perror(shell); 19913021Ssam exit(0); 20013021Ssam } 20113021Ssam while ((xpid = wait((int *)0)) != pid) 20213021Ssam if (xpid == -1 && errno == ECHILD) 20313021Ssam break; 20413021Ssam } while (xpid == -1); 2051029Sbill } 2061029Sbill 2071403Sbill runcom(oldhowto) 2081403Sbill int oldhowto; 2091029Sbill { 2101029Sbill register pid, f; 2111403Sbill int status; 2121029Sbill 2131029Sbill pid = fork(); 21413021Ssam if (pid == 0) { 215*42407Smarc (void) open(ctty, O_RDONLY); 21613021Ssam dup2(0, 1); 21713021Ssam dup2(0, 2); 218*42407Smarc if (setsid() < 0) 219*42407Smarc syslog(LOG_ERR, "setsid failed (runcom) %m"); 220*42407Smarc if (ioctl(0, TIOCSCTTY, 0) < 0) 221*42407Smarc syslog(LOG_ERR, "TIOCSCTTY failed (runcom) %m"); 2221403Sbill if (oldhowto & RB_SINGLE) 2231403Sbill execl(shell, shell, runc, (char *)0); 2241403Sbill else 2251403Sbill execl(shell, shell, runc, "autoboot", (char *)0); 2261403Sbill exit(1); 2271029Sbill } 22813021Ssam while (wait(&status) != pid) 2291029Sbill ; 23013021Ssam if (status) 23113021Ssam return (0); 23235606Sbostic logwtmp("~", "reboot", ""); 23313021Ssam return (1); 2341029Sbill } 2351029Sbill 23618542Sralph struct sigvec mvec = { merge, sigmask(SIGTERM), 0 }; 23713021Ssam /* 23813021Ssam * Multi-user. Listen for users leaving, SIGHUP's 23913021Ssam * which indicate ttys has changed, and SIGTERM's which 24013021Ssam * are used to shutdown the system. 24113021Ssam */ 2421029Sbill multiple() 2431029Sbill { 244*42407Smarc extern int errno; 2451029Sbill register struct tab *p; 2461029Sbill register pid; 24723147Sbloom int omask; 2481029Sbill 24913021Ssam sigvec(SIGHUP, &mvec, (struct sigvec *)0); 25013021Ssam for (EVER) { 2511029Sbill pid = wait((int *)0); 252*42407Smarc /* SHOULD FIX THIS IN THE KERNEL */ 253*42407Smarc if (pid == -1 && errno != EINTR) 2541029Sbill return; 25530516Sbostic omask = sigblock(sigmask(SIGHUP)); 25618542Sralph for (ALL) { 25718542Sralph /* must restart window system BEFORE emulator */ 25818542Sralph if (p->wpid == pid || p->wpid == -1) 25918542Sralph wstart(p); 26013021Ssam if (p->pid == pid || p->pid == -1) { 26118542Sralph /* disown the window system */ 26218542Sralph if (p->wpid) 26318542Sralph kill(p->wpid, SIGHUP); 26435445Sbostic cleanutmp(p); 2651029Sbill dfork(p); 2661029Sbill } 26718542Sralph } 26823147Sbloom sigsetmask(omask); 2691029Sbill } 2701029Sbill } 2711029Sbill 27213021Ssam /* 27313021Ssam * Merge current contents of ttys file 27413021Ssam * into in-core table of configured tty lines. 27513021Ssam * Entered as signal handler for SIGHUP. 27613021Ssam */ 27713021Ssam #define FOUND 1 27813021Ssam #define CHANGE 2 27918542Sralph #define WCHANGE 4 28013021Ssam 281*42407Smarc void 28213021Ssam merge() 28313021Ssam { 28413021Ssam register struct tab *p; 28516452Sroot register struct ttyent *t; 28623147Sbloom register struct tab *p1; 28713021Ssam 28813021Ssam for (ALL) 28913021Ssam p->xflag = 0; 29016452Sroot setttyent(); 29116452Sroot while (t = getttyent()) { 29216452Sroot if ((t->ty_status & TTY_ON) == 0) 29316452Sroot continue; 29413021Ssam for (ALL) { 29516452Sroot if (SCMPN(p->line, t->ty_name)) 29613021Ssam continue; 29713021Ssam p->xflag |= FOUND; 29816452Sroot if (SCMPN(p->comn, t->ty_getty)) { 29913021Ssam p->xflag |= CHANGE; 30016452Sroot SCPYN(p->comn, t->ty_getty); 30113021Ssam } 30230516Sbostic if (SCMPN(p->wcmd, t->ty_window ? t->ty_window : "")) { 30318542Sralph p->xflag |= WCHANGE|CHANGE; 30418542Sralph SCPYN(p->wcmd, t->ty_window); 30518542Sralph } 30613021Ssam goto contin1; 30713021Ssam } 30818542Sralph 30923147Sbloom /* 31023147Sbloom * Make space for a new one 31123147Sbloom */ 31223147Sbloom p1 = (struct tab *)calloc(1, sizeof(*p1)); 31323147Sbloom if (!p1) { 31423147Sbloom syslog(LOG_ERR, "no space for '%s' !?!", t->ty_name); 31513021Ssam goto contin1; 31613021Ssam } 31723147Sbloom /* 31823147Sbloom * Put new terminal at the end of the linked list. 31923147Sbloom */ 32023147Sbloom if (itab) { 32123147Sbloom for (p = itab; p->next ; p = p->next) 32223147Sbloom ; 32323147Sbloom p->next = p1; 32423147Sbloom } else 32523147Sbloom itab = p1; 32623147Sbloom 32723147Sbloom p = p1; 32823147Sbloom SCPYN(p->line, t->ty_name); 32923147Sbloom p->xflag |= FOUND|CHANGE; 33023147Sbloom SCPYN(p->comn, t->ty_getty); 33130516Sbostic if (t->ty_window && strcmp(t->ty_window, "") != 0) { 33223147Sbloom p->xflag |= WCHANGE; 33323147Sbloom SCPYN(p->wcmd, t->ty_window); 33423147Sbloom } 33513021Ssam contin1: 33613021Ssam ; 33713021Ssam } 33816452Sroot endttyent(); 33923147Sbloom p1 = (struct tab *)0; 34013021Ssam for (ALL) { 34113021Ssam if ((p->xflag&FOUND) == 0) { 34213021Ssam term(p); 34318542Sralph wterm(p); 34423147Sbloom if (p1) 34523147Sbloom p1->next = p->next; 34623147Sbloom else 34723147Sbloom itab = p->next; 34823147Sbloom free(p); 34923147Sbloom p = p1 ? p1 : itab; 35023147Sbloom } else { 35123147Sbloom /* window system should be started first */ 35223147Sbloom if (p->xflag&WCHANGE) { 35323147Sbloom wterm(p); 35423147Sbloom wstart(p); 35523147Sbloom } 35623147Sbloom if (p->xflag&CHANGE) { 35723147Sbloom term(p); 35823147Sbloom dfork(p); 35923147Sbloom } 36013021Ssam } 36123147Sbloom p1 = p; 36213021Ssam } 36313021Ssam } 36413021Ssam 3651029Sbill term(p) 36613021Ssam register struct tab *p; 3671029Sbill { 3681029Sbill 36913021Ssam if (p->pid != 0) { 37035445Sbostic cleanutmp(p); 3711029Sbill kill(p->pid, SIGKILL); 3721029Sbill } 3731029Sbill p->pid = 0; 37418542Sralph /* send SIGHUP to get rid of connections */ 37518542Sralph if (p->wpid > 0) 37618542Sralph kill(p->wpid, SIGHUP); 3771029Sbill } 3781029Sbill 3791029Sbill dfork(p) 38013021Ssam struct tab *p; 3811029Sbill { 3821029Sbill register pid; 3835971Sroot time_t t; 3845971Sroot int dowait = 0; 3851029Sbill 3865971Sroot time(&t); 3875971Sroot p->gettycnt++; 3885971Sroot if ((t - p->gettytime) >= 60) { 3895971Sroot p->gettytime = t; 3905971Sroot p->gettycnt = 1; 39118542Sralph } else if (p->gettycnt >= 5) { 39218542Sralph dowait = 1; 39318542Sralph p->gettytime = t; 39418542Sralph p->gettycnt = 1; 3955971Sroot } 3961029Sbill pid = fork(); 39713021Ssam if (pid == 0) { 3986816Ssam signal(SIGTERM, SIG_DFL); 3996816Ssam signal(SIGHUP, SIG_IGN); 40022181Skarels sigsetmask(0); /* since can be called from masked code */ 4015971Sroot if (dowait) { 40218542Sralph syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line); 40318542Sralph closelog(); 4045971Sroot sleep(30); 4055971Sroot } 406*42407Smarc if (setsid() < 0) 407*42407Smarc syslog(LOG_ERR, "setsid failed(dfork) %m"); 40818542Sralph execit(p->comn, p->line); 4091029Sbill exit(0); 4101029Sbill } 4111029Sbill p->pid = pid; 4121029Sbill } 4131029Sbill 41435445Sbostic cleanutmp(p) 41513021Ssam register struct tab *p; 4161029Sbill { 41735445Sbostic if (logout(p->line)) { 418*42407Smarc logwtmp(p->line, "", ""); 41917582Ssam /* 42017582Ssam * After a proper login force reset 42117582Ssam * of error detection code in dfork. 42217582Ssam */ 42317582Ssam p->gettytime = 0; 42422181Skarels p->windtime = 0; 4251029Sbill } 4261029Sbill } 4271029Sbill 428*42407Smarc void 4291029Sbill reset() 4301029Sbill { 4311029Sbill longjmp(sjbuf, 1); 4321029Sbill } 4332821Swnj 43413021Ssam jmp_buf idlebuf; 43513021Ssam 436*42407Smarc void 43713021Ssam idlehup() 43813021Ssam { 43913021Ssam longjmp(idlebuf, 1); 44013021Ssam } 44113021Ssam 442*42407Smarc void 4432821Swnj idle() 4442821Swnj { 4452821Swnj register struct tab *p; 4462821Swnj register pid; 4472821Swnj 44813021Ssam signal(SIGHUP, idlehup); 44918542Sralph for (EVER) { 45013021Ssam if (setjmp(idlebuf)) 45113021Ssam return; 4522821Swnj pid = wait((int *) 0); 45313021Ssam if (pid == -1) { 45413021Ssam sigpause(0); 45513021Ssam continue; 4562821Swnj } 45718542Sralph for (ALL) { 45818542Sralph /* if window system dies, mark it for restart */ 45918542Sralph if (p->wpid == pid) 46018542Sralph p->wpid = -1; 46113021Ssam if (p->pid == pid) { 46235445Sbostic cleanutmp(p); 46313021Ssam p->pid = -1; 46413021Ssam } 46518542Sralph } 4662821Swnj } 4672821Swnj } 46818542Sralph 46918542Sralph wterm(p) 47018542Sralph register struct tab *p; 47118542Sralph { 47218542Sralph if (p->wpid != 0) { 47318542Sralph kill(p->wpid, SIGKILL); 47418542Sralph } 47518542Sralph p->wpid = 0; 47618542Sralph } 47718542Sralph 47818542Sralph wstart(p) 47918542Sralph register struct tab *p; 48018542Sralph { 48122181Skarels register pid; 48222181Skarels time_t t; 48322181Skarels int dowait = 0; 48418542Sralph 48522181Skarels time(&t); 48622181Skarels p->windcnt++; 48722181Skarels if ((t - p->windtime) >= 60) { 48822181Skarels p->windtime = t; 48922181Skarels p->windcnt = 1; 49022181Skarels } else if (p->windcnt >= 5) { 49122181Skarels dowait = 1; 49222181Skarels p->windtime = t; 49322181Skarels p->windcnt = 1; 49422181Skarels } 49522181Skarels 49622181Skarels pid = fork(); 49722181Skarels 49822181Skarels if (pid == 0) { 49918542Sralph signal(SIGTERM, SIG_DFL); 50022181Skarels signal(SIGHUP, SIG_IGN); 50122181Skarels sigsetmask(0); /* since can be called from masked code */ 50222181Skarels if (dowait) { 50322181Skarels syslog(LOG_ERR, "'%s %s' failing, sleeping", p->wcmd, p->line); 50422181Skarels closelog(); 50522181Skarels sleep(30); 50622181Skarels } 507*42407Smarc if (setsid() < 0) 508*42407Smarc syslog(LOG_ERR, "setsid failed (window) %m"); 50918542Sralph execit(p->wcmd, p->line); 51018542Sralph exit(0); 51118542Sralph } 51222181Skarels p->wpid = pid; 51318542Sralph } 51418542Sralph 51522181Skarels #define NARGS 20 /* must be at least 4 */ 51618542Sralph #define ARGLEN 512 /* total size for all the argument strings */ 51718542Sralph 51818542Sralph execit(s, arg) 51918542Sralph char *s; 52018542Sralph char *arg; /* last argument on line */ 52118542Sralph { 52218542Sralph char *argv[NARGS], args[ARGLEN], *envp[1]; 52318542Sralph register char *sp = s; 52418542Sralph register char *ap = args; 52518542Sralph register char c; 52618542Sralph register int i; 52718542Sralph 52818542Sralph /* 52918542Sralph * First we have to set up the argument vector. 53018542Sralph * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2"). 53118542Sralph */ 53218542Sralph for (i = 1; i < NARGS - 2; i++) { 53318542Sralph argv[i] = ap; 53418542Sralph for (EVER) { 53518542Sralph if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) { 53618542Sralph *ap = '\0'; 53718542Sralph goto done; 53818542Sralph } 53918542Sralph if (c == ' ') { 54018542Sralph *ap++ = '\0'; 54118542Sralph while (*sp == ' ') 54218542Sralph sp++; 54318542Sralph if (*sp == '\0') 54418542Sralph goto done; 54518542Sralph break; 54618542Sralph } 54718542Sralph *ap++ = c; 54818542Sralph } 54918542Sralph } 55018542Sralph done: 55118542Sralph argv[0] = argv[1]; 55218542Sralph argv[1] = "-"; 55318542Sralph argv[i+1] = arg; 55418542Sralph argv[i+2] = 0; 55518542Sralph envp[0] = 0; 55618542Sralph execve(argv[0], &argv[1], envp); 55718542Sralph /* report failure of exec */ 55818542Sralph syslog(LOG_ERR, "%s: %m", argv[0]); 55918542Sralph closelog(); 56018542Sralph sleep(10); /* prevent failures from eating machine */ 56118542Sralph } 562