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*24494Skarels static char sccsid[] = "@(#)init.c 5.4 (Berkeley) 08/30/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> 2023147Sbloom #include <sys/stat.h> 211029Sbill 221029Sbill #define LINSIZ sizeof(wtmp.ut_line) 23*24494Skarels #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 291029Sbill char shell[] = "/bin/sh"; 301029Sbill char minus[] = "-"; 311029Sbill char runc[] = "/etc/rc"; 3223147Sbloom char utmpf[] = "/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; 4722181Skarels time_t windtime; 4822181Skarels int windcnt; 4923147Sbloom struct tab *next; 5023147Sbloom } *itab; 511029Sbill 521029Sbill int fi; 531029Sbill int mergflag; 541029Sbill char tty[20]; 551429Sbill jmp_buf sjbuf, shutpass; 562821Swnj time_t time0; 571029Sbill 581029Sbill int reset(); 592821Swnj int idle(); 601029Sbill char *strcpy(), *strcat(); 611029Sbill long lseek(); 621029Sbill 6318542Sralph struct sigvec rvec = { reset, sigmask(SIGHUP), 0 }; 6413021Ssam 6523147Sbloom 6613021Ssam #ifdef vax 671029Sbill main() 681029Sbill { 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 772821Swnj time0 = time(0); 7813021Ssam #ifdef vax 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 9818542Sralph openlog("init", LOG_CONS|LOG_ODELAY, 0); 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); 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 1451429Sbill char shutfailm[] = "WARNING: Something is hung (wont 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); 17013021Ssam f = open(wtmpf, O_WRONLY|O_APPEND); 1712821Swnj if (f >= 0) { 1722821Swnj SCPYN(wtmp.ut_line, "~"); 1732821Swnj SCPYN(wtmp.ut_name, "shutdown"); 17412682Ssam SCPYN(wtmp.ut_host, ""); 1752821Swnj time(&wtmp.ut_time); 1762821Swnj write(f, (char *)&wtmp, sizeof(wtmp)); 1772821Swnj close(f); 1782821Swnj } 17913021Ssam return (1); 1801029Sbill } 1811029Sbill 1821029Sbill single() 1831029Sbill { 1841029Sbill register pid; 1852821Swnj register xpid; 1862821Swnj extern errno; 1871029Sbill 18813021Ssam do { 18913021Ssam pid = fork(); 19013021Ssam if (pid == 0) { 19113021Ssam signal(SIGTERM, SIG_DFL); 19213021Ssam signal(SIGHUP, SIG_DFL); 19313021Ssam signal(SIGALRM, SIG_DFL); 19416452Sroot signal(SIGTSTP, SIG_IGN); 19513021Ssam (void) open(ctty, O_RDWR); 19613021Ssam dup2(0, 1); 19713021Ssam dup2(0, 2); 19813021Ssam execl(shell, minus, (char *)0); 19913021Ssam exit(0); 20013021Ssam } 20113021Ssam while ((xpid = wait((int *)0)) != pid) 20213021Ssam if (xpid == -1 && errno == ECHILD) 20313021Ssam break; 20413021Ssam } while (xpid == -1); 2051029Sbill } 2061029Sbill 2071403Sbill runcom(oldhowto) 2081403Sbill int oldhowto; 2091029Sbill { 2101029Sbill register pid, f; 2111403Sbill int status; 2121029Sbill 2131029Sbill pid = fork(); 21413021Ssam if (pid == 0) { 21513021Ssam (void) open("/", O_RDONLY); 21613021Ssam dup2(0, 1); 21713021Ssam dup2(0, 2); 2181403Sbill if (oldhowto & RB_SINGLE) 2191403Sbill execl(shell, shell, runc, (char *)0); 2201403Sbill else 2211403Sbill execl(shell, shell, runc, "autoboot", (char *)0); 2221403Sbill exit(1); 2231029Sbill } 22413021Ssam while (wait(&status) != pid) 2251029Sbill ; 22613021Ssam if (status) 22713021Ssam return (0); 22813021Ssam f = open(wtmpf, O_WRONLY|O_APPEND); 2291029Sbill if (f >= 0) { 2301029Sbill SCPYN(wtmp.ut_line, "~"); 2311029Sbill SCPYN(wtmp.ut_name, "reboot"); 23212682Ssam SCPYN(wtmp.ut_host, ""); 2332821Swnj if (time0) { 2342821Swnj wtmp.ut_time = time0; 2352821Swnj time0 = 0; 2362821Swnj } else 2372821Swnj time(&wtmp.ut_time); 2381029Sbill write(f, (char *)&wtmp, sizeof(wtmp)); 2391029Sbill close(f); 2401029Sbill } 24113021Ssam return (1); 2421029Sbill } 2431029Sbill 24418542Sralph struct sigvec mvec = { merge, sigmask(SIGTERM), 0 }; 24513021Ssam /* 24613021Ssam * Multi-user. Listen for users leaving, SIGHUP's 24713021Ssam * which indicate ttys has changed, and SIGTERM's which 24813021Ssam * are used to shutdown the system. 24913021Ssam */ 2501029Sbill multiple() 2511029Sbill { 2521029Sbill register struct tab *p; 2531029Sbill register pid; 25423147Sbloom int omask; 2551029Sbill 25613021Ssam sigvec(SIGHUP, &mvec, (struct sigvec *)0); 25713021Ssam for (EVER) { 2581029Sbill pid = wait((int *)0); 25913021Ssam if (pid == -1) 2601029Sbill return; 26123147Sbloom omask = sigblock(SIGHUP); 26218542Sralph for (ALL) { 26318542Sralph /* must restart window system BEFORE emulator */ 26418542Sralph if (p->wpid == pid || p->wpid == -1) 26518542Sralph wstart(p); 26613021Ssam if (p->pid == pid || p->pid == -1) { 26718542Sralph /* disown the window system */ 26818542Sralph if (p->wpid) 26918542Sralph kill(p->wpid, SIGHUP); 2701029Sbill rmut(p); 2711029Sbill dfork(p); 2721029Sbill } 27318542Sralph } 27423147Sbloom sigsetmask(omask); 2751029Sbill } 2761029Sbill } 2771029Sbill 27813021Ssam /* 27913021Ssam * Merge current contents of ttys file 28013021Ssam * into in-core table of configured tty lines. 28113021Ssam * Entered as signal handler for SIGHUP. 28213021Ssam */ 28313021Ssam #define FOUND 1 28413021Ssam #define CHANGE 2 28518542Sralph #define WCHANGE 4 28613021Ssam 28713021Ssam merge() 28813021Ssam { 28913021Ssam register struct tab *p; 29016452Sroot register struct ttyent *t; 29123147Sbloom register struct tab *p1; 29213021Ssam 29313021Ssam for (ALL) 29413021Ssam p->xflag = 0; 29516452Sroot setttyent(); 29616452Sroot while (t = getttyent()) { 29716452Sroot if ((t->ty_status & TTY_ON) == 0) 29816452Sroot continue; 29913021Ssam for (ALL) { 30016452Sroot if (SCMPN(p->line, t->ty_name)) 30113021Ssam continue; 30213021Ssam p->xflag |= FOUND; 30316452Sroot if (SCMPN(p->comn, t->ty_getty)) { 30413021Ssam p->xflag |= CHANGE; 30516452Sroot SCPYN(p->comn, t->ty_getty); 30613021Ssam } 30718542Sralph if (SCMPN(p->wcmd, t->ty_window)) { 30818542Sralph p->xflag |= WCHANGE|CHANGE; 30918542Sralph SCPYN(p->wcmd, t->ty_window); 31018542Sralph } 31113021Ssam goto contin1; 31213021Ssam } 31318542Sralph 31423147Sbloom /* 31523147Sbloom * Make space for a new one 31623147Sbloom */ 31723147Sbloom p1 = (struct tab *)calloc(1, sizeof(*p1)); 31823147Sbloom if (!p1) { 31923147Sbloom syslog(LOG_ERR, "no space for '%s' !?!", t->ty_name); 32013021Ssam goto contin1; 32113021Ssam } 32223147Sbloom /* 32323147Sbloom * Put new terminal at the end of the linked list. 32423147Sbloom */ 32523147Sbloom if (itab) { 32623147Sbloom for (p = itab; p->next ; p = p->next) 32723147Sbloom ; 32823147Sbloom p->next = p1; 32923147Sbloom } else 33023147Sbloom itab = p1; 33123147Sbloom 33223147Sbloom p = p1; 33323147Sbloom SCPYN(p->line, t->ty_name); 33423147Sbloom p->xflag |= FOUND|CHANGE; 33523147Sbloom SCPYN(p->comn, t->ty_getty); 33623147Sbloom if (strcmp(t->ty_window, "") != 0) { 33723147Sbloom p->xflag |= WCHANGE; 33823147Sbloom SCPYN(p->wcmd, t->ty_window); 33923147Sbloom } 34013021Ssam contin1: 34113021Ssam ; 34213021Ssam } 34316452Sroot endttyent(); 34423147Sbloom p1 = (struct tab *)0; 34513021Ssam for (ALL) { 34613021Ssam if ((p->xflag&FOUND) == 0) { 34713021Ssam term(p); 34818542Sralph wterm(p); 34923147Sbloom if (p1) 35023147Sbloom p1->next = p->next; 35123147Sbloom else 35223147Sbloom itab = p->next; 35323147Sbloom free(p); 35423147Sbloom p = p1 ? p1 : itab; 35523147Sbloom } else { 35623147Sbloom /* window system should be started first */ 35723147Sbloom if (p->xflag&WCHANGE) { 35823147Sbloom wterm(p); 35923147Sbloom wstart(p); 36023147Sbloom } 36123147Sbloom if (p->xflag&CHANGE) { 36223147Sbloom term(p); 36323147Sbloom dfork(p); 36423147Sbloom } 36513021Ssam } 36623147Sbloom p1 = p; 36713021Ssam } 36813021Ssam } 36913021Ssam 3701029Sbill term(p) 37113021Ssam register struct tab *p; 3721029Sbill { 3731029Sbill 37413021Ssam if (p->pid != 0) { 3751029Sbill rmut(p); 3761029Sbill kill(p->pid, SIGKILL); 3771029Sbill } 3781029Sbill p->pid = 0; 37918542Sralph /* send SIGHUP to get rid of connections */ 38018542Sralph if (p->wpid > 0) 38118542Sralph kill(p->wpid, SIGHUP); 3821029Sbill } 3831029Sbill 3846816Ssam #include <sys/ioctl.h> 3856816Ssam 3861029Sbill dfork(p) 38713021Ssam struct tab *p; 3881029Sbill { 3891029Sbill register pid; 3905971Sroot time_t t; 3915971Sroot int dowait = 0; 3921029Sbill 3935971Sroot time(&t); 3945971Sroot p->gettycnt++; 3955971Sroot if ((t - p->gettytime) >= 60) { 3965971Sroot p->gettytime = t; 3975971Sroot p->gettycnt = 1; 39818542Sralph } else if (p->gettycnt >= 5) { 39918542Sralph dowait = 1; 40018542Sralph p->gettytime = t; 40118542Sralph p->gettycnt = 1; 4025971Sroot } 4031029Sbill pid = fork(); 40413021Ssam if (pid == 0) { 4056816Ssam signal(SIGTERM, SIG_DFL); 4066816Ssam signal(SIGHUP, SIG_IGN); 40722181Skarels sigsetmask(0); /* since can be called from masked code */ 4085971Sroot if (dowait) { 40918542Sralph syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line); 41018542Sralph closelog(); 4115971Sroot sleep(30); 4125971Sroot } 41318542Sralph execit(p->comn, p->line); 4141029Sbill exit(0); 4151029Sbill } 4161029Sbill p->pid = pid; 4171029Sbill } 4181029Sbill 41913021Ssam /* 42013021Ssam * Remove utmp entry. 42113021Ssam */ 4221029Sbill rmut(p) 42313021Ssam register struct tab *p; 4241029Sbill { 4251029Sbill register f; 4263608Swnj int found = 0; 42723147Sbloom static unsigned utmpsize; 42823147Sbloom static struct utmp *utmp; 42923147Sbloom register struct utmp *u; 43023147Sbloom int nutmp; 43123147Sbloom struct stat statbf; 4321029Sbill 43323147Sbloom f = open(utmpf, O_RDWR); 43413021Ssam if (f >= 0) { 43523147Sbloom fstat(f, &statbf); 43623147Sbloom if (utmpsize < statbf.st_size) { 43723147Sbloom utmpsize = statbf.st_size + 10 * sizeof(struct utmp); 43823147Sbloom if (utmp) 43923147Sbloom utmp = (struct utmp *)realloc(utmp, utmpsize); 44023147Sbloom else 44123147Sbloom utmp = (struct utmp *)malloc(utmpsize); 44223147Sbloom if (!utmp) 44323147Sbloom syslog(LOG_ERR, "utmp malloc failed"); 4441029Sbill } 44523147Sbloom if (statbf.st_size && utmp) { 44623147Sbloom nutmp = read(f, utmp, statbf.st_size); 44723147Sbloom nutmp /= sizeof(struct utmp); 44823147Sbloom for (u = utmp ; u < &utmp[nutmp] ; u++) { 44923147Sbloom if (SCMPN(u->ut_line, p->line) || 45023147Sbloom u->ut_name[0]==0) 45123147Sbloom continue; 45223147Sbloom lseek(f, ((long)u)-((long)utmp), L_SET); 45323147Sbloom SCPYN(u->ut_name, ""); 45423147Sbloom SCPYN(u->ut_host, ""); 45523147Sbloom time(&u->ut_time); 45623147Sbloom write(f, (char *)u, sizeof(*u)); 45723147Sbloom found++; 45823147Sbloom } 45923147Sbloom } 4601029Sbill close(f); 4611029Sbill } 4623608Swnj if (found) { 46313021Ssam f = open(wtmpf, O_WRONLY|O_APPEND); 4643608Swnj if (f >= 0) { 4653608Swnj SCPYN(wtmp.ut_line, p->line); 4663608Swnj SCPYN(wtmp.ut_name, ""); 46712682Ssam SCPYN(wtmp.ut_host, ""); 4683608Swnj time(&wtmp.ut_time); 4693608Swnj write(f, (char *)&wtmp, sizeof(wtmp)); 4703608Swnj close(f); 4713608Swnj } 47217582Ssam /* 47317582Ssam * After a proper login force reset 47417582Ssam * of error detection code in dfork. 47517582Ssam */ 47617582Ssam p->gettytime = 0; 47722181Skarels p->windtime = 0; 4781029Sbill } 4791029Sbill } 4801029Sbill 4811029Sbill reset() 4821029Sbill { 48313021Ssam 4841029Sbill longjmp(sjbuf, 1); 4851029Sbill } 4862821Swnj 48713021Ssam jmp_buf idlebuf; 48813021Ssam 48913021Ssam idlehup() 49013021Ssam { 49113021Ssam 49213021Ssam longjmp(idlebuf, 1); 49313021Ssam } 49413021Ssam 4952821Swnj idle() 4962821Swnj { 4972821Swnj register struct tab *p; 4982821Swnj register pid; 4992821Swnj 50013021Ssam signal(SIGHUP, idlehup); 50118542Sralph for (EVER) { 50213021Ssam if (setjmp(idlebuf)) 50313021Ssam return; 5042821Swnj pid = wait((int *) 0); 50513021Ssam if (pid == -1) { 50613021Ssam sigpause(0); 50713021Ssam continue; 5082821Swnj } 50918542Sralph for (ALL) { 51018542Sralph /* if window system dies, mark it for restart */ 51118542Sralph if (p->wpid == pid) 51218542Sralph p->wpid = -1; 51313021Ssam if (p->pid == pid) { 51413021Ssam rmut(p); 51513021Ssam p->pid = -1; 51613021Ssam } 51718542Sralph } 5182821Swnj } 5192821Swnj } 52018542Sralph 52118542Sralph wterm(p) 52218542Sralph register struct tab *p; 52318542Sralph { 52418542Sralph if (p->wpid != 0) { 52518542Sralph kill(p->wpid, SIGKILL); 52618542Sralph } 52718542Sralph p->wpid = 0; 52818542Sralph } 52918542Sralph 53018542Sralph wstart(p) 53118542Sralph register struct tab *p; 53218542Sralph { 53322181Skarels register pid; 53422181Skarels time_t t; 53522181Skarels int dowait = 0; 53618542Sralph 53722181Skarels time(&t); 53822181Skarels p->windcnt++; 53922181Skarels if ((t - p->windtime) >= 60) { 54022181Skarels p->windtime = t; 54122181Skarels p->windcnt = 1; 54222181Skarels } else if (p->windcnt >= 5) { 54322181Skarels dowait = 1; 54422181Skarels p->windtime = t; 54522181Skarels p->windcnt = 1; 54622181Skarels } 54722181Skarels 54822181Skarels pid = fork(); 54922181Skarels 55022181Skarels if (pid == 0) { 55118542Sralph signal(SIGTERM, SIG_DFL); 55222181Skarels signal(SIGHUP, SIG_IGN); 55322181Skarels sigsetmask(0); /* since can be called from masked code */ 55422181Skarels if (dowait) { 55522181Skarels syslog(LOG_ERR, "'%s %s' failing, sleeping", p->wcmd, p->line); 55622181Skarels closelog(); 55722181Skarels sleep(30); 55822181Skarels } 55918542Sralph execit(p->wcmd, p->line); 56018542Sralph exit(0); 56118542Sralph } 56222181Skarels p->wpid = pid; 56318542Sralph } 56418542Sralph 56522181Skarels #define NARGS 20 /* must be at least 4 */ 56618542Sralph #define ARGLEN 512 /* total size for all the argument strings */ 56718542Sralph 56818542Sralph execit(s, arg) 56918542Sralph char *s; 57018542Sralph char *arg; /* last argument on line */ 57118542Sralph { 57218542Sralph char *argv[NARGS], args[ARGLEN], *envp[1]; 57318542Sralph register char *sp = s; 57418542Sralph register char *ap = args; 57518542Sralph register char c; 57618542Sralph register int i; 57718542Sralph 57818542Sralph /* 57918542Sralph * First we have to set up the argument vector. 58018542Sralph * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2"). 58118542Sralph */ 58218542Sralph for (i = 1; i < NARGS - 2; i++) { 58318542Sralph argv[i] = ap; 58418542Sralph for (EVER) { 58518542Sralph if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) { 58618542Sralph *ap = '\0'; 58718542Sralph goto done; 58818542Sralph } 58918542Sralph if (c == ' ') { 59018542Sralph *ap++ = '\0'; 59118542Sralph while (*sp == ' ') 59218542Sralph sp++; 59318542Sralph if (*sp == '\0') 59418542Sralph goto done; 59518542Sralph break; 59618542Sralph } 59718542Sralph *ap++ = c; 59818542Sralph } 59918542Sralph } 60018542Sralph done: 60118542Sralph argv[0] = argv[1]; 60218542Sralph argv[1] = "-"; 60318542Sralph argv[i+1] = arg; 60418542Sralph argv[i+2] = 0; 60518542Sralph envp[0] = 0; 60618542Sralph execve(argv[0], &argv[1], envp); 60718542Sralph /* report failure of exec */ 60818542Sralph syslog(LOG_ERR, "%s: %m", argv[0]); 60918542Sralph closelog(); 61018542Sralph sleep(10); /* prevent failures from eating machine */ 61118542Sralph } 612