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*35670Sbostic static char sccsid[] = "@(#)init.c 5.13 (Berkeley) 09/22/88"; 921135Sdist #endif not lint 1012682Ssam 111029Sbill #include <signal.h> 121029Sbill #include <sys/types.h> 131029Sbill #include <setjmp.h> 141403Sbill #include <sys/reboot.h> 1535606Sbostic #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 2224494Skarels #define CMDSIZ 200 /* max string length for getty or window command*/ 2323147Sbloom #define ALL p = itab; p ; p = p->next 241029Sbill #define EVER ;; 251029Sbill #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 261029Sbill #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 271029Sbill 281029Sbill char shell[] = "/bin/sh"; 291029Sbill char minus[] = "-"; 301029Sbill char runc[] = "/etc/rc"; 3123147Sbloom char utmpf[] = "/etc/utmp"; 321029Sbill char ctty[] = "/dev/console"; 331029Sbill 341029Sbill struct tab 351029Sbill { 36*35670Sbostic char line[UT_LINESIZE]; 3718542Sralph char comn[CMDSIZ]; 381029Sbill char xflag; 391029Sbill int pid; 4018542Sralph int wpid; /* window system pid for SIGHUP */ 4118542Sralph char wcmd[CMDSIZ]; /* command to start window system process */ 425971Sroot time_t gettytime; 435971Sroot int gettycnt; 4422181Skarels time_t windtime; 4522181Skarels int windcnt; 4623147Sbloom struct tab *next; 4723147Sbloom } *itab; 481029Sbill 491029Sbill int fi; 501029Sbill int mergflag; 511029Sbill char tty[20]; 521429Sbill jmp_buf sjbuf, shutpass; 531029Sbill 541029Sbill int reset(); 552821Swnj int idle(); 561029Sbill char *strcpy(), *strcat(); 571029Sbill long lseek(); 581029Sbill 5918542Sralph struct sigvec rvec = { reset, sigmask(SIGHUP), 0 }; 6013021Ssam 6123147Sbloom 6229836Ssam #if defined(vax) || defined(tahoe) 631029Sbill main() 641029Sbill { 6529836Ssam #if defined(tahoe) 6629836Ssam register int r12; /* make sure r11 gets bootflags */ 6729836Ssam #endif 681403Sbill register int r11; /* passed thru from boot */ 6913021Ssam #else 709869Spugs main(argc, argv) 719869Spugs char **argv; 729869Spugs { 7313021Ssam #endif 741403Sbill int howto, oldhowto; 751403Sbill 7629836Ssam #if defined(vax) || defined(tahoe) 771403Sbill howto = r11; 7813021Ssam #else 799869Spugs if (argc > 1 && argv[1][0] == '-') { 809869Spugs char *cp; 819869Spugs 829869Spugs howto = 0; 839869Spugs cp = &argv[1][1]; 849869Spugs while (*cp) switch (*cp++) { 859869Spugs case 'a': 869869Spugs howto |= RB_ASKNAME; 879869Spugs break; 889869Spugs case 's': 899869Spugs howto |= RB_SINGLE; 909869Spugs break; 919869Spugs } 929869Spugs } else { 939869Spugs howto = RB_SINGLE; 949869Spugs } 9513021Ssam #endif 9624854Seric openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH); 9713021Ssam sigvec(SIGTERM, &rvec, (struct sigvec *)0); 982821Swnj signal(SIGTSTP, idle); 991029Sbill signal(SIGSTOP, SIG_IGN); 1001029Sbill signal(SIGTTIN, SIG_IGN); 1011029Sbill signal(SIGTTOU, SIG_IGN); 10213021Ssam (void) setjmp(sjbuf); 10313021Ssam for (EVER) { 1041403Sbill oldhowto = howto; 1051403Sbill howto = RB_SINGLE; 1061429Sbill if (setjmp(shutpass) == 0) 1071429Sbill shutdown(); 1081403Sbill if (oldhowto & RB_SINGLE) 1091403Sbill single(); 1101403Sbill if (runcom(oldhowto) == 0) 1111403Sbill continue; 1121029Sbill merge(); 1131029Sbill multiple(); 1141029Sbill } 1151029Sbill } 1161029Sbill 1171429Sbill int shutreset(); 1181429Sbill 1191029Sbill shutdown() 1201029Sbill { 1211029Sbill register i; 12223147Sbloom register struct tab *p, *p1; 1231029Sbill 12423147Sbloom close(creat(utmpf, 0644)); 1251029Sbill signal(SIGHUP, SIG_IGN); 12623147Sbloom for (p = itab; p ; ) { 1271029Sbill term(p); 12823147Sbloom p1 = p->next; 12923147Sbloom free(p); 13023147Sbloom p = p1; 1311029Sbill } 13223147Sbloom itab = (struct tab *)0; 1331429Sbill signal(SIGALRM, shutreset); 13428801Skarels (void) kill(-1, SIGTERM); /* one chance to catch it */ 13528801Skarels sleep(5); 1361429Sbill alarm(30); 13713021Ssam for (i = 0; i < 5; i++) 1381029Sbill kill(-1, SIGKILL); 13913021Ssam while (wait((int *)0) != -1) 1401029Sbill ; 1411029Sbill alarm(0); 1421429Sbill shutend(); 1431429Sbill } 1441429Sbill 14530516Sbostic char shutfailm[] = "WARNING: Something is hung (won't die); ps axl advised\n"; 1461429Sbill 1471429Sbill shutreset() 1481429Sbill { 1491429Sbill int status; 1501429Sbill 1511429Sbill if (fork() == 0) { 1521429Sbill int ct = open(ctty, 1); 1531429Sbill write(ct, shutfailm, sizeof (shutfailm)); 1541429Sbill sleep(5); 1551429Sbill exit(1); 1561429Sbill } 1571429Sbill sleep(5); 1581429Sbill shutend(); 1591429Sbill longjmp(shutpass, 1); 1601429Sbill } 1611429Sbill 1621429Sbill shutend() 1631429Sbill { 1642821Swnj register i, f; 1651429Sbill 1662821Swnj acct(0); 1671029Sbill signal(SIGALRM, SIG_DFL); 16813021Ssam for (i = 0; i < 10; i++) 1691029Sbill close(i); 17035606Sbostic logwtmp("~", "shutdown", ""); 1711029Sbill } 1721029Sbill 1731029Sbill single() 1741029Sbill { 1751029Sbill register pid; 1762821Swnj register xpid; 17735606Sbostic extern int errno; 1781029Sbill 17913021Ssam do { 18013021Ssam pid = fork(); 18113021Ssam if (pid == 0) { 18213021Ssam signal(SIGTERM, SIG_DFL); 18313021Ssam signal(SIGHUP, SIG_DFL); 18413021Ssam signal(SIGALRM, SIG_DFL); 18516452Sroot signal(SIGTSTP, SIG_IGN); 18613021Ssam (void) open(ctty, O_RDWR); 18713021Ssam dup2(0, 1); 18813021Ssam dup2(0, 2); 18913021Ssam execl(shell, minus, (char *)0); 19030516Sbostic perror(shell); 19113021Ssam exit(0); 19213021Ssam } 19313021Ssam while ((xpid = wait((int *)0)) != pid) 19413021Ssam if (xpid == -1 && errno == ECHILD) 19513021Ssam break; 19613021Ssam } while (xpid == -1); 1971029Sbill } 1981029Sbill 1991403Sbill runcom(oldhowto) 2001403Sbill int oldhowto; 2011029Sbill { 2021029Sbill register pid, f; 2031403Sbill int status; 2041029Sbill 2051029Sbill pid = fork(); 20613021Ssam if (pid == 0) { 20713021Ssam (void) open("/", O_RDONLY); 20813021Ssam dup2(0, 1); 20913021Ssam dup2(0, 2); 2101403Sbill if (oldhowto & RB_SINGLE) 2111403Sbill execl(shell, shell, runc, (char *)0); 2121403Sbill else 2131403Sbill execl(shell, shell, runc, "autoboot", (char *)0); 2141403Sbill exit(1); 2151029Sbill } 21613021Ssam while (wait(&status) != pid) 2171029Sbill ; 21813021Ssam if (status) 21913021Ssam return (0); 22035606Sbostic logwtmp("~", "reboot", ""); 22113021Ssam return (1); 2221029Sbill } 2231029Sbill 22433302Sbostic int merge(); 22518542Sralph struct sigvec mvec = { merge, sigmask(SIGTERM), 0 }; 22613021Ssam /* 22713021Ssam * Multi-user. Listen for users leaving, SIGHUP's 22813021Ssam * which indicate ttys has changed, and SIGTERM's which 22913021Ssam * are used to shutdown the system. 23013021Ssam */ 2311029Sbill multiple() 2321029Sbill { 2331029Sbill register struct tab *p; 2341029Sbill register pid; 23523147Sbloom int omask; 2361029Sbill 23713021Ssam sigvec(SIGHUP, &mvec, (struct sigvec *)0); 23813021Ssam for (EVER) { 2391029Sbill pid = wait((int *)0); 24013021Ssam if (pid == -1) 2411029Sbill return; 24230516Sbostic omask = sigblock(sigmask(SIGHUP)); 24318542Sralph for (ALL) { 24418542Sralph /* must restart window system BEFORE emulator */ 24518542Sralph if (p->wpid == pid || p->wpid == -1) 24618542Sralph wstart(p); 24713021Ssam if (p->pid == pid || p->pid == -1) { 24818542Sralph /* disown the window system */ 24918542Sralph if (p->wpid) 25018542Sralph kill(p->wpid, SIGHUP); 25135445Sbostic cleanutmp(p); 2521029Sbill dfork(p); 2531029Sbill } 25418542Sralph } 25523147Sbloom sigsetmask(omask); 2561029Sbill } 2571029Sbill } 2581029Sbill 25913021Ssam /* 26013021Ssam * Merge current contents of ttys file 26113021Ssam * into in-core table of configured tty lines. 26213021Ssam * Entered as signal handler for SIGHUP. 26313021Ssam */ 26413021Ssam #define FOUND 1 26513021Ssam #define CHANGE 2 26618542Sralph #define WCHANGE 4 26713021Ssam 26813021Ssam merge() 26913021Ssam { 27013021Ssam register struct tab *p; 27116452Sroot register struct ttyent *t; 27223147Sbloom register struct tab *p1; 27313021Ssam 27413021Ssam for (ALL) 27513021Ssam p->xflag = 0; 27616452Sroot setttyent(); 27716452Sroot while (t = getttyent()) { 27816452Sroot if ((t->ty_status & TTY_ON) == 0) 27916452Sroot continue; 28013021Ssam for (ALL) { 28116452Sroot if (SCMPN(p->line, t->ty_name)) 28213021Ssam continue; 28313021Ssam p->xflag |= FOUND; 28416452Sroot if (SCMPN(p->comn, t->ty_getty)) { 28513021Ssam p->xflag |= CHANGE; 28616452Sroot SCPYN(p->comn, t->ty_getty); 28713021Ssam } 28830516Sbostic if (SCMPN(p->wcmd, t->ty_window ? t->ty_window : "")) { 28918542Sralph p->xflag |= WCHANGE|CHANGE; 29018542Sralph SCPYN(p->wcmd, t->ty_window); 29118542Sralph } 29213021Ssam goto contin1; 29313021Ssam } 29418542Sralph 29523147Sbloom /* 29623147Sbloom * Make space for a new one 29723147Sbloom */ 29823147Sbloom p1 = (struct tab *)calloc(1, sizeof(*p1)); 29923147Sbloom if (!p1) { 30023147Sbloom syslog(LOG_ERR, "no space for '%s' !?!", t->ty_name); 30113021Ssam goto contin1; 30213021Ssam } 30323147Sbloom /* 30423147Sbloom * Put new terminal at the end of the linked list. 30523147Sbloom */ 30623147Sbloom if (itab) { 30723147Sbloom for (p = itab; p->next ; p = p->next) 30823147Sbloom ; 30923147Sbloom p->next = p1; 31023147Sbloom } else 31123147Sbloom itab = p1; 31223147Sbloom 31323147Sbloom p = p1; 31423147Sbloom SCPYN(p->line, t->ty_name); 31523147Sbloom p->xflag |= FOUND|CHANGE; 31623147Sbloom SCPYN(p->comn, t->ty_getty); 31730516Sbostic if (t->ty_window && strcmp(t->ty_window, "") != 0) { 31823147Sbloom p->xflag |= WCHANGE; 31923147Sbloom SCPYN(p->wcmd, t->ty_window); 32023147Sbloom } 32113021Ssam contin1: 32213021Ssam ; 32313021Ssam } 32416452Sroot endttyent(); 32523147Sbloom p1 = (struct tab *)0; 32613021Ssam for (ALL) { 32713021Ssam if ((p->xflag&FOUND) == 0) { 32813021Ssam term(p); 32918542Sralph wterm(p); 33023147Sbloom if (p1) 33123147Sbloom p1->next = p->next; 33223147Sbloom else 33323147Sbloom itab = p->next; 33423147Sbloom free(p); 33523147Sbloom p = p1 ? p1 : itab; 33623147Sbloom } else { 33723147Sbloom /* window system should be started first */ 33823147Sbloom if (p->xflag&WCHANGE) { 33923147Sbloom wterm(p); 34023147Sbloom wstart(p); 34123147Sbloom } 34223147Sbloom if (p->xflag&CHANGE) { 34323147Sbloom term(p); 34423147Sbloom dfork(p); 34523147Sbloom } 34613021Ssam } 34723147Sbloom p1 = p; 34813021Ssam } 34913021Ssam } 35013021Ssam 3511029Sbill term(p) 35213021Ssam register struct tab *p; 3531029Sbill { 3541029Sbill 35513021Ssam if (p->pid != 0) { 35635445Sbostic cleanutmp(p); 3571029Sbill kill(p->pid, SIGKILL); 3581029Sbill } 3591029Sbill p->pid = 0; 36018542Sralph /* send SIGHUP to get rid of connections */ 36118542Sralph if (p->wpid > 0) 36218542Sralph kill(p->wpid, SIGHUP); 3631029Sbill } 3641029Sbill 3651029Sbill dfork(p) 36613021Ssam struct tab *p; 3671029Sbill { 3681029Sbill register pid; 3695971Sroot time_t t; 3705971Sroot int dowait = 0; 3711029Sbill 3725971Sroot time(&t); 3735971Sroot p->gettycnt++; 3745971Sroot if ((t - p->gettytime) >= 60) { 3755971Sroot p->gettytime = t; 3765971Sroot p->gettycnt = 1; 37718542Sralph } else if (p->gettycnt >= 5) { 37818542Sralph dowait = 1; 37918542Sralph p->gettytime = t; 38018542Sralph p->gettycnt = 1; 3815971Sroot } 3821029Sbill pid = fork(); 38313021Ssam if (pid == 0) { 3846816Ssam signal(SIGTERM, SIG_DFL); 3856816Ssam signal(SIGHUP, SIG_IGN); 38622181Skarels sigsetmask(0); /* since can be called from masked code */ 3875971Sroot if (dowait) { 38818542Sralph syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line); 38918542Sralph closelog(); 3905971Sroot sleep(30); 3915971Sroot } 39218542Sralph execit(p->comn, p->line); 3931029Sbill exit(0); 3941029Sbill } 3951029Sbill p->pid = pid; 3961029Sbill } 3971029Sbill 39835445Sbostic cleanutmp(p) 39913021Ssam register struct tab *p; 4001029Sbill { 40135445Sbostic if (logout(p->line)) { 40235445Sbostic logwtmp(p->line); 40317582Ssam /* 40417582Ssam * After a proper login force reset 40517582Ssam * of error detection code in dfork. 40617582Ssam */ 40717582Ssam p->gettytime = 0; 40822181Skarels p->windtime = 0; 4091029Sbill } 4101029Sbill } 4111029Sbill 4121029Sbill reset() 4131029Sbill { 41413021Ssam 4151029Sbill longjmp(sjbuf, 1); 4161029Sbill } 4172821Swnj 41813021Ssam jmp_buf idlebuf; 41913021Ssam 42013021Ssam idlehup() 42113021Ssam { 42213021Ssam 42313021Ssam longjmp(idlebuf, 1); 42413021Ssam } 42513021Ssam 4262821Swnj idle() 4272821Swnj { 4282821Swnj register struct tab *p; 4292821Swnj register pid; 4302821Swnj 43113021Ssam signal(SIGHUP, idlehup); 43218542Sralph for (EVER) { 43313021Ssam if (setjmp(idlebuf)) 43413021Ssam return; 4352821Swnj pid = wait((int *) 0); 43613021Ssam if (pid == -1) { 43713021Ssam sigpause(0); 43813021Ssam continue; 4392821Swnj } 44018542Sralph for (ALL) { 44118542Sralph /* if window system dies, mark it for restart */ 44218542Sralph if (p->wpid == pid) 44318542Sralph p->wpid = -1; 44413021Ssam if (p->pid == pid) { 44535445Sbostic cleanutmp(p); 44613021Ssam p->pid = -1; 44713021Ssam } 44818542Sralph } 4492821Swnj } 4502821Swnj } 45118542Sralph 45218542Sralph wterm(p) 45318542Sralph register struct tab *p; 45418542Sralph { 45518542Sralph if (p->wpid != 0) { 45618542Sralph kill(p->wpid, SIGKILL); 45718542Sralph } 45818542Sralph p->wpid = 0; 45918542Sralph } 46018542Sralph 46118542Sralph wstart(p) 46218542Sralph register struct tab *p; 46318542Sralph { 46422181Skarels register pid; 46522181Skarels time_t t; 46622181Skarels int dowait = 0; 46718542Sralph 46822181Skarels time(&t); 46922181Skarels p->windcnt++; 47022181Skarels if ((t - p->windtime) >= 60) { 47122181Skarels p->windtime = t; 47222181Skarels p->windcnt = 1; 47322181Skarels } else if (p->windcnt >= 5) { 47422181Skarels dowait = 1; 47522181Skarels p->windtime = t; 47622181Skarels p->windcnt = 1; 47722181Skarels } 47822181Skarels 47922181Skarels pid = fork(); 48022181Skarels 48122181Skarels if (pid == 0) { 48218542Sralph signal(SIGTERM, SIG_DFL); 48322181Skarels signal(SIGHUP, SIG_IGN); 48422181Skarels sigsetmask(0); /* since can be called from masked code */ 48522181Skarels if (dowait) { 48622181Skarels syslog(LOG_ERR, "'%s %s' failing, sleeping", p->wcmd, p->line); 48722181Skarels closelog(); 48822181Skarels sleep(30); 48922181Skarels } 49018542Sralph execit(p->wcmd, p->line); 49118542Sralph exit(0); 49218542Sralph } 49322181Skarels p->wpid = pid; 49418542Sralph } 49518542Sralph 49622181Skarels #define NARGS 20 /* must be at least 4 */ 49718542Sralph #define ARGLEN 512 /* total size for all the argument strings */ 49818542Sralph 49918542Sralph execit(s, arg) 50018542Sralph char *s; 50118542Sralph char *arg; /* last argument on line */ 50218542Sralph { 50318542Sralph char *argv[NARGS], args[ARGLEN], *envp[1]; 50418542Sralph register char *sp = s; 50518542Sralph register char *ap = args; 50618542Sralph register char c; 50718542Sralph register int i; 50818542Sralph 50918542Sralph /* 51018542Sralph * First we have to set up the argument vector. 51118542Sralph * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2"). 51218542Sralph */ 51318542Sralph for (i = 1; i < NARGS - 2; i++) { 51418542Sralph argv[i] = ap; 51518542Sralph for (EVER) { 51618542Sralph if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) { 51718542Sralph *ap = '\0'; 51818542Sralph goto done; 51918542Sralph } 52018542Sralph if (c == ' ') { 52118542Sralph *ap++ = '\0'; 52218542Sralph while (*sp == ' ') 52318542Sralph sp++; 52418542Sralph if (*sp == '\0') 52518542Sralph goto done; 52618542Sralph break; 52718542Sralph } 52818542Sralph *ap++ = c; 52918542Sralph } 53018542Sralph } 53118542Sralph done: 53218542Sralph argv[0] = argv[1]; 53318542Sralph argv[1] = "-"; 53418542Sralph argv[i+1] = arg; 53518542Sralph argv[i+2] = 0; 53618542Sralph envp[0] = 0; 53718542Sralph execve(argv[0], &argv[1], envp); 53818542Sralph /* report failure of exec */ 53918542Sralph syslog(LOG_ERR, "%s: %m", argv[0]); 54018542Sralph closelog(); 54118542Sralph sleep(10); /* prevent failures from eating machine */ 54218542Sralph } 543