#! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # Makefile # error.c # getlevel.c # main.c # process.c # startup.c # inittab.c # spawn.c # config.h # inittab.h # patchlevel.h # This archive created: Wed Mar 22 08:07:05 1989 # By: John F. Haugh II (River Parishes Programming, Dallas TX) export PATH; PATH=/bin:/usr/bin:$PATH if test -f 'Makefile' then echo shar: "will not over-write existing file 'Makefile'" else cat << \SHAR_EOF > 'Makefile' # # %Z%Init - System V compatible init # # %W% %U% %G% # SHELL = /bin/sh CFLAGS = -O -M3 -g SRCS = error.c getlevel.c main.c process.c startup.c inittab.c spawn.c HDRS = config.h inittab.h patchlevel.h OBJS = error.o getlevel.o main.o process.o startup.o inittab.o spawn.o FILES = Makefile $(SRCS) $(HDRS) init: $(OBJS) cc -o init -g $(OBJS) error.o: config.h getlevel.o: inittab.h config.h inittab.o: inittab.h config.h main.o: inittab.h config.h process.o: inittab.h config.h spawn.o: inittab.h startup.o: inittab.h config.h shar: $(FILES) shar $(FILES) > init.shar clean: rm -f *.o core clobber: clean rm -f init SHAR_EOF fi if test -f 'error.c' then echo shar: "will not over-write existing file 'error.c'" else cat << \SHAR_EOF > 'error.c' #include <fcntl.h> #include <stdio.h> #include "config.h" #ifndef lint static char _sccsid[] = "@(#)error.c 1.1 07:58:04 3/22/89"; #endif extern int proc1; extern int consolefd; error (s) char *s; { char buf[BUFSIZ]; sprintf (buf, "ERROR: %s\r\n", s); #ifdef DEBUG fputs (buf, stderr); #else if (proc1) { if (fork () == 0) { proc1 = 0; consolefd = open (CONSOLE, O_RDWR|O_NDELAY); write (consolefd, buf, strlen (buf)); _exit (0); } } else { write (consolefd, buf, strlen (buf)); _exit (0); } #endif } msg (s) char *s; { char buf[BUFSIZ]; sprintf (buf, "%s\r\n", s); #ifdef DEBUG fputs (buf, stderr); #else if (proc1) { if (fork () == 0) { proc1 = 0; consolefd = open (CONSOLE, O_RDWR|O_NDELAY); write (consolefd, buf, strlen (buf)); _exit (0); } } else { write (consolefd, buf, strlen (buf)); _exit (0); } #endif } SHAR_EOF fi if test -f 'getlevel.c' then echo shar: "will not over-write existing file 'getlevel.c'" else cat << \SHAR_EOF > 'getlevel.c' #include <stdio.h> #include <fcntl.h> #include <termio.h> #include <signal.h> #include "inittab.h" #include "config.h" #ifndef lint static char _sccsid[] = "@(#)getlevel.c 1.1 07:58:04 3/22/89"; #endif extern int proc1; extern int consolefd; extern int nproc; extern struct inittab *proc; /* * getlevel - return new run level */ int getlevel () { char buf[16]; int fd; int status; int pid; int child; int i; struct termio termio; for (i = 0;i < nproc;i++) { if (proc[i].ini_pid > 1) { kill (- proc[i].ini_pid, SIGKILL); waitfor (&proc[i]); } } kill (0, SIGKILL); switch (child = fork ()) { default: /* still proc1 ... */ while ((pid = wait (&status)) != child && pid != -1) ; if ((status & 0377) != 0) { error ("Can't get run-level, using S"); return ('S'); } break; case -1: /* couldn't fork */ error ("Can't get run-level, using S"); return ('S'); case 0: /* child process */ proc1 = 0; if ((fd = open (CONSOLE, O_RDWR|O_NDELAY)) < 0) _exit (0); /* assume 'S' ... */ #ifndef DEBUG ioctl (fd, TCGETA, &termio); termio.c_iflag = (ISTRIP|ICRNL|IXON); termio.c_oflag = (OPOST|ONLCR); termio.c_cflag &= CBAUD; termio.c_cflag |= (CREAD|HUPCL); termio.c_lflag = (ISIG|ICANON|ECHO|ECHOE|ECHOK); ioctl (fd, TCSETA, &termio); #endif fcntl (fd, F_SETFL, fcntl (fd, F_GETFL, 0) & ~O_NDELAY); consolefd = fd; do { write (fd, "Enter run-level [Ss0123456]: ", 29); i = read (fd, buf, sizeof buf); if (i >= 0) buf[i] = '\0'; } while (! (buf[0] == 's' || buf[0] == 'S' || (buf[0] >= '0' && buf[0] <= '6'))); if (buf[0] == 'S' || buf[0] == '0') _exit (0); else if (buf[0] == 's') _exit (1); else _exit (buf[0] - '0' + 1); } status = (status >> 8) & 07; return ("Ss123456"[status]); } SHAR_EOF fi if test -f 'main.c' then echo shar: "will not over-write existing file 'main.c'" else cat << \SHAR_EOF > 'main.c' #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <signal.h> #include <utmp.h> #include <string.h> #include "config.h" #include "inittab.h" #ifndef lint static char _sccsid[] = "@(#)main.c 1.1 07:58:07 3/22/89"; #endif char intrflag; int proc1; int runlevel; int prevlevel; int runcnt[8]; int consolefd; int wtmpfd; int nproc; struct inittab *proc; reinit () { int i; msg ("Reloading INIT"); #ifndef DEBUG kill (-1, SIGKILL); #endif #ifdef DEBUG execl ("./init", "init", "proc1", (char *) 0); #else execl ("/etc/init", "/etc/init", (char *) 0); #endif } main (argc, argv) int argc; char **argv; { int newlevel; char buf[BUFSIZ]; #ifdef DEBUG if (proc1 = (argc > 1 && strcmp (argv[1], "proc1") == 0)) { argv[1] = argv[0]; argc--; argv++; } #else proc1 = getpid () == 1; #endif if (proc1) startup (); while (1) { process (runlevel); newlevel = getlevel (); if (newlevel != runlevel) sprintf (buf, "INIT: New run-level: %c", newlevel); else sprintf (buf, "INIT: Run-level: %c", newlevel); msg (buf); runlevel = newlevel; } } SHAR_EOF fi if test -f 'process.c' then echo shar: "will not over-write existing file 'process.c'" else cat << \SHAR_EOF > 'process.c' #include <signal.h> #include <sys/types.h> #include <utmp.h> #include <fcntl.h> #include "config.h" #include "inittab.h" #ifndef lint static char _sccsid[] = "@(#)process.c 1.1 07:58:08 3/22/89"; #endif extern char intrflag; extern int nproc; extern int prevlevel; extern int runlevel; extern int runcnt[]; extern int wtmpfd; extern struct inittab *proc; /* * process - perform entries specified in inittab * * perform respawn, wait, and once commands. */ process () { int i; int utmpfd; int count; struct inittab *ip; struct utmp utmp; struct utmp utent; if (runlevel == 'S') i = runcnt[0]++; else if (runlevel == 's') i = runcnt[1]++; else i = runcnt[runlevel - '0' + 1]++; #ifdef DEBUG utmpfd = -1; #else utmpfd = open ("/etc/utmp", O_RDWR|O_CREAT, 0644); #endif memset ((char *) &utmp, 0, sizeof utmp); sprintf (utmp.ut_line, RUNLVL_MSG, runlevel); utmp.ut_type = RUN_LVL; utmp.ut_pid = i; utmp.ut_exit.e_termination = runlevel; utmp.ut_exit.e_exit = prevlevel; utmp.ut_time = time ((time_t *) 0); prevlevel = runlevel; intrflag = 0; if (utmpfd >= 0) { while (read (utmpfd, &utent, sizeof utent) == sizeof utent) if (utent.ut_type == RUN_LVL) break; if (utent.ut_type == RUN_LVL) lseek (utmpfd, (off_t) - sizeof utent, 1); write (utmpfd, &utmp, sizeof utmp); close (utmpfd); utmpfd = -1; } if (wtmpfd >= 0) write (wtmpfd, &utmp, sizeof utmp); again: inittab (runlevel); #ifdef DEBUG prtab (); #endif for (count = 0, ip = proc;ip != &proc[nproc];ip++) { if (ip->ini_pid && kill (ip->ini_pid, 0) != 0) waitfor (ip); if (! (ip->ini_pid && kill (ip->ini_pid, 0) == 0)) { switch (ip->ini_action) { case INIT_RESPAWN: spawn (ip); count++; break; case INIT_WAIT: if (intrflag == 0) spawn (ip); count++; break; case INIT_ONCE: if (ip->ini_count == 0) spawn (ip); count++; break; } } } intrflag = 0; if (count) waitfor ((struct inittab *) 0); if (intrflag && intrflag != SIGUSR1) goto again; } SHAR_EOF fi if test -f 'startup.c' then echo shar: "will not over-write existing file 'startup.c'" else cat << \SHAR_EOF > 'startup.c' #include <sys/types.h> #include <stdio.h> #include <fcntl.h> #include <signal.h> #include <utmp.h> #include "config.h" #include "inittab.h" extern void reread (); extern void reinit (); extern char intrflag; extern int runlevel; extern int prevlevel; extern int nproc; extern int wtmpfd; extern struct inittab *proc; #ifndef lint static char _sccsid[] = "@(#)startup.c 1.1 07:58:09 3/22/89"; #endif /* * startup - set up the initial state */ void startup () { int i; int fd; int utmpfd; struct utmp utent; struct utmp utmp; wtmpfd = open ("/etc/wtmp", O_RDWR|O_APPEND|O_CREAT, 0644); #ifdef DEBUG utmpfd = -1; #else utmpfd = open ("/etc/utmp", O_RDWR|O_CREAT|O_TRUNC, 0644); #endif memset (utmp, sizeof utmp, 0); strcpy (utmp.ut_line, BOOT_MSG); utmp.ut_type = BOOT_TIME; utmp.ut_time = time ((time_t *) 0); if (utmpfd >= 0) { while (read (utmpfd, &utent, sizeof utent) == sizeof utent) if (utent.ut_type == BOOT_TIME) break; if (utent.ut_type == BOOT_TIME) lseek (utmpfd, (off_t) - sizeof utent, 1); write (utmpfd, &utmp, sizeof utmp); } if (wtmpfd >= 0) write (wtmpfd, &utmp, sizeof utmp); #ifndef DEBUG for (i = 1;i < NSIG;i++) signal (i, SIG_IGN); #endif signal (SIGHUP, reread); signal (SIGINT, reread); signal (SIGQUIT, reread); signal (SIGUSR1, reread); signal (SIGUSR2, reinit); signal (SIGCLD, SIG_DFL); inittab (-1); #ifdef DEBUG printf ("INIT: BOOT\n"); prtab (); #endif /* * certain entries must be executed first. initdefault is * the first one of them. if there is no initdefault entry, * we assume 'S' for the initial run level. */ for (i = 0;i < nproc && ! runlevel;i++) /* scan for initdefault */ if (proc[i].ini_action == INIT_INITDEFAULT) runlevel = proc[i].ini_levels[0]; if (! runlevel) runlevel = 'S'; prevlevel = runlevel; memset (utmp, sizeof utmp, 0); sprintf (utmp.ut_line, RUNLVL_MSG, runlevel); utmp.ut_type = RUN_LVL; utmp.ut_pid = 0; utmp.ut_exit.e_termination = utmp.ut_exit.e_exit = runlevel; utmp.ut_time = time ((time_t *) 0); if (utmpfd >= 0) { while (read (utmpfd, &utent, sizeof utent) == sizeof utent) if (utent.ut_type == RUN_LVL) break; if (utent.ut_type == RUN_LVL) lseek (utmpfd, (off_t) - sizeof utent, 1); write (utmpfd, &utmp, sizeof utmp); } if (wtmpfd >= 0) write (wtmpfd, &utmp, sizeof utmp); /* * next we must exec all `sysinit' commands ... */ for (i = 0;i < nproc;i++) /* scan for sysinit */ if (proc[i].ini_action == INIT_SYSINIT) spawn (&proc[i]); /* * now we execute the `boot time only' commands ... */ for (i = 0;i < nproc;i++) if (proc[i].ini_action == INIT_BOOT || proc[i].ini_action == INIT_BOOTWAIT) spawn (&proc[i]); close (utmpfd); } SHAR_EOF fi if test -f 'inittab.c' then echo shar: "will not over-write existing file 'inittab.c'" else cat << \SHAR_EOF > 'inittab.c' #include <stdio.h> #include <string.h> #include <signal.h> #include "inittab.h" #include "config.h" #ifndef lint static char _sccsid[] = "@(#)inittab.c 1.1 07:58:06 3/22/89"; #endif char *actions[] = { "respawn", "wait", "once", "boot", "bootwait", "powerfail", "powerwait", "off", "ondemand", "initdefault", "sysinit" }; struct inittab initdefault = { "default", "Ss123456", INIT_ONCE, "/etc/sulogin", 0 }; extern struct inittab *proc; extern int nproc; extern char intrflag; extern char *malloc (); extern char *realloc (); struct inittab *getinit (fp, entry) FILE *fp; struct inittab *entry; { char *cp; char buf[BUFSIZ]; char id[16]; char levels[16]; char actions[16]; char command[BUFSIZ]; while (fgets (buf, BUFSIZ, fp) != (char *) 0) { if (buf[0] == '#') continue; if (cp = strtok (buf, ":")) strcpy (id, cp); else continue; if (cp = strtok ((char *) 0, ":")) strcpy (levels, cp); else continue; if (cp = strtok ((char *) 0, ":")) strcpy (actions, cp); else continue; if (cp = strtok ((char *) 0, ":")) strcpy (command, cp); else continue; if (cp = strchr (command, '\n')) *cp = '\0'; if (strcmp (actions, "respawn") == 0) entry->ini_action = INIT_RESPAWN; else if (strcmp (actions, "wait") == 0) entry->ini_action = INIT_WAIT; else if (strcmp (actions, "once") == 0) entry->ini_action = INIT_ONCE; else if (strcmp (actions, "boot") == 0) entry->ini_action = INIT_BOOT; else if (strcmp (actions, "bootwait") == 0) entry->ini_action = INIT_BOOTWAIT; else if (strcmp (actions, "off") == 0) entry->ini_action = INIT_OFF; else if (strcmp (actions, "ondemand") == 0) entry->ini_action = INIT_ONDEMAND; else if (strcmp (actions, "initdefault") == 0) entry->ini_action = INIT_INITDEFAULT; else if (strcmp (actions, "sysinit") == 0) entry->ini_action = INIT_SYSINIT; else continue; entry->ini_id = strdup (id); entry->ini_levels = strdup (levels); entry->ini_command = strdup (command); return (entry); } return ((struct inittab *) 0); } freeinit (entry) struct inittab *entry; { free (entry->ini_id); free (entry->ini_levels); free (entry->ini_command); } struct inittab *findinit (id, table, entries) char *id; struct inittab *table; int entries; { while (--entries >= 0) { if (strcmp (id, table->ini_id) == 0) return (table); else table++; } return ((struct inittab *) 0); } /* * inittab - read the inittab */ inittab (runlevel) int runlevel; { FILE *fp; int i, j; struct inittab it; struct inittab *ip; struct inittab *newproc; int newprocs; int kills; if ((fp = fopen (INITTAB, "r")) == (FILE *) 0) { nproc = 1; proc = (struct inittab *) malloc (sizeof it); proc[0] = initdefault; return; } newprocs = 0; if (runlevel != -1) { for (kills = i = 0;i < nproc;i++) { if (proc[i].ini_pid == 0) continue; if (strchr (proc[i].ini_levels, runlevel)) continue; kill (proc[i].ini_pid, SIGTERM); kills++; } if (kills) sleep (10); for (i = 0;i < nproc;i++) { if (proc[i].ini_pid == 0) continue; if (strchr (proc[i].ini_levels, runlevel)) continue; kill (proc[i].ini_pid, SIGKILL); waitfor (&proc[i]); } } while (getinit (fp, &it)) { if (runlevel != -1 && (it.ini_action == INIT_BOOT || it.ini_action == INIT_BOOTWAIT || it.ini_action == INIT_INITDEFAULT || it.ini_action == INIT_SYSINIT || ! strchr (it.ini_levels, runlevel))) { freeinit (&it); continue; } if (newprocs == 0) newproc = (struct inittab *) malloc (sizeof it); else newproc = (struct inittab *) realloc (newproc, sizeof it * (newprocs + 1)); newproc[newprocs++] = it; } fclose (fp); for (kills = i = 0;i < newprocs;i++) { if (ip = findinit (newproc[i].ini_id, proc, nproc)) { newproc[i].ini_pid = ip->ini_pid; newproc[i].ini_count = ip->ini_count; newproc[i].ini_status = ip->ini_status; if (newproc[i].ini_action == ip->ini_action && strcmp (newproc[i].ini_levels, ip->ini_levels) == 0 && strcmp (newproc[i].ini_command, ip->ini_command) == 0) continue; } else { newproc[i].ini_pid = 0; newproc[i].ini_count = 0; newproc[i].ini_status = 0; } if (newproc[i].ini_pid == 0) continue; if (newproc[i].ini_action == INIT_OFF) { kill (newproc[i].ini_pid, SIGTERM); kills++; } } if (kills) sleep (10); for (i = 0;i < newprocs;i++) { if (ip = findinit (newproc[i].ini_id, proc, nproc)) { if (newproc[i].ini_action == ip->ini_action && strcmp (newproc[i].ini_levels, ip->ini_levels) == 0 && strcmp (newproc[i].ini_command, ip->ini_command) == 0) continue; } if (newproc[i].ini_pid == 0) continue; if (newproc[i].ini_action == INIT_OFF) { kill (newproc[i].ini_pid, SIGKILL); waitfor (&newproc[i]); } } for (i = 0;i < nproc;i++) freeinit (&proc[i]); proc = newproc; nproc = newprocs; } void reread (sig) int sig; { char buf[BUFSIZ]; signal (sig, reread); intrflag = sig; } prtab () { int i; char buf[BUFSIZ]; for (i = 0;i < nproc;i++) { sprintf (buf, "%s:%s:%s:%s", proc[i].ini_id, proc[i].ini_levels, actions[proc[i].ini_action], proc[i].ini_command); msg (buf); } } SHAR_EOF fi if test -f 'spawn.c' then echo shar: "will not over-write existing file 'spawn.c'" else cat << \SHAR_EOF > 'spawn.c' #include <stdio.h> #include <sys/types.h> #include <utmp.h> #include <signal.h> #include "inittab.h" #ifndef lint static char _sccsid[] = "@(#)spawn.c 1.1 07:58:09 3/22/89"; #endif extern int proc1; extern int errno; extern int nproc; extern int wtmpfd; extern struct inittab *proc; struct utmp *getutent (); extern void waitfor (); time_t time (); /* * spawn - execute an entry */ spawn (entry) struct inittab *entry; { int mustwait = 0; int child; int type; int fd; int sig; char buf[BUFSIZ]; mustwait = (entry->ini_action == INIT_WAIT || entry->ini_action == INIT_BOOTWAIT || entry->ini_action == INIT_SYSINIT); switch (child = fork ()) { case 0: proc1 = 0; strcat (strcpy (buf, "exec "), entry->ini_command); for (fd = 0;fd < _NFILE;fd++) close (fd); setpgrp (); if (execl ("/bin/sh", "sh", "-c", buf, (char *) 0)) { sprintf (buf, "INIT: Can't exec %s", buf); error (buf); _exit (errno); } break; case -1: return; default: entry->ini_count++; entry->ini_pid = child; birth (entry); if (mustwait) waitfor (entry); break; } } void waitfor (entry) struct inittab *entry; { struct inittab *ip; int pid; int status; int i; int children; if (entry && entry->ini_pid == 0) return; if (! entry) { /* count the children to wait for */ for (children = 0, ip = proc;ip != &proc[nproc];ip++) if (ip->ini_pid) children++; } else { /* only have one to worry about */ children = 1; } while (children && (pid = wait (&status)) != -1) { if (entry && pid == entry->ini_pid) { entry->ini_status = status; bury (entry); entry->ini_pid = 0; return; } /* * find process in table and lay to rest. may require * being restarted if action is respawn. entries not * in the table are silently buried. */ for (ip = proc;ip != &proc[nproc];ip++) { if (ip->ini_pid != pid) continue; ip->ini_status = status; bury (ip); children--; ip->ini_pid = 0; if (ip->ini_action == INIT_RESPAWN) { spawn (ip); children++; } break; } } } bury (entry) struct inittab *entry; { struct utmp *utmp; setutent (); while (utmp = getutent ()) { if (strcmp (utmp->ut_id, entry->ini_id) == 0) break; } if (utmp) { utmp->ut_pid = entry->ini_pid; utmp->ut_type = DEAD_PROCESS; utmp->ut_exit.e_termination = entry->ini_status & 0377; utmp->ut_exit.e_exit = (entry->ini_status >> 8) & 0377; pututline (utmp); write (wtmpfd, (char *) utmp, sizeof *utmp); } endutent (); } birth (entry) struct inittab *entry; { struct utmp *utmp; struct utmp new; setutent (); while (utmp = getutent ()) { if (strcmp (utmp->ut_id, entry->ini_id) == 0) break; } if (! utmp) { utmp = &new; memset ((char *) utmp, 0, sizeof *utmp); } strncpy (utmp->ut_id, entry->ini_id, sizeof (utmp->ut_id)); if (entry->ini_action == INIT_RESPAWN) strcpy (utmp->ut_user, "GETTY"); else memset (utmp->ut_user, '\0', sizeof utmp->ut_user); utmp->ut_pid = entry->ini_pid; utmp->ut_type = INIT_PROCESS; utmp->ut_exit.e_termination = 0; utmp->ut_exit.e_exit = 0; utmp->ut_time = time ((time_t *) 0); pututline (utmp); write (wtmpfd, (char *) utmp, sizeof *utmp); endutent (); } SHAR_EOF fi if test -f 'config.h' then echo shar: "will not over-write existing file 'config.h'" else cat << \SHAR_EOF > 'config.h' /* * config.h - init configuration file * * @(#)config.h 1.1 07:58:03 3/22/89 */ #ifndef DEBUG #define CONSOLE "/dev/console" #define NPROC 100 #define INITTAB "/etc/inittab" #else #define CONSOLE "/dev/tty" #define NPROC 20 #define INITTAB "inittab" #endif SHAR_EOF fi if test -f 'inittab.h' then echo shar: "will not over-write existing file 'inittab.h'" else cat << \SHAR_EOF > 'inittab.h' #include <stdio.h> #include "config.h" /* * inittab - structure of the inittab file * * @(#)inittab.h 1.1 07:58:06 3/22/89 */ struct inittab { char *ini_id; char *ini_levels; int ini_action; char *ini_command; long ini_count; int ini_pid; int ini_status; }; #define INIT_RESPAWN 0 #define INIT_WAIT 1 #define INIT_ONCE 2 #define INIT_BOOT 3 #define INIT_BOOTWAIT 4 #define INIT_POWERFAIL 5 #define INIT_POWERWAIT 6 #define INIT_OFF 7 #define INIT_ONDEMAND 8 #define INIT_INITDEFAULT 9 #define INIT_SYSINIT 10 SHAR_EOF fi if test -f 'patchlevel.h' then echo shar: "will not over-write existing file 'patchlevel.h'" else cat << \SHAR_EOF > 'patchlevel.h' /* * patchlevel.h - current patch level * * @(#)patchlevel.h 1.1 07:58:07 3/22/89 */ #define PATCHLEVEL 1 SHAR_EOF fi exit 0 # End of shell archive