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*37284Sbostic static char sccsid[] = "@(#)init.c 5.14 (Berkeley) 04/02/89"; 921135Sdist #endif not lint 1012682Ssam 111029Sbill #include <sys/types.h> 12*37284Sbostic #include <sys/file.h> 13*37284Sbostic #include <sys/signal.h> 14*37284Sbostic #include <sys/reboot.h> 15*37284Sbostic #include <sys/syslog.h> 16*37284Sbostic #include <sys/stat.h> 171029Sbill #include <setjmp.h> 1835606Sbostic #include <utmp.h> 192821Swnj #include <errno.h> 2016452Sroot #include <ttyent.h> 21*37284Sbostic #include "pathnames.h" 221029Sbill 2324494Skarels #define CMDSIZ 200 /* max string length for getty or window command*/ 2423147Sbloom #define ALL p = itab; p ; p = p->next 251029Sbill #define EVER ;; 261029Sbill #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 271029Sbill #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 281029Sbill 29*37284Sbostic char shell[] = _PATH_BSHELL; 301029Sbill char minus[] = "-"; 31*37284Sbostic char runc[] = _PATH_RC; 32*37284Sbostic char utmpf[] = _PATH_UTMP; 33*37284Sbostic 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 int reset(); 562821Swnj int idle(); 571029Sbill char *strcpy(), *strcat(); 581029Sbill long lseek(); 591029Sbill 6018542Sralph struct sigvec rvec = { reset, sigmask(SIGHUP), 0 }; 6113021Ssam 6223147Sbloom 6329836Ssam #if defined(vax) || defined(tahoe) 641029Sbill main() 651029Sbill { 6629836Ssam #if defined(tahoe) 6729836Ssam register int r12; /* make sure r11 gets bootflags */ 6829836Ssam #endif 691403Sbill register int r11; /* passed thru from boot */ 7013021Ssam #else 719869Spugs main(argc, argv) 729869Spugs char **argv; 739869Spugs { 7413021Ssam #endif 751403Sbill int howto, oldhowto; 761403Sbill 7729836Ssam #if defined(vax) || defined(tahoe) 781403Sbill howto = r11; 7913021Ssam #else 809869Spugs if (argc > 1 && argv[1][0] == '-') { 819869Spugs char *cp; 829869Spugs 839869Spugs howto = 0; 849869Spugs cp = &argv[1][1]; 859869Spugs while (*cp) switch (*cp++) { 869869Spugs case 'a': 879869Spugs howto |= RB_ASKNAME; 889869Spugs break; 899869Spugs case 's': 909869Spugs howto |= RB_SINGLE; 919869Spugs break; 929869Spugs } 939869Spugs } else { 949869Spugs howto = RB_SINGLE; 959869Spugs } 9613021Ssam #endif 9724854Seric openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH); 9813021Ssam sigvec(SIGTERM, &rvec, (struct sigvec *)0); 992821Swnj signal(SIGTSTP, idle); 1001029Sbill signal(SIGSTOP, SIG_IGN); 1011029Sbill signal(SIGTTIN, SIG_IGN); 1021029Sbill signal(SIGTTOU, SIG_IGN); 10313021Ssam (void) setjmp(sjbuf); 10413021Ssam for (EVER) { 1051403Sbill oldhowto = howto; 1061403Sbill howto = RB_SINGLE; 1071429Sbill if (setjmp(shutpass) == 0) 1081429Sbill shutdown(); 1091403Sbill if (oldhowto & RB_SINGLE) 1101403Sbill single(); 1111403Sbill if (runcom(oldhowto) == 0) 1121403Sbill continue; 1131029Sbill merge(); 1141029Sbill multiple(); 1151029Sbill } 1161029Sbill } 1171029Sbill 1181429Sbill int shutreset(); 1191429Sbill 1201029Sbill shutdown() 1211029Sbill { 1221029Sbill register i; 12323147Sbloom register struct tab *p, *p1; 1241029Sbill 12523147Sbloom close(creat(utmpf, 0644)); 1261029Sbill signal(SIGHUP, SIG_IGN); 12723147Sbloom for (p = itab; p ; ) { 1281029Sbill term(p); 12923147Sbloom p1 = p->next; 13023147Sbloom free(p); 13123147Sbloom p = p1; 1321029Sbill } 13323147Sbloom itab = (struct tab *)0; 1341429Sbill signal(SIGALRM, shutreset); 13528801Skarels (void) kill(-1, SIGTERM); /* one chance to catch it */ 13628801Skarels sleep(5); 1371429Sbill alarm(30); 13813021Ssam for (i = 0; i < 5; i++) 1391029Sbill kill(-1, SIGKILL); 14013021Ssam while (wait((int *)0) != -1) 1411029Sbill ; 1421029Sbill alarm(0); 1431429Sbill shutend(); 1441429Sbill } 1451429Sbill 14630516Sbostic char shutfailm[] = "WARNING: Something is hung (won't die); ps axl advised\n"; 1471429Sbill 1481429Sbill shutreset() 1491429Sbill { 1501429Sbill int status; 1511429Sbill 1521429Sbill if (fork() == 0) { 1531429Sbill int ct = open(ctty, 1); 1541429Sbill write(ct, shutfailm, sizeof (shutfailm)); 1551429Sbill sleep(5); 1561429Sbill exit(1); 1571429Sbill } 1581429Sbill sleep(5); 1591429Sbill shutend(); 1601429Sbill longjmp(shutpass, 1); 1611429Sbill } 1621429Sbill 1631429Sbill shutend() 1641429Sbill { 1652821Swnj register i, f; 1661429Sbill 1672821Swnj acct(0); 1681029Sbill signal(SIGALRM, SIG_DFL); 16913021Ssam for (i = 0; i < 10; i++) 1701029Sbill close(i); 17135606Sbostic logwtmp("~", "shutdown", ""); 1721029Sbill } 1731029Sbill 1741029Sbill single() 1751029Sbill { 1761029Sbill register pid; 1772821Swnj register xpid; 17835606Sbostic extern int errno; 1791029Sbill 18013021Ssam do { 18113021Ssam pid = fork(); 18213021Ssam if (pid == 0) { 18313021Ssam signal(SIGTERM, SIG_DFL); 18413021Ssam signal(SIGHUP, SIG_DFL); 18513021Ssam signal(SIGALRM, SIG_DFL); 18616452Sroot signal(SIGTSTP, SIG_IGN); 18713021Ssam (void) open(ctty, O_RDWR); 18813021Ssam dup2(0, 1); 18913021Ssam dup2(0, 2); 19013021Ssam execl(shell, minus, (char *)0); 19130516Sbostic perror(shell); 19213021Ssam exit(0); 19313021Ssam } 19413021Ssam while ((xpid = wait((int *)0)) != pid) 19513021Ssam if (xpid == -1 && errno == ECHILD) 19613021Ssam break; 19713021Ssam } while (xpid == -1); 1981029Sbill } 1991029Sbill 2001403Sbill runcom(oldhowto) 2011403Sbill int oldhowto; 2021029Sbill { 2031029Sbill register pid, f; 2041403Sbill int status; 2051029Sbill 2061029Sbill pid = fork(); 20713021Ssam if (pid == 0) { 20813021Ssam (void) open("/", O_RDONLY); 20913021Ssam dup2(0, 1); 21013021Ssam dup2(0, 2); 2111403Sbill if (oldhowto & RB_SINGLE) 2121403Sbill execl(shell, shell, runc, (char *)0); 2131403Sbill else 2141403Sbill execl(shell, shell, runc, "autoboot", (char *)0); 2151403Sbill exit(1); 2161029Sbill } 21713021Ssam while (wait(&status) != pid) 2181029Sbill ; 21913021Ssam if (status) 22013021Ssam return (0); 22135606Sbostic logwtmp("~", "reboot", ""); 22213021Ssam return (1); 2231029Sbill } 2241029Sbill 22533302Sbostic int merge(); 22618542Sralph struct sigvec mvec = { merge, sigmask(SIGTERM), 0 }; 22713021Ssam /* 22813021Ssam * Multi-user. Listen for users leaving, SIGHUP's 22913021Ssam * which indicate ttys has changed, and SIGTERM's which 23013021Ssam * are used to shutdown the system. 23113021Ssam */ 2321029Sbill multiple() 2331029Sbill { 2341029Sbill register struct tab *p; 2351029Sbill register pid; 23623147Sbloom int omask; 2371029Sbill 23813021Ssam sigvec(SIGHUP, &mvec, (struct sigvec *)0); 23913021Ssam for (EVER) { 2401029Sbill pid = wait((int *)0); 24113021Ssam if (pid == -1) 2421029Sbill return; 24330516Sbostic omask = sigblock(sigmask(SIGHUP)); 24418542Sralph for (ALL) { 24518542Sralph /* must restart window system BEFORE emulator */ 24618542Sralph if (p->wpid == pid || p->wpid == -1) 24718542Sralph wstart(p); 24813021Ssam if (p->pid == pid || p->pid == -1) { 24918542Sralph /* disown the window system */ 25018542Sralph if (p->wpid) 25118542Sralph kill(p->wpid, SIGHUP); 25235445Sbostic cleanutmp(p); 2531029Sbill dfork(p); 2541029Sbill } 25518542Sralph } 25623147Sbloom sigsetmask(omask); 2571029Sbill } 2581029Sbill } 2591029Sbill 26013021Ssam /* 26113021Ssam * Merge current contents of ttys file 26213021Ssam * into in-core table of configured tty lines. 26313021Ssam * Entered as signal handler for SIGHUP. 26413021Ssam */ 26513021Ssam #define FOUND 1 26613021Ssam #define CHANGE 2 26718542Sralph #define WCHANGE 4 26813021Ssam 26913021Ssam merge() 27013021Ssam { 27113021Ssam register struct tab *p; 27216452Sroot register struct ttyent *t; 27323147Sbloom register struct tab *p1; 27413021Ssam 27513021Ssam for (ALL) 27613021Ssam p->xflag = 0; 27716452Sroot setttyent(); 27816452Sroot while (t = getttyent()) { 27916452Sroot if ((t->ty_status & TTY_ON) == 0) 28016452Sroot continue; 28113021Ssam for (ALL) { 28216452Sroot if (SCMPN(p->line, t->ty_name)) 28313021Ssam continue; 28413021Ssam p->xflag |= FOUND; 28516452Sroot if (SCMPN(p->comn, t->ty_getty)) { 28613021Ssam p->xflag |= CHANGE; 28716452Sroot SCPYN(p->comn, t->ty_getty); 28813021Ssam } 28930516Sbostic if (SCMPN(p->wcmd, t->ty_window ? t->ty_window : "")) { 29018542Sralph p->xflag |= WCHANGE|CHANGE; 29118542Sralph SCPYN(p->wcmd, t->ty_window); 29218542Sralph } 29313021Ssam goto contin1; 29413021Ssam } 29518542Sralph 29623147Sbloom /* 29723147Sbloom * Make space for a new one 29823147Sbloom */ 29923147Sbloom p1 = (struct tab *)calloc(1, sizeof(*p1)); 30023147Sbloom if (!p1) { 30123147Sbloom syslog(LOG_ERR, "no space for '%s' !?!", t->ty_name); 30213021Ssam goto contin1; 30313021Ssam } 30423147Sbloom /* 30523147Sbloom * Put new terminal at the end of the linked list. 30623147Sbloom */ 30723147Sbloom if (itab) { 30823147Sbloom for (p = itab; p->next ; p = p->next) 30923147Sbloom ; 31023147Sbloom p->next = p1; 31123147Sbloom } else 31223147Sbloom itab = p1; 31323147Sbloom 31423147Sbloom p = p1; 31523147Sbloom SCPYN(p->line, t->ty_name); 31623147Sbloom p->xflag |= FOUND|CHANGE; 31723147Sbloom SCPYN(p->comn, t->ty_getty); 31830516Sbostic if (t->ty_window && strcmp(t->ty_window, "") != 0) { 31923147Sbloom p->xflag |= WCHANGE; 32023147Sbloom SCPYN(p->wcmd, t->ty_window); 32123147Sbloom } 32213021Ssam contin1: 32313021Ssam ; 32413021Ssam } 32516452Sroot endttyent(); 32623147Sbloom p1 = (struct tab *)0; 32713021Ssam for (ALL) { 32813021Ssam if ((p->xflag&FOUND) == 0) { 32913021Ssam term(p); 33018542Sralph wterm(p); 33123147Sbloom if (p1) 33223147Sbloom p1->next = p->next; 33323147Sbloom else 33423147Sbloom itab = p->next; 33523147Sbloom free(p); 33623147Sbloom p = p1 ? p1 : itab; 33723147Sbloom } else { 33823147Sbloom /* window system should be started first */ 33923147Sbloom if (p->xflag&WCHANGE) { 34023147Sbloom wterm(p); 34123147Sbloom wstart(p); 34223147Sbloom } 34323147Sbloom if (p->xflag&CHANGE) { 34423147Sbloom term(p); 34523147Sbloom dfork(p); 34623147Sbloom } 34713021Ssam } 34823147Sbloom p1 = p; 34913021Ssam } 35013021Ssam } 35113021Ssam 3521029Sbill term(p) 35313021Ssam register struct tab *p; 3541029Sbill { 3551029Sbill 35613021Ssam if (p->pid != 0) { 35735445Sbostic cleanutmp(p); 3581029Sbill kill(p->pid, SIGKILL); 3591029Sbill } 3601029Sbill p->pid = 0; 36118542Sralph /* send SIGHUP to get rid of connections */ 36218542Sralph if (p->wpid > 0) 36318542Sralph kill(p->wpid, SIGHUP); 3641029Sbill } 3651029Sbill 3661029Sbill dfork(p) 36713021Ssam struct tab *p; 3681029Sbill { 3691029Sbill register pid; 3705971Sroot time_t t; 3715971Sroot int dowait = 0; 3721029Sbill 3735971Sroot time(&t); 3745971Sroot p->gettycnt++; 3755971Sroot if ((t - p->gettytime) >= 60) { 3765971Sroot p->gettytime = t; 3775971Sroot p->gettycnt = 1; 37818542Sralph } else if (p->gettycnt >= 5) { 37918542Sralph dowait = 1; 38018542Sralph p->gettytime = t; 38118542Sralph p->gettycnt = 1; 3825971Sroot } 3831029Sbill pid = fork(); 38413021Ssam if (pid == 0) { 3856816Ssam signal(SIGTERM, SIG_DFL); 3866816Ssam signal(SIGHUP, SIG_IGN); 38722181Skarels sigsetmask(0); /* since can be called from masked code */ 3885971Sroot if (dowait) { 38918542Sralph syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line); 39018542Sralph closelog(); 3915971Sroot sleep(30); 3925971Sroot } 39318542Sralph execit(p->comn, p->line); 3941029Sbill exit(0); 3951029Sbill } 3961029Sbill p->pid = pid; 3971029Sbill } 3981029Sbill 39935445Sbostic cleanutmp(p) 40013021Ssam register struct tab *p; 4011029Sbill { 40235445Sbostic if (logout(p->line)) { 40335445Sbostic logwtmp(p->line); 40417582Ssam /* 40517582Ssam * After a proper login force reset 40617582Ssam * of error detection code in dfork. 40717582Ssam */ 40817582Ssam p->gettytime = 0; 40922181Skarels p->windtime = 0; 4101029Sbill } 4111029Sbill } 4121029Sbill 4131029Sbill reset() 4141029Sbill { 41513021Ssam 4161029Sbill longjmp(sjbuf, 1); 4171029Sbill } 4182821Swnj 41913021Ssam jmp_buf idlebuf; 42013021Ssam 42113021Ssam idlehup() 42213021Ssam { 42313021Ssam 42413021Ssam longjmp(idlebuf, 1); 42513021Ssam } 42613021Ssam 4272821Swnj idle() 4282821Swnj { 4292821Swnj register struct tab *p; 4302821Swnj register pid; 4312821Swnj 43213021Ssam signal(SIGHUP, idlehup); 43318542Sralph for (EVER) { 43413021Ssam if (setjmp(idlebuf)) 43513021Ssam return; 4362821Swnj pid = wait((int *) 0); 43713021Ssam if (pid == -1) { 43813021Ssam sigpause(0); 43913021Ssam continue; 4402821Swnj } 44118542Sralph for (ALL) { 44218542Sralph /* if window system dies, mark it for restart */ 44318542Sralph if (p->wpid == pid) 44418542Sralph p->wpid = -1; 44513021Ssam if (p->pid == pid) { 44635445Sbostic cleanutmp(p); 44713021Ssam p->pid = -1; 44813021Ssam } 44918542Sralph } 4502821Swnj } 4512821Swnj } 45218542Sralph 45318542Sralph wterm(p) 45418542Sralph register struct tab *p; 45518542Sralph { 45618542Sralph if (p->wpid != 0) { 45718542Sralph kill(p->wpid, SIGKILL); 45818542Sralph } 45918542Sralph p->wpid = 0; 46018542Sralph } 46118542Sralph 46218542Sralph wstart(p) 46318542Sralph register struct tab *p; 46418542Sralph { 46522181Skarels register pid; 46622181Skarels time_t t; 46722181Skarels int dowait = 0; 46818542Sralph 46922181Skarels time(&t); 47022181Skarels p->windcnt++; 47122181Skarels if ((t - p->windtime) >= 60) { 47222181Skarels p->windtime = t; 47322181Skarels p->windcnt = 1; 47422181Skarels } else if (p->windcnt >= 5) { 47522181Skarels dowait = 1; 47622181Skarels p->windtime = t; 47722181Skarels p->windcnt = 1; 47822181Skarels } 47922181Skarels 48022181Skarels pid = fork(); 48122181Skarels 48222181Skarels if (pid == 0) { 48318542Sralph signal(SIGTERM, SIG_DFL); 48422181Skarels signal(SIGHUP, SIG_IGN); 48522181Skarels sigsetmask(0); /* since can be called from masked code */ 48622181Skarels if (dowait) { 48722181Skarels syslog(LOG_ERR, "'%s %s' failing, sleeping", p->wcmd, p->line); 48822181Skarels closelog(); 48922181Skarels sleep(30); 49022181Skarels } 49118542Sralph execit(p->wcmd, p->line); 49218542Sralph exit(0); 49318542Sralph } 49422181Skarels p->wpid = pid; 49518542Sralph } 49618542Sralph 49722181Skarels #define NARGS 20 /* must be at least 4 */ 49818542Sralph #define ARGLEN 512 /* total size for all the argument strings */ 49918542Sralph 50018542Sralph execit(s, arg) 50118542Sralph char *s; 50218542Sralph char *arg; /* last argument on line */ 50318542Sralph { 50418542Sralph char *argv[NARGS], args[ARGLEN], *envp[1]; 50518542Sralph register char *sp = s; 50618542Sralph register char *ap = args; 50718542Sralph register char c; 50818542Sralph register int i; 50918542Sralph 51018542Sralph /* 51118542Sralph * First we have to set up the argument vector. 51218542Sralph * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2"). 51318542Sralph */ 51418542Sralph for (i = 1; i < NARGS - 2; i++) { 51518542Sralph argv[i] = ap; 51618542Sralph for (EVER) { 51718542Sralph if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) { 51818542Sralph *ap = '\0'; 51918542Sralph goto done; 52018542Sralph } 52118542Sralph if (c == ' ') { 52218542Sralph *ap++ = '\0'; 52318542Sralph while (*sp == ' ') 52418542Sralph sp++; 52518542Sralph if (*sp == '\0') 52618542Sralph goto done; 52718542Sralph break; 52818542Sralph } 52918542Sralph *ap++ = c; 53018542Sralph } 53118542Sralph } 53218542Sralph done: 53318542Sralph argv[0] = argv[1]; 53418542Sralph argv[1] = "-"; 53518542Sralph argv[i+1] = arg; 53618542Sralph argv[i+2] = 0; 53718542Sralph envp[0] = 0; 53818542Sralph execve(argv[0], &argv[1], envp); 53918542Sralph /* report failure of exec */ 54018542Sralph syslog(LOG_ERR, "%s: %m", argv[0]); 54118542Sralph closelog(); 54218542Sralph sleep(10); /* prevent failures from eating machine */ 54318542Sralph } 544