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*33302Sbostic static char sccsid[] = "@(#)init.c 5.10 (Berkeley) 01/10/88"; 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> 1928801Skarels #include <sys/syslog.h> 2023147Sbloom #include <sys/stat.h> 211029Sbill 221029Sbill #define LINSIZ sizeof(wtmp.ut_line) 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 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 6629836Ssam #if defined(vax) || defined(tahoe) 671029Sbill main() 681029Sbill { 6929836Ssam #if defined(tahoe) 7029836Ssam register int r12; /* make sure r11 gets bootflags */ 7129836Ssam #endif 721403Sbill register int r11; /* passed thru from boot */ 7313021Ssam #else 749869Spugs main(argc, argv) 759869Spugs char **argv; 769869Spugs { 7713021Ssam #endif 781403Sbill int howto, oldhowto; 791403Sbill 802821Swnj time0 = time(0); 8129836Ssam #if defined(vax) || defined(tahoe) 821403Sbill howto = r11; 8313021Ssam #else 849869Spugs if (argc > 1 && argv[1][0] == '-') { 859869Spugs char *cp; 869869Spugs 879869Spugs howto = 0; 889869Spugs cp = &argv[1][1]; 899869Spugs while (*cp) switch (*cp++) { 909869Spugs case 'a': 919869Spugs howto |= RB_ASKNAME; 929869Spugs break; 939869Spugs case 's': 949869Spugs howto |= RB_SINGLE; 959869Spugs break; 969869Spugs } 979869Spugs } else { 989869Spugs howto = RB_SINGLE; 999869Spugs } 10013021Ssam #endif 10124854Seric openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH); 10213021Ssam sigvec(SIGTERM, &rvec, (struct sigvec *)0); 1032821Swnj signal(SIGTSTP, idle); 1041029Sbill signal(SIGSTOP, SIG_IGN); 1051029Sbill signal(SIGTTIN, SIG_IGN); 1061029Sbill signal(SIGTTOU, SIG_IGN); 10713021Ssam (void) setjmp(sjbuf); 10813021Ssam for (EVER) { 1091403Sbill oldhowto = howto; 1101403Sbill howto = RB_SINGLE; 1111429Sbill if (setjmp(shutpass) == 0) 1121429Sbill shutdown(); 1131403Sbill if (oldhowto & RB_SINGLE) 1141403Sbill single(); 1151403Sbill if (runcom(oldhowto) == 0) 1161403Sbill continue; 1171029Sbill merge(); 1181029Sbill multiple(); 1191029Sbill } 1201029Sbill } 1211029Sbill 1221429Sbill int shutreset(); 1231429Sbill 1241029Sbill shutdown() 1251029Sbill { 1261029Sbill register i; 12723147Sbloom register struct tab *p, *p1; 1281029Sbill 12923147Sbloom close(creat(utmpf, 0644)); 1301029Sbill signal(SIGHUP, SIG_IGN); 13123147Sbloom for (p = itab; p ; ) { 1321029Sbill term(p); 13323147Sbloom p1 = p->next; 13423147Sbloom free(p); 13523147Sbloom p = p1; 1361029Sbill } 13723147Sbloom itab = (struct tab *)0; 1381429Sbill signal(SIGALRM, shutreset); 13928801Skarels (void) kill(-1, SIGTERM); /* one chance to catch it */ 14028801Skarels sleep(5); 1411429Sbill alarm(30); 14213021Ssam for (i = 0; i < 5; i++) 1431029Sbill kill(-1, SIGKILL); 14413021Ssam while (wait((int *)0) != -1) 1451029Sbill ; 1461029Sbill alarm(0); 1471429Sbill shutend(); 1481429Sbill } 1491429Sbill 15030516Sbostic char shutfailm[] = "WARNING: Something is hung (won't die); ps axl advised\n"; 1511429Sbill 1521429Sbill shutreset() 1531429Sbill { 1541429Sbill int status; 1551429Sbill 1561429Sbill if (fork() == 0) { 1571429Sbill int ct = open(ctty, 1); 1581429Sbill write(ct, shutfailm, sizeof (shutfailm)); 1591429Sbill sleep(5); 1601429Sbill exit(1); 1611429Sbill } 1621429Sbill sleep(5); 1631429Sbill shutend(); 1641429Sbill longjmp(shutpass, 1); 1651429Sbill } 1661429Sbill 1671429Sbill shutend() 1681429Sbill { 1692821Swnj register i, f; 1701429Sbill 1712821Swnj acct(0); 1721029Sbill signal(SIGALRM, SIG_DFL); 17313021Ssam for (i = 0; i < 10; i++) 1741029Sbill close(i); 17513021Ssam f = open(wtmpf, O_WRONLY|O_APPEND); 1762821Swnj if (f >= 0) { 1772821Swnj SCPYN(wtmp.ut_line, "~"); 1782821Swnj SCPYN(wtmp.ut_name, "shutdown"); 17912682Ssam SCPYN(wtmp.ut_host, ""); 1802821Swnj time(&wtmp.ut_time); 1812821Swnj write(f, (char *)&wtmp, sizeof(wtmp)); 1822821Swnj close(f); 1832821Swnj } 18413021Ssam return (1); 1851029Sbill } 1861029Sbill 1871029Sbill single() 1881029Sbill { 1891029Sbill register pid; 1902821Swnj register xpid; 1912821Swnj extern errno; 1921029Sbill 19313021Ssam do { 19413021Ssam pid = fork(); 19513021Ssam if (pid == 0) { 19613021Ssam signal(SIGTERM, SIG_DFL); 19713021Ssam signal(SIGHUP, SIG_DFL); 19813021Ssam signal(SIGALRM, SIG_DFL); 19916452Sroot signal(SIGTSTP, SIG_IGN); 20013021Ssam (void) open(ctty, O_RDWR); 20113021Ssam dup2(0, 1); 20213021Ssam dup2(0, 2); 20313021Ssam execl(shell, minus, (char *)0); 20430516Sbostic perror(shell); 20513021Ssam exit(0); 20613021Ssam } 20713021Ssam while ((xpid = wait((int *)0)) != pid) 20813021Ssam if (xpid == -1 && errno == ECHILD) 20913021Ssam break; 21013021Ssam } while (xpid == -1); 2111029Sbill } 2121029Sbill 2131403Sbill runcom(oldhowto) 2141403Sbill int oldhowto; 2151029Sbill { 2161029Sbill register pid, f; 2171403Sbill int status; 2181029Sbill 2191029Sbill pid = fork(); 22013021Ssam if (pid == 0) { 22113021Ssam (void) open("/", O_RDONLY); 22213021Ssam dup2(0, 1); 22313021Ssam dup2(0, 2); 2241403Sbill if (oldhowto & RB_SINGLE) 2251403Sbill execl(shell, shell, runc, (char *)0); 2261403Sbill else 2271403Sbill execl(shell, shell, runc, "autoboot", (char *)0); 2281403Sbill exit(1); 2291029Sbill } 23013021Ssam while (wait(&status) != pid) 2311029Sbill ; 23213021Ssam if (status) 23313021Ssam return (0); 23413021Ssam f = open(wtmpf, O_WRONLY|O_APPEND); 2351029Sbill if (f >= 0) { 2361029Sbill SCPYN(wtmp.ut_line, "~"); 2371029Sbill SCPYN(wtmp.ut_name, "reboot"); 23812682Ssam SCPYN(wtmp.ut_host, ""); 2392821Swnj if (time0) { 2402821Swnj wtmp.ut_time = time0; 2412821Swnj time0 = 0; 2422821Swnj } else 2432821Swnj time(&wtmp.ut_time); 2441029Sbill write(f, (char *)&wtmp, sizeof(wtmp)); 2451029Sbill close(f); 2461029Sbill } 24713021Ssam return (1); 2481029Sbill } 2491029Sbill 250*33302Sbostic int merge(); 25118542Sralph struct sigvec mvec = { merge, sigmask(SIGTERM), 0 }; 25213021Ssam /* 25313021Ssam * Multi-user. Listen for users leaving, SIGHUP's 25413021Ssam * which indicate ttys has changed, and SIGTERM's which 25513021Ssam * are used to shutdown the system. 25613021Ssam */ 2571029Sbill multiple() 2581029Sbill { 2591029Sbill register struct tab *p; 2601029Sbill register pid; 26123147Sbloom int omask; 2621029Sbill 26313021Ssam sigvec(SIGHUP, &mvec, (struct sigvec *)0); 26413021Ssam for (EVER) { 2651029Sbill pid = wait((int *)0); 26613021Ssam if (pid == -1) 2671029Sbill return; 26830516Sbostic omask = sigblock(sigmask(SIGHUP)); 26918542Sralph for (ALL) { 27018542Sralph /* must restart window system BEFORE emulator */ 27118542Sralph if (p->wpid == pid || p->wpid == -1) 27218542Sralph wstart(p); 27313021Ssam if (p->pid == pid || p->pid == -1) { 27418542Sralph /* disown the window system */ 27518542Sralph if (p->wpid) 27618542Sralph kill(p->wpid, SIGHUP); 2771029Sbill rmut(p); 2781029Sbill dfork(p); 2791029Sbill } 28018542Sralph } 28123147Sbloom sigsetmask(omask); 2821029Sbill } 2831029Sbill } 2841029Sbill 28513021Ssam /* 28613021Ssam * Merge current contents of ttys file 28713021Ssam * into in-core table of configured tty lines. 28813021Ssam * Entered as signal handler for SIGHUP. 28913021Ssam */ 29013021Ssam #define FOUND 1 29113021Ssam #define CHANGE 2 29218542Sralph #define WCHANGE 4 29313021Ssam 29413021Ssam merge() 29513021Ssam { 29613021Ssam register struct tab *p; 29716452Sroot register struct ttyent *t; 29823147Sbloom register struct tab *p1; 29913021Ssam 30013021Ssam for (ALL) 30113021Ssam p->xflag = 0; 30216452Sroot setttyent(); 30316452Sroot while (t = getttyent()) { 30416452Sroot if ((t->ty_status & TTY_ON) == 0) 30516452Sroot continue; 30613021Ssam for (ALL) { 30716452Sroot if (SCMPN(p->line, t->ty_name)) 30813021Ssam continue; 30913021Ssam p->xflag |= FOUND; 31016452Sroot if (SCMPN(p->comn, t->ty_getty)) { 31113021Ssam p->xflag |= CHANGE; 31216452Sroot SCPYN(p->comn, t->ty_getty); 31313021Ssam } 31430516Sbostic if (SCMPN(p->wcmd, t->ty_window ? t->ty_window : "")) { 31518542Sralph p->xflag |= WCHANGE|CHANGE; 31618542Sralph SCPYN(p->wcmd, t->ty_window); 31718542Sralph } 31813021Ssam goto contin1; 31913021Ssam } 32018542Sralph 32123147Sbloom /* 32223147Sbloom * Make space for a new one 32323147Sbloom */ 32423147Sbloom p1 = (struct tab *)calloc(1, sizeof(*p1)); 32523147Sbloom if (!p1) { 32623147Sbloom syslog(LOG_ERR, "no space for '%s' !?!", t->ty_name); 32713021Ssam goto contin1; 32813021Ssam } 32923147Sbloom /* 33023147Sbloom * Put new terminal at the end of the linked list. 33123147Sbloom */ 33223147Sbloom if (itab) { 33323147Sbloom for (p = itab; p->next ; p = p->next) 33423147Sbloom ; 33523147Sbloom p->next = p1; 33623147Sbloom } else 33723147Sbloom itab = p1; 33823147Sbloom 33923147Sbloom p = p1; 34023147Sbloom SCPYN(p->line, t->ty_name); 34123147Sbloom p->xflag |= FOUND|CHANGE; 34223147Sbloom SCPYN(p->comn, t->ty_getty); 34330516Sbostic if (t->ty_window && strcmp(t->ty_window, "") != 0) { 34423147Sbloom p->xflag |= WCHANGE; 34523147Sbloom SCPYN(p->wcmd, t->ty_window); 34623147Sbloom } 34713021Ssam contin1: 34813021Ssam ; 34913021Ssam } 35016452Sroot endttyent(); 35123147Sbloom p1 = (struct tab *)0; 35213021Ssam for (ALL) { 35313021Ssam if ((p->xflag&FOUND) == 0) { 35413021Ssam term(p); 35518542Sralph wterm(p); 35623147Sbloom if (p1) 35723147Sbloom p1->next = p->next; 35823147Sbloom else 35923147Sbloom itab = p->next; 36023147Sbloom free(p); 36123147Sbloom p = p1 ? p1 : itab; 36223147Sbloom } else { 36323147Sbloom /* window system should be started first */ 36423147Sbloom if (p->xflag&WCHANGE) { 36523147Sbloom wterm(p); 36623147Sbloom wstart(p); 36723147Sbloom } 36823147Sbloom if (p->xflag&CHANGE) { 36923147Sbloom term(p); 37023147Sbloom dfork(p); 37123147Sbloom } 37213021Ssam } 37323147Sbloom p1 = p; 37413021Ssam } 37513021Ssam } 37613021Ssam 3771029Sbill term(p) 37813021Ssam register struct tab *p; 3791029Sbill { 3801029Sbill 38113021Ssam if (p->pid != 0) { 3821029Sbill rmut(p); 3831029Sbill kill(p->pid, SIGKILL); 3841029Sbill } 3851029Sbill p->pid = 0; 38618542Sralph /* send SIGHUP to get rid of connections */ 38718542Sralph if (p->wpid > 0) 38818542Sralph kill(p->wpid, SIGHUP); 3891029Sbill } 3901029Sbill 3911029Sbill dfork(p) 39213021Ssam struct tab *p; 3931029Sbill { 3941029Sbill register pid; 3955971Sroot time_t t; 3965971Sroot int dowait = 0; 3971029Sbill 3985971Sroot time(&t); 3995971Sroot p->gettycnt++; 4005971Sroot if ((t - p->gettytime) >= 60) { 4015971Sroot p->gettytime = t; 4025971Sroot p->gettycnt = 1; 40318542Sralph } else if (p->gettycnt >= 5) { 40418542Sralph dowait = 1; 40518542Sralph p->gettytime = t; 40618542Sralph p->gettycnt = 1; 4075971Sroot } 4081029Sbill pid = fork(); 40913021Ssam if (pid == 0) { 4106816Ssam signal(SIGTERM, SIG_DFL); 4116816Ssam signal(SIGHUP, SIG_IGN); 41222181Skarels sigsetmask(0); /* since can be called from masked code */ 4135971Sroot if (dowait) { 41418542Sralph syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line); 41518542Sralph closelog(); 4165971Sroot sleep(30); 4175971Sroot } 41818542Sralph execit(p->comn, p->line); 4191029Sbill exit(0); 4201029Sbill } 4211029Sbill p->pid = pid; 4221029Sbill } 4231029Sbill 42413021Ssam /* 42513021Ssam * Remove utmp entry. 42613021Ssam */ 4271029Sbill rmut(p) 42813021Ssam register struct tab *p; 4291029Sbill { 4301029Sbill register f; 4313608Swnj int found = 0; 43223147Sbloom static unsigned utmpsize; 43323147Sbloom static struct utmp *utmp; 43423147Sbloom register struct utmp *u; 43523147Sbloom int nutmp; 43623147Sbloom struct stat statbf; 4371029Sbill 43823147Sbloom f = open(utmpf, O_RDWR); 43913021Ssam if (f >= 0) { 44023147Sbloom fstat(f, &statbf); 44123147Sbloom if (utmpsize < statbf.st_size) { 44223147Sbloom utmpsize = statbf.st_size + 10 * sizeof(struct utmp); 44323147Sbloom if (utmp) 44423147Sbloom utmp = (struct utmp *)realloc(utmp, utmpsize); 44523147Sbloom else 44623147Sbloom utmp = (struct utmp *)malloc(utmpsize); 44723147Sbloom if (!utmp) 44823147Sbloom syslog(LOG_ERR, "utmp malloc failed"); 4491029Sbill } 45023147Sbloom if (statbf.st_size && utmp) { 45123147Sbloom nutmp = read(f, utmp, statbf.st_size); 45223147Sbloom nutmp /= sizeof(struct utmp); 45323147Sbloom for (u = utmp ; u < &utmp[nutmp] ; u++) { 45430908Slepreau if (u->ut_name[0] == 0 || 45530908Slepreau SCMPN(u->ut_line, p->line)) 45623147Sbloom continue; 45723147Sbloom lseek(f, ((long)u)-((long)utmp), L_SET); 45823147Sbloom SCPYN(u->ut_name, ""); 45923147Sbloom SCPYN(u->ut_host, ""); 46023147Sbloom time(&u->ut_time); 46123147Sbloom write(f, (char *)u, sizeof(*u)); 46223147Sbloom found++; 46323147Sbloom } 46423147Sbloom } 4651029Sbill close(f); 4661029Sbill } 4673608Swnj if (found) { 46813021Ssam f = open(wtmpf, O_WRONLY|O_APPEND); 4693608Swnj if (f >= 0) { 4703608Swnj SCPYN(wtmp.ut_line, p->line); 4713608Swnj SCPYN(wtmp.ut_name, ""); 47212682Ssam SCPYN(wtmp.ut_host, ""); 4733608Swnj time(&wtmp.ut_time); 4743608Swnj write(f, (char *)&wtmp, sizeof(wtmp)); 4753608Swnj close(f); 4763608Swnj } 47717582Ssam /* 47817582Ssam * After a proper login force reset 47917582Ssam * of error detection code in dfork. 48017582Ssam */ 48117582Ssam p->gettytime = 0; 48222181Skarels p->windtime = 0; 4831029Sbill } 4841029Sbill } 4851029Sbill 4861029Sbill reset() 4871029Sbill { 48813021Ssam 4891029Sbill longjmp(sjbuf, 1); 4901029Sbill } 4912821Swnj 49213021Ssam jmp_buf idlebuf; 49313021Ssam 49413021Ssam idlehup() 49513021Ssam { 49613021Ssam 49713021Ssam longjmp(idlebuf, 1); 49813021Ssam } 49913021Ssam 5002821Swnj idle() 5012821Swnj { 5022821Swnj register struct tab *p; 5032821Swnj register pid; 5042821Swnj 50513021Ssam signal(SIGHUP, idlehup); 50618542Sralph for (EVER) { 50713021Ssam if (setjmp(idlebuf)) 50813021Ssam return; 5092821Swnj pid = wait((int *) 0); 51013021Ssam if (pid == -1) { 51113021Ssam sigpause(0); 51213021Ssam continue; 5132821Swnj } 51418542Sralph for (ALL) { 51518542Sralph /* if window system dies, mark it for restart */ 51618542Sralph if (p->wpid == pid) 51718542Sralph p->wpid = -1; 51813021Ssam if (p->pid == pid) { 51913021Ssam rmut(p); 52013021Ssam p->pid = -1; 52113021Ssam } 52218542Sralph } 5232821Swnj } 5242821Swnj } 52518542Sralph 52618542Sralph wterm(p) 52718542Sralph register struct tab *p; 52818542Sralph { 52918542Sralph if (p->wpid != 0) { 53018542Sralph kill(p->wpid, SIGKILL); 53118542Sralph } 53218542Sralph p->wpid = 0; 53318542Sralph } 53418542Sralph 53518542Sralph wstart(p) 53618542Sralph register struct tab *p; 53718542Sralph { 53822181Skarels register pid; 53922181Skarels time_t t; 54022181Skarels int dowait = 0; 54118542Sralph 54222181Skarels time(&t); 54322181Skarels p->windcnt++; 54422181Skarels if ((t - p->windtime) >= 60) { 54522181Skarels p->windtime = t; 54622181Skarels p->windcnt = 1; 54722181Skarels } else if (p->windcnt >= 5) { 54822181Skarels dowait = 1; 54922181Skarels p->windtime = t; 55022181Skarels p->windcnt = 1; 55122181Skarels } 55222181Skarels 55322181Skarels pid = fork(); 55422181Skarels 55522181Skarels if (pid == 0) { 55618542Sralph signal(SIGTERM, SIG_DFL); 55722181Skarels signal(SIGHUP, SIG_IGN); 55822181Skarels sigsetmask(0); /* since can be called from masked code */ 55922181Skarels if (dowait) { 56022181Skarels syslog(LOG_ERR, "'%s %s' failing, sleeping", p->wcmd, p->line); 56122181Skarels closelog(); 56222181Skarels sleep(30); 56322181Skarels } 56418542Sralph execit(p->wcmd, p->line); 56518542Sralph exit(0); 56618542Sralph } 56722181Skarels p->wpid = pid; 56818542Sralph } 56918542Sralph 57022181Skarels #define NARGS 20 /* must be at least 4 */ 57118542Sralph #define ARGLEN 512 /* total size for all the argument strings */ 57218542Sralph 57318542Sralph execit(s, arg) 57418542Sralph char *s; 57518542Sralph char *arg; /* last argument on line */ 57618542Sralph { 57718542Sralph char *argv[NARGS], args[ARGLEN], *envp[1]; 57818542Sralph register char *sp = s; 57918542Sralph register char *ap = args; 58018542Sralph register char c; 58118542Sralph register int i; 58218542Sralph 58318542Sralph /* 58418542Sralph * First we have to set up the argument vector. 58518542Sralph * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2"). 58618542Sralph */ 58718542Sralph for (i = 1; i < NARGS - 2; i++) { 58818542Sralph argv[i] = ap; 58918542Sralph for (EVER) { 59018542Sralph if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) { 59118542Sralph *ap = '\0'; 59218542Sralph goto done; 59318542Sralph } 59418542Sralph if (c == ' ') { 59518542Sralph *ap++ = '\0'; 59618542Sralph while (*sp == ' ') 59718542Sralph sp++; 59818542Sralph if (*sp == '\0') 59918542Sralph goto done; 60018542Sralph break; 60118542Sralph } 60218542Sralph *ap++ = c; 60318542Sralph } 60418542Sralph } 60518542Sralph done: 60618542Sralph argv[0] = argv[1]; 60718542Sralph argv[1] = "-"; 60818542Sralph argv[i+1] = arg; 60918542Sralph argv[i+2] = 0; 61018542Sralph envp[0] = 0; 61118542Sralph execve(argv[0], &argv[1], envp); 61218542Sralph /* report failure of exec */ 61318542Sralph syslog(LOG_ERR, "%s: %m", argv[0]); 61418542Sralph closelog(); 61518542Sralph sleep(10); /* prevent failures from eating machine */ 61618542Sralph } 617