1*21135Sdist 2*21135Sdist /* 3*21135Sdist * Copyright (c) 1980 Regents of the University of California. 4*21135Sdist * All rights reserved. The Berkeley software License Agreement 5*21135Sdist * specifies the terms and conditions for redistribution. 6*21135Sdist */ 7*21135Sdist 812682Ssam #ifndef lint 9*21135Sdist static char sccsid[] = "@(#)init.c 5.1 (Berkeley) 05/28/85"; 10*21135Sdist #endif not lint 1112682Ssam 121029Sbill #include <signal.h> 131029Sbill #include <sys/types.h> 141029Sbill #include <utmp.h> 151029Sbill #include <setjmp.h> 161403Sbill #include <sys/reboot.h> 172821Swnj #include <errno.h> 1813021Ssam #include <sys/file.h> 1916452Sroot #include <ttyent.h> 2018542Sralph #include <syslog.h> 211029Sbill 221029Sbill #define LINSIZ sizeof(wtmp.ut_line) 2318542Sralph #define CMDSIZ 70 /* max string length for getty or window command*/ 241029Sbill #define TABSIZ 100 251029Sbill #define ALL p = &itab[0]; p < &itab[TABSIZ]; p++ 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"; 331029Sbill char utmp[] = "/etc/utmp"; 341029Sbill char wtmpf[] = "/usr/adm/wtmp"; 351029Sbill char ctty[] = "/dev/console"; 361029Sbill 371029Sbill struct utmp wtmp; 381029Sbill struct tab 391029Sbill { 401029Sbill char line[LINSIZ]; 4118542Sralph char comn[CMDSIZ]; 421029Sbill char xflag; 431029Sbill int pid; 4418542Sralph int wpid; /* window system pid for SIGHUP */ 4518542Sralph char wcmd[CMDSIZ]; /* command to start window system process */ 465971Sroot time_t gettytime; 475971Sroot int gettycnt; 481029Sbill } itab[TABSIZ]; 491029Sbill 501029Sbill int fi; 511029Sbill int mergflag; 521029Sbill char tty[20]; 531429Sbill jmp_buf sjbuf, shutpass; 542821Swnj time_t time0; 551029Sbill 561029Sbill int reset(); 572821Swnj int idle(); 581029Sbill char *strcpy(), *strcat(); 591029Sbill long lseek(); 601029Sbill 6118542Sralph struct sigvec rvec = { reset, sigmask(SIGHUP), 0 }; 6213021Ssam 6313021Ssam #ifdef vax 641029Sbill main() 651029Sbill { 661403Sbill register int r11; /* passed thru from boot */ 6713021Ssam #else 689869Spugs main(argc, argv) 699869Spugs char **argv; 709869Spugs { 7113021Ssam #endif 721403Sbill int howto, oldhowto; 731403Sbill 742821Swnj time0 = time(0); 7513021Ssam #ifdef vax 761403Sbill howto = r11; 7713021Ssam #else 789869Spugs if (argc > 1 && argv[1][0] == '-') { 799869Spugs char *cp; 809869Spugs 819869Spugs howto = 0; 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 9518542Sralph openlog("init", LOG_CONS|LOG_ODELAY, 0); 9613021Ssam sigvec(SIGTERM, &rvec, (struct sigvec *)0); 972821Swnj signal(SIGTSTP, idle); 981029Sbill signal(SIGSTOP, SIG_IGN); 991029Sbill signal(SIGTTIN, SIG_IGN); 1001029Sbill signal(SIGTTOU, SIG_IGN); 10113021Ssam (void) setjmp(sjbuf); 10213021Ssam for (EVER) { 1031403Sbill oldhowto = howto; 1041403Sbill howto = RB_SINGLE; 1051429Sbill if (setjmp(shutpass) == 0) 1061429Sbill shutdown(); 1071403Sbill if (oldhowto & RB_SINGLE) 1081403Sbill single(); 1091403Sbill if (runcom(oldhowto) == 0) 1101403Sbill continue; 1111029Sbill merge(); 1121029Sbill multiple(); 1131029Sbill } 1141029Sbill } 1151029Sbill 1161429Sbill int shutreset(); 1171429Sbill 1181029Sbill shutdown() 1191029Sbill { 1201029Sbill register i; 1211029Sbill register struct tab *p; 1221029Sbill 1231029Sbill close(creat(utmp, 0644)); 1241029Sbill signal(SIGHUP, SIG_IGN); 12513021Ssam for (ALL) { 1261029Sbill term(p); 1271029Sbill p->line[0] = 0; 1281029Sbill } 1291429Sbill signal(SIGALRM, shutreset); 1301429Sbill alarm(30); 13113021Ssam for (i = 0; i < 5; i++) 1321029Sbill kill(-1, SIGKILL); 13313021Ssam while (wait((int *)0) != -1) 1341029Sbill ; 1351029Sbill alarm(0); 1361429Sbill shutend(); 1371429Sbill } 1381429Sbill 1391429Sbill char shutfailm[] = "WARNING: Something is hung (wont die); ps axl advised\n"; 1401429Sbill 1411429Sbill shutreset() 1421429Sbill { 1431429Sbill int status; 1441429Sbill 1451429Sbill if (fork() == 0) { 1461429Sbill int ct = open(ctty, 1); 1471429Sbill write(ct, shutfailm, sizeof (shutfailm)); 1481429Sbill sleep(5); 1491429Sbill exit(1); 1501429Sbill } 1511429Sbill sleep(5); 1521429Sbill shutend(); 1531429Sbill longjmp(shutpass, 1); 1541429Sbill } 1551429Sbill 1561429Sbill shutend() 1571429Sbill { 1582821Swnj register i, f; 1591429Sbill 1602821Swnj acct(0); 1611029Sbill signal(SIGALRM, SIG_DFL); 16213021Ssam for (i = 0; i < 10; i++) 1631029Sbill close(i); 16413021Ssam f = open(wtmpf, O_WRONLY|O_APPEND); 1652821Swnj if (f >= 0) { 1662821Swnj SCPYN(wtmp.ut_line, "~"); 1672821Swnj SCPYN(wtmp.ut_name, "shutdown"); 16812682Ssam SCPYN(wtmp.ut_host, ""); 1692821Swnj time(&wtmp.ut_time); 1702821Swnj write(f, (char *)&wtmp, sizeof(wtmp)); 1712821Swnj close(f); 1722821Swnj } 17313021Ssam return (1); 1741029Sbill } 1751029Sbill 1761029Sbill single() 1771029Sbill { 1781029Sbill register pid; 1792821Swnj register xpid; 1802821Swnj extern errno; 1811029Sbill 18213021Ssam do { 18313021Ssam pid = fork(); 18413021Ssam if (pid == 0) { 18513021Ssam signal(SIGTERM, SIG_DFL); 18613021Ssam signal(SIGHUP, SIG_DFL); 18713021Ssam signal(SIGALRM, SIG_DFL); 18816452Sroot signal(SIGTSTP, SIG_IGN); 18913021Ssam (void) open(ctty, O_RDWR); 19013021Ssam dup2(0, 1); 19113021Ssam dup2(0, 2); 19213021Ssam execl(shell, minus, (char *)0); 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); 22213021Ssam f = open(wtmpf, O_WRONLY|O_APPEND); 2231029Sbill if (f >= 0) { 2241029Sbill SCPYN(wtmp.ut_line, "~"); 2251029Sbill SCPYN(wtmp.ut_name, "reboot"); 22612682Ssam SCPYN(wtmp.ut_host, ""); 2272821Swnj if (time0) { 2282821Swnj wtmp.ut_time = time0; 2292821Swnj time0 = 0; 2302821Swnj } else 2312821Swnj time(&wtmp.ut_time); 2321029Sbill write(f, (char *)&wtmp, sizeof(wtmp)); 2331029Sbill close(f); 2341029Sbill } 23513021Ssam return (1); 2361029Sbill } 2371029Sbill 23818542Sralph struct sigvec mvec = { merge, sigmask(SIGTERM), 0 }; 23913021Ssam /* 24013021Ssam * Multi-user. Listen for users leaving, SIGHUP's 24113021Ssam * which indicate ttys has changed, and SIGTERM's which 24213021Ssam * are used to shutdown the system. 24313021Ssam */ 2441029Sbill multiple() 2451029Sbill { 2461029Sbill register struct tab *p; 2471029Sbill register pid; 2481029Sbill 24913021Ssam sigvec(SIGHUP, &mvec, (struct sigvec *)0); 25013021Ssam for (EVER) { 2511029Sbill pid = wait((int *)0); 25213021Ssam if (pid == -1) 2531029Sbill return; 25418542Sralph for (ALL) { 25518542Sralph /* must restart window system BEFORE emulator */ 25618542Sralph if (p->wpid == pid || p->wpid == -1) 25718542Sralph wstart(p); 25813021Ssam if (p->pid == pid || p->pid == -1) { 25918542Sralph /* disown the window system */ 26018542Sralph if (p->wpid) 26118542Sralph kill(p->wpid, SIGHUP); 2621029Sbill rmut(p); 2631029Sbill dfork(p); 2641029Sbill } 26518542Sralph } 2661029Sbill } 2671029Sbill } 2681029Sbill 26913021Ssam /* 27013021Ssam * Merge current contents of ttys file 27113021Ssam * into in-core table of configured tty lines. 27213021Ssam * Entered as signal handler for SIGHUP. 27313021Ssam */ 27413021Ssam #define FOUND 1 27513021Ssam #define CHANGE 2 27618542Sralph #define WCHANGE 4 27713021Ssam 27813021Ssam merge() 27913021Ssam { 28013021Ssam register struct tab *p; 28116452Sroot register struct ttyent *t; 28213021Ssam 28313021Ssam for (ALL) 28413021Ssam p->xflag = 0; 28516452Sroot setttyent(); 28616452Sroot while (t = getttyent()) { 28716452Sroot if ((t->ty_status & TTY_ON) == 0) 28816452Sroot continue; 28913021Ssam for (ALL) { 29016452Sroot if (SCMPN(p->line, t->ty_name)) 29113021Ssam continue; 29213021Ssam p->xflag |= FOUND; 29316452Sroot if (SCMPN(p->comn, t->ty_getty)) { 29413021Ssam p->xflag |= CHANGE; 29516452Sroot SCPYN(p->comn, t->ty_getty); 29613021Ssam } 29718542Sralph if (SCMPN(p->wcmd, t->ty_window)) { 29818542Sralph p->xflag |= WCHANGE|CHANGE; 29918542Sralph SCPYN(p->wcmd, t->ty_window); 30018542Sralph } 30113021Ssam goto contin1; 30213021Ssam } 30318542Sralph 30413021Ssam for (ALL) { 30513021Ssam if (p->line[0] != 0) 30613021Ssam continue; 30716452Sroot SCPYN(p->line, t->ty_name); 30813021Ssam p->xflag |= FOUND|CHANGE; 30916452Sroot SCPYN(p->comn, t->ty_getty); 31018542Sralph if (strcmp(t->ty_window, "") != 0) { 31118542Sralph p->xflag |= WCHANGE; 31218542Sralph SCPYN(p->wcmd, t->ty_window); 31318542Sralph } 31413021Ssam goto contin1; 31513021Ssam } 31613021Ssam contin1: 31713021Ssam ; 31813021Ssam } 31916452Sroot endttyent(); 32013021Ssam for (ALL) { 32113021Ssam if ((p->xflag&FOUND) == 0) { 32213021Ssam term(p); 32313021Ssam p->line[0] = 0; 32418542Sralph wterm(p); 32513021Ssam } 32618542Sralph /* window system should be started first */ 32718542Sralph if (p->xflag&WCHANGE) { 32818542Sralph wterm(p); 32918542Sralph wstart(p); 33018542Sralph } 33113021Ssam if (p->xflag&CHANGE) { 33213021Ssam term(p); 33313021Ssam dfork(p); 33413021Ssam } 33513021Ssam } 33613021Ssam } 33713021Ssam 3381029Sbill term(p) 33913021Ssam register struct tab *p; 3401029Sbill { 3411029Sbill 34213021Ssam if (p->pid != 0) { 3431029Sbill rmut(p); 3441029Sbill kill(p->pid, SIGKILL); 3451029Sbill } 3461029Sbill p->pid = 0; 34718542Sralph /* send SIGHUP to get rid of connections */ 34818542Sralph if (p->wpid > 0) 34918542Sralph kill(p->wpid, SIGHUP); 3501029Sbill } 3511029Sbill 3526816Ssam #include <sys/ioctl.h> 3536816Ssam 3541029Sbill dfork(p) 35513021Ssam struct tab *p; 3561029Sbill { 3571029Sbill register pid; 3585971Sroot time_t t; 3595971Sroot int dowait = 0; 3601029Sbill 3615971Sroot time(&t); 3625971Sroot p->gettycnt++; 3635971Sroot if ((t - p->gettytime) >= 60) { 3645971Sroot p->gettytime = t; 3655971Sroot p->gettycnt = 1; 36618542Sralph } else if (p->gettycnt >= 5) { 36718542Sralph dowait = 1; 36818542Sralph p->gettytime = t; 36918542Sralph p->gettycnt = 1; 3705971Sroot } 3711029Sbill pid = fork(); 37213021Ssam if (pid == 0) { 3736816Ssam signal(SIGTERM, SIG_DFL); 3746816Ssam signal(SIGHUP, SIG_IGN); 3755971Sroot if (dowait) { 37618542Sralph syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line); 37718542Sralph closelog(); 3785971Sroot sleep(30); 3795971Sroot } 38018542Sralph execit(p->comn, p->line); 3811029Sbill exit(0); 3821029Sbill } 3831029Sbill p->pid = pid; 3841029Sbill } 3851029Sbill 38613021Ssam /* 38713021Ssam * Remove utmp entry. 38813021Ssam */ 3891029Sbill rmut(p) 39013021Ssam register struct tab *p; 3911029Sbill { 3921029Sbill register f; 3933608Swnj int found = 0; 3941029Sbill 39513021Ssam f = open(utmp, O_RDWR); 39613021Ssam if (f >= 0) { 39713021Ssam while (read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) { 3983608Swnj if (SCMPN(wtmp.ut_line, p->line) || wtmp.ut_name[0]==0) 3991029Sbill continue; 4001029Sbill lseek(f, -(long)sizeof(wtmp), 1); 4011029Sbill SCPYN(wtmp.ut_name, ""); 40212682Ssam SCPYN(wtmp.ut_host, ""); 4031029Sbill time(&wtmp.ut_time); 4041029Sbill write(f, (char *)&wtmp, sizeof(wtmp)); 4053608Swnj found++; 4061029Sbill } 4071029Sbill close(f); 4081029Sbill } 4093608Swnj if (found) { 41013021Ssam f = open(wtmpf, O_WRONLY|O_APPEND); 4113608Swnj if (f >= 0) { 4123608Swnj SCPYN(wtmp.ut_line, p->line); 4133608Swnj SCPYN(wtmp.ut_name, ""); 41412682Ssam SCPYN(wtmp.ut_host, ""); 4153608Swnj time(&wtmp.ut_time); 4163608Swnj write(f, (char *)&wtmp, sizeof(wtmp)); 4173608Swnj close(f); 4183608Swnj } 41917582Ssam /* 42017582Ssam * After a proper login force reset 42117582Ssam * of error detection code in dfork. 42217582Ssam */ 42317582Ssam p->gettytime = 0; 4241029Sbill } 4251029Sbill } 4261029Sbill 4271029Sbill reset() 4281029Sbill { 42913021Ssam 4301029Sbill longjmp(sjbuf, 1); 4311029Sbill } 4322821Swnj 43313021Ssam jmp_buf idlebuf; 43413021Ssam 43513021Ssam idlehup() 43613021Ssam { 43713021Ssam 43813021Ssam longjmp(idlebuf, 1); 43913021Ssam } 44013021Ssam 4412821Swnj idle() 4422821Swnj { 4432821Swnj register struct tab *p; 4442821Swnj register pid; 4452821Swnj 44613021Ssam signal(SIGHUP, idlehup); 44718542Sralph for (EVER) { 44813021Ssam if (setjmp(idlebuf)) 44913021Ssam return; 4502821Swnj pid = wait((int *) 0); 45113021Ssam if (pid == -1) { 45213021Ssam sigpause(0); 45313021Ssam continue; 4542821Swnj } 45518542Sralph for (ALL) { 45618542Sralph /* if window system dies, mark it for restart */ 45718542Sralph if (p->wpid == pid) 45818542Sralph p->wpid = -1; 45913021Ssam if (p->pid == pid) { 46013021Ssam rmut(p); 46113021Ssam p->pid = -1; 46213021Ssam } 46318542Sralph } 4642821Swnj } 4652821Swnj } 46618542Sralph 46718542Sralph wterm(p) 46818542Sralph register struct tab *p; 46918542Sralph { 47018542Sralph if (p->wpid != 0) { 47118542Sralph kill(p->wpid, SIGKILL); 47218542Sralph } 47318542Sralph p->wpid = 0; 47418542Sralph } 47518542Sralph 47618542Sralph wstart(p) 47718542Sralph register struct tab *p; 47818542Sralph { 47918542Sralph int npid = fork(); 48018542Sralph 48118542Sralph if (npid == 0) { 48218542Sralph /* 48318542Sralph signal(SIGTERM, SIG_DFL); 48418542Sralph signal(SIGHUP, SIG_DFL); 48518542Sralph signal(SIGALRM, SIG_DFL); 48618542Sralph signal(SIGTSTP, SIG_IGN); 48718542Sralph */ 48818542Sralph execit(p->wcmd, p->line); 48918542Sralph exit(0); 49018542Sralph } 49118542Sralph p->wpid = npid; 49218542Sralph } 49318542Sralph 49418542Sralph #define NARGS 20 /* must be at lease 4 */ 49518542Sralph #define ARGLEN 512 /* total size for all the argument strings */ 49618542Sralph 49718542Sralph execit(s, arg) 49818542Sralph char *s; 49918542Sralph char *arg; /* last argument on line */ 50018542Sralph { 50118542Sralph char *argv[NARGS], args[ARGLEN], *envp[1]; 50218542Sralph register char *sp = s; 50318542Sralph register char *ap = args; 50418542Sralph register char c; 50518542Sralph register int i; 50618542Sralph 50718542Sralph /* 50818542Sralph * First we have to set up the argument vector. 50918542Sralph * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2"). 51018542Sralph */ 51118542Sralph for (i = 1; i < NARGS - 2; i++) { 51218542Sralph argv[i] = ap; 51318542Sralph for (EVER) { 51418542Sralph if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) { 51518542Sralph *ap = '\0'; 51618542Sralph goto done; 51718542Sralph } 51818542Sralph if (c == ' ') { 51918542Sralph *ap++ = '\0'; 52018542Sralph while (*sp == ' ') 52118542Sralph sp++; 52218542Sralph if (*sp == '\0') 52318542Sralph goto done; 52418542Sralph break; 52518542Sralph } 52618542Sralph *ap++ = c; 52718542Sralph } 52818542Sralph } 52918542Sralph done: 53018542Sralph argv[0] = argv[1]; 53118542Sralph argv[1] = "-"; 53218542Sralph argv[i+1] = arg; 53318542Sralph argv[i+2] = 0; 53418542Sralph envp[0] = 0; 53518542Sralph execve(argv[0], &argv[1], envp); 53618542Sralph /* report failure of exec */ 53718542Sralph syslog(LOG_ERR, "%s: %m", argv[0]); 53818542Sralph closelog(); 53918542Sralph sleep(10); /* prevent failures from eating machine */ 54018542Sralph } 541