121135Sdist /* 221135Sdist * Copyright (c) 1980 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*22181Skarels static char sccsid[] = "@(#)init.c 5.2 (Berkeley) 06/05/85"; 921135Sdist #endif not lint 1012682Ssam 111029Sbill #include <signal.h> 121029Sbill #include <sys/types.h> 131029Sbill #include <utmp.h> 141029Sbill #include <setjmp.h> 151403Sbill #include <sys/reboot.h> 162821Swnj #include <errno.h> 1713021Ssam #include <sys/file.h> 1816452Sroot #include <ttyent.h> 1918542Sralph #include <syslog.h> 201029Sbill 211029Sbill #define LINSIZ sizeof(wtmp.ut_line) 2218542Sralph #define CMDSIZ 70 /* max string length for getty or window command*/ 231029Sbill #define TABSIZ 100 241029Sbill #define ALL p = &itab[0]; p < &itab[TABSIZ]; p++ 251029Sbill #define EVER ;; 261029Sbill #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 271029Sbill #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 281029Sbill 291029Sbill char shell[] = "/bin/sh"; 301029Sbill char minus[] = "-"; 311029Sbill char runc[] = "/etc/rc"; 321029Sbill char utmp[] = "/etc/utmp"; 331029Sbill char wtmpf[] = "/usr/adm/wtmp"; 341029Sbill char ctty[] = "/dev/console"; 351029Sbill 361029Sbill struct utmp wtmp; 371029Sbill struct tab 381029Sbill { 391029Sbill char line[LINSIZ]; 4018542Sralph char comn[CMDSIZ]; 411029Sbill char xflag; 421029Sbill int pid; 4318542Sralph int wpid; /* window system pid for SIGHUP */ 4418542Sralph char wcmd[CMDSIZ]; /* command to start window system process */ 455971Sroot time_t gettytime; 465971Sroot int gettycnt; 47*22181Skarels time_t windtime; 48*22181Skarels int windcnt; 491029Sbill } itab[TABSIZ]; 501029Sbill 511029Sbill int fi; 521029Sbill int mergflag; 531029Sbill char tty[20]; 541429Sbill jmp_buf sjbuf, shutpass; 552821Swnj time_t time0; 561029Sbill 571029Sbill int reset(); 582821Swnj int idle(); 591029Sbill char *strcpy(), *strcat(); 601029Sbill long lseek(); 611029Sbill 6218542Sralph struct sigvec rvec = { reset, sigmask(SIGHUP), 0 }; 6313021Ssam 6413021Ssam #ifdef vax 651029Sbill main() 661029Sbill { 671403Sbill register int r11; /* passed thru from boot */ 6813021Ssam #else 699869Spugs main(argc, argv) 709869Spugs char **argv; 719869Spugs { 7213021Ssam #endif 731403Sbill int howto, oldhowto; 741403Sbill 752821Swnj time0 = time(0); 7613021Ssam #ifdef vax 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 9618542Sralph openlog("init", LOG_CONS|LOG_ODELAY, 0); 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; 1221029Sbill register struct tab *p; 1231029Sbill 1241029Sbill close(creat(utmp, 0644)); 1251029Sbill signal(SIGHUP, SIG_IGN); 12613021Ssam for (ALL) { 1271029Sbill term(p); 1281029Sbill p->line[0] = 0; 1291029Sbill } 1301429Sbill signal(SIGALRM, shutreset); 1311429Sbill alarm(30); 13213021Ssam for (i = 0; i < 5; i++) 1331029Sbill kill(-1, SIGKILL); 13413021Ssam while (wait((int *)0) != -1) 1351029Sbill ; 1361029Sbill alarm(0); 1371429Sbill shutend(); 1381429Sbill } 1391429Sbill 1401429Sbill char shutfailm[] = "WARNING: Something is hung (wont die); ps axl advised\n"; 1411429Sbill 1421429Sbill shutreset() 1431429Sbill { 1441429Sbill int status; 1451429Sbill 1461429Sbill if (fork() == 0) { 1471429Sbill int ct = open(ctty, 1); 1481429Sbill write(ct, shutfailm, sizeof (shutfailm)); 1491429Sbill sleep(5); 1501429Sbill exit(1); 1511429Sbill } 1521429Sbill sleep(5); 1531429Sbill shutend(); 1541429Sbill longjmp(shutpass, 1); 1551429Sbill } 1561429Sbill 1571429Sbill shutend() 1581429Sbill { 1592821Swnj register i, f; 1601429Sbill 1612821Swnj acct(0); 1621029Sbill signal(SIGALRM, SIG_DFL); 16313021Ssam for (i = 0; i < 10; i++) 1641029Sbill close(i); 16513021Ssam f = open(wtmpf, O_WRONLY|O_APPEND); 1662821Swnj if (f >= 0) { 1672821Swnj SCPYN(wtmp.ut_line, "~"); 1682821Swnj SCPYN(wtmp.ut_name, "shutdown"); 16912682Ssam SCPYN(wtmp.ut_host, ""); 1702821Swnj time(&wtmp.ut_time); 1712821Swnj write(f, (char *)&wtmp, sizeof(wtmp)); 1722821Swnj close(f); 1732821Swnj } 17413021Ssam return (1); 1751029Sbill } 1761029Sbill 1771029Sbill single() 1781029Sbill { 1791029Sbill register pid; 1802821Swnj register xpid; 1812821Swnj extern 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); 19013021Ssam (void) open(ctty, O_RDWR); 19113021Ssam dup2(0, 1); 19213021Ssam dup2(0, 2); 19313021Ssam execl(shell, minus, (char *)0); 19413021Ssam exit(0); 19513021Ssam } 19613021Ssam while ((xpid = wait((int *)0)) != pid) 19713021Ssam if (xpid == -1 && errno == ECHILD) 19813021Ssam break; 19913021Ssam } while (xpid == -1); 2001029Sbill } 2011029Sbill 2021403Sbill runcom(oldhowto) 2031403Sbill int oldhowto; 2041029Sbill { 2051029Sbill register pid, f; 2061403Sbill int status; 2071029Sbill 2081029Sbill pid = fork(); 20913021Ssam if (pid == 0) { 21013021Ssam (void) open("/", O_RDONLY); 21113021Ssam dup2(0, 1); 21213021Ssam dup2(0, 2); 2131403Sbill if (oldhowto & RB_SINGLE) 2141403Sbill execl(shell, shell, runc, (char *)0); 2151403Sbill else 2161403Sbill execl(shell, shell, runc, "autoboot", (char *)0); 2171403Sbill exit(1); 2181029Sbill } 21913021Ssam while (wait(&status) != pid) 2201029Sbill ; 22113021Ssam if (status) 22213021Ssam return (0); 22313021Ssam f = open(wtmpf, O_WRONLY|O_APPEND); 2241029Sbill if (f >= 0) { 2251029Sbill SCPYN(wtmp.ut_line, "~"); 2261029Sbill SCPYN(wtmp.ut_name, "reboot"); 22712682Ssam SCPYN(wtmp.ut_host, ""); 2282821Swnj if (time0) { 2292821Swnj wtmp.ut_time = time0; 2302821Swnj time0 = 0; 2312821Swnj } else 2322821Swnj time(&wtmp.ut_time); 2331029Sbill write(f, (char *)&wtmp, sizeof(wtmp)); 2341029Sbill close(f); 2351029Sbill } 23613021Ssam return (1); 2371029Sbill } 2381029Sbill 23918542Sralph struct sigvec mvec = { merge, sigmask(SIGTERM), 0 }; 24013021Ssam /* 24113021Ssam * Multi-user. Listen for users leaving, SIGHUP's 24213021Ssam * which indicate ttys has changed, and SIGTERM's which 24313021Ssam * are used to shutdown the system. 24413021Ssam */ 2451029Sbill multiple() 2461029Sbill { 2471029Sbill register struct tab *p; 2481029Sbill register pid; 2491029Sbill 25013021Ssam sigvec(SIGHUP, &mvec, (struct sigvec *)0); 25113021Ssam for (EVER) { 2521029Sbill pid = wait((int *)0); 25313021Ssam if (pid == -1) 2541029Sbill return; 25518542Sralph for (ALL) { 25618542Sralph /* must restart window system BEFORE emulator */ 25718542Sralph if (p->wpid == pid || p->wpid == -1) 25818542Sralph wstart(p); 25913021Ssam if (p->pid == pid || p->pid == -1) { 26018542Sralph /* disown the window system */ 26118542Sralph if (p->wpid) 26218542Sralph kill(p->wpid, SIGHUP); 2631029Sbill rmut(p); 2641029Sbill dfork(p); 2651029Sbill } 26618542Sralph } 2671029Sbill } 2681029Sbill } 2691029Sbill 27013021Ssam /* 27113021Ssam * Merge current contents of ttys file 27213021Ssam * into in-core table of configured tty lines. 27313021Ssam * Entered as signal handler for SIGHUP. 27413021Ssam */ 27513021Ssam #define FOUND 1 27613021Ssam #define CHANGE 2 27718542Sralph #define WCHANGE 4 27813021Ssam 27913021Ssam merge() 28013021Ssam { 28113021Ssam register struct tab *p; 28216452Sroot register struct ttyent *t; 28313021Ssam 28413021Ssam for (ALL) 28513021Ssam p->xflag = 0; 28616452Sroot setttyent(); 28716452Sroot while (t = getttyent()) { 28816452Sroot if ((t->ty_status & TTY_ON) == 0) 28916452Sroot continue; 29013021Ssam for (ALL) { 29116452Sroot if (SCMPN(p->line, t->ty_name)) 29213021Ssam continue; 29313021Ssam p->xflag |= FOUND; 29416452Sroot if (SCMPN(p->comn, t->ty_getty)) { 29513021Ssam p->xflag |= CHANGE; 29616452Sroot SCPYN(p->comn, t->ty_getty); 29713021Ssam } 29818542Sralph if (SCMPN(p->wcmd, t->ty_window)) { 29918542Sralph p->xflag |= WCHANGE|CHANGE; 30018542Sralph SCPYN(p->wcmd, t->ty_window); 30118542Sralph } 30213021Ssam goto contin1; 30313021Ssam } 30418542Sralph 30513021Ssam for (ALL) { 30613021Ssam if (p->line[0] != 0) 30713021Ssam continue; 30816452Sroot SCPYN(p->line, t->ty_name); 30913021Ssam p->xflag |= FOUND|CHANGE; 31016452Sroot SCPYN(p->comn, t->ty_getty); 31118542Sralph if (strcmp(t->ty_window, "") != 0) { 31218542Sralph p->xflag |= WCHANGE; 31318542Sralph SCPYN(p->wcmd, t->ty_window); 31418542Sralph } 31513021Ssam goto contin1; 31613021Ssam } 31713021Ssam contin1: 31813021Ssam ; 31913021Ssam } 32016452Sroot endttyent(); 32113021Ssam for (ALL) { 32213021Ssam if ((p->xflag&FOUND) == 0) { 32313021Ssam term(p); 32413021Ssam p->line[0] = 0; 32518542Sralph wterm(p); 32613021Ssam } 32718542Sralph /* window system should be started first */ 32818542Sralph if (p->xflag&WCHANGE) { 32918542Sralph wterm(p); 33018542Sralph wstart(p); 33118542Sralph } 33213021Ssam if (p->xflag&CHANGE) { 33313021Ssam term(p); 33413021Ssam dfork(p); 33513021Ssam } 33613021Ssam } 33713021Ssam } 33813021Ssam 3391029Sbill term(p) 34013021Ssam register struct tab *p; 3411029Sbill { 3421029Sbill 34313021Ssam if (p->pid != 0) { 3441029Sbill rmut(p); 3451029Sbill kill(p->pid, SIGKILL); 3461029Sbill } 3471029Sbill p->pid = 0; 34818542Sralph /* send SIGHUP to get rid of connections */ 34918542Sralph if (p->wpid > 0) 35018542Sralph kill(p->wpid, SIGHUP); 3511029Sbill } 3521029Sbill 3536816Ssam #include <sys/ioctl.h> 3546816Ssam 3551029Sbill dfork(p) 35613021Ssam struct tab *p; 3571029Sbill { 3581029Sbill register pid; 3595971Sroot time_t t; 3605971Sroot int dowait = 0; 3611029Sbill 3625971Sroot time(&t); 3635971Sroot p->gettycnt++; 3645971Sroot if ((t - p->gettytime) >= 60) { 3655971Sroot p->gettytime = t; 3665971Sroot p->gettycnt = 1; 36718542Sralph } else if (p->gettycnt >= 5) { 36818542Sralph dowait = 1; 36918542Sralph p->gettytime = t; 37018542Sralph p->gettycnt = 1; 3715971Sroot } 3721029Sbill pid = fork(); 37313021Ssam if (pid == 0) { 3746816Ssam signal(SIGTERM, SIG_DFL); 3756816Ssam signal(SIGHUP, SIG_IGN); 376*22181Skarels sigsetmask(0); /* since can be called from masked code */ 3775971Sroot if (dowait) { 37818542Sralph syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line); 37918542Sralph closelog(); 3805971Sroot sleep(30); 3815971Sroot } 38218542Sralph execit(p->comn, p->line); 3831029Sbill exit(0); 3841029Sbill } 3851029Sbill p->pid = pid; 3861029Sbill } 3871029Sbill 38813021Ssam /* 38913021Ssam * Remove utmp entry. 39013021Ssam */ 3911029Sbill rmut(p) 39213021Ssam register struct tab *p; 3931029Sbill { 3941029Sbill register f; 3953608Swnj int found = 0; 3961029Sbill 39713021Ssam f = open(utmp, O_RDWR); 39813021Ssam if (f >= 0) { 39913021Ssam while (read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) { 4003608Swnj if (SCMPN(wtmp.ut_line, p->line) || wtmp.ut_name[0]==0) 4011029Sbill continue; 4021029Sbill lseek(f, -(long)sizeof(wtmp), 1); 4031029Sbill SCPYN(wtmp.ut_name, ""); 40412682Ssam SCPYN(wtmp.ut_host, ""); 4051029Sbill time(&wtmp.ut_time); 4061029Sbill write(f, (char *)&wtmp, sizeof(wtmp)); 4073608Swnj found++; 4081029Sbill } 4091029Sbill close(f); 4101029Sbill } 4113608Swnj if (found) { 41213021Ssam f = open(wtmpf, O_WRONLY|O_APPEND); 4133608Swnj if (f >= 0) { 4143608Swnj SCPYN(wtmp.ut_line, p->line); 4153608Swnj SCPYN(wtmp.ut_name, ""); 41612682Ssam SCPYN(wtmp.ut_host, ""); 4173608Swnj time(&wtmp.ut_time); 4183608Swnj write(f, (char *)&wtmp, sizeof(wtmp)); 4193608Swnj close(f); 4203608Swnj } 42117582Ssam /* 42217582Ssam * After a proper login force reset 42317582Ssam * of error detection code in dfork. 42417582Ssam */ 42517582Ssam p->gettytime = 0; 426*22181Skarels p->windtime = 0; 4271029Sbill } 4281029Sbill } 4291029Sbill 4301029Sbill reset() 4311029Sbill { 43213021Ssam 4331029Sbill longjmp(sjbuf, 1); 4341029Sbill } 4352821Swnj 43613021Ssam jmp_buf idlebuf; 43713021Ssam 43813021Ssam idlehup() 43913021Ssam { 44013021Ssam 44113021Ssam longjmp(idlebuf, 1); 44213021Ssam } 44313021Ssam 4442821Swnj idle() 4452821Swnj { 4462821Swnj register struct tab *p; 4472821Swnj register pid; 4482821Swnj 44913021Ssam signal(SIGHUP, idlehup); 45018542Sralph for (EVER) { 45113021Ssam if (setjmp(idlebuf)) 45213021Ssam return; 4532821Swnj pid = wait((int *) 0); 45413021Ssam if (pid == -1) { 45513021Ssam sigpause(0); 45613021Ssam continue; 4572821Swnj } 45818542Sralph for (ALL) { 45918542Sralph /* if window system dies, mark it for restart */ 46018542Sralph if (p->wpid == pid) 46118542Sralph p->wpid = -1; 46213021Ssam if (p->pid == pid) { 46313021Ssam rmut(p); 46413021Ssam p->pid = -1; 46513021Ssam } 46618542Sralph } 4672821Swnj } 4682821Swnj } 46918542Sralph 47018542Sralph wterm(p) 47118542Sralph register struct tab *p; 47218542Sralph { 47318542Sralph if (p->wpid != 0) { 47418542Sralph kill(p->wpid, SIGKILL); 47518542Sralph } 47618542Sralph p->wpid = 0; 47718542Sralph } 47818542Sralph 47918542Sralph wstart(p) 48018542Sralph register struct tab *p; 48118542Sralph { 482*22181Skarels register pid; 483*22181Skarels time_t t; 484*22181Skarels int dowait = 0; 48518542Sralph 486*22181Skarels time(&t); 487*22181Skarels p->windcnt++; 488*22181Skarels if ((t - p->windtime) >= 60) { 489*22181Skarels p->windtime = t; 490*22181Skarels p->windcnt = 1; 491*22181Skarels } else if (p->windcnt >= 5) { 492*22181Skarels dowait = 1; 493*22181Skarels p->windtime = t; 494*22181Skarels p->windcnt = 1; 495*22181Skarels } 496*22181Skarels 497*22181Skarels pid = fork(); 498*22181Skarels 499*22181Skarels if (pid == 0) { 50018542Sralph signal(SIGTERM, SIG_DFL); 501*22181Skarels signal(SIGHUP, SIG_IGN); 502*22181Skarels sigsetmask(0); /* since can be called from masked code */ 503*22181Skarels if (dowait) { 504*22181Skarels syslog(LOG_ERR, "'%s %s' failing, sleeping", p->wcmd, p->line); 505*22181Skarels closelog(); 506*22181Skarels sleep(30); 507*22181Skarels } 50818542Sralph execit(p->wcmd, p->line); 50918542Sralph exit(0); 51018542Sralph } 511*22181Skarels p->wpid = pid; 51218542Sralph } 51318542Sralph 514*22181Skarels #define NARGS 20 /* must be at least 4 */ 51518542Sralph #define ARGLEN 512 /* total size for all the argument strings */ 51618542Sralph 51718542Sralph execit(s, arg) 51818542Sralph char *s; 51918542Sralph char *arg; /* last argument on line */ 52018542Sralph { 52118542Sralph char *argv[NARGS], args[ARGLEN], *envp[1]; 52218542Sralph register char *sp = s; 52318542Sralph register char *ap = args; 52418542Sralph register char c; 52518542Sralph register int i; 52618542Sralph 52718542Sralph /* 52818542Sralph * First we have to set up the argument vector. 52918542Sralph * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2"). 53018542Sralph */ 53118542Sralph for (i = 1; i < NARGS - 2; i++) { 53218542Sralph argv[i] = ap; 53318542Sralph for (EVER) { 53418542Sralph if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) { 53518542Sralph *ap = '\0'; 53618542Sralph goto done; 53718542Sralph } 53818542Sralph if (c == ' ') { 53918542Sralph *ap++ = '\0'; 54018542Sralph while (*sp == ' ') 54118542Sralph sp++; 54218542Sralph if (*sp == '\0') 54318542Sralph goto done; 54418542Sralph break; 54518542Sralph } 54618542Sralph *ap++ = c; 54718542Sralph } 54818542Sralph } 54918542Sralph done: 55018542Sralph argv[0] = argv[1]; 55118542Sralph argv[1] = "-"; 55218542Sralph argv[i+1] = arg; 55318542Sralph argv[i+2] = 0; 55418542Sralph envp[0] = 0; 55518542Sralph execve(argv[0], &argv[1], envp); 55618542Sralph /* report failure of exec */ 55718542Sralph syslog(LOG_ERR, "%s: %m", argv[0]); 55818542Sralph closelog(); 55918542Sralph sleep(10); /* prevent failures from eating machine */ 56018542Sralph } 561