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*35606Sbostic static char sccsid[] = "@(#)init.c 5.12 (Berkeley) 09/20/88"; 921135Sdist #endif not lint 1012682Ssam 111029Sbill #include <signal.h> 121029Sbill #include <sys/types.h> 131029Sbill #include <setjmp.h> 141403Sbill #include <sys/reboot.h> 15*35606Sbostic #include <utmp.h> 162821Swnj #include <errno.h> 1713021Ssam #include <sys/file.h> 1816452Sroot #include <ttyent.h> 1928801Skarels #include <sys/syslog.h> 2023147Sbloom #include <sys/stat.h> 211029Sbill 22*35606Sbostic struct utmp ut; 23*35606Sbostic #define LINSIZ sizeof(ut.ut_line) 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 301029Sbill char shell[] = "/bin/sh"; 311029Sbill char minus[] = "-"; 321029Sbill char runc[] = "/etc/rc"; 3323147Sbloom char utmpf[] = "/etc/utmp"; 341029Sbill char ctty[] = "/dev/console"; 351029Sbill 361029Sbill struct tab 371029Sbill { 381029Sbill char line[LINSIZ]; 3918542Sralph char comn[CMDSIZ]; 401029Sbill char xflag; 411029Sbill int pid; 4218542Sralph int wpid; /* window system pid for SIGHUP */ 4318542Sralph char wcmd[CMDSIZ]; /* command to start window system process */ 445971Sroot time_t gettytime; 455971Sroot int gettycnt; 4622181Skarels time_t windtime; 4722181Skarels int windcnt; 4823147Sbloom struct tab *next; 4923147Sbloom } *itab; 501029Sbill 511029Sbill int fi; 521029Sbill int mergflag; 531029Sbill char tty[20]; 541429Sbill jmp_buf sjbuf, shutpass; 551029Sbill 561029Sbill int reset(); 572821Swnj int idle(); 581029Sbill char *strcpy(), *strcat(); 591029Sbill long lseek(); 601029Sbill 6118542Sralph struct sigvec rvec = { reset, sigmask(SIGHUP), 0 }; 6213021Ssam 6323147Sbloom 6429836Ssam #if defined(vax) || defined(tahoe) 651029Sbill main() 661029Sbill { 6729836Ssam #if defined(tahoe) 6829836Ssam register int r12; /* make sure r11 gets bootflags */ 6929836Ssam #endif 701403Sbill register int r11; /* passed thru from boot */ 7113021Ssam #else 729869Spugs main(argc, argv) 739869Spugs char **argv; 749869Spugs { 7513021Ssam #endif 761403Sbill int howto, oldhowto; 771403Sbill 7829836Ssam #if defined(vax) || defined(tahoe) 791403Sbill howto = r11; 8013021Ssam #else 819869Spugs if (argc > 1 && argv[1][0] == '-') { 829869Spugs char *cp; 839869Spugs 849869Spugs howto = 0; 859869Spugs cp = &argv[1][1]; 869869Spugs while (*cp) switch (*cp++) { 879869Spugs case 'a': 889869Spugs howto |= RB_ASKNAME; 899869Spugs break; 909869Spugs case 's': 919869Spugs howto |= RB_SINGLE; 929869Spugs break; 939869Spugs } 949869Spugs } else { 959869Spugs howto = RB_SINGLE; 969869Spugs } 9713021Ssam #endif 9824854Seric openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH); 9913021Ssam sigvec(SIGTERM, &rvec, (struct sigvec *)0); 1002821Swnj signal(SIGTSTP, idle); 1011029Sbill signal(SIGSTOP, SIG_IGN); 1021029Sbill signal(SIGTTIN, SIG_IGN); 1031029Sbill signal(SIGTTOU, SIG_IGN); 10413021Ssam (void) setjmp(sjbuf); 10513021Ssam for (EVER) { 1061403Sbill oldhowto = howto; 1071403Sbill howto = RB_SINGLE; 1081429Sbill if (setjmp(shutpass) == 0) 1091429Sbill shutdown(); 1101403Sbill if (oldhowto & RB_SINGLE) 1111403Sbill single(); 1121403Sbill if (runcom(oldhowto) == 0) 1131403Sbill continue; 1141029Sbill merge(); 1151029Sbill multiple(); 1161029Sbill } 1171029Sbill } 1181029Sbill 1191429Sbill int shutreset(); 1201429Sbill 1211029Sbill shutdown() 1221029Sbill { 1231029Sbill register i; 12423147Sbloom register struct tab *p, *p1; 1251029Sbill 12623147Sbloom close(creat(utmpf, 0644)); 1271029Sbill signal(SIGHUP, SIG_IGN); 12823147Sbloom for (p = itab; p ; ) { 1291029Sbill term(p); 13023147Sbloom p1 = p->next; 13123147Sbloom free(p); 13223147Sbloom p = p1; 1331029Sbill } 13423147Sbloom itab = (struct tab *)0; 1351429Sbill signal(SIGALRM, shutreset); 13628801Skarels (void) kill(-1, SIGTERM); /* one chance to catch it */ 13728801Skarels sleep(5); 1381429Sbill alarm(30); 13913021Ssam for (i = 0; i < 5; i++) 1401029Sbill kill(-1, SIGKILL); 14113021Ssam while (wait((int *)0) != -1) 1421029Sbill ; 1431029Sbill alarm(0); 1441429Sbill shutend(); 1451429Sbill } 1461429Sbill 14730516Sbostic char shutfailm[] = "WARNING: Something is hung (won't die); ps axl advised\n"; 1481429Sbill 1491429Sbill shutreset() 1501429Sbill { 1511429Sbill int status; 1521429Sbill 1531429Sbill if (fork() == 0) { 1541429Sbill int ct = open(ctty, 1); 1551429Sbill write(ct, shutfailm, sizeof (shutfailm)); 1561429Sbill sleep(5); 1571429Sbill exit(1); 1581429Sbill } 1591429Sbill sleep(5); 1601429Sbill shutend(); 1611429Sbill longjmp(shutpass, 1); 1621429Sbill } 1631429Sbill 1641429Sbill shutend() 1651429Sbill { 1662821Swnj register i, f; 1671429Sbill 1682821Swnj acct(0); 1691029Sbill signal(SIGALRM, SIG_DFL); 17013021Ssam for (i = 0; i < 10; i++) 1711029Sbill close(i); 172*35606Sbostic logwtmp("~", "shutdown", ""); 1731029Sbill } 1741029Sbill 1751029Sbill single() 1761029Sbill { 1771029Sbill register pid; 1782821Swnj register xpid; 179*35606Sbostic extern int errno; 1801029Sbill 18113021Ssam do { 18213021Ssam pid = fork(); 18313021Ssam if (pid == 0) { 18413021Ssam signal(SIGTERM, SIG_DFL); 18513021Ssam signal(SIGHUP, SIG_DFL); 18613021Ssam signal(SIGALRM, SIG_DFL); 18716452Sroot signal(SIGTSTP, SIG_IGN); 18813021Ssam (void) open(ctty, O_RDWR); 18913021Ssam dup2(0, 1); 19013021Ssam dup2(0, 2); 19113021Ssam execl(shell, minus, (char *)0); 19230516Sbostic perror(shell); 19313021Ssam exit(0); 19413021Ssam } 19513021Ssam while ((xpid = wait((int *)0)) != pid) 19613021Ssam if (xpid == -1 && errno == ECHILD) 19713021Ssam break; 19813021Ssam } while (xpid == -1); 1991029Sbill } 2001029Sbill 2011403Sbill runcom(oldhowto) 2021403Sbill int oldhowto; 2031029Sbill { 2041029Sbill register pid, f; 2051403Sbill int status; 2061029Sbill 2071029Sbill pid = fork(); 20813021Ssam if (pid == 0) { 20913021Ssam (void) open("/", O_RDONLY); 21013021Ssam dup2(0, 1); 21113021Ssam dup2(0, 2); 2121403Sbill if (oldhowto & RB_SINGLE) 2131403Sbill execl(shell, shell, runc, (char *)0); 2141403Sbill else 2151403Sbill execl(shell, shell, runc, "autoboot", (char *)0); 2161403Sbill exit(1); 2171029Sbill } 21813021Ssam while (wait(&status) != pid) 2191029Sbill ; 22013021Ssam if (status) 22113021Ssam return (0); 222*35606Sbostic logwtmp("~", "reboot", ""); 22313021Ssam return (1); 2241029Sbill } 2251029Sbill 22633302Sbostic int merge(); 22718542Sralph struct sigvec mvec = { merge, sigmask(SIGTERM), 0 }; 22813021Ssam /* 22913021Ssam * Multi-user. Listen for users leaving, SIGHUP's 23013021Ssam * which indicate ttys has changed, and SIGTERM's which 23113021Ssam * are used to shutdown the system. 23213021Ssam */ 2331029Sbill multiple() 2341029Sbill { 2351029Sbill register struct tab *p; 2361029Sbill register pid; 23723147Sbloom int omask; 2381029Sbill 23913021Ssam sigvec(SIGHUP, &mvec, (struct sigvec *)0); 24013021Ssam for (EVER) { 2411029Sbill pid = wait((int *)0); 24213021Ssam if (pid == -1) 2431029Sbill return; 24430516Sbostic omask = sigblock(sigmask(SIGHUP)); 24518542Sralph for (ALL) { 24618542Sralph /* must restart window system BEFORE emulator */ 24718542Sralph if (p->wpid == pid || p->wpid == -1) 24818542Sralph wstart(p); 24913021Ssam if (p->pid == pid || p->pid == -1) { 25018542Sralph /* disown the window system */ 25118542Sralph if (p->wpid) 25218542Sralph kill(p->wpid, SIGHUP); 25335445Sbostic cleanutmp(p); 2541029Sbill dfork(p); 2551029Sbill } 25618542Sralph } 25723147Sbloom sigsetmask(omask); 2581029Sbill } 2591029Sbill } 2601029Sbill 26113021Ssam /* 26213021Ssam * Merge current contents of ttys file 26313021Ssam * into in-core table of configured tty lines. 26413021Ssam * Entered as signal handler for SIGHUP. 26513021Ssam */ 26613021Ssam #define FOUND 1 26713021Ssam #define CHANGE 2 26818542Sralph #define WCHANGE 4 26913021Ssam 27013021Ssam merge() 27113021Ssam { 27213021Ssam register struct tab *p; 27316452Sroot register struct ttyent *t; 27423147Sbloom register struct tab *p1; 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 } 29030516Sbostic if (SCMPN(p->wcmd, t->ty_window ? t->ty_window : "")) { 29118542Sralph p->xflag |= WCHANGE|CHANGE; 29218542Sralph SCPYN(p->wcmd, t->ty_window); 29318542Sralph } 29413021Ssam goto contin1; 29513021Ssam } 29618542Sralph 29723147Sbloom /* 29823147Sbloom * Make space for a new one 29923147Sbloom */ 30023147Sbloom p1 = (struct tab *)calloc(1, sizeof(*p1)); 30123147Sbloom if (!p1) { 30223147Sbloom syslog(LOG_ERR, "no space for '%s' !?!", t->ty_name); 30313021Ssam goto contin1; 30413021Ssam } 30523147Sbloom /* 30623147Sbloom * Put new terminal at the end of the linked list. 30723147Sbloom */ 30823147Sbloom if (itab) { 30923147Sbloom for (p = itab; p->next ; p = p->next) 31023147Sbloom ; 31123147Sbloom p->next = p1; 31223147Sbloom } else 31323147Sbloom itab = p1; 31423147Sbloom 31523147Sbloom p = p1; 31623147Sbloom SCPYN(p->line, t->ty_name); 31723147Sbloom p->xflag |= FOUND|CHANGE; 31823147Sbloom SCPYN(p->comn, t->ty_getty); 31930516Sbostic if (t->ty_window && strcmp(t->ty_window, "") != 0) { 32023147Sbloom p->xflag |= WCHANGE; 32123147Sbloom SCPYN(p->wcmd, t->ty_window); 32223147Sbloom } 32313021Ssam contin1: 32413021Ssam ; 32513021Ssam } 32616452Sroot endttyent(); 32723147Sbloom p1 = (struct tab *)0; 32813021Ssam for (ALL) { 32913021Ssam if ((p->xflag&FOUND) == 0) { 33013021Ssam term(p); 33118542Sralph wterm(p); 33223147Sbloom if (p1) 33323147Sbloom p1->next = p->next; 33423147Sbloom else 33523147Sbloom itab = p->next; 33623147Sbloom free(p); 33723147Sbloom p = p1 ? p1 : itab; 33823147Sbloom } else { 33923147Sbloom /* window system should be started first */ 34023147Sbloom if (p->xflag&WCHANGE) { 34123147Sbloom wterm(p); 34223147Sbloom wstart(p); 34323147Sbloom } 34423147Sbloom if (p->xflag&CHANGE) { 34523147Sbloom term(p); 34623147Sbloom dfork(p); 34723147Sbloom } 34813021Ssam } 34923147Sbloom p1 = p; 35013021Ssam } 35113021Ssam } 35213021Ssam 3531029Sbill term(p) 35413021Ssam register struct tab *p; 3551029Sbill { 3561029Sbill 35713021Ssam if (p->pid != 0) { 35835445Sbostic cleanutmp(p); 3591029Sbill kill(p->pid, SIGKILL); 3601029Sbill } 3611029Sbill p->pid = 0; 36218542Sralph /* send SIGHUP to get rid of connections */ 36318542Sralph if (p->wpid > 0) 36418542Sralph kill(p->wpid, SIGHUP); 3651029Sbill } 3661029Sbill 3671029Sbill dfork(p) 36813021Ssam struct tab *p; 3691029Sbill { 3701029Sbill register pid; 3715971Sroot time_t t; 3725971Sroot int dowait = 0; 3731029Sbill 3745971Sroot time(&t); 3755971Sroot p->gettycnt++; 3765971Sroot if ((t - p->gettytime) >= 60) { 3775971Sroot p->gettytime = t; 3785971Sroot p->gettycnt = 1; 37918542Sralph } else if (p->gettycnt >= 5) { 38018542Sralph dowait = 1; 38118542Sralph p->gettytime = t; 38218542Sralph p->gettycnt = 1; 3835971Sroot } 3841029Sbill pid = fork(); 38513021Ssam if (pid == 0) { 3866816Ssam signal(SIGTERM, SIG_DFL); 3876816Ssam signal(SIGHUP, SIG_IGN); 38822181Skarels sigsetmask(0); /* since can be called from masked code */ 3895971Sroot if (dowait) { 39018542Sralph syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line); 39118542Sralph closelog(); 3925971Sroot sleep(30); 3935971Sroot } 39418542Sralph execit(p->comn, p->line); 3951029Sbill exit(0); 3961029Sbill } 3971029Sbill p->pid = pid; 3981029Sbill } 3991029Sbill 40035445Sbostic cleanutmp(p) 40113021Ssam register struct tab *p; 4021029Sbill { 40335445Sbostic if (logout(p->line)) { 40435445Sbostic logwtmp(p->line); 40517582Ssam /* 40617582Ssam * After a proper login force reset 40717582Ssam * of error detection code in dfork. 40817582Ssam */ 40917582Ssam p->gettytime = 0; 41022181Skarels p->windtime = 0; 4111029Sbill } 4121029Sbill } 4131029Sbill 4141029Sbill reset() 4151029Sbill { 41613021Ssam 4171029Sbill longjmp(sjbuf, 1); 4181029Sbill } 4192821Swnj 42013021Ssam jmp_buf idlebuf; 42113021Ssam 42213021Ssam idlehup() 42313021Ssam { 42413021Ssam 42513021Ssam longjmp(idlebuf, 1); 42613021Ssam } 42713021Ssam 4282821Swnj idle() 4292821Swnj { 4302821Swnj register struct tab *p; 4312821Swnj register pid; 4322821Swnj 43313021Ssam signal(SIGHUP, idlehup); 43418542Sralph for (EVER) { 43513021Ssam if (setjmp(idlebuf)) 43613021Ssam return; 4372821Swnj pid = wait((int *) 0); 43813021Ssam if (pid == -1) { 43913021Ssam sigpause(0); 44013021Ssam continue; 4412821Swnj } 44218542Sralph for (ALL) { 44318542Sralph /* if window system dies, mark it for restart */ 44418542Sralph if (p->wpid == pid) 44518542Sralph p->wpid = -1; 44613021Ssam if (p->pid == pid) { 44735445Sbostic cleanutmp(p); 44813021Ssam p->pid = -1; 44913021Ssam } 45018542Sralph } 4512821Swnj } 4522821Swnj } 45318542Sralph 45418542Sralph wterm(p) 45518542Sralph register struct tab *p; 45618542Sralph { 45718542Sralph if (p->wpid != 0) { 45818542Sralph kill(p->wpid, SIGKILL); 45918542Sralph } 46018542Sralph p->wpid = 0; 46118542Sralph } 46218542Sralph 46318542Sralph wstart(p) 46418542Sralph register struct tab *p; 46518542Sralph { 46622181Skarels register pid; 46722181Skarels time_t t; 46822181Skarels int dowait = 0; 46918542Sralph 47022181Skarels time(&t); 47122181Skarels p->windcnt++; 47222181Skarels if ((t - p->windtime) >= 60) { 47322181Skarels p->windtime = t; 47422181Skarels p->windcnt = 1; 47522181Skarels } else if (p->windcnt >= 5) { 47622181Skarels dowait = 1; 47722181Skarels p->windtime = t; 47822181Skarels p->windcnt = 1; 47922181Skarels } 48022181Skarels 48122181Skarels pid = fork(); 48222181Skarels 48322181Skarels if (pid == 0) { 48418542Sralph signal(SIGTERM, SIG_DFL); 48522181Skarels signal(SIGHUP, SIG_IGN); 48622181Skarels sigsetmask(0); /* since can be called from masked code */ 48722181Skarels if (dowait) { 48822181Skarels syslog(LOG_ERR, "'%s %s' failing, sleeping", p->wcmd, p->line); 48922181Skarels closelog(); 49022181Skarels sleep(30); 49122181Skarels } 49218542Sralph execit(p->wcmd, p->line); 49318542Sralph exit(0); 49418542Sralph } 49522181Skarels p->wpid = pid; 49618542Sralph } 49718542Sralph 49822181Skarels #define NARGS 20 /* must be at least 4 */ 49918542Sralph #define ARGLEN 512 /* total size for all the argument strings */ 50018542Sralph 50118542Sralph execit(s, arg) 50218542Sralph char *s; 50318542Sralph char *arg; /* last argument on line */ 50418542Sralph { 50518542Sralph char *argv[NARGS], args[ARGLEN], *envp[1]; 50618542Sralph register char *sp = s; 50718542Sralph register char *ap = args; 50818542Sralph register char c; 50918542Sralph register int i; 51018542Sralph 51118542Sralph /* 51218542Sralph * First we have to set up the argument vector. 51318542Sralph * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2"). 51418542Sralph */ 51518542Sralph for (i = 1; i < NARGS - 2; i++) { 51618542Sralph argv[i] = ap; 51718542Sralph for (EVER) { 51818542Sralph if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) { 51918542Sralph *ap = '\0'; 52018542Sralph goto done; 52118542Sralph } 52218542Sralph if (c == ' ') { 52318542Sralph *ap++ = '\0'; 52418542Sralph while (*sp == ' ') 52518542Sralph sp++; 52618542Sralph if (*sp == '\0') 52718542Sralph goto done; 52818542Sralph break; 52918542Sralph } 53018542Sralph *ap++ = c; 53118542Sralph } 53218542Sralph } 53318542Sralph done: 53418542Sralph argv[0] = argv[1]; 53518542Sralph argv[1] = "-"; 53618542Sralph argv[i+1] = arg; 53718542Sralph argv[i+2] = 0; 53818542Sralph envp[0] = 0; 53918542Sralph execve(argv[0], &argv[1], envp); 54018542Sralph /* report failure of exec */ 54118542Sralph syslog(LOG_ERR, "%s: %m", argv[0]); 54218542Sralph closelog(); 54318542Sralph sleep(10); /* prevent failures from eating machine */ 54418542Sralph } 545