Radix cross Linux

The main Radix cross Linux repository contains the build scripts of packages, which have the most complete and common functionality for desktop machines

452 Commits   2 Branches   1 Tag
Index: Makefile
===================================================================
--- Makefile	(nonexistent)
+++ Makefile	(revision 5)
@@ -0,0 +1,60 @@
+
+COMPONENT_TARGETS = $(HARDWARE_NOARCH)
+
+
+include ../../../../build-system/constants.mk
+
+
+url         = $(DOWNLOAD_SERVER)/sources/packages/a/sysvinit
+
+versions    = 2.99
+pkgname     = sysvinit
+suffix      = tar.xz
+
+tarballs    = $(addsuffix .$(suffix), $(addprefix $(pkgname)-, $(versions)))
+sha1s       = $(addsuffix .sha1sum, $(tarballs))
+
+patches     = $(CURDIR)/patches/sysvinit-2.99-initctl.patch
+patches    += $(CURDIR)/patches/sysvinit-2.99-paths.patch
+patches    += $(CURDIR)/patches/sysvinit-2.99-version.patch
+
+.NOTPARALLEL: $(patches)
+
+
+BUILD_TARGETS = $(tarballs) $(sha1s) $(patches)
+
+
+include ../../../../build-system/core.mk
+
+
+.PHONY: download_clean
+
+
+$(tarballs):
+	@echo -e "\n======= Downloading source tarballs =======" ; \
+	 for tarball in $(tarballs) ; do \
+	   echo "$(url)/$$tarball" | xargs -n 1 -P 100 wget $(WGET_OPTIONS) - & \
+	 done ; wait
+
+$(sha1s): $(tarballs)
+	@for sha in $@ ; do \
+	   echo -e "\n======= Downloading '$$sha' signature =======\n" ; \
+	   echo "$(url)/$$sha" | xargs -n 1 -P 100 wget $(WGET_OPTIONS) - & wait %1 ; \
+	   touch $$sha ; \
+	   echo -e "\n======= Check the '$$sha' sha1sum =======\n" ; \
+	   sha1sum --check $$sha ; ret="$$?" ; \
+	   if [ "$$ret" == "1" ]; then \
+	     echo -e "\n======= ERROR: Bad '$$sha' sha1sum =======\n" ; \
+	     exit 1 ; \
+	   fi ; \
+	 done
+
+$(patches): $(sha1s)
+	@echo -e "\n======= Create Patches =======\n" ; \
+	 ( cd create-2.99-initctl-patch ; ./create.patch.sh ) ; \
+	 ( cd create-2.99-paths-patch   ; ./create.patch.sh ) ; \
+	 ( cd create-2.99-version-patch ; ./create.patch.sh ) ; \
+	 echo -e "\n"
+
+download_clean:
+	@rm -f $(tarballs) $(sha1s) $(patches)
Index: create-2.99-initctl-patch/create.patch.sh
===================================================================
--- create-2.99-initctl-patch/create.patch.sh	(nonexistent)
+++ create-2.99-initctl-patch/create.patch.sh	(revision 5)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+VERSION=2.99
+
+tar --files-from=file.list -xJvf ../sysvinit-$VERSION.tar.xz
+mv sysvinit-$VERSION sysvinit-$VERSION-orig
+
+cp -rf ./sysvinit-$VERSION-new ./sysvinit-$VERSION
+
+diff --unified -Nr  sysvinit-$VERSION-orig  sysvinit-$VERSION > sysvinit-$VERSION-initctl.patch
+
+mv sysvinit-$VERSION-initctl.patch ../patches
+
+rm -rf ./sysvinit-$VERSION
+rm -rf ./sysvinit-$VERSION-orig

Property changes on: create-2.99-initctl-patch/create.patch.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: create-2.99-initctl-patch/file.list
===================================================================
--- create-2.99-initctl-patch/file.list	(nonexistent)
+++ create-2.99-initctl-patch/file.list	(revision 5)
@@ -0,0 +1,8 @@
+sysvinit-2.99/doc/Install
+sysvinit-2.99/doc/initctl
+sysvinit-2.99/man/init.8
+sysvinit-2.99/man/initctl.5
+sysvinit-2.99/src/Makefile
+sysvinit-2.99/src/init.c
+sysvinit-2.99/src/initreq.h
+sysvinit-2.99/src/shutdown.c
Index: create-2.99-initctl-patch/sysvinit-2.99-new/doc/Install
===================================================================
--- create-2.99-initctl-patch/sysvinit-2.99-new/doc/Install	(nonexistent)
+++ create-2.99-initctl-patch/sysvinit-2.99-new/doc/Install	(revision 5)
@@ -0,0 +1,73 @@
+
+Install instructions for the System V style init
+
+init, shutdown, halt, reboot, wall, last, mesg, runlevel,
+killall5, pidof, sulogin.
+
+All programs, files and scripts in this package are covered by
+the GNU General Public License version 2, and copyrighted by
+Miquel van Smoorenburg (1991-2004) and, Jesse Smith (2018). 
+
+If you are not using Debian and the debianized package,
+you may have to install the new init by hand if Debian is
+using an init system other than SysV (eg systemd). You should
+be able to drop the binaries into a Slackware or Devuan system, I think.
+
+The SysV init software, core programs and manual pages can be
+installed by running the following two commands from the top-level
+source directory.
+
+make
+sudo make install
+
+If sudo is not installed, the "make install" command may be run as
+the root user.
+
+Other than the GNU make utility, SysV init has few dependencies.
+SysV can be built on virtually any Linux system featuring
+the GNU C library or musl libc. A C compiler, such as the GNU Compiler
+Collection (GCC) or Clang is also required.
+
+Here is a list of preferred directories to install the progs & manpages,
+this should be done for you automatically when you run "make install"
+as the root user, or via sudo, ie "sudo make install".
+
+wall.1, last.1, mesg.1	   /usr/man/man1
+inittab.5, initscript.5	   /usr/man/man5
+init.8, halt.8, reboot.8,
+shutdown.8, powerd.8,
+killall5.8, pidof.8,
+runlevel.8, sulogin.8	   /usr/man/man8
+
+init			   /sbin/init
+inittab		   	   /etc/inittab
+initscript.sample          /etc/initscript.sample
+telinit		   	   a link (with ln(1) ) to init, either
+			   in /bin or in /sbin.
+halt			   /sbin/halt
+reboot			   a link to /sbin/halt in the same directory
+killall5		   /sbin/killall5
+pidof			   a link to /sbin/killall5 in the same directory.
+runlevel		   /sbin/runlevel
+shutdown		   /sbin/shutdown.
+wall			   /usr/bin/wall
+mesg			   /usr/bin/mesg
+last			   /usr/bin/last
+sulogin			   /sbin/sulogin
+bootlogd		   /sbin/bootlogd
+utmpdump                   don't install, it's just a debug thingy.
+
+If you already _have_ a "wall" in /bin (the SLS release had, for example)
+do _not_ install this version of wall. Chances are that the wall you are already
+using is linked to /bin/write. Either first _remove_ /bin/wall before
+installing the new one, or don't install the new one at all.
+
+You might want to create a file called "/etc/shutdown.allow". Read the
+manual page on shutdown to find out more about this.
+
+Running from a read-only file system (CDROM?):
+* All communication to init goes through the FIFO /dev/initctl.
+  There should be no problem using a read-only root file system
+  If you use a Linux kernel > 1.3.66. Older kernels don't allow
+  writing to a FIFO on a read-only file system.
+ 
Index: create-2.99-initctl-patch/sysvinit-2.99-new/doc/initctl
===================================================================
--- create-2.99-initctl-patch/sysvinit-2.99-new/doc/initctl	(nonexistent)
+++ create-2.99-initctl-patch/sysvinit-2.99-new/doc/initctl	(revision 5)
@@ -0,0 +1,94 @@
+This document describes the communiction pipe set up by SysV init
+at /dev/initctl. This named pipe allows programs with the proper
+permissions (typically programs run by root have read+write access to
+the pipe) to send signals to the init program (PID 1).
+
+The init manual page has, up until recently, simply stated
+that people wishing to understand how to send messages to init
+should read the init program's source code, but that is not usually practical.
+
+Messages sent to the pipe to talk to init must have a special format.
+This format is defined as a C structure and the technical break-down
+is presented here:
+
+/*
+ *      Because of legacy interfaces, "runlevel" and "sleeptime"
+ *      aren't in a separate struct in the union.
+ *
+ *      The weird sizes are because init expects the whole
+ *      struct to be 384 bytes.
+ */
+struct init_request {
+        int     magic;                  /* Magic number                 */
+        int     cmd;                    /* What kind of request         */
+        int     runlevel;               /* Runlevel to change to        */
+        int     sleeptime;              /* Time between TERM and KILL   */
+        union {
+                struct init_request_bsd bsd;
+                char                    data[368];
+        } i;
+};
+
+
+Let's go through the init_request structure one line at a time. The
+first variable, the "magic" number must be of the value 0x03091969.
+The init program then knows that only programs with root access which send
+this magic number are authorized to communicate with init.
+
+The cmd variable is a value in the range of 0-8 (currently). This cmd
+variable tells init what we want it to do. Here are the possible options:
+
+1 - Set the current runlevel, specified by the runlevel variable.
+2 - The power will fail soon (probably low battery) prepare to shutdown.
+3 - The power is failing, do shutdown immediately.
+4 - The power is okay, cancel shutdown.
+6 - Set an environment variable to a value to be specified in 
+    the data variable of this structure.
+
+Other cmd options may be added to init later. For example, command values
+0, 5 and 7 are defined but currently not implemented.
+
+The runlevel variable will specify the runlevel to switch to (0-6).
+
+The sleeptime variable is to be used when we want to tell init to change
+the time spent waiting between sending SIGTERM and SIGKILL during the
+shutdown process. Changing this at run time is not yet implemented.
+
+The data variable (in the union) can be used to pass misc data which init
+might need to process our request. For example, when setting environment
+variables.
+
+When setting an environment variable through init's /dev/initctl pipe,
+the data variable should have the format VARIABLE=VALUE. The string
+should be terminated with a NULL '\0' character.
+
+
+The following C code example shows how to send a set environment variable
+request to the init process using the /dev/initctl pipe. This example
+is simplified and skips the error checking. A more comlpete example can be
+found in the shutdown.c program's init_setnv() function.
+
+
+struct init_request     request;           /* this is the structure defined above */
+int                     fd;                /* file descriptor for the pipe */
+
+memset(&request, 0, sizeof(request));      /* initialize structure */
+request.magic = 0x03091969;                /* this magic number must be included */
+request.cmd = 6;                           /* 6 is the command to set a variable */
+sprintf(request.data, "VARIABLE=VALUE");   /* set VARIABLE to VALUE  in init */
+if ((fd = open(INIT_FIFO, O_WRONLY)) >= 0) /* open pipe for writing */
+{ 
+    size_t s  = sizeof(request);           /* size of the structure to write */
+    void *ptr = &request;                  /* temporary pointer */
+    write(fd, ptr, s);                     /* send the structure to the pipe */
+    close(fd);                             /* close the pipe when done */
+}
+
+
+
+Usually the /dev/initctl pipe would only be used by low-level programs to
+request a power-related shutdown or change the runlevel, like telinit
+would do. Most of the time there is no need to talk to init directly, but
+this gives us an extenable approach so init can be taught how to learn
+more commands.
+
Index: create-2.99-initctl-patch/sysvinit-2.99-new/doc
===================================================================
--- create-2.99-initctl-patch/sysvinit-2.99-new/doc	(nonexistent)
+++ create-2.99-initctl-patch/sysvinit-2.99-new/doc	(revision 5)

Property changes on: create-2.99-initctl-patch/sysvinit-2.99-new/doc
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: create-2.99-initctl-patch/sysvinit-2.99-new/man/init.8
===================================================================
--- create-2.99-initctl-patch/sysvinit-2.99-new/man/init.8	(nonexistent)
+++ create-2.99-initctl-patch/sysvinit-2.99-new/man/init.8	(revision 5)
@@ -0,0 +1,353 @@
+'\" -*- coding: UTF-8 -*-
+.\" Copyright (C) 1998-2004 Miquel van Smoorenburg.
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+.\"
+.\"{{{}}}
+.\"{{{  Title
+.TH INIT 8 "29 Jul 2004" "" "Linux System Administrator's Manual"
+.\"}}}
+.\"{{{  Name
+.SH NAME
+init, telinit \- process control initialization
+.\"}}}
+.\"{{{  Synopsis
+.SH SYNOPSIS
+.B /sbin/init
+.RB [ " -a " ]
+.RB [ " -s " ]
+.RB [ " -b " ]
+[ \fB\-z\fP \fIxxx\fP ]
+.RB [ " 0123456Ss " ]
+.br
+.B /sbin/init
+.RB [ " --version " ]
+.br
+.B /sbin/telinit
+[ \fB\-t\fP \fISECONDS\fP ]
+.RB [ " 0123456sSQqabcUu " ]
+.br
+.B /sbin/telinit
+[ \fB\-e\fP \fIVAR\fP[\fB=\fP\fIVAL\fP] ]
+.\"}}}
+.\"{{{  Description
+.SH DESCRIPTION
+.\"{{{  init
+.SS Init
+.B Init
+is the parent of all processes.  Its primary role is to create processes
+from a script stored in the file \fB/etc/inittab\fP (see
+\fIinittab\fP(5)).  This file usually has entries which cause \fBinit\fP
+to spawn \fBgetty\fPs on each line that users can log in.  It also
+controls autonomous processes required by any particular system.
+.PP
+.\"{{{ Runlevels
+.SH RUNLEVELS
+A \fIrunlevel\fP is a software configuration of the system which allows
+only a selected group of processes to exist.  The processes spawned by
+\fBinit\fP for each of these runlevels are defined in the
+\fB/etc/inittab\fP file.  \fBInit\fP can be in one of eight runlevels:
+\fB0\(en6\fP and \fBS\fP (a.k.a. \fBs\fP).  The runlevel is
+changed by having a privileged user run \fBtelinit\fP, which sends
+appropriate signals to \fBinit\fP, telling it which runlevel to change
+to.
+.PP
+Runlevels \fBS\fP, \fB0\fP, \fB1\fP, and \fB6\fP are reserved.
+Runlevel S is used to initialize the system on boot.
+When starting runlevel S (on boot)
+or runlevel 1 (switching from a multi-user runlevel)
+the system is entering ``single-user mode'', after which the
+current runlevel is S.
+Runlevel 0 is used to halt the system;
+runlevel 6 is used to reboot the system.
+.PP
+After booting through S the system automatically enters one of
+the multi-user runlevels 2 through 5, unless there was some
+problem that needs to be fixed by the administrator in
+single-user mode.
+Normally after entering single-user mode
+the administrator performs maintenance and then reboots the system.
+.PP
+For more information,
+see the manpages for \fBshutdown\fP(8) and \fBinittab\fP(5).
+.PP
+Runlevels 7-9 are also valid, though not really documented. This is
+because "traditional" Unix variants don't use them.
+.PP
+Runlevels \fIS\fP and \fIs\fP are the same.
+Internally they are aliases for the same runlevel.
+.\"}}}
+.PP
+.SH BOOTING
+After \fBinit\fP is invoked as the last step of the kernel boot sequence,
+it looks for the file \fB/etc/inittab\fP to see if there is an entry of the
+type \fBinitdefault\fP (see \fIinittab\fP(5)). The \fBinitdefault\fP entry
+determines the initial runlevel of the system.  If there is no such
+entry (or no \fB/etc/inittab\fP at all), a runlevel must be
+entered at the system console.
+.PP
+Runlevel \fBS\fP or \fBs\fP initialize the system
+and do not require an \fB/etc/inittab\fP file.
+.PP
+In single user mode, \fB/sbin/sulogin\fP is invoked on \fB/dev/console\fP.
+.PP
+When entering single user mode, \fBinit\fP initializes the consoles
+\fBstty\fP settings to sane values. Clocal mode is set. Hardware
+speed and handshaking are not changed.
+.PP
+When entering a multi-user mode for the first time, \fBinit\fP performs the
+\fBboot\fP and \fBbootwait\fP entries to allow file systems to be
+mounted before users can log in.  Then all entries matching the runlevel
+are processed.
+.PP
+When starting a new process, \fBinit\fP first checks whether the file
+\fI/etc/initscript\fP exists. If it does, it uses this script to
+start the process.
+.PP
+Each time a child terminates, \fBinit\fP records the fact and the reason
+it died in \fB/var/run/utmp\fP and \fB/var/log/wtmp\fP,
+provided that these files exist.
+.SH CHANGING RUNLEVELS
+After it has spawned all of the processes specified, \fBinit\fP waits
+for one of its descendant processes to die, a powerfail signal, or until
+it is signaled by \fBtelinit\fP to change the system's runlevel.  
+When one of the above three conditions occurs, it re-examines
+the \fB/etc/inittab\fP file.  New entries can be added to this file at
+any time.  However, \fBinit\fP still waits for one of the above three
+conditions to occur.  To provide for an instantaneous response, the
+\fBtelinit Q\fP or \fBq\fP command can wake up \fBinit\fP to re-examine (reload) the
+\fB/etc/inittab\fP file.
+.PP
+If \fBinit\fP is not in single user mode and receives a powerfail
+signal (SIGPWR), it reads the file \fB/etc/powerstatus\fP. It then starts
+a command based on the contents of this file:
+.IP F(AIL)
+Power is failing, UPS is providing the power. Execute the \fBpowerwait\fP
+and \fBpowerfail\fP entries.
+.IP O(K)
+The power has been restored, execute the \fBpowerokwait\fP entries.
+.IP L(OW)
+The power is failing and the UPS has a low battery. Execute the
+\fBpowerfailnow\fP entries.
+.PP
+If /etc/powerstatus doesn't exist or contains anything else then the
+letters \fBF\fP, \fBO\fP or \fBL\fP, init will behave as if it has read
+the letter \fBF\fP.
+.PP
+Usage of \fBSIGPWR\fP and \fB/etc/powerstatus\fP is discouraged. Someone
+wanting to interact with \fBinit\fP should use the \fB/dev/initctl\fP
+control channel - see the initctl manual page for more documentation
+about this.
+.PP
+When \fBinit\fP is requested to change the runlevel, it sends the
+warning signal \s-1\fBSIGTERM\fP\s0 to all processes that are undefined
+in the new runlevel.  It then waits 3 seconds before forcibly
+terminating these processes via the \s-1\fBSIGKILL\fP\s0 signal.
+Note that \fBinit\fP assumes that all these processes (and their
+descendants) remain in the same process group which \fBinit\fP
+originally created for them.  If any process changes its process group
+affiliation it will not receive these signals.  Such processes need to
+be terminated separately.
+.\"}}}
+.\"{{{  telinit
+.SH TELINIT
+\fB/sbin/telinit\fP is linked to \fB/sbin/init\fP.  It takes a
+one-character argument and signals \fBinit\fP to perform the appropriate
+action.  The following arguments serve as directives to
+\fBtelinit\fP:
+.IP "\fB0\fP,\fB1\fP,\fB2\fP,\fB3\fP,\fB4\fP,\fB5\fP or \fB6\fP"
+tell \fBinit\fP to switch to the specified run level.
+.IP \fBa\fP,\fBb\fP,\fBc\fP
+tell \fBinit\fP to process only those \fB/etc/inittab\fP file
+entries having runlevel \fBa\fP,\fBb\fP or \fBc\fP.
+.IP "\fBQ\fP or \fBq\fP"
+tell \fBinit\fP to re-examine the \fB/etc/inittab\fP file.
+.IP "\fBS\fP or \fBs\fP"
+tell \fBinit\fP to switch to single user mode.
+.IP "\fBU\fP or \fBu\fP"
+tell \fBinit\fP to re-execute itself (preserving the state). No re-examining of 
+\fB/etc/inittab\fP file happens. Runlevel should be one of
+\fBSs0123456\fP
+otherwise request would be silently ignored.
+.PP
+\fBtelinit\fP can tell \fBinit\fP how long it should wait
+between sending processes the SIGTERM and SIGKILL signals.  The default
+is 3 seconds, but this can be changed with the \fB-t\fP option.
+.PP
+\fBtelinit -e\fP tells \fBinit\fP to change the environment
+for processes it spawns.
+The argument of \fB-e\fP is either of the form \fIVAR\fP=\fIVAL\fP
+which sets variable \fIVAR\fP to value \fIVAL\fP,
+or of the form \fIVAR\fP
+(without an equality sign)
+which unsets variable \fIVAR\fP.
+.PP
+\fBtelinit\fP can be invoked only by users with appropriate
+privileges.
+.PP
+The \fBinit\fP binary checks if it is \fBinit\fP or \fBtelinit\fP by looking
+at its \fIprocess id\fP; the real \fBinit\fP's process id is always \fB1\fP.
+From this it follows that instead of calling \fBtelinit\fP one can also
+just use \fBinit\fP instead as a shortcut.
+.\"}}}
+.\"}}}
+.SH ENVIRONMENT
+\fBInit\fP sets the following environment variables for all its children:
+.IP \fBPATH\fP
+\fI/bin:/usr/bin:/sbin:/usr/sbin\fP
+.IP \fBINIT_VERSION\fP
+As the name says. Useful to determine if a script runs directly from \fBinit\fP.
+.IP \fBRUNLEVEL\fP
+The current system runlevel.
+.IP \fBPREVLEVEL\fP
+The previous runlevel (useful after a runlevel switch).
+.IP \fBCONSOLE\fP
+The system console. This is really inherited from the kernel; however
+if it is not set \fBinit\fP will set it to \fB/dev/console\fP by default.
+.SH BOOTFLAGS
+It is possible to pass a number of flags to \fBinit\fP from the
+boot monitor (eg. LILO or GRUB). \fBInit\fP accepts the following flags:
+.TP 0.5i
+.B -s, S, single
+Single user mode boot. In this mode \fI/etc/inittab\fP is
+examined and the bootup rc scripts are usually run before
+the single user mode shell is started.
+.PP
+.TP 0.5i
+.B 1-5
+Runlevel to boot into.
+.PP
+.TP 0.5i
+.B -b, emergency
+Boot directly into a single user shell without running any
+other startup scripts.
+.PP
+.TP 0.5i
+.B -a, auto
+The LILO boot loader adds the word "auto" to the command line if it
+booted the kernel with the default command line (without user intervention).
+If this is found \fBinit\fP sets the "AUTOBOOT" environment
+variable to "yes". Note that you cannot use this for any security
+measures - of course the user could specify "auto" or \-a on the
+command line manually.
+.PP
+.TP 0.5i
+.BI "-z " xxx
+The argument to \fB-z\fP is ignored. You can use this to expand the command
+line a bit, so that it takes some more space on the stack. \fBInit\fP
+can then manipulate the command line so that \fBps\fP(1) shows
+the current runlevel.
+.PP
+.TP 0.5i
+.B \-\-version
+This argument, when used on its own, displays the current version of init
+to the console/stdout. It is a quick way to determine which init software and
+version is being used. After the version information is displayed, init
+immediately exits with a return code of zero. 
+.PP
+.SH INTERFACE
+Init listens on a \fIfifo\fP in /dev, \fI/dev/initctl\fP, for messages.
+\fBTelinit\fP uses this to communicate with init. The interface is not
+very well documented or finished. Those interested should study the
+\fIinitreq.h\fP file in the \fIsrc/\fP subdirectory of the \fBinit\fP
+source code tar archive.
+.SH SIGNALS
+Init reacts to several signals:
+.TP 0.5i
+.B SIGHUP
+Has the same effect as \fBtelinit q\fP.
+.PP
+.TP 0.5i
+.B SIGUSR1
+On receipt of this signals, init closes and re-opens its control fifo,
+\fB/dev/initctl\fP. Useful for bootscripts when /dev is remounted.
+.TP 0.5i
+.B SIGUSR2
+When init receives SIGUSR2, init closes and leaves the control fifo,
+\fB/dev/initctl\fP, closed. This may be used to make sure init is not
+holding open any files. However, it also prevents init from switching
+runlevels. Which means commands like shutdown no longer work.
+The fifo can be re-opened by sending init the SIGUSR1 signal.
+.TP 0.5i
+.B SIGINT
+Normally the kernel sends this signal to init when CTRL-ALT-DEL is
+pressed. It activates the \fIctrlaltdel\fP action.
+.TP 0.5i
+.B SIGWINCH
+The kernel sends this signal when the \fIKeyboardSignal\fP key is hit.
+It activates the \fIkbrequest\fP action.
+\"{{{  Conforming to
+.SH CONFORMING TO
+\fBInit\fP is compatible with the System V init. It works closely
+together with the scripts in the directories
+\fI/etc/init.d\fP and \fI/etc/rc{runlevel}.d\fP.
+If your system uses this convention, there should be a \fIREADME\fP
+file in the directory \fI/etc/init.d\fP explaining how these scripts work.
+.\"}}}
+.\"{{{  Files
+.SH FILES
+.nf
+/etc/inittab
+/etc/initscript
+/dev/console
+/var/run/utmp
+/var/log/wtmp
+/dev/initctl
+.fi
+.\"}}}
+.\"{{{  Warnings
+.SH WARNINGS
+\fBInit\fP assumes that processes and descendants of processes
+remain in the same process group which was originally created
+for them.  If the processes change their group, \fBinit\fP can't
+kill them and you may end up with two processes reading from one
+terminal line.
+.PP
+On a Debian system, entering runlevel 1 causes all processes
+to be killed except for kernel threads and the script that does
+the killing and other processes in its session.
+As a consequence of this, it isn't safe to return from runlevel 1
+to a multi-user runlevel: daemons that were started in runlevel S
+and are needed for normal operation are no longer running.
+The system should be rebooted.
+.\"}}}
+.\"{{{  Diagnostics
+.SH DIAGNOSTICS
+If \fBinit\fP finds that it is continuously respawning an entry
+more than 10 times in 2 minutes, it will assume that there is an error
+in the command string, generate an error message on the system console,
+and refuse to respawn this entry until either 5 minutes has elapsed or
+it receives a signal.  This prevents it from eating up system resources
+when someone makes a typographical error in the \fB/etc/inittab\fP file
+or the program for the entry is removed.
+.\"}}}
+.\"{{{  Author
+.SH AUTHOR
+Miquel van Smoorenburg (miquels@cistron.nl), initial manual
+page by Michael Haardt (u31b3hs@pool.informatik.rwth-aachen.de).
+.\"}}}
+.\"{{{  See also
+.SH "SEE ALSO"
+.BR getty (1),
+.BR login (1),
+.BR sh (1),
+.BR runlevel (8),
+.BR shutdown (8),
+.BR kill (1),
+.BR initctl (5),
+.BR inittab (5),
+.BR initscript (5),
+.BR utmp (5)
+.\"}}}
Index: create-2.99-initctl-patch/sysvinit-2.99-new/man/initctl.5
===================================================================
--- create-2.99-initctl-patch/sysvinit-2.99-new/man/initctl.5	(nonexistent)
+++ create-2.99-initctl-patch/sysvinit-2.99-new/man/initctl.5	(revision 5)
@@ -0,0 +1,148 @@
+'\" -*- coding: UTF-8 -*-
+.\" Copyright (C) 2018 Jesse Smith
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+.\"
+.TH INITCTL 5 "April 13, 2018" "" "Linux System Administrator's Manual"
+.SH NAME
+initctl \- /dev/initctl is a named pipe which passes commands to SysV init.
+.SH SYNOPSIS
+/dev/initctl
+.SH DESCRIPTION
+
+This document describes the communiction pipe set up by SysV init
+at /dev/initctl. This named pipe allows programs with the proper
+permissions (typically programs run by root have read+write access to
+the pipe) to send signals to the init program (PID 1).
+
+The init manual page has, up until recently, simply stated
+that people wishing to understand how to send messages to init
+should read the init program's source code, but that is not usually practical.
+
+Messages sent to the pipe to talk to init must have a special format.
+This format is defined as a C structure and the technical break-down
+is presented here:
+
+/*
+ *      Because of legacy interfaces, "runlevel" and "sleeptime"
+ *      aren't in a separate struct in the union.
+ *
+ *      The weird sizes are because init expects the whole
+ *      struct to be 384 bytes.
+ */
+
+struct init_request {
+        int     magic;                  /* Magic number                 */
+        int     cmd;                    /* What kind of request         */
+        int     runlevel;               /* Runlevel to change to        */
+        int     sleeptime;              /* Time between TERM and KILL   */
+        union {
+                struct init_request_bsd bsd;
+                char                    data[368];
+        } i;
+};
+
+
+Let's go through the init_request structure one line at a time. The
+first variable, the "magic" number must be of the value 0x03091969.
+The init program then knows that only programs with root access which send
+this magic number are authorized to communicate with init.
+
+The cmd variable is a value in the range of 0-8 (currently). This cmd
+variable tells init what we want it to do. Here are the possible options:
+
+1 - Set the current runlevel, specified by the runlevel variable.
+
+2 - The power will fail soon (probably low battery) prepare to shutdown.
+
+3 - The power is failing, do shutdown immediately.
+
+4 - The power is okay, cancel shutdown.
+
+6 - Set an environment variable to a value to be specified in 
+    the data variable of this structure.
+
+Other cmd options may be added to init later. For example, command values
+0, 5 and 7 are defined but currently not implemented.
+
+The runlevel variable will specify the runlevel to switch to (0-6).
+
+The sleeptime variable is to be used when we want to tell init to change
+the time spent waiting between sending SIGTERM and SIGKILL during the
+shutdown process. Changing this at run time is not yet implemented.
+
+The data variable (in the union) can be used to pass misc data which init
+might need to process our request. For example, when setting environment
+variables.
+
+When setting an environment variable through init's /dev/initctl pipe,
+the data variable should have the format VARIABLE=VALUE. The string
+should be terminated with a NULL character.
+
+.SH EXAMPLES
+
+The following C code example shows how to send a set environment variable
+request to the init process using the /dev/initctl pipe. This example
+is simplified and skips the error checking. A more comlpete example can be
+found in the shutdown.c program's init_setnv() function.
+
+.nf
+struct init_request     request;           /* structure defined above */
+int                     fd;                /* file descriptor for pipe */
+
+memset(&request, 0, sizeof(request));      /* initialize structure */
+request.magic = 0x03091969;                /* magic number required */
+request.cmd = 6;                           /* 6 is to set a variable */
+sprintf(request.data, "VARIABLE=VALUE");   /* set VAR to VALUE in init */
+
+if ((fd = open(INIT_FIFO, O_WRONLY)) >= 0) /* open pipe for writing */
+{ 
+    size_t s  = sizeof(request);           /* size of structure to write */
+    void *ptr = &request;                  /* temporary pointer */
+    write(fd, ptr, s);                     /* send structure to the pipe */
+    close(fd);                             /* close the pipe when done */
+}
+.fi
+
+.sp
+.SH NOTES
+Usually the /dev/initctl pipe would only be used by low-level programs to
+request a power-related shutdown or change the runlevel, like telinit
+would do. Most of the time there is no need to talk to init directly, but
+this gives us an extenable approach so init can be taught how to learn
+more commands.
+.PP
+The commands passed through the /dev/initctl pipe must be sent in a specific
+binary format and be of a specific length. Larger data structures or ones
+not using the proper format will be ignored. Typically, only root has the
+ability to write to the initctl pipe for security reasons.
+.PP
+The /dev/initctl pipe can be closed by sending init (PID 1) the SIGUSR2
+signal. This closes the pipe and leaves it closed. This may be useful
+for making sure init is not keeping any files open. However, when the
+pipe is closed, init no longer receives signals, such as those sent by
+shutdown or telinit. In other words if we close the pipe, init cannot
+change its runlevel directly. The pipe may be re-opened by sending init (PID 1)
+the SIGUSR1 signal.
+.PP
+If the /dev/initctl pipe is closed then it may still be possible to bring
+down the system using the shutdown command's -n flag, but this is not
+always clean and not recommended.
+.SH FILES
+/dev/initctl
+/sbin/init
+.SH AUTHOR
+Jesse Smith <jsmith@resonatingmedia.com> 
+.SH "SEE ALSO"
+init(8)
Index: create-2.99-initctl-patch/sysvinit-2.99-new/man
===================================================================
--- create-2.99-initctl-patch/sysvinit-2.99-new/man	(nonexistent)
+++ create-2.99-initctl-patch/sysvinit-2.99-new/man	(revision 5)

Property changes on: create-2.99-initctl-patch/sysvinit-2.99-new/man
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: create-2.99-initctl-patch/sysvinit-2.99-new/src/Makefile
===================================================================
--- create-2.99-initctl-patch/sysvinit-2.99-new/src/Makefile	(nonexistent)
+++ create-2.99-initctl-patch/sysvinit-2.99-new/src/Makefile	(revision 5)
@@ -0,0 +1,240 @@
+#
+# Makefile	Makefile for the systemV init suite.
+#		Targets:   all      compiles everything
+#		           install  installs the binaries (not the scripts)
+#                          clean    cleans up object files
+#			   clobber  really cleans up
+#
+# Version:	@(#)Makefile  2.85-13  23-Mar-2004  miquels@cistron.nl
+#
+
+CPPFLAGS =
+CFLAGS  ?= -O2
+override CFLAGS += -ansi -fomit-frame-pointer -fstack-protector-strong -W -Wall -Wunreachable-code -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2 -D_XOPEN_SOURCE -D_GNU_SOURCE -DVERSION=\"$(VERSION)\"
+override CFLAGS += $(shell getconf LFS_CFLAGS)
+STATIC	=
+MANDB	:= s@^\('\\\\\"\)[^\*-]*-\*- coding: [^[:blank:]]\+ -\*-@\1@
+
+#
+# Leave empty if the mountpoint(1) command from util-linux 2.20
+# and above should be used, otherwise set it to yes.
+#
+MNTPOINT=
+
+# For some known distributions we do not build all programs, otherwise we do.
+BIN	=
+SBIN	= init halt shutdown runlevel killall5 fstab-decode logsave
+USRBIN	= last mesg readbootlog
+
+MAN1	= last.1 lastb.1 mesg.1 readbootlog.1
+MAN5	= initscript.5 inittab.5 initctl.5
+MAN8	= halt.8 init.8 killall5.8 pidof.8 poweroff.8 reboot.8 runlevel.8
+MAN8	+= shutdown.8 telinit.8 fstab-decode.8 logsave.8
+
+ifeq ($(DISTRO),)
+SBIN	+= sulogin bootlogd
+USRBIN	+= utmpdump wall
+MAN1	+= utmpdump.1 wall.1
+MAN8	+= sulogin.8 bootlogd.8
+endif
+
+ifeq ($(DISTRO),Debian)
+CPPFLAGS+= -DACCTON_OFF
+SBIN	+= sulogin bootlogd
+MAN8	+= sulogin.8 bootlogd.8
+MANDB	:=
+endif
+
+ifeq ($(DISTRO),Owl)
+USRBIN	+= wall
+MAN1	+= wall.1
+MANDB	:=
+endif
+
+ifeq ($(DISTRO),SuSE)
+CPPFLAGS+= -DUSE_SYSFS -DSANE_TIO -DSIGINT_ONLYONCE -DUSE_ONELINE
+SBIN	+= sulogin
+USRBIN	+= utmpdump
+MAN1	+= utmpdump.1
+MAN8	+= sulogin.8
+MANDB	:=
+endif
+
+ifeq ($(MNTPOINT),yes)
+BIN	+= mountpoint
+MAN1	+= mountpoint.1
+endif
+
+ID		= $(shell id -u)
+BIN_OWNER	= root
+BIN_GROUP	= root
+BIN_COMBO	= $(BIN_OWNER):$(BIN_GROUP)
+ifeq ($(ID),0)
+  INSTALL_EXEC	= install -o $(BIN_OWNER) -g $(BIN_GROUP) -m 755
+  INSTALL_DATA	= install -o $(BIN_OWNER) -g $(BIN_GROUP) -m 644
+else
+  INSTALL_EXEC	= install -m 755
+  INSTALL_DATA	= install -m 644
+endif
+INSTALL_DIR	= install -m 755 -d
+MANDIR		= /usr/share/man
+
+ifeq ($(WITH_SELINUX),yes)
+  SELINUX_DEF	=  -DWITH_SELINUX
+  INITLIBS	+= -lselinux
+  SULOGINLIBS	= -lselinux	
+else
+  SELINUX_DEF	=
+  INITLIBS	=
+  SULOGINLIBS	=
+endif
+
+# Additional libs for GNU libc.
+ifneq ($(wildcard $(ROOT)/usr/lib*/libcrypt.*),)
+  SULOGINLIBS	+= -lcrypt
+endif
+
+# Additional libs for GNU libc / multiarch on Debian based systems.
+ifneq ($(wildcard $(ROOT)/usr/lib/*/libcrypt.*),)
+ifneq ($(findstring -lcrypt, $(SULOGINLIBS)), -lcrypt)
+  SULOGINLIBS	+= -lcrypt
+endif
+endif
+
+all:		$(BIN) $(SBIN) $(USRBIN)
+
+#%: %.o
+#	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
+#%.o: %.c
+#	$(CC) $(CFLAGS) $(CPPFLAGS) -c $^ -o $@
+
+init:		LDLIBS += $(INITLIBS) $(STATIC)
+init:		init.o init_utmp.o runlevellog.o
+
+halt:		LDLIBS += $(STATIC)
+halt:		halt.o ifdown.o hddown.o utmp.o runlevellog.o
+
+last:		LDLIBS += $(STATIC)
+last:		last.o
+
+logsave:	LDLIBS += $(STATIC)
+logsave:	logsave.o
+
+mesg:		LDLIBS += $(STATIC)
+mesg:		mesg.o
+
+mountpoint:	LDLIBS += $(STATIC)
+mountpoint:	mountpoint.o
+
+utmpdump:	LDLIBS += $(STATIC)
+utmpdump:	utmpdump.o
+
+runlevel:	LDLIBS += $(STATIC)
+runlevel:	runlevel.o runlevellog.o
+
+sulogin:	LDLIBS += $(SULOGINLIBS) $(STATIC)
+sulogin:	sulogin.o consoles.o
+
+wall:		LDLIBS += $(STATIC)
+wall:		dowall.o wall.o
+
+shutdown:	LDLIBS += $(STATIC)
+shutdown:	dowall.o shutdown.o utmp.o
+
+bootlogd:	LDLIBS += -lutil $(STATIC)
+bootlogd:	bootlogd.o
+
+readbootlog:	LDLIBS += $(STATIC)
+readbootlog:	readbootlog.o 
+
+fstab-decode:	LDLIBS += $(STATIC)
+fstab-decode:	fstab-decode.o
+
+sulogin.o:	CPPFLAGS += $(SELINUX_DEF)
+sulogin.o:	sulogin.c 
+
+runlevellog.o:	runlevellog.h runlevellog.c paths.h
+
+init.o:		CPPFLAGS += $(SELINUX_DEF)
+init.o:		init.c init.h initreq.h paths.h reboot.h runlevellog.h runlevellog.c set.h 
+
+utmp.o:		
+
+init_utmp.o:	CPPFLAGS += -DINIT_MAIN
+init_utmp.o:	utmp.c init.h initreq.h paths.h
+		$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
+
+bootlogd.o:	bootlogd.c bootlogd.h
+
+readbootlog.o:	readbootlog.c
+ 
+utmpdump.o:	utmpdump.c oldutmp.h
+
+shutdown.o:	shutdown.c paths.h reboot.h initreq.h init.h
+
+halt.o:		halt.c reboot.h paths.h runlevellog.c runlevellog.h
+
+last.o:		last.c oldutmp.h
+
+logsave.o:	logsave.c
+
+consoles.o:	consoles.c consoles.h
+
+cleanobjs:
+		rm -f *.o *.bak
+
+clean:		cleanobjs clobber
+
+clobber:	cleanobjs
+		rm -f $(BIN) $(SBIN) $(USRBIN)
+
+distclean:	clobber
+
+install:	all
+		$(INSTALL_DIR) $(ROOT)/bin/ $(ROOT)/sbin/
+		$(INSTALL_DIR) $(ROOT)/usr/bin/
+		for i in $(BIN); do \
+			$(INSTALL_EXEC) $$i $(ROOT)/bin/ ; \
+		done
+		for i in $(SBIN); do \
+			$(INSTALL_EXEC) $$i $(ROOT)/sbin/ ; \
+		done
+		for i in $(USRBIN); do \
+			$(INSTALL_EXEC) $$i $(ROOT)/usr/bin/ ; \
+		done
+		# $(INSTALL_DIR) $(ROOT)/etc/
+		$(INSTALL_DIR) $(ROOT)/etc/inittab.d
+		# $(INSTALL_EXEC) ../doc/initscript.sample $(ROOT)/etc/
+		ln -sf halt $(ROOT)/sbin/reboot
+		ln -sf halt $(ROOT)/sbin/poweroff
+		ln -sf init $(ROOT)/sbin/telinit
+		ln -sf /sbin/killall5 $(ROOT)/bin/pidof
+		if [ ! -f $(ROOT)/usr/bin/lastb ]; then \
+			ln -sf last $(ROOT)/usr/bin/lastb; \
+		fi
+		$(INSTALL_DIR) $(ROOT)/usr/include/
+		$(INSTALL_DATA) initreq.h $(ROOT)/usr/include/
+		$(INSTALL_DIR) $(ROOT)$(MANDIR)/man1/
+		$(INSTALL_DIR) $(ROOT)$(MANDIR)/man5/
+		$(INSTALL_DIR) $(ROOT)$(MANDIR)/man8/
+		for man in $(MAN1); do \
+			$(INSTALL_DATA) ../man/$$man $(ROOT)$(MANDIR)/man1/; \
+			sed -i "1{ $(MANDB); }" $(ROOT)$(MANDIR)/man1/$$man ; \
+		done
+		for man in $(MAN5); do \
+			$(INSTALL_DATA) ../man/$$man $(ROOT)$(MANDIR)/man5/; \
+			sed -i "1{ $(MANDB); }" $(ROOT)$(MANDIR)/man5/$$man ; \
+		done
+		for man in $(MAN8); do \
+			$(INSTALL_DATA) ../man/$$man $(ROOT)$(MANDIR)/man8/; \
+			sed -i "1{ $(MANDB); }" $(ROOT)$(MANDIR)/man8/$$man ; \
+		done
+ifeq ($(ROOT),)
+		#
+		# This part is skipped on Debian systems, the
+		# debian.preinst script takes care of it.
+		@if [ ! -p /dev/initctl ]; then \
+		 echo "Creating /dev/initctl"; \
+		 rm -f /dev/initctl; \
+		 mknod -m 600 /dev/initctl p; fi
+endif
Index: create-2.99-initctl-patch/sysvinit-2.99-new/src/init.c
===================================================================
--- create-2.99-initctl-patch/sysvinit-2.99-new/src/init.c	(nonexistent)
+++ create-2.99-initctl-patch/sysvinit-2.99-new/src/init.c	(revision 5)
@@ -0,0 +1,3190 @@
+/*
+ * Init		A System-V Init Clone.
+ *
+ * Usage:	/sbin/init
+ *		     init [0123456SsQqAaBbCc]
+ *		  telinit [0123456SsQqAaBbCc]
+ *
+ * Version:	@(#)init.c  2.86  30-Jul-2004  miquels@cistron.nl
+ * Version:     init.c 2.90 18-Jun-2018 jsmith@resonatingmedia.com
+ */
+
+/*
+Version information is not placed in the top-level Makefile by default
+*/
+#ifndef VERSION
+#define VERSION "2.94"
+#endif
+/*
+ *		This file is part of the sysvinit suite,
+ *		Copyright (C) 1991-2004 Miquel van Smoorenburg.
+ *		Copyright (C) 2017-2019 Jesse Smith
+ *
+ *		This program is free software; you can redistribute it and/or modify
+ *		it under the terms of the GNU General Public License as published by
+ *		the Free Software Foundation; either version 2 of the License, or
+ *		(at your option) any later version.
+ *
+ *		This program is distributed in the hope that it will be useful,
+ *		but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *		GNU General Public License for more details.
+ *
+ *		You should have received a copy of the GNU General Public License
+ *		along with this program; if not, write to the Free Software
+ *		Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#ifdef __linux__
+#include <sys/kd.h>
+#endif
+#include <sys/resource.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <time.h>
+#include <fcntl.h>
+#include <string.h>
+#include <signal.h>
+#include <termios.h>
+#ifdef __FreeBSD__
+#include <utmpx.h>
+#else
+#include <utmp.h>
+#endif
+#include <ctype.h>
+#include <stdarg.h>
+#include <sys/ttydefaults.h>
+#include <sys/syslog.h>
+#include <sys/time.h>
+/*
+ * inittab.d
+ */
+#include <sys/types.h>
+#include <dirent.h>
+
+#ifdef WITH_SELINUX
+#  include <selinux/selinux.h>
+#endif
+#ifdef __FreeBSD__
+extern char **environ;
+#endif
+
+#ifdef __i386__
+#  ifdef __GLIBC__
+     /* GNU libc 2.x */
+#    define STACK_DEBUG 1
+#    if (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
+       /* Only glibc 2.0 needs this */
+#      include <sigcontext.h>
+#    elif ( __GLIBC__ > 2) && ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1))
+#      include <bits/sigcontext.h>
+#    endif
+#  endif
+#endif
+
+#include "init.h"
+#include "initreq.h"
+#include "paths.h"
+#include "reboot.h"
+#include "runlevellog.h"
+#include "set.h"
+
+#ifndef SIGPWR
+#  define SIGPWR SIGUSR2
+#endif
+
+#ifndef CBAUD
+#  define CBAUD		0
+#endif
+#ifndef CBAUDEX
+#  define CBAUDEX	0
+#endif
+
+/* Set a signal handler. */
+#define SETSIG(sa, sig, fun, flags) \
+		do { \
+			memset(&sa, 0, sizeof(sa)); \
+			sa.sa_handler = fun; \
+			sa.sa_flags = flags; \
+			sigemptyset(&sa.sa_mask); \
+			sigaction(sig, &sa, NULL); \
+		} while(0)
+
+/* Version information */
+char *Version = "@(#) init " VERSION " miquels@cistron.nl";
+char *bootmsg = "version " VERSION " %s";
+#define E_VERSION "INIT_VERSION=sysvinit-" VERSION
+
+CHILD *family = NULL;		/* The linked list of all entries */
+CHILD *newFamily = NULL;	/* The list after inittab re-read */
+
+CHILD ch_emerg = {		/* Emergency shell */
+	WAITING, 0, 0, 0, 0,
+	"~~",
+	"S",
+	3,
+	"/sbin/sulogin",
+	NULL,
+	NULL
+};
+
+char runlevel = 'S';		/* The current run level */
+char thislevel = 'S';		/* The current runlevel */
+char prevlevel = 'N';		/* Previous runlevel */
+int dfl_level = 0;		/* Default runlevel */
+sig_atomic_t got_cont = 0;	/* Set if we received the SIGCONT signal */
+sig_atomic_t got_signals;	/* Set if we received a signal. */
+int emerg_shell = 0;		/* Start emergency shell? */
+int wrote_wtmp_reboot = 1;	/* Set when we wrote the reboot record */
+int wrote_utmp_reboot = 1;	/* Set when we wrote the reboot record */
+int wrote_wtmp_rlevel = 1;	/* Set when we wrote the runlevel record */
+int wrote_utmp_rlevel = 1;	/* Set when we wrote the runlevel record */
+int sleep_time = WAIT_BETWEEN_SIGNALS;    /* Sleep time between TERM and KILL */
+char *argv0;			/* First arguments; show up in ps listing */
+int maxproclen;			/* Maximal length of argv[0] with \0 */
+struct utmp utproto;		/* Only used for sizeof(utproto.ut_id) */
+char *console_dev;		/* Console device. */
+int pipe_fd = -1;		/* /dev/initctl */
+int did_boot = 0;		/* Did we already do BOOT* stuff? */
+int main(int, char **);
+
+/*	Used by re-exec part */
+int reload = 0;			/* Should we do initialization stuff? */
+char *myname=INIT;		/* What should we exec */
+int oops_error;			/* Used by some of the re-exec code. */
+const char *Signature = "12567362";	/* Signature for re-exec fd */
+
+/* Macro to see if this is a special action */
+#define ISPOWER(i) ((i) == POWERWAIT || (i) == POWERFAIL || \
+		    (i) == POWEROKWAIT || (i) == POWERFAILNOW || \
+		    (i) == CTRLALTDEL)
+
+/* ascii values for the `action' field. */
+struct actions {
+  char *name;
+  int act;
+} actions[] = {
+  { "respawn", 	   RESPAWN	},
+  { "wait",	   WAIT		},
+  { "once",	   ONCE		},
+  { "boot",	   BOOT		},
+  { "bootwait",	   BOOTWAIT	},
+  { "powerfail",   POWERFAIL	},
+  { "powerfailnow",POWERFAILNOW },
+  { "powerwait",   POWERWAIT	},
+  { "powerokwait", POWEROKWAIT	},
+  { "ctrlaltdel",  CTRLALTDEL	},
+  { "off",	   OFF		},
+  { "ondemand",	   ONDEMAND	},
+  { "initdefault", INITDEFAULT	},
+  { "sysinit",	   SYSINIT	},
+  { "kbrequest",   KBREQUEST    },
+  { NULL,	   0		},
+};
+
+/*
+ *	State parser token table (see receive_state)
+ */
+struct {
+  char name[4];	
+  int cmd;
+} cmds[] = {
+  { "VER", 	   C_VER	},
+  { "END",	   C_END	},
+  { "REC",	   C_REC	},
+  { "EOR",	   C_EOR	},
+  { "LEV",	   C_LEV	},
+  { "FL ",	   C_FLAG	},
+  { "AC ",	   C_ACTION	},
+  { "CMD",	   C_PROCESS	},
+  { "PID",	   C_PID	},
+  { "EXS",	   C_EXS	},
+  { "-RL",	   D_RUNLEVEL	},
+  { "-TL",	   D_THISLEVEL	},
+  { "-PL",	   D_PREVLEVEL	},
+  { "-SI",	   D_GOTSIGN	},
+  { "-WR",	   D_WROTE_WTMP_REBOOT},
+  { "-WU",	   D_WROTE_UTMP_REBOOT},
+  { "-ST",	   D_SLTIME	},
+  { "-DB",	   D_DIDBOOT	},
+  { "-LW",	   D_WROTE_WTMP_RLEVEL},
+  { "-LU",	   D_WROTE_UTMP_RLEVEL},
+  { "",	   	   0		}
+};
+struct {
+	char *name;
+	int mask;
+} flags[]={
+	{"RU",RUNNING},
+	{"DE",DEMAND},
+	{"XD",XECUTED},
+	{"WT",WAITING},
+	{NULL,0}
+};
+
+#define NR_EXTRA_ENV	16
+char *extra_env[NR_EXTRA_ENV];
+
+#define MINI_SLEEP 10      /* ten milliseconds */
+#define SHORT_SLEEP 5000   /* five seconds */
+#define LONG_SLEEP 30000   /* 30 seconds sleep to deal with memory issues*/
+
+/*
+ *	Sleep a number of milliseconds.
+ *
+ *	This only works correctly because Linux select updates
+ *	the elapsed time in the struct timeval passed to select!
+ */
+static
+void do_msleep(int msec)
+{
+	struct timeval tv;
+
+	tv.tv_sec = msec / 1000;
+	tv.tv_usec = (msec % 1000) * 1000;
+
+	while(select(0, NULL, NULL, NULL, &tv) < 0 && errno == EINTR)
+		;
+}
+
+
+/*
+ *	Non-failing allocation routines (init cannot fail).
+ */
+static
+void *imalloc(size_t size)
+{
+	void	*m;
+
+	while ((m = malloc(size)) == NULL) {
+		initlog(L_VB, "out of memory");
+		do_msleep(SHORT_SLEEP);
+	}
+	memset(m, 0, size);
+	return m;
+}
+
+static
+char *istrdup(const char *s)
+{
+	char	*m;
+	int	l;
+
+	l = strlen(s) + 1;
+	m = imalloc(l);
+	memcpy(m, s, l);
+	return m;
+}
+
+
+/*
+ *	Send the state info of the previous running init to
+ *	the new one, in a version-independant way.
+ */
+static
+void send_state(int fd)
+{
+	FILE	*fp;
+	CHILD	*p;
+	int	i,val;
+
+	fp = fdopen(fd,"w");
+
+	fprintf(fp, "VER%s\n", Version);
+	fprintf(fp, "-RL%c\n", runlevel);
+	fprintf(fp, "-TL%c\n", thislevel);
+	fprintf(fp, "-PL%c\n", prevlevel);
+	fprintf(fp, "-SI%u\n", got_signals);
+	fprintf(fp, "-WR%d\n", wrote_wtmp_reboot);
+	fprintf(fp, "-WU%d\n", wrote_utmp_reboot);
+	fprintf(fp, "-ST%d\n", sleep_time);
+	fprintf(fp, "-DB%d\n", did_boot);
+
+	for (p = family; p; p = p->next) {
+		fprintf(fp, "REC%s\n", p->id);
+		fprintf(fp, "LEV%s\n", p->rlevel);
+		for (i = 0, val = p->flags; flags[i].mask; i++)
+			if (val & flags[i].mask) {
+				val &= ~flags[i].mask;
+				fprintf(fp, "FL %s\n",flags[i].name);
+			}
+		fprintf(fp, "PID%d\n",p->pid);
+		fprintf(fp, "EXS%u\n",p->exstat);
+		for(i = 0; actions[i].act; i++)
+			if (actions[i].act == p->action) {
+				fprintf(fp, "AC %s\n", actions[i].name);
+				break;
+			}
+		fprintf(fp, "CMD%s\n", p->process);
+		fprintf(fp, "EOR\n");
+	}
+	fprintf(fp, "END\n");
+	fclose(fp);
+}
+
+/*
+ *	Read a string from a file descriptor.
+ *	Q: why not use fgets() ?
+ *      A: Answer: looked into this. Turns out after all the checks
+ *      required in the fgets() approach (removing newline, read errors, etc)
+ *      the function is longer and takes approximately the same amount of
+ *      time to do one big fgets and checks as it does to do a pile of getcs.
+ *      We don't benefit from switching.
+ *      - Jesse
+ */
+static int get_string(char *p, int size, FILE *f)
+{
+	int	c;
+
+	while ((c = getc(f)) != EOF && c != '\n') {
+		if (--size > 0)
+			*p++ = c;
+	}
+	*p = '\0';
+	return (c != EOF) && (size > 0);
+}
+
+/*
+ *	Read trailing data from the state pipe until we see a newline.
+ */
+static int get_void(FILE *f)
+{
+	int	c;
+
+	while ((c = getc(f)) != EOF && c != '\n')
+		;
+
+	return (c != EOF);
+}
+
+/*
+ *	Read the next "command" from the state pipe.
+ */
+static int get_cmd(FILE *f)
+{
+	char	cmd[4] = "   ";
+	int	i;
+
+	if (fread(cmd, 1, sizeof(cmd) - 1, f) != sizeof(cmd) - 1)
+		return C_EOF;
+
+	for(i = 0; cmds[i].cmd && strcmp(cmds[i].name, cmd) != 0; i++)
+		;
+	return cmds[i].cmd;
+}
+
+/*
+ *	Read a CHILD * from the state pipe.
+ */
+static CHILD *get_record(FILE *f)
+{
+	int	cmd;
+	char	s[32];
+	int	i;
+	CHILD	*p;
+
+	do {
+		errno = 0;
+		switch (cmd = get_cmd(f)) {
+			case C_END:
+				get_void(f);
+				return NULL;
+			case 0:
+				get_void(f);
+				break;
+			case C_REC:
+				break;
+			case D_RUNLEVEL:
+				if (fscanf(f, "%c\n", &runlevel) == EOF && errno != 0) {
+					fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+				}
+				break;
+			case D_THISLEVEL:
+				if (fscanf(f, "%c\n", &thislevel) == EOF && errno != 0) {
+					fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+				}
+				break;
+			case D_PREVLEVEL:
+				if (fscanf(f, "%c\n", &prevlevel) == EOF && errno != 0) {
+					fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+				}
+				break;
+			case D_GOTSIGN:
+				if (fscanf(f, "%u\n", &got_signals) == EOF && errno != 0) {
+					fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+				}
+				break;
+			case D_WROTE_WTMP_REBOOT:
+				if (fscanf(f, "%d\n", &wrote_wtmp_reboot) == EOF && errno != 0) {
+					fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+				}
+				break;
+			case D_WROTE_UTMP_REBOOT:
+				if (fscanf(f, "%d\n", &wrote_utmp_reboot) == EOF && errno != 0) {
+					fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+				}
+				break;
+			case D_SLTIME:
+				if (fscanf(f, "%d\n", &sleep_time) == EOF && errno != 0) {
+					fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+				}
+				break;
+			case D_DIDBOOT:
+				if (fscanf(f, "%d\n", &did_boot) == EOF && errno != 0) {
+					fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+				}
+				break;
+			case D_WROTE_WTMP_RLEVEL:
+				if (fscanf(f, "%d\n", &wrote_wtmp_rlevel) == EOF && errno != 0) {
+					fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+				}
+				break;
+			case D_WROTE_UTMP_RLEVEL:
+				if (fscanf(f, "%d\n", &wrote_utmp_rlevel) == EOF && errno != 0) {
+					fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+				}
+				break;
+			default:
+				if (cmd > 0 || cmd == C_EOF) {
+					oops_error = -1;
+					return NULL;
+				}
+		}
+	} while (cmd != C_REC);
+
+	p = imalloc(sizeof(CHILD));
+	get_string(p->id, sizeof(p->id), f);
+
+	do switch(cmd = get_cmd(f)) {
+		case 0:
+		case C_EOR:
+			get_void(f);
+			break;
+		case C_PID:
+			if (fscanf(f, "%d\n", &(p->pid)) == EOF && errno != 0) {
+				fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+			}
+			break;
+		case C_EXS:
+			if (fscanf(f, "%u\n", &(p->exstat)) == EOF && errno != 0) {
+				fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+			}
+			break;
+		case C_LEV:
+			get_string(p->rlevel, sizeof(p->rlevel), f);
+			break;
+		case C_PROCESS:
+			get_string(p->process, sizeof(p->process), f);
+			break;
+		case C_FLAG:
+			get_string(s, sizeof(s), f);
+			for(i = 0; flags[i].name; i++) {
+				if (strcmp(flags[i].name,s) == 0)
+					break;
+			}
+			p->flags |= flags[i].mask;
+			break;
+		case C_ACTION:
+			get_string(s, sizeof(s), f);
+			for(i = 0; actions[i].name; i++) {
+				if (strcmp(actions[i].name, s) == 0)
+					break;
+			}
+			p->action = actions[i].act ? actions[i].act : OFF;
+			break;
+		default:
+			free(p);
+			oops_error = -1;
+			return NULL;
+	} while( cmd != C_EOR);
+
+	return p;
+}
+
+/*
+ *	Read the complete state info from the state pipe.
+ *	Returns 0 on success
+ */
+static
+int receive_state(int fd)
+{
+	FILE	*f;
+	char	old_version[256];
+	CHILD	**pp;
+
+	f = fdopen(fd, "r");
+
+ 	if (get_cmd(f) != C_VER) {
+		fclose(f);
+		return -1;
+	}
+	get_string(old_version, sizeof(old_version), f);
+	oops_error = 0;
+	for (pp = &family; (*pp = get_record(f)) != NULL; pp = &((*pp)->next))
+		;
+	fclose(f);
+	return oops_error;
+}
+
+/*
+ *	Set the process title.
+ */
+#ifdef __GNUC__
+#ifndef __FreeBSD__
+__attribute__ ((format (printf, 1, 2)))
+#endif
+#endif
+/* This function already exists on FreeBSD. No need to declare it. */
+#ifndef __FreeBSD__
+static int setproctitle(char *fmt, ...)
+{
+	va_list ap;
+	int len;
+	char buf[256];
+
+	buf[0] = 0;
+
+	va_start(ap, fmt);
+	len = vsnprintf(buf, sizeof(buf), fmt, ap);
+	va_end(ap);
+
+	if (maxproclen > 1) {
+		memset(argv0, 0, maxproclen);
+		strncpy(argv0, buf, maxproclen - 1);
+	}
+
+	return len;
+}
+#endif
+
+/*
+ *	Set console_dev to a working console.
+ */
+static
+void console_init(void)
+{
+	int fd;
+	int tried_devcons = 0;
+	int tried_vtmaster = 0;
+	char *s;
+
+	if ((s = getenv("CONSOLE")) != NULL)
+		console_dev = s;
+	else {
+		console_dev = CONSOLE;
+		tried_devcons++;
+	}
+
+	while ((fd = open(console_dev, O_RDONLY|O_NONBLOCK)) < 0) {
+		if (!tried_devcons) {
+			tried_devcons++;
+			console_dev = CONSOLE;
+			continue;
+		}
+		if (!tried_vtmaster) {
+			tried_vtmaster++;
+			console_dev = VT_MASTER;
+			continue;
+		}
+		break;
+	}
+	if (fd < 0)
+		console_dev = "/dev/null";
+	else
+		close(fd);
+}
+
+
+/*
+ *	Open the console with retries.
+ */
+static
+int console_open(int mode)
+{
+	int f, fd = -1;
+	int m;
+
+	/*
+	 *	Open device in nonblocking mode.
+	 */
+	m = mode | O_NONBLOCK;
+
+	/*
+	 *	Retry the open five times.
+	 */
+	for(f = 0; f < 5; f++) {
+		if ((fd = open(console_dev, m)) >= 0) break;
+		usleep(10000);
+	}
+
+	if (fd < 0) return fd;
+
+	/*
+	 *	Set original flags.
+	 */
+	if (m != mode)
+  		fcntl(fd, F_SETFL, mode);
+	return fd;
+}
+
+/*
+ *	We got a signal (HUP PWR WINCH ALRM INT)
+ */
+static
+void signal_handler(int sig)
+{
+	ADDSET(got_signals, sig);
+}
+
+/*
+ *	SIGCHLD: one of our children has died.
+ */
+static
+# ifdef __GNUC__
+void chld_handler(int sig __attribute__((unused)))
+# else
+void chld_handler(int sig)
+# endif
+{
+	CHILD		*ch;
+	int		pid, st;
+	int		saved_errno = errno;
+
+	/*
+	 *	Find out which process(es) this was (were)
+	 */
+	while((pid = waitpid(-1, &st, WNOHANG)) != 0) {
+		if (errno == ECHILD) break;
+		for( ch = family; ch; ch = ch->next )
+			if ( ch->pid == pid && (ch->flags & RUNNING) ) {
+				INITDBG(L_VB,
+					"chld_handler: marked %d as zombie",
+					ch->pid);
+				ADDSET(got_signals, SIGCHLD);
+				ch->exstat = st;
+				ch->flags |= ZOMBIE;
+				if (ch->new) {
+					ch->new->exstat = st;
+					ch->new->flags |= ZOMBIE;
+				}
+				break;
+			}
+		if (ch == NULL) {
+			INITDBG(L_VB, "chld_handler: unknown child %d exited.",
+				pid);
+		}
+	}
+	errno = saved_errno;
+}
+
+/*
+ *	Linux ignores all signals sent to init when the
+ *	SIG_DFL handler is installed. Therefore we must catch SIGTSTP
+ *	and SIGCONT, or else they won't work....
+ *
+ *	The SIGCONT handler
+ */
+static
+# ifdef __GNUC__
+void cont_handler(int sig __attribute__((unused)))
+# else
+void cont_handler(int sig)
+# endif
+{
+	got_cont = 1;
+}
+
+/*
+ *	Fork and dump core in /.
+ */
+static
+void coredump(void)
+{
+	static int		dumped = 0;
+	struct rlimit		rlim;
+	sigset_t		mask;
+
+	if (dumped) return;
+	dumped = 1;
+
+	if (fork() != 0) return;
+
+	sigfillset(&mask);
+	sigprocmask(SIG_SETMASK, &mask, NULL);
+
+	rlim.rlim_cur = RLIM_INFINITY;
+	rlim.rlim_max = RLIM_INFINITY;
+	setrlimit(RLIMIT_CORE, &rlim);
+	if (0 != chdir("/"))
+		initlog(L_VB, "unable to chdir to /: %s",
+			strerror(errno));
+
+	signal(SIGSEGV, SIG_DFL);
+	raise(SIGSEGV);
+	sigdelset(&mask, SIGSEGV);
+	sigprocmask(SIG_SETMASK, &mask, NULL);
+
+	do_msleep(SHORT_SLEEP);
+	exit(0);
+}
+
+/*
+ *	OOPS: segmentation violation!
+ *	If we have the info, print where it occurred.
+ *	Then sleep 30 seconds and try to continue.
+ */
+static
+#if defined(STACK_DEBUG) && defined(__linux__)
+# ifdef __GNUC__
+void segv_handler(int sig __attribute__((unused)), struct sigcontext ctx)
+# else
+void segv_handler(int sig, struct sigcontext ctx)
+# endif
+{
+	char	*p = "";
+	int	saved_errno = errno;
+
+	if ((void *)ctx.eip >= (void *)do_msleep &&
+	    (void *)ctx.eip < (void *)main)
+		p = " (code)";
+	initlog(L_VB, "PANIC: segmentation violation at %p%s! "
+		  "sleeping for 30 seconds.", (void *)ctx.eip, p);
+	coredump();
+	do_msleep(LONG_SLEEP);
+	errno = saved_errno;
+}
+#else
+# ifdef __GNUC__
+void segv_handler(int sig __attribute__((unused)))
+# else
+void segv_handler(int sig)
+# endif
+{
+	int	saved_errno = errno;
+
+	initlog(L_VB,
+		"PANIC: segmentation violation! sleeping for 30 seconds.");
+	coredump();
+	do_msleep(LONG_SLEEP);
+	errno = saved_errno;
+}
+#endif
+
+/*
+ *	The SIGSTOP & SIGTSTP handler
+ */
+static
+# ifdef __GNUC__
+void stop_handler(int sig __attribute__((unused)))
+# else
+void stop_handler(int sig)
+# endif
+{
+	int	saved_errno = errno;
+
+	got_cont = 0;
+	while(!got_cont) pause();
+	got_cont = 0;
+	errno = saved_errno;
+}
+
+/*
+ *	Set terminal settings to reasonable defaults
+ */
+static
+void console_stty(void)
+{
+	struct termios tty;
+	int fd;
+
+	if ((fd = console_open(O_RDWR|O_NOCTTY)) < 0) {
+		initlog(L_VB, "can't open %s", console_dev);
+		return;
+	}
+
+#ifdef __FreeBSD_kernel__
+	/*
+	 * The kernel of FreeBSD expects userland to set TERM.  Usually, we want
+	 * "xterm".  Later, gettys might disagree on this (i.e. we're not using
+	 * syscons) but some boot scripts, like /etc/init.d/xserver-xorg, still
+	 * need a non-dumb terminal.
+	 */
+	putenv ("TERM=xterm");
+#endif
+
+	(void) tcgetattr(fd, &tty);
+
+	tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD;
+	tty.c_cflag |= HUPCL|CLOCAL|CREAD;
+
+	tty.c_cc[VINTR]	    = CINTR;
+	tty.c_cc[VQUIT]	    = CQUIT;
+	tty.c_cc[VERASE]    = CERASE; /* ASCII DEL (0177) */
+	tty.c_cc[VKILL]	    = CKILL;
+	tty.c_cc[VEOF]	    = CEOF;
+	tty.c_cc[VTIME]	    = 0;
+	tty.c_cc[VMIN]	    = 1;
+#ifdef VSWTC /* not defined on FreeBSD */
+	tty.c_cc[VSWTC]	    = _POSIX_VDISABLE;
+#endif /* VSWTC */
+	tty.c_cc[VSTART]    = CSTART;
+	tty.c_cc[VSTOP]	    = CSTOP;
+	tty.c_cc[VSUSP]	    = CSUSP;
+	tty.c_cc[VEOL]	    = _POSIX_VDISABLE;
+	tty.c_cc[VREPRINT]  = CREPRINT;
+	tty.c_cc[VDISCARD]  = CDISCARD;
+	tty.c_cc[VWERASE]   = CWERASE;
+	tty.c_cc[VLNEXT]    = CLNEXT;
+	tty.c_cc[VEOL2]	    = _POSIX_VDISABLE;
+
+	/*
+	 *	Set pre and post processing
+	 */
+	tty.c_iflag = IGNPAR|ICRNL|IXON|IXANY
+#ifdef IUTF8	/* Not defined on FreeBSD */
+			| (tty.c_iflag & IUTF8)
+#endif /* IUTF8 */
+		;
+	tty.c_oflag = OPOST|ONLCR;
+	tty.c_lflag = ISIG|ICANON|ECHO|ECHOCTL|ECHOE|ECHOKE;
+
+#if defined(SANE_TIO) && (SANE_TIO == 1)
+	/*
+	 *	Disable flow control (-ixon), ignore break (ignbrk),
+	 *	and make nl/cr more usable (sane).
+	 */
+	tty.c_iflag |=  IGNBRK;
+	tty.c_iflag &= ~(BRKINT|INLCR|IGNCR|IXON);
+	tty.c_oflag &= ~(OCRNL|ONLRET);
+#endif
+	/*
+	 *	Now set the terminal line.
+	 *	We don't care about non-transmitted output data
+	 *	and non-read input data.
+	 */
+	(void) tcsetattr(fd, TCSANOW, &tty);
+	(void) tcflush(fd, TCIOFLUSH);
+	(void) close(fd);
+}
+
+static  ssize_t
+safe_write(int fd, const char *buffer, size_t count)
+{
+	ssize_t offset = 0;
+
+	while (count > 0) {
+		ssize_t block = write(fd, &buffer[offset], count);
+
+		if (block < 0 && errno == EINTR)
+			continue;
+		if (block <= 0)
+			return offset ? offset : block;
+		offset += block;
+		count -= block;
+	}
+	return offset;
+}
+
+/*
+ *	Print to the system console
+ */
+void print(char *s)
+{
+	int fd;
+
+	if ((fd = console_open(O_WRONLY|O_NOCTTY|O_NDELAY)) >= 0) {
+		safe_write(fd, s, strlen(s));
+		close(fd);
+	}
+}
+
+/*
+ *	Log something to a logfile and the console.
+ */
+#ifdef __GNUC__
+__attribute__ ((format (printf, 2, 3)))
+#endif
+void initlog(int loglevel, char *s, ...)
+{
+	va_list va_alist;
+	char buf[256];
+	sigset_t nmask, omask;
+
+	va_start(va_alist, s);
+	vsnprintf(buf, sizeof(buf), s, va_alist);
+	va_end(va_alist);
+
+	if (loglevel & L_SY) {
+		/*
+		 *	Re-establish connection with syslogd every time.
+		 *	Block signals while talking to syslog.
+		 */
+		sigfillset(&nmask);
+		sigprocmask(SIG_BLOCK, &nmask, &omask);
+		openlog("init", 0, LOG_DAEMON);
+		syslog(LOG_INFO, "%s", buf);
+		closelog();
+		sigprocmask(SIG_SETMASK, &omask, NULL);
+	}
+
+	/*
+	 *	And log to the console.
+	 */
+	if (loglevel & L_CO) {
+		print("\rINIT: ");
+		print(buf);
+		print("\r\n");
+	}
+}
+
+/*
+ *	Add or replace specific environment value
+ */
+int addnewenv(const char *new, char **curr, int n)
+{
+	size_t nlen = strcspn(new, "=");
+	int i;
+	for (i = 0; i < n; i++) {
+		if (nlen != strcspn(curr[i], "="))
+			continue;
+		if (strncmp (new, curr[i], nlen) == 0)
+			break;
+	}
+	if (i >= n)
+		curr[n++] = istrdup(new);
+	else {
+		free(curr[i]);
+		curr[i] = istrdup(new);
+	}
+	return n;
+}
+
+/*
+ *	Build a new environment for execve().
+ */
+char **init_buildenv(int child)
+{
+	char		i_lvl[] = "RUNLEVEL=x";
+	char		i_prev[] = "PREVLEVEL=x";
+	char		i_cons[128];
+	char		i_shell[] = "SHELL=" SHELL;
+	char		**e;
+	int		n, i;
+
+	for (n = 0; environ[n]; n++)
+		;
+	n += NR_EXTRA_ENV + 1;	    /* Also room for last NULL */
+	if (child)
+		n += 8;
+
+	while ((e = (char**)calloc(n, sizeof(char *))) == NULL) {
+		initlog(L_VB, "out of memory");
+		do_msleep(SHORT_SLEEP);
+	}
+
+	for (n = 0; environ[n]; n++)
+		e[n] = istrdup(environ[n]);
+
+	for (i = 0; i < NR_EXTRA_ENV; i++) {
+		if (extra_env[i] == NULL || *extra_env[i] == '\0')
+			continue;
+		n = addnewenv(extra_env[i], e, n);
+	}
+
+	if (child) {
+		snprintf(i_cons, sizeof(i_cons), "CONSOLE=%s", console_dev);
+		i_lvl[9]   = thislevel;
+		i_prev[10] = prevlevel;
+		n = addnewenv(i_shell, e, n);
+		n = addnewenv(i_lvl, e, n);
+		n = addnewenv(i_prev, e, n);
+		n = addnewenv(i_cons, e, n);
+		n = addnewenv(E_VERSION, e, n);
+	}
+
+	e[n++] = NULL;
+
+	return e;
+}
+
+
+void init_freeenv(char **e)
+{
+	int		n;
+
+	for (n = 0; e[n]; n++)
+		free(e[n]);
+	free(e);
+}
+
+
+/*
+ *	Fork and execute.
+ *
+ *	This function is too long and indents too deep.
+ *
+ */
+static
+pid_t spawn(CHILD *ch, int *res)
+{
+  char *args[16];		/* Argv array */
+  char buf[136];		/* Line buffer */
+  int f, st;			/* Scratch variables */
+  char *ptr;			/* Ditto */
+  time_t t;			/* System time */
+  int oldAlarm;			/* Previous alarm value */
+  char *proc = ch->process;	/* Command line */
+  pid_t pid, pgrp;		/* child, console process group. */
+  sigset_t nmask, omask;	/* For blocking SIGCHLD */
+  struct sigaction sa;
+
+  *res = -1;
+  buf[sizeof(buf) - 1] = 0;
+
+  /* Skip '+' if it's there */
+  if (proc[0] == '+') proc++;
+
+  ch->flags |= XECUTED;
+
+  if (ch->action == RESPAWN || ch->action == ONDEMAND) {
+	/* Is the date stamp from less than 2 minutes ago? */
+	time(&t);
+	if (ch->tm + TESTTIME > t) {
+		ch->count++;
+	} else {
+		ch->count = 0;
+		ch->tm = t;
+	}
+
+	/* Do we try to respawn too fast? */
+	if (ch->count >= MAXSPAWN) {
+
+	  initlog(L_VB,
+		"Id \"%s\" respawning too fast: disabled for %d minutes",
+		ch->id, SLEEPTIME / 60);
+	  ch->flags &= ~RUNNING;
+	  ch->flags |= FAILING;
+
+	  /* Remember the time we stopped */
+	  ch->tm = t;
+
+	  /* Try again in 5 minutes */
+	  oldAlarm = alarm(0);
+	  if (oldAlarm > SLEEPTIME || oldAlarm <= 0) oldAlarm = SLEEPTIME;
+	  alarm(oldAlarm);
+	  return(-1);
+	}
+  }
+
+  /* See if there is an "initscript" (except in single user mode). */
+  if (access(INITSCRIPT, R_OK) == 0 && runlevel != 'S') {
+	/* Build command line using "initscript" */
+	args[1] = SHELL;
+	args[2] = INITSCRIPT;
+	args[3] = ch->id;
+	args[4] = ch->rlevel;
+	args[5] = "unknown";
+	for(f = 0; actions[f].name; f++) {
+		if (ch->action == actions[f].act) {
+			args[5] = actions[f].name;
+			break;
+		}
+	}
+	args[6] = proc;
+	args[7] = NULL;
+  } else if (strpbrk(proc, "~`!$^&*()=|\\{}[];\"'<>?")) {
+  /* See if we need to fire off a shell for this command */
+  	/* Give command line to shell */
+  	args[1] = SHELL;
+  	args[2] = "-c";
+  	strcpy(buf, "exec ");
+  	strncat(buf, proc, sizeof(buf) - strlen(buf) - 1);
+  	args[3] = buf;
+  	args[4] = NULL;
+  } else {
+	/* Split up command line arguments */
+	buf[0] = 0;
+  	strncat(buf, proc, sizeof(buf) - 1);
+  	ptr = buf;
+  	for(f = 1; f < 15; f++) {
+  		/* Skip white space */
+  		while(*ptr == ' ' || *ptr == '\t') ptr++;
+  		args[f] = ptr;
+  		
+		/* May be trailing space.. */
+		if (*ptr == 0) break;
+
+  		/* Skip this `word' */
+  		while(*ptr && *ptr != ' ' && *ptr != '\t' && *ptr != '#')
+  			ptr++;
+  		
+  		/* If end-of-line, break */	
+  		if (*ptr == '#' || *ptr == 0) {
+  			f++;
+  			*ptr = 0;
+  			break;
+  		}
+  		/* End word with \0 and continue */
+  		*ptr++ = 0;
+  	}
+  	args[f] = NULL;
+  }
+  args[0] = args[1];
+  while(1) {
+	/*
+	 *	Block sigchild while forking.
+	 */
+	sigemptyset(&nmask);
+	sigaddset(&nmask, SIGCHLD);
+	sigprocmask(SIG_BLOCK, &nmask, &omask);
+
+	if ((pid = fork()) == 0) {
+
+		close(0);
+		close(1);
+		close(2);
+		if (pipe_fd >= 0)
+                {
+                    close(pipe_fd);
+                    pipe_fd = -1;
+                }
+
+  		sigprocmask(SIG_SETMASK, &omask, NULL);
+
+		/*
+		 *	In sysinit, boot, bootwait or single user mode:
+		 *	for any wait-type subprocess we _force_ the console
+		 *	to be its controlling tty.
+		 */
+  		if (strchr("*#sS", runlevel) && ch->flags & WAITING) {
+			int ftty;	/* Handler for tty controlling */
+			/*
+			 *	We fork once extra. This is so that we can
+			 *	wait and change the process group and session
+			 *	of the console after exit of the leader.
+			 */
+			setsid();
+			if ((ftty = console_open(O_RDWR|O_NOCTTY)) >= 0) {
+				/* Take over controlling tty by force */
+				(void)ioctl(ftty, TIOCSCTTY, 1);
+
+				if(dup(ftty) < 0){
+				        initlog(L_VB, "cannot duplicate console fd");
+				}
+				
+				if(dup(ftty) < 0){
+				        initlog(L_VB, "cannot duplicate console fd");
+				}
+
+			}
+
+			/*
+			 * 4 Sep 2001, Andrea Arcangeli:
+			 * Fix a race in spawn() that is used to deadlock init in a
+			 * waitpid() loop: must set the childhandler as default before forking
+			 * off the child or the chld_handler could run before the waitpid loop
+			 * has a chance to find its zombie-child.
+			 */
+			SETSIG(sa, SIGCHLD, SIG_DFL, SA_RESTART);
+			if ((pid = fork()) < 0) {
+  				initlog(L_VB, "cannot fork: %s",
+					strerror(errno));
+				exit(1);
+			}
+			if (pid > 0) {
+				pid_t rc;
+				/*
+				 *	Ignore keyboard signals etc.
+				 *	Then wait for child to exit.
+				 */
+				SETSIG(sa, SIGINT, SIG_IGN, SA_RESTART);
+				SETSIG(sa, SIGTSTP, SIG_IGN, SA_RESTART);
+				SETSIG(sa, SIGQUIT, SIG_IGN, SA_RESTART);
+
+				while ((rc = waitpid(pid, &st, 0)) != pid)
+					if (rc < 0 && errno == ECHILD)
+						break;
+
+				/*
+				 *	Small optimization. See if stealing
+				 *	controlling tty back is needed.
+				 */
+				pgrp = tcgetpgrp(ftty);
+				if (pgrp != getpid())
+					exit(0);
+
+				/*
+				 *	Steal controlling tty away. We do
+				 *	this with a temporary process.
+				 */
+				if ((pid = fork()) < 0) {
+  					initlog(L_VB, "cannot fork: %s",
+						strerror(errno));
+					exit(1);
+				}
+				if (pid == 0) {
+					setsid();
+					(void)ioctl(ftty, TIOCSCTTY, 1);
+					exit(0);
+				}
+				while((rc = waitpid(pid, &st, 0)) != pid)
+					if (rc < 0 && errno == ECHILD)
+						break;
+				exit(0);
+			}
+
+			/* Set ioctl settings to default ones */
+			console_stty();
+
+  		} else { /* parent */
+			int fd;
+			setsid();
+			if ((fd = console_open(O_RDWR|O_NOCTTY)) < 0) {
+				initlog(L_VB, "open(%s): %s", console_dev,
+					strerror(errno));
+				fd = open("/dev/null", O_RDWR);
+			}
+
+			if(dup(fd) < 0) {
+				initlog(L_VB, "cannot duplicate /dev/null fd");
+			}
+			
+			if(dup(fd) < 0) {
+				initlog(L_VB, "cannot duplicate /dev/null fd");
+			}
+
+		}
+
+		/*
+		 * Update utmp/wtmp file prior to starting
+		 * any child.  This MUST be done right here in
+		 * the child process in order to prevent a race
+		 * condition that occurs when the child
+		 * process' time slice executes before the
+		 * parent (can and does happen in a uniprocessor
+		 * environment).  If the child is a getty and
+		 * the race condition happens, then init's utmp
+		 * update will happen AFTER the getty runs
+		 * and expects utmp to be updated already!
+		 *
+		 * Do NOT log if process field starts with '+'
+		 * This is for compatibility with *very*
+		 * old getties - probably it can be taken out.
+		 */
+		if (ch->process[0] != '+')
+			write_utmp_wtmp("", ch->id, getpid(), INIT_PROCESS, "");
+
+  		/* Reset all the signals, set up environment */
+  		for(f = 1; f < NSIG; f++) SETSIG(sa, f, SIG_DFL, SA_RESTART);
+		environ = init_buildenv(1);
+
+		/*
+		 *	Execute prog. In case of ENOEXEC try again
+		 *	as a shell script.
+		 */
+  		execvp(args[1], args + 1);
+		if (errno == ENOEXEC) {
+  			args[1] = SHELL;
+  			args[2] = "-c";
+  			strcpy(buf, "exec ");
+  			strncat(buf, proc, sizeof(buf) - strlen(buf) - 1);
+  			args[3] = buf;
+  			args[4] = NULL;
+			execvp(args[1], args + 1);
+		}
+  		initlog(L_VB, "cannot execute \"%s\"", args[1]);
+
+		if (ch->process[0] != '+')
+			write_utmp_wtmp("", ch->id, getpid(), DEAD_PROCESS, NULL);
+  		exit(1);
+  	}
+	*res = pid;
+  	sigprocmask(SIG_SETMASK, &omask, NULL);
+
+	INITDBG(L_VB, "Started id %s (pid %d)", ch->id, pid);
+
+	if (pid == -1) {
+		initlog(L_VB, "cannot fork, retry..");
+		do_msleep(SHORT_SLEEP);
+		continue;
+	}
+	return(pid);
+  }
+}
+
+/*
+ *	Start a child running!
+ */
+static
+void startup(CHILD *ch)
+{
+	/*
+	 *	See if it's disabled
+	 */
+	if (ch->flags & FAILING) return;
+
+	switch(ch->action) {
+
+		case SYSINIT:
+		case BOOTWAIT:
+		case WAIT:
+		case POWERWAIT:
+		case POWERFAILNOW:
+		case POWEROKWAIT:
+		case CTRLALTDEL:
+			if (!(ch->flags & XECUTED)) ch->flags |= WAITING;
+			/* Fall through */
+		case KBREQUEST:
+		case BOOT:
+		case POWERFAIL:
+		case ONCE:
+			if (ch->flags & XECUTED) break;
+                        /* Fall through */
+		case ONDEMAND:
+		case RESPAWN:
+  			ch->flags |= RUNNING;
+  			(void)spawn(ch, &(ch->pid));
+  			break;
+	}
+}
+
+#ifdef __linux__
+static
+void check_kernel_console()
+{
+	FILE* fp;
+	char buf[4096];
+	if ((fp = fopen("/proc/cmdline", "r")) == 0) {    
+		return;
+	}    
+	if (fgets(buf, sizeof(buf), fp)) {    
+		char* p = buf;
+           if ( strstr(p, "init.autocon=1") )
+           {
+		while ((p = strstr(p, "console="))) {    
+			char* e;
+			p += strlen("console=");
+			for (e = p; *e; ++e) {
+				switch (*e) {
+					case '-' ... '9':
+					case 'A' ... 'Z':
+					case '_':
+					case 'a' ... 'z':
+						continue;
+				}
+				break;
+			}
+			if (p != e) {
+				CHILD* old;
+				int dup = 0;
+				char id[8] = {0};
+				char dev[32] = {0};
+				strncpy(dev, p, MIN(sizeof(dev), (unsigned)(e-p)));
+				if (!strncmp(dev, "tty", 3))
+					strncpy(id, dev+3, sizeof(id));
+				else
+					strncpy(id, dev, sizeof(id));
+
+				for(old = newFamily; old; old = old->next) {
+					if (!strcmp(old->id, id)) {
+						dup = 1;
+					}
+				}
+				if (!dup) {
+					CHILD* ch = imalloc(sizeof(CHILD));
+					ch->action = RESPAWN;
+					strcpy(ch->id, id);
+					strcpy(ch->rlevel, "2345");
+					sprintf(ch->process, "/sbin/agetty -L -s 115200,38400,9600 %s vt102", dev);
+					ch->next = NULL;
+					for(old = family; old; old = old->next) {
+						if (strcmp(old->id, ch->id) == 0) {
+							old->new = ch;
+							break;
+						}
+					}
+					/* add to end */
+					for(old = newFamily; old; old = old->next) {
+						if (!old->next) {
+							old->next = ch;
+							break;
+						}
+					}
+
+					initlog(L_VB, "added agetty on %s with id %s", dev, id);
+				}
+			}
+		}
+            } 
+	}    
+	fclose(fp);
+	return;
+}
+#endif
+
+/*
+ *	Read the inittab file.
+ */
+static
+void read_inittab(void)
+{
+  FILE		*fp;			/* The INITTAB file */
+  FILE		*fp_tab;		/* The INITTABD files */
+  CHILD		*ch, *old, *i;		/* Pointers to CHILD structure */
+  CHILD		*head = NULL;		/* Head of linked list */
+#ifdef INITLVL
+  struct stat	st;			/* To stat INITLVL */
+#endif
+  sigset_t	nmask, omask;		/* For blocking SIGCHLD. */
+  char		buf[256];		/* Line buffer */
+  char		err[64];		/* Error message. */
+  char		*id, *rlevel,
+		*action, *process;	/* Fields of a line */
+  char		*p;
+  int		lineNo = 0;		/* Line number in INITTAB file */
+  int		actionNo;		/* Decoded action field */
+  int		f;			/* Counter */
+  int		round;			/* round 0 for SIGTERM, 1 for SIGKILL */
+  int		foundOne = 0;		/* No killing no sleep */
+  int		talk;			/* Talk to the user */
+  int		done = -1;		/* Ready yet? , 2 level : -1 nothing done, 0 inittab done, 1 inittab and inittab.d done */
+  DIR 		*tabdir=NULL;		/* the INITTAB.D dir */
+  struct dirent *file_entry;		/* inittab.d entry */
+  char 		f_name[272];		/* size d_name + strlen /etc/inittad.d/ */
+
+#if DEBUG
+  if (newFamily != NULL) {
+	INITDBG(L_VB, "PANIC newFamily != NULL");
+	exit(1);
+  }
+  INITDBG(L_VB, "Reading inittab");
+#endif
+
+  /*
+   *	Open INITTAB and read line by line.
+   */
+  if ((fp = fopen(INITTAB, "r")) == NULL)
+	initlog(L_VB, "No inittab file found");
+
+  /*
+   *  Open INITTAB.D directory 
+   */
+  if( (tabdir = opendir(INITTABD))==NULL)
+	  initlog(L_VB, "No inittab.d directory found");
+
+  while(done!=1) {
+	/*
+	 *	Add single user shell entry at the end.
+	 */
+	if(done == -1) {
+		if (fp == NULL || fgets(buf, sizeof(buf), fp) == NULL) {
+			done = 0;
+			/*
+			 *	See if we have a single user entry.
+			 */
+			for(old = newFamily; old; old = old->next)
+				if (strpbrk(old->rlevel, "S"))  break;
+			if (old == NULL)
+				snprintf(buf, sizeof(buf), "~~:S:wait:%s\n", SULOGIN);
+			else
+				continue;
+		}
+	} /* end if( done==-1) */
+	else if ( done == 0 ){
+		/* parse /etc/inittab.d and read all .tab files */
+		if(tabdir!=NULL){
+			if( (file_entry = readdir(tabdir))!=NULL){
+				/* ignore files not like *.tab */
+				if (!strcmp(file_entry->d_name, ".") || !strcmp(file_entry->d_name, ".."))
+					continue;
+				if (strlen(file_entry->d_name) < 5 || strcmp(file_entry->d_name + strlen(file_entry->d_name) - 4, ".tab"))
+					continue;
+				/*
+				 * initialize filename
+				 */
+				memset(f_name,0,sizeof(char)*272);
+				snprintf(f_name,272,"/etc/inittab.d/%s",file_entry->d_name);
+				initlog(L_VB, "Reading: %s",f_name);
+				/*
+				 * read file in inittab.d only one entry per file
+				 */
+				if ((fp_tab = fopen(f_name, "r")) == NULL)
+					continue;
+				/* read the file while the line contain comment */
+				while( fgets(buf, sizeof(buf), fp_tab) != NULL) {
+					for(p = buf; *p == ' ' || *p == '\t'; p++);
+					if (*p != '#' && *p != '\n')
+						break;
+				}
+				fclose(fp_tab);
+				/* do some checks */
+				if( buf == NULL ) 
+					continue;
+				if( strlen( p  ) == 0 )
+					continue;
+			} /* end of readdir, all is done */
+			else { 
+				done = 1;
+				continue;
+			}
+		} /* end of if(tabdir!=NULL) */
+		else {
+			done = 1;
+			continue;
+		}
+	} /* end of if ( done == 0 ) */
+	lineNo++;
+	/*
+	 *	Skip comments and empty lines
+	 */
+	for(p = buf; *p == ' ' || *p == '\t'; p++)
+		;
+	if (*p == '#' || *p == '\n') continue;
+
+	/*
+	 *	Decode the fields
+	 */
+	id =      strsep(&p, ":");
+	rlevel =  strsep(&p, ":");
+	action =  strsep(&p, ":");
+	process = strsep(&p, "\n");
+
+	/*
+	 *	Check if syntax is OK. Be very verbose here, to
+	 *	avoid newbie postings on comp.os.linux.setup :)
+	 */
+	err[0] = 0;
+	if (!id || !*id) strcpy(err, "missing id field");
+	if (!rlevel)     strcpy(err, "missing runlevel field");
+	if (!process)    strcpy(err, "missing process field");
+	if (!action || !*action)
+			strcpy(err, "missing action field");
+	if (id && strlen(id) > sizeof(utproto.ut_id))
+		sprintf(err, "id field too long (max %d characters)",
+			(int)sizeof(utproto.ut_id));
+	if (rlevel && strlen(rlevel) > 11)
+		strcpy(err, "rlevel field too long (max 11 characters)");
+	if (process && strlen(process) > 127)
+		strcpy(err, "process field too long (max 127 characters)");
+	if (action && strlen(action) > 32)
+		strcpy(err, "action field too long");
+	if (err[0] != 0) {
+		initlog(L_VB, "%s[%d]: %s", INITTAB, lineNo, err);
+		INITDBG(L_VB, "%s:%s:%s:%s", id, rlevel, action, process);
+		continue;
+	}
+  
+	/*
+	 *	Decode the "action" field
+	 */
+	actionNo = -1;
+	for(f = 0; actions[f].name; f++)
+		if (strcasecmp(action, actions[f].name) == 0) {
+			actionNo = actions[f].act;
+			break;
+		}
+	if (actionNo == -1) {
+		initlog(L_VB, "%s[%d]: %s: unknown action field",
+			INITTAB, lineNo, action);
+		continue;
+	}
+
+	/*
+	 *	See if the id field is unique
+	 */
+	for(old = newFamily; old; old = old->next) {
+		if(strcmp(old->id, id) == 0 && strcmp(id, "~~")) {
+			initlog(L_VB, "%s[%d]: duplicate ID field \"%s\"",
+				INITTAB, lineNo, id);
+			break;
+		}
+	}
+	if (old) continue;
+
+	/*
+	 *	Allocate a CHILD structure
+	 */
+	ch = imalloc(sizeof(CHILD));
+
+	/*
+	 *	And fill it in.
+	 */
+	ch->action = actionNo;
+	strncpy(ch->id, id, sizeof(utproto.ut_id) + 1); /* Hack for different libs. */
+	strncpy(ch->process, process, sizeof(ch->process) - 1);
+	if (rlevel[0]) {
+		for(f = 0; f < (int)sizeof(rlevel) - 1 && rlevel[f]; f++) {
+			ch->rlevel[f] = rlevel[f];
+			if (ch->rlevel[f] == 's') ch->rlevel[f] = 'S';
+		}
+		strncpy(ch->rlevel, rlevel, sizeof(ch->rlevel) - 1);
+	} else {
+		strcpy(ch->rlevel, "0123456789");
+		if (ISPOWER(ch->action))
+			strcpy(ch->rlevel, "S0123456789");
+	}
+	/*
+	 *	We have the fake runlevel '#' for SYSINIT  and
+	 *	'*' for BOOT and BOOTWAIT.
+	 */
+	if (ch->action == SYSINIT) strcpy(ch->rlevel, "#");
+	if (ch->action == BOOT || ch->action == BOOTWAIT)
+		strcpy(ch->rlevel, "*");
+
+	/*
+	 *	Now add it to the linked list. Special for powerfail.
+	 */
+	if (ISPOWER(ch->action)) {
+
+		/*
+		 *	Disable by default
+		 */
+		ch->flags |= XECUTED;
+
+		/*
+		 *	Tricky: insert at the front of the list..
+		 */
+		old = NULL;
+		for(i = newFamily; i; i = i->next) {
+			if (!ISPOWER(i->action)) break;
+			old = i;
+		}
+		/*
+		 *	Now add after entry "old"
+		 */
+		if (old) {
+			ch->next = i;
+			old->next = ch;
+			if (i == NULL) head = ch;
+		} else {
+			ch->next = newFamily;
+			newFamily = ch;
+			if (ch->next == NULL) head = ch;
+		}
+	} else {
+		/*
+		 *	Just add at end of the list
+		 */
+		if (ch->action == KBREQUEST) ch->flags |= XECUTED;
+		ch->next = NULL;
+		if (head)
+			head->next = ch;
+		else
+			newFamily = ch;
+		head = ch;
+	}
+
+	/*
+	 *	Walk through the old list comparing id fields
+	 */
+	for(old = family; old; old = old->next)
+		if (strcmp(old->id, ch->id) == 0) {
+			old->new = ch;
+			break;
+		}
+  }
+
+  /*
+   *	We're done.
+   */
+  if (fp) fclose(fp);
+  if(tabdir) closedir(tabdir);
+
+#ifdef __linux__
+  check_kernel_console();
+#endif
+
+  /*
+   *	Loop through the list of children, and see if they need to
+   *	be killed. 
+   */
+
+  INITDBG(L_VB, "Checking for children to kill");
+  for(round = 0; round < 2; round++) {
+    talk = 1;
+    for(ch = family; ch; ch = ch->next) {
+	ch->flags &= ~KILLME;
+
+	/*
+	 *	Is this line deleted?
+	 */
+	if (ch->new == NULL) ch->flags |= KILLME;
+
+	/*
+	 *	If the entry has changed, kill it anyway. Note that
+	 *	we do not check ch->process, only the "action" field.
+	 *	This way, you can turn an entry "off" immediately, but
+	 *	changes in the command line will only become effective
+	 *	after the running version has exited.
+	 */
+	if (ch->new && ch->action != ch->new->action) ch->flags |= KILLME;
+
+	/*
+	 *	Only BOOT processes may live in all levels
+	 */
+	if (ch->action != BOOT &&
+	    strchr(ch->rlevel, runlevel) == NULL) {
+		/*
+		 *	Ondemand procedures live always,
+		 *	except in single user
+		 */
+		if (runlevel == 'S' || !(ch->flags & DEMAND))
+			ch->flags |= KILLME;
+	}
+
+	/*
+	 *	Now, if this process may live note so in the new list
+	 */
+	if ((ch->flags & KILLME) == 0) {
+		ch->new->flags  = ch->flags;
+		ch->new->pid    = ch->pid;
+		ch->new->exstat = ch->exstat;
+		continue;
+	}
+
+
+	/*
+	 *	Is this process still around?
+	 */
+	if ((ch->flags & RUNNING) == 0) {
+		ch->flags &= ~KILLME;
+		continue;
+	}
+	INITDBG(L_VB, "Killing \"%s\"", ch->process);
+	switch(round) {
+		case 0: /* Send TERM signal */
+			if (talk)
+				initlog(L_CO,
+					"Sending processes configured via /etc/inittab the TERM signal");
+			kill(-(ch->pid), SIGTERM);
+			foundOne = 1;
+			break;
+		case 1: /* Send KILL signal and collect status */
+			if (talk)
+				initlog(L_CO,
+					"Sending processes configured via /etc/inittab the KILL signal");
+			kill(-(ch->pid), SIGKILL);
+			break;
+	}
+	talk = 0;
+	
+    }
+    /*
+     *	See if we have to wait sleep_time seconds
+     */
+    if (foundOne && round == 0) {
+	/*
+	 *	Yup, but check every 10 milliseconds if we still have children.
+         *      The f < 100 * sleep_time refers to sleep time in 10 millisecond chunks.
+	 */
+	for(f = 0; f < 100 * sleep_time; f++) {
+		for(ch = family; ch; ch = ch->next) {
+			if (!(ch->flags & KILLME)) continue;
+			if ((ch->flags & RUNNING) && !(ch->flags & ZOMBIE))
+				break;
+		}
+		if (ch == NULL) {
+			/*
+			 *	No running children, skip SIGKILL
+			 */
+			round = 1;
+			foundOne = 0; /* Skip the sleep below. */
+			break;
+		}
+		do_msleep(MINI_SLEEP);
+	}
+    }
+  }
+
+  /*
+   *	Now give all processes the chance to die and collect exit statuses.
+   */
+  if (foundOne) do_msleep(MINI_SLEEP);
+  for(ch = family; ch; ch = ch->next)
+	if (ch->flags & KILLME) {
+		if (!(ch->flags & ZOMBIE))
+		    initlog(L_CO, "Pid %d [id %s] seems to hang", ch->pid,
+				ch->id);
+		else {
+		    INITDBG(L_VB, "Updating utmp for pid %d [id %s]",
+				ch->pid, ch->id);
+		    ch->flags &= ~RUNNING;
+		    if (ch->process[0] != '+')
+		    	write_utmp_wtmp("", ch->id, ch->pid, DEAD_PROCESS, NULL);
+		}
+	}
+
+  /*
+   *	Both rounds done; clean up the list.
+   */
+  sigemptyset(&nmask);
+  sigaddset(&nmask, SIGCHLD);
+  sigprocmask(SIG_BLOCK, &nmask, &omask);
+  for(ch = family; ch; ch = old) {
+	old = ch->next;
+	free(ch);
+  }
+  family = newFamily;
+  for(ch = family; ch; ch = ch->next) ch->new = NULL;
+  newFamily = NULL;
+  sigprocmask(SIG_SETMASK, &omask, NULL);
+
+#ifdef INITLVL
+  /*
+   *	Dispose of INITLVL file.
+   */
+  if (lstat(INITLVL, &st) >= 0 && S_ISLNK(st.st_mode)) {
+	/*
+	 *	INITLVL is a symbolic link, so just truncate the file.
+	 */
+	close(open(INITLVL, O_WRONLY|O_TRUNC));
+  } else {
+	/*
+	 *	Delete INITLVL file.
+	 */
+  	unlink(INITLVL);
+  }
+#endif
+#ifdef INITLVL2
+  /*
+   *	Dispose of INITLVL2 file.
+   */
+  if (lstat(INITLVL2, &st) >= 0 && S_ISLNK(st.st_mode)) {
+	/*
+	 *	INITLVL2 is a symbolic link, so just truncate the file.
+	 */
+	close(open(INITLVL2, O_WRONLY|O_TRUNC));
+  } else {
+	/*
+	 *	Delete INITLVL2 file.
+	 */
+  	unlink(INITLVL2);
+  }
+#endif
+}
+
+/*
+ *	Walk through the family list and start up children.
+ *	The entries that do not belong here at all are removed
+ *	from the list.
+ */
+static
+void start_if_needed(void)
+{
+	CHILD *ch;		/* Pointer to child */
+	int delete;		/* Delete this entry from list? */
+
+	INITDBG(L_VB, "Checking for children to start");
+
+	for(ch = family; ch; ch = ch->next) {
+
+#if DEBUG
+		if (ch->rlevel[0] == 'C') {
+			INITDBG(L_VB, "%s: flags %d", ch->process, ch->flags);
+		}
+#endif
+
+		/* Are we waiting for this process? Then quit here. */
+		if (ch->flags & WAITING) break;
+
+		/* Already running? OK, don't touch it */
+		if (ch->flags & RUNNING) continue;
+
+		/* See if we have to start it up */
+		delete = 1;
+		if (strchr(ch->rlevel, runlevel) ||
+		    ((ch->flags & DEMAND) && !strchr("#*Ss", runlevel))) {
+			startup(ch);
+			delete = 0;
+		}
+
+		if (delete) {
+			/* is this OK? */
+			ch->flags &= ~(RUNNING|WAITING);
+			if (!ISPOWER(ch->action) && ch->action != KBREQUEST)
+				ch->flags &= ~XECUTED;
+			ch->pid = 0;
+		} else
+			/* Do we have to wait for this process? */
+			if (ch->flags & WAITING) break;
+	}
+	/* Done. */
+}
+
+/*
+ *	Ask the user on the console for a runlevel
+ */
+static
+int ask_runlevel(void)
+{
+	const char	prompt[] = "\nEnter runlevel: ";
+	char		buf[8];
+	int		lvl = -1;
+	int		fd;
+
+	console_stty();
+	fd = console_open(O_RDWR|O_NOCTTY);
+
+	if (fd < 0) return('S');
+
+	while(!strchr("0123456789S", lvl)) {
+		safe_write(fd, prompt, sizeof(prompt) - 1);
+		if (read(fd, buf, sizeof(buf)) <= 0)
+			buf[0] = 0;
+  		if (buf[0] != 0 && (buf[1] == '\r' || buf[1] == '\n'))
+			lvl = buf[0];
+		if (islower(lvl)) lvl = toupper(lvl);
+	}
+	close(fd);
+	return lvl;
+}
+
+/*
+ *	Search the INITTAB file for the 'initdefault' field, with the default
+ *	runlevel. If this fails, ask the user to supply a runlevel.
+ */
+static
+int get_init_default(void)
+{
+	CHILD *ch;
+	int lvl = -1;
+	char *p;
+
+	/*
+	 *	Look for initdefault.
+	 */
+	for(ch = family; ch; ch = ch->next)
+		if (ch->action == INITDEFAULT) {
+			p = ch->rlevel;
+			while(*p) {
+				if (*p > lvl) lvl = *p;
+				p++;
+			}
+			break;
+		}
+	/*
+	 *	See if level is valid
+	 */
+	if (lvl > 0) {
+		if (islower(lvl)) lvl = toupper(lvl);
+		if (strchr("0123456789S", lvl) == NULL) {
+			initlog(L_VB,
+				"Initdefault level '%c' is invalid", lvl);
+			lvl = 0;
+		}
+	}
+	/*
+	 *	Ask for runlevel on console if needed.
+	 */
+	if (lvl <= 0) lvl = ask_runlevel();
+
+	/*
+	 *	Log the fact that we have a runlevel now.
+	 */
+        Write_Runlevel_Log(lvl);
+	return lvl;
+}
+
+
+/*
+ *	We got signaled.
+ *
+ *	Do actions for the new level. If we are compatible with
+ *	the "old" INITLVL and arg == 0, try to read the new
+ *	runlevel from that file first.
+ */
+static
+int read_level(int arg)
+{
+	CHILD		*ch;			/* Walk through list */
+	unsigned char	foo = 'X';		/* Contents of INITLVL */
+	int		ok = 1;
+#ifdef INITLVL
+	FILE		*fp;
+	struct stat	stt;
+	int		st;
+#endif
+
+	if (arg) foo = arg;
+
+#ifdef INITLVL
+	ok = 0;
+
+	if (arg == 0) {
+		fp = NULL;
+		if (stat(INITLVL, &stt) != 0 || stt.st_size != 0L)
+			fp = fopen(INITLVL, "r");
+#ifdef INITLVL2
+		if (fp == NULL &&
+		    (stat(INITLVL2, &stt) != 0 || stt.st_size != 0L))
+			fp = fopen(INITLVL2, "r");
+#endif
+		if (fp == NULL) {
+			/* INITLVL file empty or not there - act as 'init q' */
+			initlog(L_SY, "Re-reading inittab");
+  			return(runlevel);
+		}
+		ok = fscanf(fp, "%c %d", &foo, &st);
+		fclose(fp);
+	} else {
+		/* We go to the new runlevel passed as an argument. */
+		foo = arg;
+		ok = 1;
+	}
+	if (ok == 2) sleep_time = st;
+
+#endif /* INITLVL */
+
+	if (islower(foo)) foo = toupper(foo);
+	if (ok < 1 || ok > 2 || strchr("QS0123456789ABCU", foo) == NULL) {
+ 		initlog(L_VB, "bad runlevel: %c", foo);
+  		return runlevel;
+	}
+
+	/* Log this action */
+	switch(foo) {
+		case 'S':
+  			initlog(L_VB, "Going single user");
+			break;
+		case 'Q':
+			initlog(L_SY, "Re-reading inittab");
+			break;
+		case 'A':
+		case 'B':
+		case 'C':
+			initlog(L_SY,
+				"Activating demand-procedures for '%c'", foo);
+			break;
+		case 'U':
+			initlog(L_SY, "Trying to re-exec init");
+			return 'U';
+		default:
+		  	initlog(L_VB, "Switching to runlevel: %c", foo);
+	}
+
+	if (foo == 'Q') {
+#if defined(SIGINT_ONLYONCE) && (SIGINT_ONLYONCE == 1)
+		/* Re-enable signal from keyboard */
+		struct sigaction sa;
+		SETSIG(sa, SIGINT, signal_handler, 0);
+#endif
+		return runlevel;
+	}
+
+	/* Check if this is a runlevel a, b or c */
+	if (strchr("ABC", foo)) {
+		if (runlevel == 'S') return(runlevel);
+
+		/* Read inittab again first! */
+		read_inittab();
+
+  		/* Mark those special tasks */
+		for(ch = family; ch; ch = ch->next)
+			if (strchr(ch->rlevel, foo) != NULL ||
+			    strchr(ch->rlevel, tolower(foo)) != NULL) {
+				ch->flags |= DEMAND;
+				ch->flags &= ~XECUTED;
+				INITDBG(L_VB,
+					"Marking (%s) as ondemand, flags %d",
+					ch->id, ch->flags);
+			}
+  		return runlevel;
+	}
+
+	/* Store both the old and the new runlevel. */
+	wrote_utmp_rlevel = 0;
+	wrote_wtmp_rlevel = 0;
+	write_utmp_wtmp("runlevel", "~~", foo + 256*runlevel, RUN_LVL, "~");
+	thislevel = foo;
+	prevlevel = runlevel;
+        Write_Runlevel_Log(runlevel);
+	return foo;
+}
+
+
+/*
+ *	This procedure is called after every signal (SIGHUP, SIGALRM..)
+ *
+ *	Only clear the 'failing' flag if the process is sleeping
+ *	longer than 5 minutes, or inittab was read again due
+ *	to user interaction.
+ */
+static
+void fail_check(void)
+{
+	CHILD	*ch;			/* Pointer to child structure */
+	time_t	t;			/* System time */
+	time_t	next_alarm = 0;		/* When to set next alarm */
+
+	time(&t);
+
+	for(ch = family; ch; ch = ch->next) {
+
+		if (ch->flags & FAILING) {
+			/* Can we free this sucker? */
+			if (ch->tm + SLEEPTIME < t) {
+				ch->flags &= ~FAILING;
+				ch->count = 0;
+				ch->tm = 0;
+			} else {
+				/* No, we'll look again later */
+				if (next_alarm == 0 ||
+				    ch->tm + SLEEPTIME > next_alarm)
+					next_alarm = ch->tm + SLEEPTIME;
+			}
+		}
+	}
+	if (next_alarm) {
+		next_alarm -= t;
+		if (next_alarm < 1) next_alarm = 1;
+		alarm(next_alarm);
+	}
+}
+
+/* Set all 'Fail' timers to 0 */
+static
+void fail_cancel(void)
+{
+	CHILD *ch;
+
+	for(ch = family; ch; ch = ch->next) {
+		ch->count = 0;
+		ch->tm = 0;
+		ch->flags &= ~FAILING;
+	}
+}
+
+/*
+ *	Start up powerfail entries.
+ */
+static
+void do_power_fail(int pwrstat)
+{
+	CHILD *ch;
+
+	/*
+	 *	Tell powerwait & powerfail entries to start up
+	 */
+	for (ch = family; ch; ch = ch->next) {
+		if (pwrstat == 'O') {
+			/*
+		 	 *	The power is OK again.
+		 	 */
+			if (ch->action == POWEROKWAIT)
+				ch->flags &= ~XECUTED;
+		} else if (pwrstat == 'L') {
+			/*
+			 *	Low battery, shut down now.
+			 */
+			if (ch->action == POWERFAILNOW)
+				ch->flags &= ~XECUTED;
+		} else {
+			/*
+			 *	Power is failing, shutdown imminent
+			 */
+			if (ch->action == POWERFAIL || ch->action == POWERWAIT)
+				ch->flags &= ~XECUTED;
+		}
+	}
+}
+
+/*
+ *	Check for state-pipe presence
+ */
+static
+int check_pipe(int fd)
+{
+	struct timeval	t;
+	fd_set		s;
+	char		signature[8];
+
+	FD_ZERO(&s);
+	FD_SET(fd, &s);
+	t.tv_sec = t.tv_usec = 0;
+
+	if (select(fd+1, &s, NULL, NULL, &t) != 1)
+		return 0;
+	if (read(fd, signature, 8) != 8)
+		 return 0;
+	return strncmp(Signature, signature, 8) == 0;
+}
+
+/*
+ *	 Make a state-pipe.
+ */
+static
+int make_pipe(int fd)
+{
+	int fds[2];
+
+	if (pipe(fds)) {
+		initlog(L_VB, "pipe: %m");
+		return -1;
+	}
+	dup2(fds[0], fd);
+	close(fds[0]);
+	fcntl(fds[1], F_SETFD, 1);
+	fcntl(fd, F_SETFD, 0);
+	safe_write(fds[1], Signature, 8);
+
+	return fds[1];
+}
+
+/*
+ *	Attempt to re-exec.
+ *      Renaming to my_re_exec since re_exec is now a common function name
+ *      which conflicts.
+ */
+static
+void my_re_exec(void)
+{
+	CHILD		*ch;
+	sigset_t	mask, oldset;
+	pid_t		pid;
+	char		**env;
+	int		fd;
+
+	if (strchr("S0123456",runlevel) == NULL)
+		return;
+
+	/*
+	 *	Reset the alarm, and block all signals.
+	 */
+	alarm(0);
+	sigfillset(&mask);
+	sigprocmask(SIG_BLOCK, &mask, &oldset);
+
+	/*
+	 *	construct a pipe fd --> STATE_PIPE and write a signature
+	 */
+	if ((fd = make_pipe(STATE_PIPE)) < 0) {
+		sigprocmask(SIG_SETMASK, &oldset, NULL);
+		initlog(L_CO, "Attempt to re-exec failed");
+	}
+
+	fail_cancel();
+	if (pipe_fd >= 0) 
+          close(pipe_fd);
+   	pipe_fd = -1;
+	DELSET(got_signals, SIGCHLD);
+	DELSET(got_signals, SIGHUP);
+	DELSET(got_signals, SIGUSR1);
+	DELSET(got_signals, SIGUSR2);
+
+	/*
+	 *	That should be cleaned.
+	 */
+	for(ch = family; ch; ch = ch->next)
+	    if (ch->flags & ZOMBIE) {
+		INITDBG(L_VB, "Child died, PID= %d", ch->pid);
+		ch->flags &= ~(RUNNING|ZOMBIE|WAITING);
+		if (ch->process[0] != '+')
+			write_utmp_wtmp("", ch->id, ch->pid, DEAD_PROCESS, NULL);
+	    }
+
+	if ((pid = fork()) == 0) {
+		/*
+		 *	Child sends state information to the parent.
+		 */
+		send_state(fd);
+		exit(0);
+	}
+
+	/*
+	 *	The existing init process execs a new init binary.
+	 */
+	env = init_buildenv(0);
+	execle(myname, myname, "--init", NULL, env);
+
+	/*
+	 *	We shouldn't be here, something failed. 
+	 *	Close the state pipe, unblock signals and return.
+	 */
+	init_freeenv(env);
+	close(fd);
+	close(STATE_PIPE);
+	sigprocmask(SIG_SETMASK, &oldset, NULL);
+	initlog(L_CO, "Attempt to re-exec failed");
+}
+
+/*
+ *	Redo utmp/wtmp entries if required or requested
+ *	Check for written records and size of utmp
+ */
+static
+void redo_utmp_wtmp(void)
+{
+	struct stat ustat;
+	const int ret = stat(UTMP_FILE, &ustat);
+
+	if ((ret < 0) || (ustat.st_size == 0))
+		wrote_utmp_rlevel = wrote_utmp_reboot = 0;
+
+	if ((wrote_wtmp_reboot == 0) || (wrote_utmp_reboot == 0))
+		write_utmp_wtmp("reboot", "~~", 0, BOOT_TIME, "~");
+
+	if ((wrote_wtmp_rlevel == 0) || (wrote_utmp_rlevel == 0))
+		write_utmp_wtmp("runlevel", "~~", thislevel + 256 * prevlevel, RUN_LVL, "~");
+}
+
+/*
+ *	We got a change runlevel request through the
+ *	init.fifo. Process it.
+ */
+static
+void fifo_new_level(int level)
+{
+#if CHANGE_WAIT
+	CHILD	*ch;
+#endif
+	int	oldlevel;
+
+	if (level == runlevel) return;
+
+#if CHANGE_WAIT
+	/* Are we waiting for a child? */
+	for(ch = family; ch; ch = ch->next)
+		if (ch->flags & WAITING) break;
+	if (ch == NULL)
+#endif
+	{
+		/* We need to go into a new runlevel */
+		oldlevel = runlevel;
+		runlevel = read_level(level);
+		if (runlevel == 'U') {
+			runlevel = oldlevel;
+			my_re_exec();
+		} else {
+			if (oldlevel != 'S' && runlevel == 'S') console_stty();
+			if (runlevel == '6' || runlevel == '0' ||
+			    runlevel == '1') console_stty();
+			if (runlevel  > '1' && runlevel  < '6') redo_utmp_wtmp();
+			read_inittab();
+			fail_cancel();
+			setproctitle("init [%c]", (int)runlevel);
+		}
+	}
+        Write_Runlevel_Log(runlevel);
+}
+
+
+/*
+ *	Set/unset environment variables. The variables are
+ *	encoded as KEY=VAL\0KEY=VAL\0\0. With "=VAL" it means
+ *	setenv, without it means unsetenv.
+ */
+static
+void initcmd_setenv(char *data, int size)
+{
+	char		*env, *p, *e;
+	size_t		sz;
+	int		i, eq;
+
+	e = data + size;
+
+	while (*data && data < e) {
+		for (p = data; *p && p < e; p++)
+			;
+		if (*p) break;
+		env = data;
+		data = ++p;
+
+		/*
+		 *	We only allow INIT_* to be set.
+		 */
+		if (strncmp(env, "INIT_", 5) != 0)
+			continue;
+
+		sz = strcspn(env, "=");
+		eq = (env[sz] == '=');
+
+		/*initlog(L_SY, "init_setenv: %s, %d, %d", env, eq, sz);*/
+
+		/* Free existing vars. */
+		for (i = 0; i < NR_EXTRA_ENV; i++) {
+			if (extra_env[i] == NULL)
+				continue;
+			if (sz != strcspn(extra_env[i], "="))
+				continue;
+			if (strncmp(extra_env[i], env, sz) == 0) {
+				free(extra_env[i]);
+				extra_env[i] = NULL;
+			}
+		}
+
+		if (eq == 0)
+			continue;
+
+		/* Set new vars if needed. */
+		for (i = 0; i < NR_EXTRA_ENV; i++) {
+			if (extra_env[i] == NULL) {
+				extra_env[i] = istrdup(env);
+				break;
+			}
+		}
+	}
+}
+
+
+/*
+ *	Read from the init FIFO. Processes like telnetd and rlogind can
+ *	ask us to create login processes on their behalf.
+ */
+static
+void check_init_fifo(void)
+{
+  struct init_request	request;
+  struct timeval	tv;
+  struct stat		st, st2;
+  fd_set		fds;
+  int			n;
+  int			quit = 0;
+
+  /*
+   *	First, try to create /dev/initctl if not present.
+   */
+  if (stat(INIT_FIFO, &st2) < 0 && errno == ENOENT)
+	(void)mkfifo(INIT_FIFO, 0600);
+
+  /*
+   *	If /dev/initctl is open, stat the file to see if it
+   *	is still the _same_ inode.
+   */
+  if (pipe_fd >= 0) {
+	fstat(pipe_fd, &st);
+	if (stat(INIT_FIFO, &st2) < 0 ||
+	    st.st_dev != st2.st_dev ||
+	    st.st_ino != st2.st_ino) {
+		close(pipe_fd);
+		pipe_fd = -1;
+	}
+  }
+
+  /*
+   *	Now finally try to open /dev/initctl if pipe_fd is -1
+   *    if it is -2, then we leave it closed
+   */
+  if (pipe_fd == -1) {
+	if ((pipe_fd = open(INIT_FIFO, O_RDWR|O_NONBLOCK)) >= 0) {
+		fstat(pipe_fd, &st);
+		if (!S_ISFIFO(st.st_mode)) {
+			initlog(L_VB, "%s is not a fifo", INIT_FIFO);
+			close(pipe_fd);
+			pipe_fd = -1;
+		}
+	}
+	if (pipe_fd >= 0) {
+		/*
+		 *	Don't use fd's 0, 1 or 2.
+		 */
+		(void) dup2(pipe_fd, PIPE_FD);
+		close(pipe_fd);
+		pipe_fd = PIPE_FD;
+
+		/*
+		 *	Return to caller - we'll be back later.
+		 */
+	}
+  }
+
+  /* Wait for data to appear, _if_ the pipe was opened. */
+  if (pipe_fd >= 0) { 
+     while(!quit) {
+
+	/* Do select, return on EINTR. */
+	FD_ZERO(&fds);
+	FD_SET(pipe_fd, &fds);
+	tv.tv_sec = 5;
+	tv.tv_usec = 0;
+	n = select(pipe_fd + 1, &fds, NULL, NULL, &tv);
+	if (n <= 0) {
+		if (n == 0 || errno == EINTR) return;
+		continue;
+	}
+
+	/* Read the data, return on EINTR. */
+	n = read(pipe_fd, &request, sizeof(request));
+	if (n == 0) {
+		/*
+		 *	End of file. This can't happen under Linux (because
+		 *	the pipe is opened O_RDWR - see select() in the
+		 *	kernel) but you never know...
+		 */
+		close(pipe_fd);
+		pipe_fd = -1;
+		return;
+	}
+	if (n <= 0) {
+		if (errno == EINTR) return;
+		initlog(L_VB, "error reading initrequest");
+		continue;
+	}
+
+	/*
+	 *	This is a convenient point to also try to
+	 *	find the console device or check if it changed.
+	 */
+	console_init();
+
+	/*
+	 *	Process request.
+	 */
+	if (request.magic != INIT_MAGIC || n != sizeof(request)) {
+		initlog(L_VB, "got bogus initrequest");
+		continue;
+	}
+	switch(request.cmd) {
+		case INIT_CMD_RUNLVL:
+			sleep_time = request.sleeptime;
+			fifo_new_level(request.runlevel);
+			quit = 1;
+			break;
+		case INIT_CMD_POWERFAIL:
+			sleep_time = request.sleeptime;
+			do_power_fail('F');
+			quit = 1;
+			break;
+		case INIT_CMD_POWERFAILNOW:
+			sleep_time = request.sleeptime;
+			do_power_fail('L');
+			quit = 1;
+			break;
+		case INIT_CMD_POWEROK:
+			sleep_time = request.sleeptime;
+			do_power_fail('O');
+			quit = 1;
+			break;
+		case INIT_CMD_SETENV:
+			initcmd_setenv(request.i.data, sizeof(request.i.data));
+			break;
+		default:
+			initlog(L_VB, "got unimplemented initrequest.");
+			break;
+	}   /* end of switch */
+    }       /* end of while loop not quitting */
+  }         /* end of if the pipe is open */
+  /*
+   *	We come here if the pipe couldn't be opened.
+   */
+  if (pipe_fd == -1) pause();
+
+}
+
+
+/*
+ *	This function is used in the transition
+ *	sysinit (-> single user) boot -> multi-user.
+ */
+static
+void boot_transitions()
+{
+  CHILD		*ch;
+  static int	newlevel = 0;
+  static int	warn = 1;
+  int		loglevel;
+  int		oldlevel;
+
+  /* Check if there is something to wait for! */
+  for( ch = family; ch; ch = ch->next )
+	if ((ch->flags & RUNNING) && ch->action != BOOT) break;
+     
+  if (ch == NULL) {
+	/* No processes left in this level, proceed to next level. */
+	loglevel = -1;
+	oldlevel = 'N';
+	switch(runlevel) {
+		case '#': /* SYSINIT -> BOOT */
+			INITDBG(L_VB, "SYSINIT -> BOOT");
+
+			/* Write a boot record. */
+			wrote_utmp_reboot = 0;
+			wrote_wtmp_reboot = 0;
+			write_utmp_wtmp("reboot", "~~", 0, BOOT_TIME, "~");
+
+  			/* Get our run level */
+  			newlevel = dfl_level ? dfl_level : get_init_default();
+			if (newlevel == 'S') {
+				runlevel = newlevel;
+				/* Not really 'S' but show anyway. */
+				setproctitle("init [S]");
+			} else
+				runlevel = '*';
+			break;
+		case '*': /* BOOT -> NORMAL */
+			INITDBG(L_VB, "BOOT -> NORMAL");
+			if (runlevel != newlevel)
+				loglevel = newlevel;
+			runlevel = newlevel;
+			did_boot = 1;
+			warn = 1;
+			break;
+		case 'S': /* Ended SU mode */
+		case 's':
+			INITDBG(L_VB, "END SU MODE");
+			newlevel = get_init_default();
+			if (!did_boot && newlevel != 'S')
+				runlevel = '*';
+			else {
+				if (runlevel != newlevel)
+					loglevel = newlevel;
+				runlevel = newlevel;
+				oldlevel = 'S';
+			}
+			warn = 1;
+			for(ch = family; ch; ch = ch->next)
+			    if (strcmp(ch->rlevel, "S") == 0)
+				ch->flags &= ~(FAILING|WAITING|XECUTED);
+			break;
+		default:
+			if (warn)
+			  initlog(L_VB,
+				"no more processes left in this runlevel");
+			warn = 0;
+			loglevel = -1;
+			if (got_signals == 0)
+				check_init_fifo();
+			break;
+	}
+	if (loglevel > 0) {
+		initlog(L_VB, "Entering runlevel: %c", runlevel);
+		wrote_utmp_rlevel = 0;
+		wrote_wtmp_rlevel = 0;
+		write_utmp_wtmp("runlevel", "~~", runlevel + 256 * oldlevel, RUN_LVL, "~");
+		thislevel = runlevel;
+		prevlevel = oldlevel;
+		setproctitle("init [%c]", (int)runlevel);
+	}
+        Write_Runlevel_Log(runlevel);
+  }
+}
+
+/*
+ *	Init got hit by a signal. See which signal it is,
+ *	and act accordingly.
+ */
+static
+void process_signals()
+{
+  CHILD		*ch;
+  int		pwrstat;
+  int		oldlevel;
+  int		fd;
+  char		c;
+
+  if (ISMEMBER(got_signals, SIGPWR)) {
+	INITDBG(L_VB, "got SIGPWR");
+	/* See _what_ kind of SIGPWR this is. */
+	pwrstat = 0;
+	if ((fd = open(PWRSTAT, O_RDONLY)) >= 0) {
+		if (read(fd, &c, 1) != 1)
+			c = 0;
+		pwrstat = c;
+		close(fd);
+		unlink(PWRSTAT);
+	} else if ((fd = open(PWRSTAT_OLD, O_RDONLY)) >= 0) {
+		/* Path changed 2010-03-20.  Look for the old path for a while. */
+		initlog(L_VB, "warning: found obsolete path %s, use %s instead",
+			PWRSTAT_OLD, PWRSTAT);
+		if (read(fd, &c, 1) != 1)
+			c = 0;
+		pwrstat = c;
+		close(fd);
+		unlink(PWRSTAT_OLD);
+        }
+	do_power_fail(pwrstat);
+	DELSET(got_signals, SIGPWR);
+  }
+
+  if (ISMEMBER(got_signals, SIGINT)) {
+#if defined(SIGINT_ONLYONCE) && (SIGINT_ONLYONCE == 1)
+	/* Ignore any further signal from keyboard */
+	struct sigaction sa;
+	SETSIG(sa, SIGINT, SIG_IGN, SA_RESTART);
+#endif
+	INITDBG(L_VB, "got SIGINT");
+	/* Tell ctrlaltdel entry to start up */
+	for(ch = family; ch; ch = ch->next)
+		if (ch->action == CTRLALTDEL)
+			ch->flags &= ~XECUTED;
+	DELSET(got_signals, SIGINT);
+  }
+
+  if (ISMEMBER(got_signals, SIGWINCH)) {
+	INITDBG(L_VB, "got SIGWINCH");
+	/* Tell kbrequest entry to start up */
+	for(ch = family; ch; ch = ch->next)
+		if (ch->action == KBREQUEST)
+			ch->flags &= ~XECUTED;
+	DELSET(got_signals, SIGWINCH);
+  }
+
+  if (ISMEMBER(got_signals, SIGALRM)) {
+	INITDBG(L_VB, "got SIGALRM");
+	/* The timer went off: check it out */
+	DELSET(got_signals, SIGALRM);
+  }
+
+  if (ISMEMBER(got_signals, SIGCHLD)) {
+	INITDBG(L_VB, "got SIGCHLD");
+	/* First set flag to 0 */
+	DELSET(got_signals, SIGCHLD);
+
+	/* See which child this was */
+	for(ch = family; ch; ch = ch->next)
+	    if (ch->flags & ZOMBIE) {
+		INITDBG(L_VB, "Child died, PID= %d", ch->pid);
+		ch->flags &= ~(RUNNING|ZOMBIE|WAITING);
+		if (ch->process[0] != '+')
+			write_utmp_wtmp("", ch->id, ch->pid, DEAD_PROCESS, NULL);
+	    }
+
+  }
+
+  if (ISMEMBER(got_signals, SIGHUP)) {
+	INITDBG(L_VB, "got SIGHUP");
+#if CHANGE_WAIT
+	/* Are we waiting for a child? */
+	for(ch = family; ch; ch = ch->next)
+		if (ch->flags & WAITING) break;
+	if (ch == NULL)
+#endif
+	{
+		/* We need to go into a new runlevel */
+		oldlevel = runlevel;
+#ifdef INITLVL
+		runlevel = read_level(0);
+#endif
+		if (runlevel == 'U') {
+			runlevel = oldlevel;
+			my_re_exec();
+		} else {
+			if (oldlevel != 'S' && runlevel == 'S') console_stty();
+			if (runlevel == '6' || runlevel == '0' ||
+			    runlevel == '1') console_stty();
+			read_inittab();
+			fail_cancel();
+			setproctitle("init [%c]", (int)runlevel);
+			DELSET(got_signals, SIGHUP);
+		}
+                Write_Runlevel_Log(runlevel);
+	}
+  }
+  if (ISMEMBER(got_signals, SIGUSR1)) {
+	/*
+	 *	SIGUSR1 means close and reopen /dev/initctl
+	 */
+	INITDBG(L_VB, "got SIGUSR1");
+	if (pipe_fd)
+           close(pipe_fd);
+	pipe_fd = -1;
+	DELSET(got_signals, SIGUSR1);
+  }
+  else if (ISMEMBER(got_signals, SIGUSR2)) {
+       /* SIGUSR1 mean close the pipe and leave it closed */
+       INITDBG(L_VB, "got SIGUSR2");
+       if (pipe_fd)
+           close(pipe_fd);
+       pipe_fd = -2;
+       DELSET(got_signals, SIGUSR2);
+  }
+}
+
+/*
+ *	The main loop
+ */ 
+static
+void init_main(void)
+{
+  CHILD			*ch;
+  struct sigaction	sa;
+  sigset_t		sgt;
+  int			f, st;
+
+  if (!reload) {
+  
+#if INITDEBUG
+	/*
+	 * Fork so we can debug the init process.
+	 */
+	if ((f = fork()) > 0) {
+		static const char killmsg[] = "PRNT: init killed.\r\n";
+		pid_t rc;
+
+		while((rc = wait(&st)) != f)
+			if (rc < 0 && errno == ECHILD)
+				break;
+		safe_write(1, killmsg, sizeof(killmsg) - 1);
+		while(1) pause();
+	}
+#endif
+
+#ifdef __linux__
+	/*
+	 *	Tell the kernel to send us SIGINT when CTRL-ALT-DEL
+	 *	is pressed, and that we want to handle keyboard signals.
+	 */
+	init_reboot(BMAGIC_SOFT);
+	if ((f = open(VT_MASTER, O_RDWR | O_NOCTTY)) >= 0) {
+		(void) ioctl(f, KDSIGACCEPT, SIGWINCH);
+		close(f);
+	} else
+		(void) ioctl(0, KDSIGACCEPT, SIGWINCH);
+#endif
+
+	/*
+	 *	Ignore all signals.
+	 */
+	for(f = 1; f <= NSIG; f++)
+		SETSIG(sa, f, SIG_IGN, SA_RESTART);
+  }
+
+  SETSIG(sa, SIGALRM,  signal_handler, 0);
+  SETSIG(sa, SIGHUP,   signal_handler, 0);
+  SETSIG(sa, SIGINT,   signal_handler, 0);
+  SETSIG(sa, SIGCHLD,  chld_handler, SA_RESTART);
+  SETSIG(sa, SIGPWR,   signal_handler, 0);
+  SETSIG(sa, SIGWINCH, signal_handler, 0);
+  SETSIG(sa, SIGUSR1,  signal_handler, 0);
+  SETSIG(sa, SIGUSR2,  signal_handler, 0);
+  SETSIG(sa, SIGSTOP,  stop_handler, SA_RESTART);
+  SETSIG(sa, SIGTSTP,  stop_handler, SA_RESTART);
+  SETSIG(sa, SIGCONT,  cont_handler, SA_RESTART);
+  SETSIG(sa, SIGSEGV,  (void (*)(int))segv_handler, SA_RESTART);
+
+  console_init();
+
+  if (!reload) {
+	int fd;
+
+  	/* Close whatever files are open, and reset the console. */
+	close(0);
+	close(1);
+	close(2);
+  	console_stty();
+  	setsid();
+
+  	/*
+	 *	Set default PATH variable.
+	 */
+  	setenv("PATH", PATH_DEFAULT, 1 /* Overwrite */);
+
+  	/*
+	 *	Initialize /var/run/utmp (only works if /var is on
+	 *	root and mounted rw)
+	 */
+	if ((fd = open(UTMP_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0644)) >= 0)
+		close(fd);
+
+  	/*
+	 *	Say hello to the world
+	 */
+  	initlog(L_CO, bootmsg, "booting");
+
+  	/*
+	 *	See if we have to start an emergency shell.
+	 */
+	if (emerg_shell) {
+		pid_t rc;
+		SETSIG(sa, SIGCHLD, SIG_DFL, SA_RESTART);
+		if (spawn(&ch_emerg, &f) > 0) {
+			while((rc = wait(&st)) != f)
+				if (rc < 0 && errno == ECHILD)
+					break;
+		}
+  		SETSIG(sa, SIGCHLD,  chld_handler, SA_RESTART);
+  	}
+
+  	/*
+	 *	Start normal boot procedure.
+	 */
+  	runlevel = '#';
+  	read_inittab();
+  
+  } else {
+	/*
+	 *	Restart: unblock signals and let the show go on
+	 */
+	initlog(L_CO, bootmsg, "reloading");
+	sigfillset(&sgt);
+	sigprocmask(SIG_UNBLOCK, &sgt, NULL);
+
+  	/*
+	 *	Set default PATH variable.
+	 */
+  	setenv("PATH", PATH_DEFAULT, 0 /* Don't overwrite */);
+  }
+  start_if_needed();
+
+  while(1) {
+
+     /* See if we need to make the boot transitions. */
+     boot_transitions();
+     INITDBG(L_VB, "init_main: waiting..");
+
+     /* Check if there are processes to be waited on. */
+     for(ch = family; ch; ch = ch->next)
+	if ((ch->flags & RUNNING) && ch->action != BOOT) break;
+
+#if CHANGE_WAIT
+     /* Wait until we get hit by some signal. */
+     while (ch != NULL && got_signals == 0) {
+	if (ISMEMBER(got_signals, SIGHUP)) {
+		/* See if there are processes to be waited on. */
+		for(ch = family; ch; ch = ch->next)
+			if (ch->flags & WAITING) break;
+	}
+	if (ch != NULL) check_init_fifo();
+     }
+#else /* CHANGE_WAIT */
+     if (ch != NULL && got_signals == 0) check_init_fifo();
+#endif /* CHANGE_WAIT */
+
+     /* Check the 'failing' flags */
+     fail_check();
+
+     /* Process any signals. */
+     process_signals();
+
+     /* See what we need to start up (again) */
+     start_if_needed();
+  }
+  /*NOTREACHED*/
+}
+
+/*
+ * Tell the user about the syntax we expect.
+ */
+static
+void usage(char *s)
+{
+	fprintf(stderr, "Usage: %s {-e VAR[=VAL] | [-t SECONDS] {0|1|2|3|4|5|6|S|s|Q|q|A|a|B|b|C|c|U|u}}\n", s);
+	exit(1);
+}
+
+static
+int telinit(char *progname, int argc, char **argv)
+{
+#ifdef TELINIT_USES_INITLVL
+	FILE			*fp;
+#endif
+	struct init_request	request;
+	struct sigaction	sa;
+	int			f, fd, l;
+	char			*env = NULL;
+
+	memset(&request, 0, sizeof(request));
+	request.magic     = INIT_MAGIC;
+
+	while ((f = getopt(argc, argv, "t:e:")) != EOF) switch(f) {
+		case 't':
+			sleep_time = atoi(optarg);
+			break;
+		case 'e':
+			if (env == NULL)
+				env = request.i.data;
+			l = strlen(optarg);
+			if (env + l + 2 > request.i.data + sizeof(request.i.data)) {
+				fprintf(stderr, "%s: -e option data "
+					"too large\n", progname);
+				exit(1);
+			}
+			memcpy(env, optarg, l);
+			env += l;
+			*env++ = 0;
+			break;
+		default:
+			usage(progname);
+			break;
+	}
+
+	if (env) *env++ = 0;
+
+	if (env) {
+		if (argc != optind)
+			usage(progname);
+		request.cmd = INIT_CMD_SETENV;
+	} else {
+		if (argc - optind != 1 || strlen(argv[optind]) != 1)
+			usage(progname);
+		if (!strchr("0123456789SsQqAaBbCcUu", argv[optind][0]))
+			usage(progname);
+		request.cmd = INIT_CMD_RUNLVL;
+		request.runlevel  = argv[optind][0];
+		request.sleeptime = sleep_time;
+	}
+
+	/* Change to the root directory. */
+	if (0 != chdir("/"))
+		initlog(L_VB, "unable to chdir to /: %s",
+			strerror(errno));
+
+	/* Open the fifo and write a command. */
+	/* Make sure we don't hang on opening /dev/initctl */
+	SETSIG(sa, SIGALRM, signal_handler, 0);
+	alarm(3);
+	if ((fd = open(INIT_FIFO, O_WRONLY)) >= 0) {
+		ssize_t p = 0;
+		size_t s  = sizeof(request);
+		void *ptr = &request;
+
+		while (s > 0) {
+			p = write(fd, ptr, s);
+			if (p < 0) {
+				if (errno == EINTR || errno == EAGAIN)
+					continue;
+				break;
+			}
+			ptr += p;
+			s -= p;
+		}
+		close(fd);
+		alarm(0);
+		return 0;
+	}
+
+#ifdef TELINIT_USES_INITLVL
+	if (request.cmd == INIT_CMD_RUNLVL) {
+		/* Fallthrough to the old method. */
+
+		/* Now write the new runlevel. */
+		if ((fp = fopen(INITLVL, "w")) == NULL) {
+			fprintf(stderr, "%s: cannot create %s\n",
+				progname, INITLVL);
+			exit(1);
+		}
+		fprintf(fp, "%s %d", argv[optind], sleep_time);
+		fclose(fp);
+
+		/* And tell init about the pending runlevel change. */
+		if (kill(INITPID, SIGHUP) < 0) perror(progname);
+
+		return 0;
+	}
+#endif
+
+	fprintf(stderr, "%s: ", progname);
+	if (ISMEMBER(got_signals, SIGALRM)) {
+		fprintf(stderr, "timeout opening/writing control channel %s\n",
+			INIT_FIFO);
+	} else {
+		perror(INIT_FIFO);
+	}
+	return 1;
+}
+
+/*
+ * Main entry for init and telinit.
+ */
+int main(int argc, char **argv)
+{
+	char			*p;
+	int			f;
+	int			isinit;
+#ifdef WITH_SELINUX
+	int			enforce = 0;
+#endif
+
+	/* Get my own name */
+	if ((p = strrchr(argv[0], '/')) != NULL)
+  		p++;
+	else
+  		p = argv[0];
+
+        if ( (argc == 2) && (! strcmp(argv[1], "--version") ) )
+        {
+           printf("SysV init version: %s\n\n", VERSION);
+           exit(0);
+        }
+
+	/* Common umask */
+	umask(umask(077) | 022);
+
+	/* Quick check */
+	if (geteuid() != 0) {
+		fprintf(stderr, "%s: must be superuser.\n", p);
+		exit(1);
+	}
+
+	/*
+	 *	Is this telinit or init ?
+	 */
+	isinit = (getpid() == 1);
+	for (f = 1; f < argc; f++) {
+		if (!strcmp(argv[f], "-i") || !strcmp(argv[f], "--init")) {
+			isinit = 1;
+			break;
+		}
+	}
+	if (!isinit) exit(telinit(p, argc, argv));
+
+	/*
+	 *	Check for re-exec
+	 */ 	
+	if (check_pipe(STATE_PIPE)) {
+
+		receive_state(STATE_PIPE);
+
+		myname = istrdup(argv[0]);
+		argv0 = argv[0];
+		maxproclen = 0;
+		for (f = 0; f < argc; f++)
+			maxproclen += strlen(argv[f]) + 1;
+		reload = 1;
+		setproctitle("init [%c]", (int)runlevel);
+
+		init_main();
+	}
+
+  	/* Check command line arguments */
+	maxproclen = strlen(argv[0]) + 1;
+  	for(f = 1; f < argc; f++) {
+		if (!strcmp(argv[f], "single") || !strcmp(argv[f], "-s"))
+			dfl_level = 'S';
+		else if (!strcmp(argv[f], "-a") || !strcmp(argv[f], "auto"))
+			putenv("AUTOBOOT=YES");
+		else if (!strcmp(argv[f], "-b") || !strcmp(argv[f],"emergency"))
+			emerg_shell = 1;
+		else if (!strcmp(argv[f], "-z")) {
+			/* Ignore -z xxx */
+			if (argv[f + 1]) f++;
+		} else if (strchr("0123456789sS", argv[f][0])
+			&& strlen(argv[f]) == 1)
+			dfl_level = argv[f][0];
+		/* "init u" in the very beginning makes no sense */
+		if (dfl_level == 's') dfl_level = 'S';
+		maxproclen += strlen(argv[f]) + 1;
+	}
+
+#ifdef WITH_SELINUX
+	if (getenv("SELINUX_INIT") == NULL) {
+         if (is_selinux_enabled() != 1) {
+	    if (selinux_init_load_policy(&enforce) == 0) {
+             putenv("SELINUX_INIT=YES");
+	      execv(myname, argv);
+	    } else {
+	      if (enforce > 0) {
+		/* SELinux in enforcing mode but load_policy failed */
+		/* At this point, we probably can't open /dev/console, so log() won't work */
+		fprintf(stderr,"Unable to load SELinux Policy. Machine is in enforcing mode. Halting now.\n");
+		exit(1);
+	      }
+	    }
+	  }
+	}
+#endif  
+	/* Start booting. */
+	argv0 = argv[0];
+	argv[1] = NULL;
+	setproctitle("init boot");
+	init_main();
+
+	/*NOTREACHED*/
+	return 0;
+}
Index: create-2.99-initctl-patch/sysvinit-2.99-new/src/initreq.h
===================================================================
--- create-2.99-initctl-patch/sysvinit-2.99-new/src/initreq.h	(nonexistent)
+++ create-2.99-initctl-patch/sysvinit-2.99-new/src/initreq.h	(revision 5)
@@ -0,0 +1,82 @@
+/*
+ * initreq.h	Interface to talk to init through /dev/initctl.
+ *
+ *		Copyright (C) 1995-2004 Miquel van Smoorenburg
+ *
+ *		This program is free software; you can redistribute it and/or modify
+ *		it under the terms of the GNU General Public License as published by
+ *		the Free Software Foundation; either version 2 of the License, or
+ *		(at your option) any later version.
+ *
+ *		This program is distributed in the hope that it will be useful,
+ *		but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *		GNU General Public License for more details.
+ *
+ *		You should have received a copy of the GNU General Public License
+ *		along with this program; if not, write to the Free Software
+ *		Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Version:     @(#)initreq.h  1.28  31-Mar-2004 MvS
+ *
+ */
+#ifndef _INITREQ_H
+#define _INITREQ_H
+
+#include <sys/param.h>
+
+#ifndef INIT_FIFO
+#define INIT_FIFO  "/dev/initctl"
+#endif
+
+#define INIT_MAGIC 0x03091969
+#define INIT_CMD_START		0
+#define INIT_CMD_RUNLVL		1
+#define INIT_CMD_POWERFAIL	2
+#define INIT_CMD_POWERFAILNOW	3
+#define INIT_CMD_POWEROK	4
+#define INIT_CMD_BSD		5
+#define INIT_CMD_SETENV		6
+#define INIT_CMD_UNSETENV	7
+
+#ifdef MAXHOSTNAMELEN
+#  define INITRQ_HLEN	MAXHOSTNAMELEN
+#else
+#  define INITRQ_HLEN	64
+#endif
+
+/*
+ *	This is what BSD 4.4 uses when talking to init.
+ *	Linux doesn't use this right now.
+ */
+struct init_request_bsd {
+	char	gen_id[8];		/* Beats me.. telnetd uses "fe" */
+	char	tty_id[16];		/* Tty name minus /dev/tty      */
+	char	host[INITRQ_HLEN];	/* Hostname                     */
+	char	term_type[16];		/* Terminal type                */
+	int	signal;			/* Signal to send               */
+	int	pid;			/* Process to send to           */
+	char	exec_name[128];	        /* Program to execute           */
+	char	reserved[128];		/* For future expansion.        */
+};
+
+
+/*
+ *	Because of legacy interfaces, "runlevel" and "sleeptime"
+ *	aren't in a separate struct in the union.
+ *
+ *	The weird sizes are because init expects the whole
+ *	struct to be 384 bytes.
+ */
+struct init_request {
+	int	magic;			/* Magic number                 */
+	int	cmd;			/* What kind of request         */
+	int	runlevel;		/* Runlevel to change to        */
+	int	sleeptime;		/* Time between TERM and KILL   */
+	union {
+		struct init_request_bsd	bsd;
+		char			data[368];
+	} i;
+};
+
+#endif
Index: create-2.99-initctl-patch/sysvinit-2.99-new/src/shutdown.c
===================================================================
--- create-2.99-initctl-patch/sysvinit-2.99-new/src/shutdown.c	(nonexistent)
+++ create-2.99-initctl-patch/sysvinit-2.99-new/src/shutdown.c	(revision 5)
@@ -0,0 +1,846 @@
+/*
+ * shutdown.c	Shut the system down.
+ *
+ * Usage:	shutdown [-krhfnc] time [warning message]
+ *		  -k: don't really shutdown, only warn.
+ *		  -r: reboot after shutdown.
+ *		  -h: halt after shutdown.
+ *		  -f: do a 'fast' reboot (skip fsck).
+ *		  -F: Force fsck on reboot.
+ *		  -n: do not go through init but do it ourselves.
+ *		  -c: cancel an already running shutdown.
+ *		  -t secs: delay between SIGTERM and SIGKILL for init.
+ *
+ * Author:	Miquel van Smoorenburg, miquels@cistron.nl
+ *
+ * Version:	@(#)shutdown  2.86-1  31-Jul-2004  miquels@cistron.nl
+ *
+ *		This file is part of the sysvinit suite,
+ *		Copyright (C) 1991-2004 Miquel van Smoorenburg.
+ *
+ *		This program is free software; you can redistribute it and/or modify
+ *		it under the terms of the GNU General Public License as published by
+ *		the Free Software Foundation; either version 2 of the License, or
+ *		(at your option) any later version.
+ *
+ *		This program is distributed in the hope that it will be useful,
+ *		but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *		GNU General Public License for more details.
+ *
+ *		You should have received a copy of the GNU General Public License
+ *		along with this program; if not, write to the Free Software
+ *		Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE	/* otherwise `extern char **environ' is missed */
+#endif
+#ifndef ACCTON_OFF
+# define ACCTON_OFF	0
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#ifdef __linux__
+#include <sys/sysmacros.h>   /* brought in my LFS patch */
+#endif
+#include <time.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h> 
+#include <signal.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#ifdef __FreeBSD__
+#include <utmpx.h>
+#else
+#include <utmp.h>
+#endif
+#include <syslog.h>
+#include "paths.h"
+#include "reboot.h"
+#include "initreq.h"
+#include "init.h"
+
+#ifdef __FreeBSD__
+extern char **environ;
+#endif
+
+#define MESSAGELEN	256
+#define STATELEN        64
+#define WHEN_SIZE       64
+
+/* Whether we should warn system is shutting down */
+#define QUIET_FULL 2
+#define QUIET_PARTIAL 1
+#define QUIET_NONE 0
+
+int dontshut = 0;	/* Don't shutdown, only warn	*/
+char down_level[2];	/* What runlevel to go to.	*/
+int dosync = 1;		/* Sync before reboot or halt	*/
+int fastboot = 0;	/* Do a 'fast' reboot		*/
+int forcefsck = 0;	/* Force fsck on reboot		*/
+char message[MESSAGELEN];	/* Warning message	*/
+char *sltime = 0;	/* Sleep time			*/
+char newstate[STATELEN];	/* What are we gonna do		*/
+int doself = 0;		/* Don't use init		*/
+int got_alrm = 0;
+
+char *clean_env[] = {
+	"HOME=/",
+	"PATH=" PATH_DEFAULT,
+	"TERM=dumb",
+	"SHELL=/bin/sh",
+	NULL,
+};
+
+/* From "utmp.c" */
+extern void write_wtmp(char *user, char *id, int pid, int type, char *line);
+
+/*
+ *	Sleep without being interrupted.
+ */
+void hardsleep(int secs)
+{
+	struct timespec ts, rem;
+
+	ts.tv_sec = secs;
+	ts.tv_nsec = 0;
+
+	while(nanosleep(&ts, &rem) < 0 && errno == EINTR)
+		ts = rem;
+}
+
+/*
+ *	Break off an already running shutdown.
+ */
+# ifdef __GNUC__
+void stopit(int sig __attribute__((unused)))
+# else
+void stopit(int sig)
+# endif
+
+{
+	unlink(NOLOGIN);
+	unlink(FASTBOOT);
+	unlink(FORCEFSCK);
+	unlink(SDPID);
+	printf("\r\nShutdown cancelled.\r\n");
+	exit(0);
+}
+
+/*
+ *	Show usage message.
+ */
+void usage(void)
+{
+	fprintf(stderr,
+	"Usage:\t  shutdown [-akrhPHfFnc] [-t sec] time [warning message]\n"
+	"\t\t  -a:      use /etc/shutdown.allow\n"
+	"\t\t  -k:      don't really shutdown, only warn.\n"
+	"\t\t  -r:      reboot after shutdown.\n"
+	"\t\t  -h:      halt after shutdown.\n"
+	"\t\t  -P:      halt action is to turn off power.\n"
+        "\t\t           can only be used along with -h flag.\n"
+	"\t\t  -H:      halt action is to just halt.\n"
+        "\t\t           can only be used along with -h flag.\n"
+	"\t\t  -f:      do a 'fast' reboot (skip fsck).\n"
+	"\t\t  -F:      Force fsck on reboot.\n"
+	"\t\t  -n:      do not go through \"init\" but go down real fast.\n"
+	"\t\t  -c:      cancel a running shutdown.\n"
+        "\t\t  -q:      quiet mode - display fewer shutdown warnings.\n"
+        "\t\t  -Q:      full quiet mode - display only final shutdown warning.\n"
+	"\t\t  -t secs: delay between warning and kill signal.\n"
+	"\t\t  ** the \"time\" argument is mandatory! (try \"now\") **\n");
+	exit(1);
+}
+
+
+void alrm_handler(int sig)
+{
+	got_alrm = sig;
+}
+
+
+/*
+ *	Set environment variables in the init process.
+ */
+int init_setenv(char *name, char *value)
+{
+	struct init_request	request;
+	struct sigaction	sa;
+	int			fd;
+	size_t			nl, vl;
+
+	memset(&request, 0, sizeof(request));
+	request.magic = INIT_MAGIC;
+	request.cmd = INIT_CMD_SETENV;
+	nl = strlen(name);
+	vl = value ? strlen(value) : 0;
+
+	if (nl + vl + 3 >= (int)sizeof(request.i.data))
+		return -1;
+
+	memcpy(request.i.data, name, nl);
+	if (value) {
+		request.i.data[nl] = '=';
+		memcpy(request.i.data + nl + 1, value, vl);
+	}
+
+        /*
+	 *	Open the fifo and write the command.
+         *	Make sure we don't hang on opening /dev/initctl
+	 */
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = alrm_handler;
+	sigaction(SIGALRM, &sa, NULL);
+	got_alrm = 0;
+	alarm(3);
+	if ((fd = open(INIT_FIFO, O_WRONLY)) >= 0) {
+		ssize_t p = 0;
+		size_t s  = sizeof(request);
+		void *ptr = &request;
+		while (s > 0) {
+			p = write(fd, ptr, s);
+			if (p < 0) {
+				if (errno == EINTR || errno == EAGAIN)
+					continue;
+				break;
+			}
+			ptr += p;
+			s -= p;
+		}
+		close(fd);
+		alarm(0);
+		return 0;
+	}
+                                                                                
+	fprintf(stderr, "shutdown: ");
+	if (got_alrm) {
+		fprintf(stderr, "timeout opening/writing control channel %s\n",
+			INIT_FIFO);
+	} else {
+		perror(INIT_FIFO);
+	}
+	return -1;
+}
+
+
+/*
+ *	Tell everyone the system is going down in 'mins' minutes.
+ */
+void issue_warn(int mins)
+{
+	char buf[MESSAGELEN + sizeof(newstate) + 1];
+	int len;
+
+	buf[0] = 0;
+	strncpy(buf, message, MESSAGELEN);
+	len = strlen(buf);
+
+	if (mins == 0)
+		snprintf(buf + len, sizeof(buf) - len,
+			"\rThe system is going down %s NOW!\r\n",
+			newstate);
+	else
+  		snprintf(buf + len, sizeof(buf) - len,
+			"\rThe system is going DOWN %s in %d minute%s!\r\n",
+				newstate, mins, mins == 1 ? "" : "s");
+	wall(buf, 0);
+}
+
+/*
+ *	Create the /etc/nologin file.
+ */
+void donologin(int min)
+{
+	FILE *fp;
+	time_t t;
+
+	time(&t);
+	t += 60 * min;
+
+	if ((fp = fopen(NOLOGIN, "w")) != NULL) {
+  		fprintf(fp, "\rThe system is going down on %s\r\n", ctime(&t));
+  		if (message[0]) fputs(message, fp);
+  		fclose(fp);
+	}
+}
+
+/*
+ *	Spawn an external program.
+ */
+int spawn(int noerr, char *prog, ...)
+{
+	va_list	ap;
+	pid_t	pid, rc;
+	int	i;
+	char	*argv[8];
+
+	i = 0;
+	while ((pid = fork()) < 0 && i < 10) {
+		perror("fork");
+		sleep(5);
+		i++;
+	}
+
+	if (pid < 0) return -1;
+
+	if (pid > 0) {
+		while((rc = wait(&i)) != pid)
+			if (rc < 0 && errno == ECHILD)
+				break;
+		return (rc == pid) ? WEXITSTATUS(i) : -1;
+	}
+
+	if (noerr) fclose(stderr);
+
+	argv[0] = prog;
+	va_start(ap, prog);
+	for (i = 1; i < 7 && (argv[i] = va_arg(ap, char *)) != NULL; i++)
+		;
+	argv[i] = NULL;
+	va_end(ap);
+
+	if (chdir("/"))
+		exit(1);
+	environ = clean_env;
+
+	execvp(argv[0], argv);
+	perror(argv[0]);
+	exit(1);
+
+	/*NOTREACHED*/
+	return 0;
+}
+
+/*
+ *	Kill all processes, call /etc/init.d/halt (if present)
+ */
+void fastdown()
+{
+	int do_halt = (down_level[0] == '0');
+	int i;
+#if 0
+	char cmd[128];
+	char *script;
+
+	/*
+	 *	Currently, the halt script is either init.d/halt OR rc.d/rc.0,
+	 *	likewise for the reboot script. Test for the presence
+	 *	of either.
+	 */
+	if (do_halt) {
+		if (access(HALTSCRIPT1, X_OK) == 0)
+			script = HALTSCRIPT1;
+		else
+			script = HALTSCRIPT2;
+	} else {
+		if (access(REBOOTSCRIPT1, X_OK) == 0)
+			script = REBOOTSCRIPT1;
+		else
+			script = REBOOTSCRIPT2;
+	}
+#endif
+
+	/* First close all files. */
+	for(i = 0; i < 3; i++)
+		if (!isatty(i)) {
+			close(i);
+			open("/dev/null", O_RDWR);
+		}
+	for(i = 3; i < 20; i++) close(i);
+	close(255);
+
+	/* First idle init. */
+	if (kill(1, SIGTSTP) < 0) {
+		fprintf(stderr, "shutdown: can't idle init: %s.\r\n", strerror(errno));
+		exit(1);
+	}
+
+	/* Kill all processes. */
+	fprintf(stderr, "shutdown: sending all processes the TERM signal...\r\n");
+	kill(-1, SIGTERM);
+	sleep(sltime ? atoi(sltime) : WAIT_BETWEEN_SIGNALS);
+	fprintf(stderr, "shutdown: sending all processes the KILL signal.\r\n");
+	(void) kill(-1, SIGKILL);
+
+#if 0
+	/* See if we can run /etc/init.d/halt */
+	if (access(script, X_OK) == 0) {
+		spawn(1, cmd, "fast", NULL);
+		fprintf(stderr, "shutdown: %s returned - falling back "
+				"on default routines\r\n", script);
+	}
+#endif
+
+	/* script failed or not present: do it ourself. */
+	/* Give init the chance to collect zombies. */
+        /* sleep(1); */
+
+	/* Record the fact that we're going down */
+	write_wtmp("shutdown", "~~", 0, RUN_LVL, "~~");
+
+	/* This is for those who have quota installed. */
+#if defined(ACCTON_OFF)
+# if (ACCTON_OFF > 1) && (_BSD_SOURCE || (_XOPEN_SOURCE && _XOPEN_SOURCE < 500))
+	/* This is an alternative way to disable accounting, saving a fork() */
+	if (acct(NULL))
+		fprintf(stderr, "shutdown: can not stop process accounting: %s.\r\n", strerror(errno));
+# elif (ACCTON_OFF > 0)
+	spawn(1, "accton", "off", NULL);
+# else
+	spawn(1, "accton", NULL);
+# endif
+#endif
+	spawn(1, "quotaoff", "-a", NULL);
+
+	sync();
+	fprintf(stderr, "shutdown: turning off swap\r\n");
+	spawn(0, "swapoff", "-a", NULL);
+	fprintf(stderr, "shutdown: unmounting all file systems\r\n");
+	spawn(0, "umount", "-a", NULL);
+
+	/* We're done, halt or reboot now. */
+	if (do_halt) {
+		fprintf(stderr, "The system is halted. Press CTRL-ALT-DEL "
+				"or turn off power\r\n");
+		init_reboot(BMAGIC_HALT);
+		exit(0);
+	}
+
+	fprintf(stderr, "Please stand by while rebooting the system.\r\n");
+	init_reboot(BMAGIC_REBOOT);
+	exit(0);
+}
+
+/*
+ *	Go to runlevel 0, 1 or 6.
+ */
+void issue_shutdown(char *halttype)
+{
+	char	*args[8];
+	int	argp = 0;
+	int	do_halt = (down_level[0] == '0');
+
+	/* Warn for the last time */
+	issue_warn(0);
+	if (dontshut) {
+		hardsleep(1);
+		stopit(0);
+	}
+	openlog("shutdown", LOG_PID, LOG_USER);
+	if (do_halt)
+  		syslog(LOG_NOTICE, "shutting down for system halt");
+	else
+		syslog(LOG_NOTICE, "shutting down for system reboot");
+	closelog();
+
+	/* See if we have to do it ourself. */
+	if (doself) fastdown();
+
+	/* Create the arguments for init. */
+	args[argp++] = INIT;
+	if (sltime) {
+		args[argp++] = "-t";
+		args[argp++] = sltime;
+	}
+	args[argp++] = down_level;
+	args[argp]   = (char *)NULL;
+
+	unlink(SDPID);
+	unlink(NOLOGIN);
+
+	/* Now execute init to change runlevel. */
+	sync();
+	init_setenv("INIT_HALT", halttype);
+	execv(INIT, args);
+
+	/* Oops - failed. */
+	fprintf(stderr, "\rshutdown: cannot execute %s\r\n", INIT);
+	unlink(FASTBOOT);
+	unlink(FORCEFSCK);
+	init_setenv("INIT_HALT", NULL);
+	openlog("shutdown", LOG_PID, LOG_USER);
+	syslog(LOG_NOTICE, "shutdown failed");
+	closelog();
+	exit(1);
+}
+
+/*
+ *	returns if a warning is to be sent for wt
+ */
+static int needwarning(int wt, int quiet_mode)
+{
+	int ret;
+
+        if (quiet_mode == QUIET_FULL) return FALSE;
+        else if (quiet_mode == QUIET_PARTIAL)
+        {
+            if (wt == 10)
+               return TRUE;
+            else if (wt == 5)
+               return TRUE;
+            else if ( (wt % 60) == 0)
+               return TRUE;
+            else
+               return FALSE;
+        }
+        /* no silence setting, print lots of warnings */
+	if (wt < 10)
+		ret = 1;
+	else if (wt < 60)
+		ret = (wt % 15 == 0);
+	else if (wt < 180)
+		ret = (wt % 30 == 0);
+	else
+		ret = (wt % 60 == 0);
+
+	return ret;
+}
+
+/*
+ *	Main program.
+ *	Process the options and do the final countdown.
+ */
+int main(int argc, char **argv)
+{
+	FILE			*fp;
+	extern int		getopt();
+	extern int		optind; 
+	struct sigaction	sa;
+	struct tm		*lt;
+	struct stat		st;
+	struct utmp		*ut;
+	time_t			t, target_time;
+	char			*halttype;
+	char			*downusers[32];
+	char			buf[128];
+	char			term[UT_LINESIZE + 6];
+	char			*sp;
+	char			when[WHEN_SIZE];
+	int			c, i, wt;
+	int			hours, mins;
+	int			didnolog = 0;
+	int			cancel = 0;
+	int			useacl = 0;
+	int			pid = 0;
+	int			user_ok = 0;
+        int quiet_level = QUIET_NONE;   /* Whether to display shutdown warning */
+
+	/* We can be installed setuid root (executable for a special group) */
+	/* 
+        This way is risky, do error check on setuid call.
+        setuid(geteuid());
+        */
+        errno = 0;
+        if (setuid(geteuid()) == -1) {
+            fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+            abort();
+	}
+
+	if (getuid() != 0) {
+  		fprintf(stderr, "shutdown: you must be root to do that!\n");
+		usage();
+  		exit(1);
+	}
+	strcpy(down_level, "1");
+	halttype = NULL;
+        memset(when, '\0', WHEN_SIZE);
+
+	/* Process the options. */
+	while((c = getopt(argc, argv, "HPacqQkrhnfFyt:g:i:")) != EOF) {
+  		switch(c) {
+			case 'H':
+				halttype = "HALT";
+				break;
+			case 'P':
+				halttype = "POWEROFF";
+				break;
+			case 'a': /* Access control. */
+				useacl = 1;
+				break;
+			case 'c': /* Cancel an already running shutdown. */
+				cancel = 1;
+				break;
+  			case 'k': /* Don't really shutdown, only warn.*/
+  				dontshut = 1;
+  				break;
+  			case 'r': /* Automatic reboot */
+				down_level[0] = '6';
+  				break;
+  			case 'h': /* Halt after shutdown */
+				down_level[0] = '0';
+  				break;
+  			case 'f': /* Don't perform fsck after next boot */
+  				fastboot = 1;
+  				break;
+  			case 'F': /* Force fsck after next boot */
+  				forcefsck = 1;
+  				break;
+			case 'n': /* Don't switch runlevels. */
+				doself = 1;
+				break;
+			case 't': /* Delay between TERM and KILL */
+				sltime = optarg;
+				break;
+                        case 'q': /* put into somewhat quiet mode */
+                                quiet_level = QUIET_PARTIAL;
+                                break;
+                        case 'Q': /* put into full quiet mode */
+                                quiet_level = QUIET_FULL;
+                                break;
+			case 'y': /* Ignored for sysV compatibility */
+				break;
+			case 'g': /* sysv style to specify time. */
+				strncpy(when, optarg, WHEN_SIZE - 1);
+				break;
+			case 'i': /* Level to go to. */
+				if (!strchr("0156aAbBcCsS", optarg[0])) {
+					fprintf(stderr,
+					"shutdown: `%s': bad runlevel\n",
+					optarg);
+					exit(1);
+				}
+				down_level[0] = optarg[0];
+				break;
+  			default:
+  				usage();
+  				break;	
+  		}
+	}
+
+	if (NULL != halttype && down_level[0] != '0') {
+		fprintf(stderr, "shutdown: -H and -P flags can only be used along with -h flag.\n");
+		usage();
+  		exit(1);
+	}
+
+	/* Do we need to use the shutdown.allow file ? */
+	if (useacl && (fp = fopen(SDALLOW, "r")) != NULL) {
+
+		/* Read /etc/shutdown.allow. */
+		i = 0;
+		while(fgets(buf, 128, fp)) {
+			if (buf[0] == '#' || buf[0] == '\n') continue;
+			if (i > 31) continue;
+			for(sp = buf; *sp; sp++) if (*sp == '\n') *sp = 0;
+			downusers[i++] = strdup(buf);
+		}
+		if (i < 32) downusers[i] = 0;
+		fclose(fp);
+
+		/* Now walk through /var/run/utmp to find logged in users. */
+		while(!user_ok && (ut = getutent()) != NULL) {
+
+			/* See if this is a user process on a VC. */
+			if (ut->ut_type != USER_PROCESS) continue;
+			sprintf(term, "/dev/%.*s", UT_LINESIZE, ut->ut_line);
+			if (stat(term, &st) < 0) continue;
+#ifdef major /* glibc */
+			if (major(st.st_rdev) != 4 ||
+			    minor(st.st_rdev) > 63) continue;
+#else
+			if ((st.st_rdev & 0xFFC0) != 0x0400) continue;
+#endif
+			/* Root is always OK. */
+			if (strcmp(ut->ut_user, "root") == 0) {
+				user_ok++;
+				break;
+			}
+
+			/* See if this is an allowed user. */
+			for(i = 0; i < 32 && downusers[i]; i++)
+				if (!strncmp(downusers[i], ut->ut_user,
+				    UT_NAMESIZE)) {
+					user_ok++;
+					break;
+				}
+		}
+		endutent();
+
+		/* See if user was allowed. */
+		if (!user_ok) {
+			if ((fp = fopen(CONSOLE, "w")) != NULL) {
+				fprintf(fp, "\rshutdown: no authorized users "
+						"logged in.\r\n");
+				fclose(fp);
+			}
+			exit(1);
+		}
+	}
+
+	/* Read pid of running shutdown from a file */
+	if ((fp = fopen(SDPID, "r")) != NULL) {
+		if (fscanf(fp, "%d", &pid) != 1)
+			pid = 0;
+		fclose(fp);
+	}
+
+	/* Read remaining words, skip time if needed. */
+	message[0] = 0;
+	for(c = optind + (!cancel && !when[0]); c < argc; c++) {
+		if (strlen(message) + strlen(argv[c]) + 4 > MESSAGELEN)
+			break;
+  		strcat(message, argv[c]);
+  		strcat(message, " ");
+	}
+	if (message[0]) strcat(message, "\r\n");
+
+	/* See if we want to run or cancel. */
+	if (cancel) {
+		if (pid <= 0) {
+			fprintf(stderr, "shutdown: cannot find pid "
+					"of running shutdown.\n");
+			exit(1);
+		}
+		init_setenv("INIT_HALT", NULL);
+		if (kill(pid, SIGINT) < 0) {
+			fprintf(stderr, "shutdown: not running.\n");
+			exit(1);
+		}
+		if (message[0]) wall(message, 0);
+		exit(0);
+	}
+  
+	/* Check syntax. */
+	if (when[0] == '\0') {
+		if (optind == argc) usage();
+                strncpy(when, argv[optind++], WHEN_SIZE - 1);
+	}
+
+	/* See if we are already running. */
+	if (pid > 0 && kill(pid, 0) == 0) {
+		fprintf(stderr, "\rshutdown: already running.\r\n");
+		exit(1);
+	}
+
+	/* Extra check. */
+	if (doself && down_level[0] != '0' && down_level[0] != '6') {
+		fprintf(stderr,
+		"shutdown: can use \"-n\" for halt or reboot only.\r\n");
+		exit(1);
+	}
+
+	/* Tell users what we're gonna do. */
+	switch(down_level[0]) {
+		case '0':
+			strncpy(newstate, "for system halt", STATELEN);
+			break;
+		case '6':
+			strncpy(newstate, "for reboot", STATELEN);
+			break;
+		case '1':
+			strncpy(newstate, "to maintenance mode", STATELEN);
+			break;
+		default:
+			snprintf(newstate, STATELEN, "to runlevel %s", down_level);
+			break;
+	}
+
+	/* Go to the root directory */
+	if (chdir("/")) {
+		fprintf(stderr, "shutdown: chdir(/): %m\n");
+		exit(1);
+	}
+
+	/* Create a new PID file. */
+	unlink(SDPID);
+	umask(022);
+	if ((fp = fopen(SDPID, "w")) != NULL) {
+		fprintf(fp, "%d\n", getpid());
+		fclose(fp);
+	} else if (errno != EROFS)
+		fprintf(stderr, "shutdown: warning: cannot open %s\n", SDPID);
+
+	/*
+	 *	Catch some common signals.
+	 */
+	signal(SIGQUIT, SIG_IGN);
+	signal(SIGCHLD, SIG_IGN);
+	signal(SIGHUP,  SIG_IGN);
+	signal(SIGTSTP, SIG_IGN);
+	signal(SIGTTIN, SIG_IGN);
+	signal(SIGTTOU, SIG_IGN);
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = stopit;
+	sigaction(SIGINT, &sa, NULL);
+
+	if (fastboot)  close(open(FASTBOOT,  O_CREAT | O_RDWR, 0644));
+	if (forcefsck) close(open(FORCEFSCK, O_CREAT | O_RDWR, 0644));
+
+	/* Alias now and take care of old '+mins' notation. */
+	if (!strcmp(when, "now")) strcpy(when, "0");
+
+        sp = when;
+	/* Validate time argument. */
+	for ( ; *sp; sp++) {
+		if (*sp != '+' && *sp != ':' && (*sp < '0' || *sp > '9'))
+			usage();
+	}
+	sp = when;
+	/* Decode shutdown time. */
+	if (when[0] == '+') sp++;
+	if (strchr(when, ':') == NULL) {
+		/* Time in minutes. */
+		wt = atoi(sp);
+		if (wt == 0 && sp[0] != '0') usage();
+	} else {
+		if (sscanf(when, "%d:%2d", &hours, &mins) != 2) usage();
+		/* Time in hh:mm format. */
+		if (when[0] == '+') {
+			/* Hours and minutes from now */
+			if (hours > 99999 || mins > 59) usage();
+			wt = (60*hours + mins);
+			if (wt < 0) usage();
+		} else {
+			/* Time of day */
+			if (hours > 23 || mins > 59) usage();
+			time(&t);
+			lt = localtime(&t);
+			wt = (60*hours + mins) - (60*lt->tm_hour + lt->tm_min);
+			if (wt < 0) wt += 1440;
+		}
+	}
+	/* Shutdown NOW if time == 0 */
+	if (wt == 0) issue_shutdown(halttype);
+
+        /* Rather than loop and reduce wt (wait time) once per minute,
+           we shall check the current time against the target time.
+           Then calculate the remaining waiting time based on the difference
+           between current time and target time.
+           This avoids missing shutdown time (target time) after the
+           computer has been asleep. -- Jesse
+        */
+        /* target time, in seconds = current time + wait time */
+        time(&t);
+        target_time = t + (60 * wt); 
+
+	/* Give warnings on regular intervals and finally shutdown. */
+	if (wt < 15 && !needwarning(wt, quiet_level)) issue_warn(wt);
+	while(wt) {
+		if (wt <= 5 && !didnolog) {
+			donologin(wt);
+			didnolog++;
+		}
+		if (needwarning(wt, quiet_level)) issue_warn(wt);
+		hardsleep(60);
+                time(&t);    /* get current time once per minute */
+                if (t >= target_time)     /* past the target */
+                  wt = 0;
+                else if ( (target_time - t) <= 60 )  /* less 1 min remains */
+                {
+                    hardsleep(target_time - t);
+                    wt = 0;
+                }
+                else                      /* more than 1 min remains */
+                   wt = (int) (target_time - t) / 60;
+	}
+	issue_shutdown(halttype);
+
+	return 0; /* Never happens */
+}
Index: create-2.99-initctl-patch/sysvinit-2.99-new/src
===================================================================
--- create-2.99-initctl-patch/sysvinit-2.99-new/src	(nonexistent)
+++ create-2.99-initctl-patch/sysvinit-2.99-new/src	(revision 5)

Property changes on: create-2.99-initctl-patch/sysvinit-2.99-new/src
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: create-2.99-initctl-patch/sysvinit-2.99-new
===================================================================
--- create-2.99-initctl-patch/sysvinit-2.99-new	(nonexistent)
+++ create-2.99-initctl-patch/sysvinit-2.99-new	(revision 5)

Property changes on: create-2.99-initctl-patch/sysvinit-2.99-new
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: create-2.99-initctl-patch
===================================================================
--- create-2.99-initctl-patch	(nonexistent)
+++ create-2.99-initctl-patch	(revision 5)

Property changes on: create-2.99-initctl-patch
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: create-2.99-paths-patch/create.patch.sh
===================================================================
--- create-2.99-paths-patch/create.patch.sh	(nonexistent)
+++ create-2.99-paths-patch/create.patch.sh	(revision 5)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+VERSION=2.99
+
+tar --files-from=file.list -xJvf ../sysvinit-$VERSION.tar.xz
+mv sysvinit-$VERSION sysvinit-$VERSION-orig
+
+cp -rf ./sysvinit-$VERSION-new ./sysvinit-$VERSION
+
+diff --unified -Nr  sysvinit-$VERSION-orig  sysvinit-$VERSION > sysvinit-$VERSION-paths.patch
+
+mv sysvinit-$VERSION-paths.patch ../patches
+
+rm -rf ./sysvinit-$VERSION
+rm -rf ./sysvinit-$VERSION-orig

Property changes on: create-2.99-paths-patch/create.patch.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: create-2.99-paths-patch/file.list
===================================================================
--- create-2.99-paths-patch/file.list	(nonexistent)
+++ create-2.99-paths-patch/file.list	(revision 5)
@@ -0,0 +1 @@
+sysvinit-2.99/src/paths.h
Index: create-2.99-paths-patch/sysvinit-2.99-new/src/paths.h
===================================================================
--- create-2.99-paths-patch/sysvinit-2.99-new/src/paths.h	(nonexistent)
+++ create-2.99-paths-patch/sysvinit-2.99-new/src/paths.h	(revision 5)
@@ -0,0 +1,52 @@
+/*
+ * paths.h	Paths of files that init and related utilities need.
+ *
+ * Version:	@(#) paths.h 2.85-8 05-Nov-2003
+ *
+ * Author:	Miquel van Smoorenburg, <miquels@cistron.nl>
+ *
+ *		This file is part of the sysvinit suite,
+ *		Copyright (C) 1991-2001 Miquel van Smoorenburg.
+ *
+ *		This program is free software; you can redistribute it and/or modify
+ *		it under the terms of the GNU General Public License as published by
+ *		the Free Software Foundation; either version 2 of the License, or
+ *		(at your option) any later version.
+ *
+ *		This program is distributed in the hope that it will be useful,
+ *		but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *		GNU General Public License for more details.
+ *
+ *		You should have received a copy of the GNU General Public License
+ *		along with this program; if not, write to the Free Software
+ *		Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#define VT_MASTER	"/dev/tty0"		/* Virtual console master */
+#define CONSOLE		"/dev/console"		/* Logical system console */
+#define SECURETTY	"/etc/securetty"	/* List of root terminals */
+#define SDALLOW		"/etc/shutdown.allow"	/* Users allowed to shutdown */
+#define INITTAB		"/etc/inittab"		/* Location of inittab */
+#define INITTABD	"/etc/inittab.d"	/* Location of inittab.d directory */
+#define INIT		"/sbin/init"		/* Location of init itself. */
+#define NOLOGIN		"/etc/nologin"		/* Stop user logging in. */
+#define FASTBOOT	"/etc/fastboot"		/* Enable fast boot. */
+#define FORCEFSCK	"/etc/forcefsck"	/* Force fsck on boot */
+#define SDPID		"/var/run/shutdown.pid"	/* PID of shutdown program */
+#define SHELL		"/bin/sh"		/* Default shell */
+#define SULOGIN		"/sbin/sulogin"		/* Sulogin */
+#define INITSCRIPT	"/etc/initscript"	/* Initscript. */
+#define PWRSTAT_OLD	"/etc/powerstatus"	/* COMPAT: SIGPWR reason (OK/BAD) */
+#define PWRSTAT		"/var/run/powerstatus"	/* COMPAT: SIGPWR reason (OK/BAD) */
+#define RUNLEVEL_LOG    "/var/run/runlevel"     /* neutral place to store run level */
+
+#if 0
+#define INITLVL		"/etc/initrunlvl"	/* COMPAT: New runlevel */
+#define INITLVL2	"/var/log/initrunlvl"	/* COMPAT: New runlevel */
+				/* Note: INITLVL2 definition needs INITLVL */
+#define HALTSCRIPT1	"/etc/init.d/halt"	/* Called by "fast" shutdown */
+#define HALTSCRIPT2	"/etc/rc.d/rc.0"	/* Called by "fast" shutdown */
+#define REBOOTSCRIPT1	"/etc/init.d/reboot"	/* Ditto. */
+#define REBOOTSCRIPT2	"/etc/rc.d/rc.6"	/* Ditto. */
+#endif
+
Index: create-2.99-paths-patch/sysvinit-2.99-new/src
===================================================================
--- create-2.99-paths-patch/sysvinit-2.99-new/src	(nonexistent)
+++ create-2.99-paths-patch/sysvinit-2.99-new/src	(revision 5)

Property changes on: create-2.99-paths-patch/sysvinit-2.99-new/src
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: create-2.99-paths-patch/sysvinit-2.99-new
===================================================================
--- create-2.99-paths-patch/sysvinit-2.99-new	(nonexistent)
+++ create-2.99-paths-patch/sysvinit-2.99-new	(revision 5)

Property changes on: create-2.99-paths-patch/sysvinit-2.99-new
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: create-2.99-paths-patch
===================================================================
--- create-2.99-paths-patch	(nonexistent)
+++ create-2.99-paths-patch	(revision 5)

Property changes on: create-2.99-paths-patch
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: create-2.99-version-patch/create.patch.sh
===================================================================
--- create-2.99-version-patch/create.patch.sh	(nonexistent)
+++ create-2.99-version-patch/create.patch.sh	(revision 5)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+VERSION=2.99
+
+tar --files-from=file.list -xJvf ../sysvinit-$VERSION.tar.xz
+mv sysvinit-$VERSION sysvinit-$VERSION-orig
+
+cp -rf ./sysvinit-$VERSION-new ./sysvinit-$VERSION
+
+diff --unified -Nr  sysvinit-$VERSION-orig  sysvinit-$VERSION > sysvinit-$VERSION-version.patch
+
+mv sysvinit-$VERSION-version.patch ../patches
+
+rm -rf ./sysvinit-$VERSION
+rm -rf ./sysvinit-$VERSION-orig

Property changes on: create-2.99-version-patch/create.patch.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: create-2.99-version-patch/file.list
===================================================================
--- create-2.99-version-patch/file.list	(nonexistent)
+++ create-2.99-version-patch/file.list	(revision 5)
@@ -0,0 +1 @@
+sysvinit-2.99/src/init.c
Index: create-2.99-version-patch/sysvinit-2.99-new/src/init.c
===================================================================
--- create-2.99-version-patch/sysvinit-2.99-new/src/init.c	(nonexistent)
+++ create-2.99-version-patch/sysvinit-2.99-new/src/init.c	(revision 5)
@@ -0,0 +1,3188 @@
+/*
+ * Init		A System-V Init Clone.
+ *
+ * Usage:	/sbin/init
+ *		     init [0123456SsQqAaBbCc]
+ *		  telinit [0123456SsQqAaBbCc]
+ *
+ * Version:	@(#)init.c  2.86  30-Jul-2004  miquels@cistron.nl
+ * Version:     init.c 2.90 18-Jun-2018 jsmith@resonatingmedia.com
+ */
+
+/*
+Version information is not placed in the top-level Makefile by default
+*/
+#define VERSION "2.99"
+/*
+ *		This file is part of the sysvinit suite,
+ *		Copyright (C) 1991-2004 Miquel van Smoorenburg.
+ *		Copyright (C) 2017-2019 Jesse Smith
+ *
+ *		This program is free software; you can redistribute it and/or modify
+ *		it under the terms of the GNU General Public License as published by
+ *		the Free Software Foundation; either version 2 of the License, or
+ *		(at your option) any later version.
+ *
+ *		This program is distributed in the hope that it will be useful,
+ *		but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *		GNU General Public License for more details.
+ *
+ *		You should have received a copy of the GNU General Public License
+ *		along with this program; if not, write to the Free Software
+ *		Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#ifdef __linux__
+#include <sys/kd.h>
+#endif
+#include <sys/resource.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <time.h>
+#include <fcntl.h>
+#include <string.h>
+#include <signal.h>
+#include <termios.h>
+#ifdef __FreeBSD__
+#include <utmpx.h>
+#else
+#include <utmp.h>
+#endif
+#include <ctype.h>
+#include <stdarg.h>
+#include <sys/ttydefaults.h>
+#include <sys/syslog.h>
+#include <sys/time.h>
+/*
+ * inittab.d
+ */
+#include <sys/types.h>
+#include <dirent.h>
+
+#ifdef WITH_SELINUX
+#  include <selinux/selinux.h>
+#endif
+#ifdef __FreeBSD__
+extern char **environ;
+#endif
+
+#ifdef __i386__
+#  ifdef __GLIBC__
+     /* GNU libc 2.x */
+#    define STACK_DEBUG 1
+#    if (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
+       /* Only glibc 2.0 needs this */
+#      include <sigcontext.h>
+#    elif ( __GLIBC__ > 2) && ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1))
+#      include <bits/sigcontext.h>
+#    endif
+#  endif
+#endif
+
+#include "init.h"
+#include "initreq.h"
+#include "paths.h"
+#include "reboot.h"
+#include "runlevellog.h"
+#include "set.h"
+
+#ifndef SIGPWR
+#  define SIGPWR SIGUSR2
+#endif
+
+#ifndef CBAUD
+#  define CBAUD		0
+#endif
+#ifndef CBAUDEX
+#  define CBAUDEX	0
+#endif
+
+/* Set a signal handler. */
+#define SETSIG(sa, sig, fun, flags) \
+		do { \
+			memset(&sa, 0, sizeof(sa)); \
+			sa.sa_handler = fun; \
+			sa.sa_flags = flags; \
+			sigemptyset(&sa.sa_mask); \
+			sigaction(sig, &sa, NULL); \
+		} while(0)
+
+/* Version information */
+char *Version = "@(#) init " VERSION " miquels@cistron.nl";
+char *bootmsg = "version " VERSION " %s";
+#define E_VERSION "INIT_VERSION=sysvinit-" VERSION
+
+CHILD *family = NULL;		/* The linked list of all entries */
+CHILD *newFamily = NULL;	/* The list after inittab re-read */
+
+CHILD ch_emerg = {		/* Emergency shell */
+	WAITING, 0, 0, 0, 0,
+	"~~",
+	"S",
+	3,
+	"/sbin/sulogin",
+	NULL,
+	NULL
+};
+
+char runlevel = 'S';		/* The current run level */
+char thislevel = 'S';		/* The current runlevel */
+char prevlevel = 'N';		/* Previous runlevel */
+int dfl_level = 0;		/* Default runlevel */
+sig_atomic_t got_cont = 0;	/* Set if we received the SIGCONT signal */
+sig_atomic_t got_signals;	/* Set if we received a signal. */
+int emerg_shell = 0;		/* Start emergency shell? */
+int wrote_wtmp_reboot = 1;	/* Set when we wrote the reboot record */
+int wrote_utmp_reboot = 1;	/* Set when we wrote the reboot record */
+int wrote_wtmp_rlevel = 1;	/* Set when we wrote the runlevel record */
+int wrote_utmp_rlevel = 1;	/* Set when we wrote the runlevel record */
+int sleep_time = WAIT_BETWEEN_SIGNALS;    /* Sleep time between TERM and KILL */
+char *argv0;			/* First arguments; show up in ps listing */
+int maxproclen;			/* Maximal length of argv[0] with \0 */
+struct utmp utproto;		/* Only used for sizeof(utproto.ut_id) */
+char *console_dev;		/* Console device. */
+int pipe_fd = -1;		/* /run/initctl */
+int did_boot = 0;		/* Did we already do BOOT* stuff? */
+int main(int, char **);
+
+/*	Used by re-exec part */
+int reload = 0;			/* Should we do initialization stuff? */
+char *myname=INIT;		/* What should we exec */
+int oops_error;			/* Used by some of the re-exec code. */
+const char *Signature = "12567362";	/* Signature for re-exec fd */
+
+/* Macro to see if this is a special action */
+#define ISPOWER(i) ((i) == POWERWAIT || (i) == POWERFAIL || \
+		    (i) == POWEROKWAIT || (i) == POWERFAILNOW || \
+		    (i) == CTRLALTDEL)
+
+/* ascii values for the `action' field. */
+struct actions {
+  char *name;
+  int act;
+} actions[] = {
+  { "respawn", 	   RESPAWN	},
+  { "wait",	   WAIT		},
+  { "once",	   ONCE		},
+  { "boot",	   BOOT		},
+  { "bootwait",	   BOOTWAIT	},
+  { "powerfail",   POWERFAIL	},
+  { "powerfailnow",POWERFAILNOW },
+  { "powerwait",   POWERWAIT	},
+  { "powerokwait", POWEROKWAIT	},
+  { "ctrlaltdel",  CTRLALTDEL	},
+  { "off",	   OFF		},
+  { "ondemand",	   ONDEMAND	},
+  { "initdefault", INITDEFAULT	},
+  { "sysinit",	   SYSINIT	},
+  { "kbrequest",   KBREQUEST    },
+  { NULL,	   0		},
+};
+
+/*
+ *	State parser token table (see receive_state)
+ */
+struct {
+  char name[4];	
+  int cmd;
+} cmds[] = {
+  { "VER", 	   C_VER	},
+  { "END",	   C_END	},
+  { "REC",	   C_REC	},
+  { "EOR",	   C_EOR	},
+  { "LEV",	   C_LEV	},
+  { "FL ",	   C_FLAG	},
+  { "AC ",	   C_ACTION	},
+  { "CMD",	   C_PROCESS	},
+  { "PID",	   C_PID	},
+  { "EXS",	   C_EXS	},
+  { "-RL",	   D_RUNLEVEL	},
+  { "-TL",	   D_THISLEVEL	},
+  { "-PL",	   D_PREVLEVEL	},
+  { "-SI",	   D_GOTSIGN	},
+  { "-WR",	   D_WROTE_WTMP_REBOOT},
+  { "-WU",	   D_WROTE_UTMP_REBOOT},
+  { "-ST",	   D_SLTIME	},
+  { "-DB",	   D_DIDBOOT	},
+  { "-LW",	   D_WROTE_WTMP_RLEVEL},
+  { "-LU",	   D_WROTE_UTMP_RLEVEL},
+  { "",	   	   0		}
+};
+struct {
+	char *name;
+	int mask;
+} flags[]={
+	{"RU",RUNNING},
+	{"DE",DEMAND},
+	{"XD",XECUTED},
+	{"WT",WAITING},
+	{NULL,0}
+};
+
+#define NR_EXTRA_ENV	16
+char *extra_env[NR_EXTRA_ENV];
+
+#define MINI_SLEEP 10      /* ten milliseconds */
+#define SHORT_SLEEP 5000   /* five seconds */
+#define LONG_SLEEP 30000   /* 30 seconds sleep to deal with memory issues*/
+
+/*
+ *	Sleep a number of milliseconds.
+ *
+ *	This only works correctly because Linux select updates
+ *	the elapsed time in the struct timeval passed to select!
+ */
+static
+void do_msleep(int msec)
+{
+	struct timeval tv;
+
+	tv.tv_sec = msec / 1000;
+	tv.tv_usec = (msec % 1000) * 1000;
+
+	while(select(0, NULL, NULL, NULL, &tv) < 0 && errno == EINTR)
+		;
+}
+
+
+/*
+ *	Non-failing allocation routines (init cannot fail).
+ */
+static
+void *imalloc(size_t size)
+{
+	void	*m;
+
+	while ((m = malloc(size)) == NULL) {
+		initlog(L_VB, "out of memory");
+		do_msleep(SHORT_SLEEP);
+	}
+	memset(m, 0, size);
+	return m;
+}
+
+static
+char *istrdup(const char *s)
+{
+	char	*m;
+	int	l;
+
+	l = strlen(s) + 1;
+	m = imalloc(l);
+	memcpy(m, s, l);
+	return m;
+}
+
+
+/*
+ *	Send the state info of the previous running init to
+ *	the new one, in a version-independant way.
+ */
+static
+void send_state(int fd)
+{
+	FILE	*fp;
+	CHILD	*p;
+	int	i,val;
+
+	fp = fdopen(fd,"w");
+
+	fprintf(fp, "VER%s\n", Version);
+	fprintf(fp, "-RL%c\n", runlevel);
+	fprintf(fp, "-TL%c\n", thislevel);
+	fprintf(fp, "-PL%c\n", prevlevel);
+	fprintf(fp, "-SI%u\n", got_signals);
+	fprintf(fp, "-WR%d\n", wrote_wtmp_reboot);
+	fprintf(fp, "-WU%d\n", wrote_utmp_reboot);
+	fprintf(fp, "-ST%d\n", sleep_time);
+	fprintf(fp, "-DB%d\n", did_boot);
+
+	for (p = family; p; p = p->next) {
+		fprintf(fp, "REC%s\n", p->id);
+		fprintf(fp, "LEV%s\n", p->rlevel);
+		for (i = 0, val = p->flags; flags[i].mask; i++)
+			if (val & flags[i].mask) {
+				val &= ~flags[i].mask;
+				fprintf(fp, "FL %s\n",flags[i].name);
+			}
+		fprintf(fp, "PID%d\n",p->pid);
+		fprintf(fp, "EXS%u\n",p->exstat);
+		for(i = 0; actions[i].act; i++)
+			if (actions[i].act == p->action) {
+				fprintf(fp, "AC %s\n", actions[i].name);
+				break;
+			}
+		fprintf(fp, "CMD%s\n", p->process);
+		fprintf(fp, "EOR\n");
+	}
+	fprintf(fp, "END\n");
+	fclose(fp);
+}
+
+/*
+ *	Read a string from a file descriptor.
+ *	Q: why not use fgets() ?
+ *      A: Answer: looked into this. Turns out after all the checks
+ *      required in the fgets() approach (removing newline, read errors, etc)
+ *      the function is longer and takes approximately the same amount of
+ *      time to do one big fgets and checks as it does to do a pile of getcs.
+ *      We don't benefit from switching.
+ *      - Jesse
+ */
+static int get_string(char *p, int size, FILE *f)
+{
+	int	c;
+
+	while ((c = getc(f)) != EOF && c != '\n') {
+		if (--size > 0)
+			*p++ = c;
+	}
+	*p = '\0';
+	return (c != EOF) && (size > 0);
+}
+
+/*
+ *	Read trailing data from the state pipe until we see a newline.
+ */
+static int get_void(FILE *f)
+{
+	int	c;
+
+	while ((c = getc(f)) != EOF && c != '\n')
+		;
+
+	return (c != EOF);
+}
+
+/*
+ *	Read the next "command" from the state pipe.
+ */
+static int get_cmd(FILE *f)
+{
+	char	cmd[4] = "   ";
+	int	i;
+
+	if (fread(cmd, 1, sizeof(cmd) - 1, f) != sizeof(cmd) - 1)
+		return C_EOF;
+
+	for(i = 0; cmds[i].cmd && strcmp(cmds[i].name, cmd) != 0; i++)
+		;
+	return cmds[i].cmd;
+}
+
+/*
+ *	Read a CHILD * from the state pipe.
+ */
+static CHILD *get_record(FILE *f)
+{
+	int	cmd;
+	char	s[32];
+	int	i;
+	CHILD	*p;
+
+	do {
+		errno = 0;
+		switch (cmd = get_cmd(f)) {
+			case C_END:
+				get_void(f);
+				return NULL;
+			case 0:
+				get_void(f);
+				break;
+			case C_REC:
+				break;
+			case D_RUNLEVEL:
+				if (fscanf(f, "%c\n", &runlevel) == EOF && errno != 0) {
+					fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+				}
+				break;
+			case D_THISLEVEL:
+				if (fscanf(f, "%c\n", &thislevel) == EOF && errno != 0) {
+					fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+				}
+				break;
+			case D_PREVLEVEL:
+				if (fscanf(f, "%c\n", &prevlevel) == EOF && errno != 0) {
+					fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+				}
+				break;
+			case D_GOTSIGN:
+				if (fscanf(f, "%u\n", &got_signals) == EOF && errno != 0) {
+					fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+				}
+				break;
+			case D_WROTE_WTMP_REBOOT:
+				if (fscanf(f, "%d\n", &wrote_wtmp_reboot) == EOF && errno != 0) {
+					fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+				}
+				break;
+			case D_WROTE_UTMP_REBOOT:
+				if (fscanf(f, "%d\n", &wrote_utmp_reboot) == EOF && errno != 0) {
+					fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+				}
+				break;
+			case D_SLTIME:
+				if (fscanf(f, "%d\n", &sleep_time) == EOF && errno != 0) {
+					fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+				}
+				break;
+			case D_DIDBOOT:
+				if (fscanf(f, "%d\n", &did_boot) == EOF && errno != 0) {
+					fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+				}
+				break;
+			case D_WROTE_WTMP_RLEVEL:
+				if (fscanf(f, "%d\n", &wrote_wtmp_rlevel) == EOF && errno != 0) {
+					fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+				}
+				break;
+			case D_WROTE_UTMP_RLEVEL:
+				if (fscanf(f, "%d\n", &wrote_utmp_rlevel) == EOF && errno != 0) {
+					fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+				}
+				break;
+			default:
+				if (cmd > 0 || cmd == C_EOF) {
+					oops_error = -1;
+					return NULL;
+				}
+		}
+	} while (cmd != C_REC);
+
+	p = imalloc(sizeof(CHILD));
+	get_string(p->id, sizeof(p->id), f);
+
+	do switch(cmd = get_cmd(f)) {
+		case 0:
+		case C_EOR:
+			get_void(f);
+			break;
+		case C_PID:
+			if (fscanf(f, "%d\n", &(p->pid)) == EOF && errno != 0) {
+				fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+			}
+			break;
+		case C_EXS:
+			if (fscanf(f, "%u\n", &(p->exstat)) == EOF && errno != 0) {
+				fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno));
+			}
+			break;
+		case C_LEV:
+			get_string(p->rlevel, sizeof(p->rlevel), f);
+			break;
+		case C_PROCESS:
+			get_string(p->process, sizeof(p->process), f);
+			break;
+		case C_FLAG:
+			get_string(s, sizeof(s), f);
+			for(i = 0; flags[i].name; i++) {
+				if (strcmp(flags[i].name,s) == 0)
+					break;
+			}
+			p->flags |= flags[i].mask;
+			break;
+		case C_ACTION:
+			get_string(s, sizeof(s), f);
+			for(i = 0; actions[i].name; i++) {
+				if (strcmp(actions[i].name, s) == 0)
+					break;
+			}
+			p->action = actions[i].act ? actions[i].act : OFF;
+			break;
+		default:
+			free(p);
+			oops_error = -1;
+			return NULL;
+	} while( cmd != C_EOR);
+
+	return p;
+}
+
+/*
+ *	Read the complete state info from the state pipe.
+ *	Returns 0 on success
+ */
+static
+int receive_state(int fd)
+{
+	FILE	*f;
+	char	old_version[256];
+	CHILD	**pp;
+
+	f = fdopen(fd, "r");
+
+ 	if (get_cmd(f) != C_VER) {
+		fclose(f);
+		return -1;
+	}
+	get_string(old_version, sizeof(old_version), f);
+	oops_error = 0;
+	for (pp = &family; (*pp = get_record(f)) != NULL; pp = &((*pp)->next))
+		;
+	fclose(f);
+	return oops_error;
+}
+
+/*
+ *	Set the process title.
+ */
+#ifdef __GNUC__
+#ifndef __FreeBSD__
+__attribute__ ((format (printf, 1, 2)))
+#endif
+#endif
+/* This function already exists on FreeBSD. No need to declare it. */
+#ifndef __FreeBSD__
+static int setproctitle(char *fmt, ...)
+{
+	va_list ap;
+	int len;
+	char buf[256];
+
+	buf[0] = 0;
+
+	va_start(ap, fmt);
+	len = vsnprintf(buf, sizeof(buf), fmt, ap);
+	va_end(ap);
+
+	if (maxproclen > 1) {
+		memset(argv0, 0, maxproclen);
+		strncpy(argv0, buf, maxproclen - 1);
+	}
+
+	return len;
+}
+#endif
+
+/*
+ *	Set console_dev to a working console.
+ */
+static
+void console_init(void)
+{
+	int fd;
+	int tried_devcons = 0;
+	int tried_vtmaster = 0;
+	char *s;
+
+	if ((s = getenv("CONSOLE")) != NULL)
+		console_dev = s;
+	else {
+		console_dev = CONSOLE;
+		tried_devcons++;
+	}
+
+	while ((fd = open(console_dev, O_RDONLY|O_NONBLOCK)) < 0) {
+		if (!tried_devcons) {
+			tried_devcons++;
+			console_dev = CONSOLE;
+			continue;
+		}
+		if (!tried_vtmaster) {
+			tried_vtmaster++;
+			console_dev = VT_MASTER;
+			continue;
+		}
+		break;
+	}
+	if (fd < 0)
+		console_dev = "/dev/null";
+	else
+		close(fd);
+}
+
+
+/*
+ *	Open the console with retries.
+ */
+static
+int console_open(int mode)
+{
+	int f, fd = -1;
+	int m;
+
+	/*
+	 *	Open device in nonblocking mode.
+	 */
+	m = mode | O_NONBLOCK;
+
+	/*
+	 *	Retry the open five times.
+	 */
+	for(f = 0; f < 5; f++) {
+		if ((fd = open(console_dev, m)) >= 0) break;
+		usleep(10000);
+	}
+
+	if (fd < 0) return fd;
+
+	/*
+	 *	Set original flags.
+	 */
+	if (m != mode)
+  		fcntl(fd, F_SETFL, mode);
+	return fd;
+}
+
+/*
+ *	We got a signal (HUP PWR WINCH ALRM INT)
+ */
+static
+void signal_handler(int sig)
+{
+	ADDSET(got_signals, sig);
+}
+
+/*
+ *	SIGCHLD: one of our children has died.
+ */
+static
+# ifdef __GNUC__
+void chld_handler(int sig __attribute__((unused)))
+# else
+void chld_handler(int sig)
+# endif
+{
+	CHILD		*ch;
+	int		pid, st;
+	int		saved_errno = errno;
+
+	/*
+	 *	Find out which process(es) this was (were)
+	 */
+	while((pid = waitpid(-1, &st, WNOHANG)) != 0) {
+		if (errno == ECHILD) break;
+		for( ch = family; ch; ch = ch->next )
+			if ( ch->pid == pid && (ch->flags & RUNNING) ) {
+				INITDBG(L_VB,
+					"chld_handler: marked %d as zombie",
+					ch->pid);
+				ADDSET(got_signals, SIGCHLD);
+				ch->exstat = st;
+				ch->flags |= ZOMBIE;
+				if (ch->new) {
+					ch->new->exstat = st;
+					ch->new->flags |= ZOMBIE;
+				}
+				break;
+			}
+		if (ch == NULL) {
+			INITDBG(L_VB, "chld_handler: unknown child %d exited.",
+				pid);
+		}
+	}
+	errno = saved_errno;
+}
+
+/*
+ *	Linux ignores all signals sent to init when the
+ *	SIG_DFL handler is installed. Therefore we must catch SIGTSTP
+ *	and SIGCONT, or else they won't work....
+ *
+ *	The SIGCONT handler
+ */
+static
+# ifdef __GNUC__
+void cont_handler(int sig __attribute__((unused)))
+# else
+void cont_handler(int sig)
+# endif
+{
+	got_cont = 1;
+}
+
+/*
+ *	Fork and dump core in /.
+ */
+static
+void coredump(void)
+{
+	static int		dumped = 0;
+	struct rlimit		rlim;
+	sigset_t		mask;
+
+	if (dumped) return;
+	dumped = 1;
+
+	if (fork() != 0) return;
+
+	sigfillset(&mask);
+	sigprocmask(SIG_SETMASK, &mask, NULL);
+
+	rlim.rlim_cur = RLIM_INFINITY;
+	rlim.rlim_max = RLIM_INFINITY;
+	setrlimit(RLIMIT_CORE, &rlim);
+	if (0 != chdir("/"))
+		initlog(L_VB, "unable to chdir to /: %s",
+			strerror(errno));
+
+	signal(SIGSEGV, SIG_DFL);
+	raise(SIGSEGV);
+	sigdelset(&mask, SIGSEGV);
+	sigprocmask(SIG_SETMASK, &mask, NULL);
+
+	do_msleep(SHORT_SLEEP);
+	exit(0);
+}
+
+/*
+ *	OOPS: segmentation violation!
+ *	If we have the info, print where it occurred.
+ *	Then sleep 30 seconds and try to continue.
+ */
+static
+#if defined(STACK_DEBUG) && defined(__linux__)
+# ifdef __GNUC__
+void segv_handler(int sig __attribute__((unused)), struct sigcontext ctx)
+# else
+void segv_handler(int sig, struct sigcontext ctx)
+# endif
+{
+	char	*p = "";
+	int	saved_errno = errno;
+
+	if ((void *)ctx.eip >= (void *)do_msleep &&
+	    (void *)ctx.eip < (void *)main)
+		p = " (code)";
+	initlog(L_VB, "PANIC: segmentation violation at %p%s! "
+		  "sleeping for 30 seconds.", (void *)ctx.eip, p);
+	coredump();
+	do_msleep(LONG_SLEEP);
+	errno = saved_errno;
+}
+#else
+# ifdef __GNUC__
+void segv_handler(int sig __attribute__((unused)))
+# else
+void segv_handler(int sig)
+# endif
+{
+	int	saved_errno = errno;
+
+	initlog(L_VB,
+		"PANIC: segmentation violation! sleeping for 30 seconds.");
+	coredump();
+	do_msleep(LONG_SLEEP);
+	errno = saved_errno;
+}
+#endif
+
+/*
+ *	The SIGSTOP & SIGTSTP handler
+ */
+static
+# ifdef __GNUC__
+void stop_handler(int sig __attribute__((unused)))
+# else
+void stop_handler(int sig)
+# endif
+{
+	int	saved_errno = errno;
+
+	got_cont = 0;
+	while(!got_cont) pause();
+	got_cont = 0;
+	errno = saved_errno;
+}
+
+/*
+ *	Set terminal settings to reasonable defaults
+ */
+static
+void console_stty(void)
+{
+	struct termios tty;
+	int fd;
+
+	if ((fd = console_open(O_RDWR|O_NOCTTY)) < 0) {
+		initlog(L_VB, "can't open %s", console_dev);
+		return;
+	}
+
+#ifdef __FreeBSD_kernel__
+	/*
+	 * The kernel of FreeBSD expects userland to set TERM.  Usually, we want
+	 * "xterm".  Later, gettys might disagree on this (i.e. we're not using
+	 * syscons) but some boot scripts, like /etc/init.d/xserver-xorg, still
+	 * need a non-dumb terminal.
+	 */
+	putenv ("TERM=xterm");
+#endif
+
+	(void) tcgetattr(fd, &tty);
+
+	tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD;
+	tty.c_cflag |= HUPCL|CLOCAL|CREAD;
+
+	tty.c_cc[VINTR]	    = CINTR;
+	tty.c_cc[VQUIT]	    = CQUIT;
+	tty.c_cc[VERASE]    = CERASE; /* ASCII DEL (0177) */
+	tty.c_cc[VKILL]	    = CKILL;
+	tty.c_cc[VEOF]	    = CEOF;
+	tty.c_cc[VTIME]	    = 0;
+	tty.c_cc[VMIN]	    = 1;
+#ifdef VSWTC /* not defined on FreeBSD */
+	tty.c_cc[VSWTC]	    = _POSIX_VDISABLE;
+#endif /* VSWTC */
+	tty.c_cc[VSTART]    = CSTART;
+	tty.c_cc[VSTOP]	    = CSTOP;
+	tty.c_cc[VSUSP]	    = CSUSP;
+	tty.c_cc[VEOL]	    = _POSIX_VDISABLE;
+	tty.c_cc[VREPRINT]  = CREPRINT;
+	tty.c_cc[VDISCARD]  = CDISCARD;
+	tty.c_cc[VWERASE]   = CWERASE;
+	tty.c_cc[VLNEXT]    = CLNEXT;
+	tty.c_cc[VEOL2]	    = _POSIX_VDISABLE;
+
+	/*
+	 *	Set pre and post processing
+	 */
+	tty.c_iflag = IGNPAR|ICRNL|IXON|IXANY
+#ifdef IUTF8	/* Not defined on FreeBSD */
+			| (tty.c_iflag & IUTF8)
+#endif /* IUTF8 */
+		;
+	tty.c_oflag = OPOST|ONLCR;
+	tty.c_lflag = ISIG|ICANON|ECHO|ECHOCTL|ECHOE|ECHOKE;
+
+#if defined(SANE_TIO) && (SANE_TIO == 1)
+	/*
+	 *	Disable flow control (-ixon), ignore break (ignbrk),
+	 *	and make nl/cr more usable (sane).
+	 */
+	tty.c_iflag |=  IGNBRK;
+	tty.c_iflag &= ~(BRKINT|INLCR|IGNCR|IXON);
+	tty.c_oflag &= ~(OCRNL|ONLRET);
+#endif
+	/*
+	 *	Now set the terminal line.
+	 *	We don't care about non-transmitted output data
+	 *	and non-read input data.
+	 */
+	(void) tcsetattr(fd, TCSANOW, &tty);
+	(void) tcflush(fd, TCIOFLUSH);
+	(void) close(fd);
+}
+
+static  ssize_t
+safe_write(int fd, const char *buffer, size_t count)
+{
+	ssize_t offset = 0;
+
+	while (count > 0) {
+		ssize_t block = write(fd, &buffer[offset], count);
+
+		if (block < 0 && errno == EINTR)
+			continue;
+		if (block <= 0)
+			return offset ? offset : block;
+		offset += block;
+		count -= block;
+	}
+	return offset;
+}
+
+/*
+ *	Print to the system console
+ */
+void print(char *s)
+{
+	int fd;
+
+	if ((fd = console_open(O_WRONLY|O_NOCTTY|O_NDELAY)) >= 0) {
+		safe_write(fd, s, strlen(s));
+		close(fd);
+	}
+}
+
+/*
+ *	Log something to a logfile and the console.
+ */
+#ifdef __GNUC__
+__attribute__ ((format (printf, 2, 3)))
+#endif
+void initlog(int loglevel, char *s, ...)
+{
+	va_list va_alist;
+	char buf[256];
+	sigset_t nmask, omask;
+
+	va_start(va_alist, s);
+	vsnprintf(buf, sizeof(buf), s, va_alist);
+	va_end(va_alist);
+
+	if (loglevel & L_SY) {
+		/*
+		 *	Re-establish connection with syslogd every time.
+		 *	Block signals while talking to syslog.
+		 */
+		sigfillset(&nmask);
+		sigprocmask(SIG_BLOCK, &nmask, &omask);
+		openlog("init", 0, LOG_DAEMON);
+		syslog(LOG_INFO, "%s", buf);
+		closelog();
+		sigprocmask(SIG_SETMASK, &omask, NULL);
+	}
+
+	/*
+	 *	And log to the console.
+	 */
+	if (loglevel & L_CO) {
+		print("\rINIT: ");
+		print(buf);
+		print("\r\n");
+	}
+}
+
+/*
+ *	Add or replace specific environment value
+ */
+int addnewenv(const char *new, char **curr, int n)
+{
+	size_t nlen = strcspn(new, "=");
+	int i;
+	for (i = 0; i < n; i++) {
+		if (nlen != strcspn(curr[i], "="))
+			continue;
+		if (strncmp (new, curr[i], nlen) == 0)
+			break;
+	}
+	if (i >= n)
+		curr[n++] = istrdup(new);
+	else {
+		free(curr[i]);
+		curr[i] = istrdup(new);
+	}
+	return n;
+}
+
+/*
+ *	Build a new environment for execve().
+ */
+char **init_buildenv(int child)
+{
+	char		i_lvl[] = "RUNLEVEL=x";
+	char		i_prev[] = "PREVLEVEL=x";
+	char		i_cons[128];
+	char		i_shell[] = "SHELL=" SHELL;
+	char		**e;
+	int		n, i;
+
+	for (n = 0; environ[n]; n++)
+		;
+	n += NR_EXTRA_ENV + 1;	    /* Also room for last NULL */
+	if (child)
+		n += 8;
+
+	while ((e = (char**)calloc(n, sizeof(char *))) == NULL) {
+		initlog(L_VB, "out of memory");
+		do_msleep(SHORT_SLEEP);
+	}
+
+	for (n = 0; environ[n]; n++)
+		e[n] = istrdup(environ[n]);
+
+	for (i = 0; i < NR_EXTRA_ENV; i++) {
+		if (extra_env[i] == NULL || *extra_env[i] == '\0')
+			continue;
+		n = addnewenv(extra_env[i], e, n);
+	}
+
+	if (child) {
+		snprintf(i_cons, sizeof(i_cons), "CONSOLE=%s", console_dev);
+		i_lvl[9]   = thislevel;
+		i_prev[10] = prevlevel;
+		n = addnewenv(i_shell, e, n);
+		n = addnewenv(i_lvl, e, n);
+		n = addnewenv(i_prev, e, n);
+		n = addnewenv(i_cons, e, n);
+		n = addnewenv(E_VERSION, e, n);
+	}
+
+	e[n++] = NULL;
+
+	return e;
+}
+
+
+void init_freeenv(char **e)
+{
+	int		n;
+
+	for (n = 0; e[n]; n++)
+		free(e[n]);
+	free(e);
+}
+
+
+/*
+ *	Fork and execute.
+ *
+ *	This function is too long and indents too deep.
+ *
+ */
+static
+pid_t spawn(CHILD *ch, int *res)
+{
+  char *args[16];		/* Argv array */
+  char buf[136];		/* Line buffer */
+  int f, st;			/* Scratch variables */
+  char *ptr;			/* Ditto */
+  time_t t;			/* System time */
+  int oldAlarm;			/* Previous alarm value */
+  char *proc = ch->process;	/* Command line */
+  pid_t pid, pgrp;		/* child, console process group. */
+  sigset_t nmask, omask;	/* For blocking SIGCHLD */
+  struct sigaction sa;
+
+  *res = -1;
+  buf[sizeof(buf) - 1] = 0;
+
+  /* Skip '+' if it's there */
+  if (proc[0] == '+') proc++;
+
+  ch->flags |= XECUTED;
+
+  if (ch->action == RESPAWN || ch->action == ONDEMAND) {
+	/* Is the date stamp from less than 2 minutes ago? */
+	time(&t);
+	if (ch->tm + TESTTIME > t) {
+		ch->count++;
+	} else {
+		ch->count = 0;
+		ch->tm = t;
+	}
+
+	/* Do we try to respawn too fast? */
+	if (ch->count >= MAXSPAWN) {
+
+	  initlog(L_VB,
+		"Id \"%s\" respawning too fast: disabled for %d minutes",
+		ch->id, SLEEPTIME / 60);
+	  ch->flags &= ~RUNNING;
+	  ch->flags |= FAILING;
+
+	  /* Remember the time we stopped */
+	  ch->tm = t;
+
+	  /* Try again in 5 minutes */
+	  oldAlarm = alarm(0);
+	  if (oldAlarm > SLEEPTIME || oldAlarm <= 0) oldAlarm = SLEEPTIME;
+	  alarm(oldAlarm);
+	  return(-1);
+	}
+  }
+
+  /* See if there is an "initscript" (except in single user mode). */
+  if (access(INITSCRIPT, R_OK) == 0 && runlevel != 'S') {
+	/* Build command line using "initscript" */
+	args[1] = SHELL;
+	args[2] = INITSCRIPT;
+	args[3] = ch->id;
+	args[4] = ch->rlevel;
+	args[5] = "unknown";
+	for(f = 0; actions[f].name; f++) {
+		if (ch->action == actions[f].act) {
+			args[5] = actions[f].name;
+			break;
+		}
+	}
+	args[6] = proc;
+	args[7] = NULL;
+  } else if (strpbrk(proc, "~`!$^&*()=|\\{}[];\"'<>?")) {
+  /* See if we need to fire off a shell for this command */
+  	/* Give command line to shell */
+  	args[1] = SHELL;
+  	args[2] = "-c";
+  	strcpy(buf, "exec ");
+  	strncat(buf, proc, sizeof(buf) - strlen(buf) - 1);
+  	args[3] = buf;
+  	args[4] = NULL;
+  } else {
+	/* Split up command line arguments */
+	buf[0] = 0;
+  	strncat(buf, proc, sizeof(buf) - 1);
+  	ptr = buf;
+  	for(f = 1; f < 15; f++) {
+  		/* Skip white space */
+  		while(*ptr == ' ' || *ptr == '\t') ptr++;
+  		args[f] = ptr;
+  		
+		/* May be trailing space.. */
+		if (*ptr == 0) break;
+
+  		/* Skip this `word' */
+  		while(*ptr && *ptr != ' ' && *ptr != '\t' && *ptr != '#')
+  			ptr++;
+  		
+  		/* If end-of-line, break */	
+  		if (*ptr == '#' || *ptr == 0) {
+  			f++;
+  			*ptr = 0;
+  			break;
+  		}
+  		/* End word with \0 and continue */
+  		*ptr++ = 0;
+  	}
+  	args[f] = NULL;
+  }
+  args[0] = args[1];
+  while(1) {
+	/*
+	 *	Block sigchild while forking.
+	 */
+	sigemptyset(&nmask);
+	sigaddset(&nmask, SIGCHLD);
+	sigprocmask(SIG_BLOCK, &nmask, &omask);
+
+	if ((pid = fork()) == 0) {
+
+		close(0);
+		close(1);
+		close(2);
+		if (pipe_fd >= 0)
+                {
+                    close(pipe_fd);
+                    pipe_fd = -1;
+                }
+
+  		sigprocmask(SIG_SETMASK, &omask, NULL);
+
+		/*
+		 *	In sysinit, boot, bootwait or single user mode:
+		 *	for any wait-type subprocess we _force_ the console
+		 *	to be its controlling tty.
+		 */
+  		if (strchr("*#sS", runlevel) && ch->flags & WAITING) {
+			int ftty;	/* Handler for tty controlling */
+			/*
+			 *	We fork once extra. This is so that we can
+			 *	wait and change the process group and session
+			 *	of the console after exit of the leader.
+			 */
+			setsid();
+			if ((ftty = console_open(O_RDWR|O_NOCTTY)) >= 0) {
+				/* Take over controlling tty by force */
+				(void)ioctl(ftty, TIOCSCTTY, 1);
+
+				if(dup(ftty) < 0){
+				        initlog(L_VB, "cannot duplicate console fd");
+				}
+				
+				if(dup(ftty) < 0){
+				        initlog(L_VB, "cannot duplicate console fd");
+				}
+
+			}
+
+			/*
+			 * 4 Sep 2001, Andrea Arcangeli:
+			 * Fix a race in spawn() that is used to deadlock init in a
+			 * waitpid() loop: must set the childhandler as default before forking
+			 * off the child or the chld_handler could run before the waitpid loop
+			 * has a chance to find its zombie-child.
+			 */
+			SETSIG(sa, SIGCHLD, SIG_DFL, SA_RESTART);
+			if ((pid = fork()) < 0) {
+  				initlog(L_VB, "cannot fork: %s",
+					strerror(errno));
+				exit(1);
+			}
+			if (pid > 0) {
+				pid_t rc;
+				/*
+				 *	Ignore keyboard signals etc.
+				 *	Then wait for child to exit.
+				 */
+				SETSIG(sa, SIGINT, SIG_IGN, SA_RESTART);
+				SETSIG(sa, SIGTSTP, SIG_IGN, SA_RESTART);
+				SETSIG(sa, SIGQUIT, SIG_IGN, SA_RESTART);
+
+				while ((rc = waitpid(pid, &st, 0)) != pid)
+					if (rc < 0 && errno == ECHILD)
+						break;
+
+				/*
+				 *	Small optimization. See if stealing
+				 *	controlling tty back is needed.
+				 */
+				pgrp = tcgetpgrp(ftty);
+				if (pgrp != getpid())
+					exit(0);
+
+				/*
+				 *	Steal controlling tty away. We do
+				 *	this with a temporary process.
+				 */
+				if ((pid = fork()) < 0) {
+  					initlog(L_VB, "cannot fork: %s",
+						strerror(errno));
+					exit(1);
+				}
+				if (pid == 0) {
+					setsid();
+					(void)ioctl(ftty, TIOCSCTTY, 1);
+					exit(0);
+				}
+				while((rc = waitpid(pid, &st, 0)) != pid)
+					if (rc < 0 && errno == ECHILD)
+						break;
+				exit(0);
+			}
+
+			/* Set ioctl settings to default ones */
+			console_stty();
+
+  		} else { /* parent */
+			int fd;
+			setsid();
+			if ((fd = console_open(O_RDWR|O_NOCTTY)) < 0) {
+				initlog(L_VB, "open(%s): %s", console_dev,
+					strerror(errno));
+				fd = open("/dev/null", O_RDWR);
+			}
+
+			if(dup(fd) < 0) {
+				initlog(L_VB, "cannot duplicate /dev/null fd");
+			}
+			
+			if(dup(fd) < 0) {
+				initlog(L_VB, "cannot duplicate /dev/null fd");
+			}
+
+		}
+
+		/*
+		 * Update utmp/wtmp file prior to starting
+		 * any child.  This MUST be done right here in
+		 * the child process in order to prevent a race
+		 * condition that occurs when the child
+		 * process' time slice executes before the
+		 * parent (can and does happen in a uniprocessor
+		 * environment).  If the child is a getty and
+		 * the race condition happens, then init's utmp
+		 * update will happen AFTER the getty runs
+		 * and expects utmp to be updated already!
+		 *
+		 * Do NOT log if process field starts with '+'
+		 * This is for compatibility with *very*
+		 * old getties - probably it can be taken out.
+		 */
+		if (ch->process[0] != '+')
+			write_utmp_wtmp("", ch->id, getpid(), INIT_PROCESS, "");
+
+  		/* Reset all the signals, set up environment */
+  		for(f = 1; f < NSIG; f++) SETSIG(sa, f, SIG_DFL, SA_RESTART);
+		environ = init_buildenv(1);
+
+		/*
+		 *	Execute prog. In case of ENOEXEC try again
+		 *	as a shell script.
+		 */
+  		execvp(args[1], args + 1);
+		if (errno == ENOEXEC) {
+  			args[1] = SHELL;
+  			args[2] = "-c";
+  			strcpy(buf, "exec ");
+  			strncat(buf, proc, sizeof(buf) - strlen(buf) - 1);
+  			args[3] = buf;
+  			args[4] = NULL;
+			execvp(args[1], args + 1);
+		}
+  		initlog(L_VB, "cannot execute \"%s\"", args[1]);
+
+		if (ch->process[0] != '+')
+			write_utmp_wtmp("", ch->id, getpid(), DEAD_PROCESS, NULL);
+  		exit(1);
+  	}
+	*res = pid;
+  	sigprocmask(SIG_SETMASK, &omask, NULL);
+
+	INITDBG(L_VB, "Started id %s (pid %d)", ch->id, pid);
+
+	if (pid == -1) {
+		initlog(L_VB, "cannot fork, retry..");
+		do_msleep(SHORT_SLEEP);
+		continue;
+	}
+	return(pid);
+  }
+}
+
+/*
+ *	Start a child running!
+ */
+static
+void startup(CHILD *ch)
+{
+	/*
+	 *	See if it's disabled
+	 */
+	if (ch->flags & FAILING) return;
+
+	switch(ch->action) {
+
+		case SYSINIT:
+		case BOOTWAIT:
+		case WAIT:
+		case POWERWAIT:
+		case POWERFAILNOW:
+		case POWEROKWAIT:
+		case CTRLALTDEL:
+			if (!(ch->flags & XECUTED)) ch->flags |= WAITING;
+			/* Fall through */
+		case KBREQUEST:
+		case BOOT:
+		case POWERFAIL:
+		case ONCE:
+			if (ch->flags & XECUTED) break;
+                        /* Fall through */
+		case ONDEMAND:
+		case RESPAWN:
+  			ch->flags |= RUNNING;
+  			(void)spawn(ch, &(ch->pid));
+  			break;
+	}
+}
+
+#ifdef __linux__
+static
+void check_kernel_console()
+{
+	FILE* fp;
+	char buf[4096];
+	if ((fp = fopen("/proc/cmdline", "r")) == 0) {    
+		return;
+	}    
+	if (fgets(buf, sizeof(buf), fp)) {    
+		char* p = buf;
+           if ( strstr(p, "init.autocon=1") )
+           {
+		while ((p = strstr(p, "console="))) {    
+			char* e;
+			p += strlen("console=");
+			for (e = p; *e; ++e) {
+				switch (*e) {
+					case '-' ... '9':
+					case 'A' ... 'Z':
+					case '_':
+					case 'a' ... 'z':
+						continue;
+				}
+				break;
+			}
+			if (p != e) {
+				CHILD* old;
+				int dup = 0;
+				char id[8] = {0};
+				char dev[32] = {0};
+				strncpy(dev, p, MIN(sizeof(dev), (unsigned)(e-p)));
+				if (!strncmp(dev, "tty", 3))
+					strncpy(id, dev+3, sizeof(id));
+				else
+					strncpy(id, dev, sizeof(id));
+
+				for(old = newFamily; old; old = old->next) {
+					if (!strcmp(old->id, id)) {
+						dup = 1;
+					}
+				}
+				if (!dup) {
+					CHILD* ch = imalloc(sizeof(CHILD));
+					ch->action = RESPAWN;
+					strcpy(ch->id, id);
+					strcpy(ch->rlevel, "2345");
+					sprintf(ch->process, "/sbin/agetty -L -s 115200,38400,9600 %s vt102", dev);
+					ch->next = NULL;
+					for(old = family; old; old = old->next) {
+						if (strcmp(old->id, ch->id) == 0) {
+							old->new = ch;
+							break;
+						}
+					}
+					/* add to end */
+					for(old = newFamily; old; old = old->next) {
+						if (!old->next) {
+							old->next = ch;
+							break;
+						}
+					}
+
+					initlog(L_VB, "added agetty on %s with id %s", dev, id);
+				}
+			}
+		}
+            } 
+	}    
+	fclose(fp);
+	return;
+}
+#endif
+
+/*
+ *	Read the inittab file.
+ */
+static
+void read_inittab(void)
+{
+  FILE		*fp;			/* The INITTAB file */
+  FILE		*fp_tab;		/* The INITTABD files */
+  CHILD		*ch, *old, *i;		/* Pointers to CHILD structure */
+  CHILD		*head = NULL;		/* Head of linked list */
+#ifdef INITLVL
+  struct stat	st;			/* To stat INITLVL */
+#endif
+  sigset_t	nmask, omask;		/* For blocking SIGCHLD. */
+  char		buf[256];		/* Line buffer */
+  char		err[64];		/* Error message. */
+  char		*id, *rlevel,
+		*action, *process;	/* Fields of a line */
+  char		*p;
+  int		lineNo = 0;		/* Line number in INITTAB file */
+  int		actionNo;		/* Decoded action field */
+  int		f;			/* Counter */
+  int		round;			/* round 0 for SIGTERM, 1 for SIGKILL */
+  int		foundOne = 0;		/* No killing no sleep */
+  int		talk;			/* Talk to the user */
+  int		done = -1;		/* Ready yet? , 2 level : -1 nothing done, 0 inittab done, 1 inittab and inittab.d done */
+  DIR 		*tabdir=NULL;		/* the INITTAB.D dir */
+  struct dirent *file_entry;		/* inittab.d entry */
+  char 		f_name[272];		/* size d_name + strlen /etc/inittad.d/ */
+
+#if DEBUG
+  if (newFamily != NULL) {
+	INITDBG(L_VB, "PANIC newFamily != NULL");
+	exit(1);
+  }
+  INITDBG(L_VB, "Reading inittab");
+#endif
+
+  /*
+   *	Open INITTAB and read line by line.
+   */
+  if ((fp = fopen(INITTAB, "r")) == NULL)
+	initlog(L_VB, "No inittab file found");
+
+  /*
+   *  Open INITTAB.D directory 
+   */
+  if( (tabdir = opendir(INITTABD))==NULL)
+	  initlog(L_VB, "No inittab.d directory found");
+
+  while(done!=1) {
+	/*
+	 *	Add single user shell entry at the end.
+	 */
+	if(done == -1) {
+		if (fp == NULL || fgets(buf, sizeof(buf), fp) == NULL) {
+			done = 0;
+			/*
+			 *	See if we have a single user entry.
+			 */
+			for(old = newFamily; old; old = old->next)
+				if (strpbrk(old->rlevel, "S"))  break;
+			if (old == NULL)
+				snprintf(buf, sizeof(buf), "~~:S:wait:%s\n", SULOGIN);
+			else
+				continue;
+		}
+	} /* end if( done==-1) */
+	else if ( done == 0 ){
+		/* parse /etc/inittab.d and read all .tab files */
+		if(tabdir!=NULL){
+			if( (file_entry = readdir(tabdir))!=NULL){
+				/* ignore files not like *.tab */
+				if (!strcmp(file_entry->d_name, ".") || !strcmp(file_entry->d_name, ".."))
+					continue;
+				if (strlen(file_entry->d_name) < 5 || strcmp(file_entry->d_name + strlen(file_entry->d_name) - 4, ".tab"))
+					continue;
+				/*
+				 * initialize filename
+				 */
+				memset(f_name,0,sizeof(char)*272);
+				snprintf(f_name,272,"/etc/inittab.d/%s",file_entry->d_name);
+				initlog(L_VB, "Reading: %s",f_name);
+				/*
+				 * read file in inittab.d only one entry per file
+				 */
+				if ((fp_tab = fopen(f_name, "r")) == NULL)
+					continue;
+				/* read the file while the line contain comment */
+				while( fgets(buf, sizeof(buf), fp_tab) != NULL) {
+					for(p = buf; *p == ' ' || *p == '\t'; p++);
+					if (*p != '#' && *p != '\n')
+						break;
+				}
+				fclose(fp_tab);
+				/* do some checks */
+				if( buf == NULL ) 
+					continue;
+				if( strlen( p  ) == 0 )
+					continue;
+			} /* end of readdir, all is done */
+			else { 
+				done = 1;
+				continue;
+			}
+		} /* end of if(tabdir!=NULL) */
+		else {
+			done = 1;
+			continue;
+		}
+	} /* end of if ( done == 0 ) */
+	lineNo++;
+	/*
+	 *	Skip comments and empty lines
+	 */
+	for(p = buf; *p == ' ' || *p == '\t'; p++)
+		;
+	if (*p == '#' || *p == '\n') continue;
+
+	/*
+	 *	Decode the fields
+	 */
+	id =      strsep(&p, ":");
+	rlevel =  strsep(&p, ":");
+	action =  strsep(&p, ":");
+	process = strsep(&p, "\n");
+
+	/*
+	 *	Check if syntax is OK. Be very verbose here, to
+	 *	avoid newbie postings on comp.os.linux.setup :)
+	 */
+	err[0] = 0;
+	if (!id || !*id) strcpy(err, "missing id field");
+	if (!rlevel)     strcpy(err, "missing runlevel field");
+	if (!process)    strcpy(err, "missing process field");
+	if (!action || !*action)
+			strcpy(err, "missing action field");
+	if (id && strlen(id) > sizeof(utproto.ut_id))
+		sprintf(err, "id field too long (max %d characters)",
+			(int)sizeof(utproto.ut_id));
+	if (rlevel && strlen(rlevel) > 11)
+		strcpy(err, "rlevel field too long (max 11 characters)");
+	if (process && strlen(process) > 127)
+		strcpy(err, "process field too long (max 127 characters)");
+	if (action && strlen(action) > 32)
+		strcpy(err, "action field too long");
+	if (err[0] != 0) {
+		initlog(L_VB, "%s[%d]: %s", INITTAB, lineNo, err);
+		INITDBG(L_VB, "%s:%s:%s:%s", id, rlevel, action, process);
+		continue;
+	}
+  
+	/*
+	 *	Decode the "action" field
+	 */
+	actionNo = -1;
+	for(f = 0; actions[f].name; f++)
+		if (strcasecmp(action, actions[f].name) == 0) {
+			actionNo = actions[f].act;
+			break;
+		}
+	if (actionNo == -1) {
+		initlog(L_VB, "%s[%d]: %s: unknown action field",
+			INITTAB, lineNo, action);
+		continue;
+	}
+
+	/*
+	 *	See if the id field is unique
+	 */
+	for(old = newFamily; old; old = old->next) {
+		if(strcmp(old->id, id) == 0 && strcmp(id, "~~")) {
+			initlog(L_VB, "%s[%d]: duplicate ID field \"%s\"",
+				INITTAB, lineNo, id);
+			break;
+		}
+	}
+	if (old) continue;
+
+	/*
+	 *	Allocate a CHILD structure
+	 */
+	ch = imalloc(sizeof(CHILD));
+
+	/*
+	 *	And fill it in.
+	 */
+	ch->action = actionNo;
+	strncpy(ch->id, id, sizeof(utproto.ut_id) + 1); /* Hack for different libs. */
+	strncpy(ch->process, process, sizeof(ch->process) - 1);
+	if (rlevel[0]) {
+		for(f = 0; f < (int)sizeof(rlevel) - 1 && rlevel[f]; f++) {
+			ch->rlevel[f] = rlevel[f];
+			if (ch->rlevel[f] == 's') ch->rlevel[f] = 'S';
+		}
+		strncpy(ch->rlevel, rlevel, sizeof(ch->rlevel) - 1);
+	} else {
+		strcpy(ch->rlevel, "0123456789");
+		if (ISPOWER(ch->action))
+			strcpy(ch->rlevel, "S0123456789");
+	}
+	/*
+	 *	We have the fake runlevel '#' for SYSINIT  and
+	 *	'*' for BOOT and BOOTWAIT.
+	 */
+	if (ch->action == SYSINIT) strcpy(ch->rlevel, "#");
+	if (ch->action == BOOT || ch->action == BOOTWAIT)
+		strcpy(ch->rlevel, "*");
+
+	/*
+	 *	Now add it to the linked list. Special for powerfail.
+	 */
+	if (ISPOWER(ch->action)) {
+
+		/*
+		 *	Disable by default
+		 */
+		ch->flags |= XECUTED;
+
+		/*
+		 *	Tricky: insert at the front of the list..
+		 */
+		old = NULL;
+		for(i = newFamily; i; i = i->next) {
+			if (!ISPOWER(i->action)) break;
+			old = i;
+		}
+		/*
+		 *	Now add after entry "old"
+		 */
+		if (old) {
+			ch->next = i;
+			old->next = ch;
+			if (i == NULL) head = ch;
+		} else {
+			ch->next = newFamily;
+			newFamily = ch;
+			if (ch->next == NULL) head = ch;
+		}
+	} else {
+		/*
+		 *	Just add at end of the list
+		 */
+		if (ch->action == KBREQUEST) ch->flags |= XECUTED;
+		ch->next = NULL;
+		if (head)
+			head->next = ch;
+		else
+			newFamily = ch;
+		head = ch;
+	}
+
+	/*
+	 *	Walk through the old list comparing id fields
+	 */
+	for(old = family; old; old = old->next)
+		if (strcmp(old->id, ch->id) == 0) {
+			old->new = ch;
+			break;
+		}
+  }
+
+  /*
+   *	We're done.
+   */
+  if (fp) fclose(fp);
+  if(tabdir) closedir(tabdir);
+
+#ifdef __linux__
+  check_kernel_console();
+#endif
+
+  /*
+   *	Loop through the list of children, and see if they need to
+   *	be killed. 
+   */
+
+  INITDBG(L_VB, "Checking for children to kill");
+  for(round = 0; round < 2; round++) {
+    talk = 1;
+    for(ch = family; ch; ch = ch->next) {
+	ch->flags &= ~KILLME;
+
+	/*
+	 *	Is this line deleted?
+	 */
+	if (ch->new == NULL) ch->flags |= KILLME;
+
+	/*
+	 *	If the entry has changed, kill it anyway. Note that
+	 *	we do not check ch->process, only the "action" field.
+	 *	This way, you can turn an entry "off" immediately, but
+	 *	changes in the command line will only become effective
+	 *	after the running version has exited.
+	 */
+	if (ch->new && ch->action != ch->new->action) ch->flags |= KILLME;
+
+	/*
+	 *	Only BOOT processes may live in all levels
+	 */
+	if (ch->action != BOOT &&
+	    strchr(ch->rlevel, runlevel) == NULL) {
+		/*
+		 *	Ondemand procedures live always,
+		 *	except in single user
+		 */
+		if (runlevel == 'S' || !(ch->flags & DEMAND))
+			ch->flags |= KILLME;
+	}
+
+	/*
+	 *	Now, if this process may live note so in the new list
+	 */
+	if ((ch->flags & KILLME) == 0) {
+		ch->new->flags  = ch->flags;
+		ch->new->pid    = ch->pid;
+		ch->new->exstat = ch->exstat;
+		continue;
+	}
+
+
+	/*
+	 *	Is this process still around?
+	 */
+	if ((ch->flags & RUNNING) == 0) {
+		ch->flags &= ~KILLME;
+		continue;
+	}
+	INITDBG(L_VB, "Killing \"%s\"", ch->process);
+	switch(round) {
+		case 0: /* Send TERM signal */
+			if (talk)
+				initlog(L_CO,
+					"Sending processes configured via /etc/inittab the TERM signal");
+			kill(-(ch->pid), SIGTERM);
+			foundOne = 1;
+			break;
+		case 1: /* Send KILL signal and collect status */
+			if (talk)
+				initlog(L_CO,
+					"Sending processes configured via /etc/inittab the KILL signal");
+			kill(-(ch->pid), SIGKILL);
+			break;
+	}
+	talk = 0;
+	
+    }
+    /*
+     *	See if we have to wait sleep_time seconds
+     */
+    if (foundOne && round == 0) {
+	/*
+	 *	Yup, but check every 10 milliseconds if we still have children.
+         *      The f < 100 * sleep_time refers to sleep time in 10 millisecond chunks.
+	 */
+	for(f = 0; f < 100 * sleep_time; f++) {
+		for(ch = family; ch; ch = ch->next) {
+			if (!(ch->flags & KILLME)) continue;
+			if ((ch->flags & RUNNING) && !(ch->flags & ZOMBIE))
+				break;
+		}
+		if (ch == NULL) {
+			/*
+			 *	No running children, skip SIGKILL
+			 */
+			round = 1;
+			foundOne = 0; /* Skip the sleep below. */
+			break;
+		}
+		do_msleep(MINI_SLEEP);
+	}
+    }
+  }
+
+  /*
+   *	Now give all processes the chance to die and collect exit statuses.
+   */
+  if (foundOne) do_msleep(MINI_SLEEP);
+  for(ch = family; ch; ch = ch->next)
+	if (ch->flags & KILLME) {
+		if (!(ch->flags & ZOMBIE))
+		    initlog(L_CO, "Pid %d [id %s] seems to hang", ch->pid,
+				ch->id);
+		else {
+		    INITDBG(L_VB, "Updating utmp for pid %d [id %s]",
+				ch->pid, ch->id);
+		    ch->flags &= ~RUNNING;
+		    if (ch->process[0] != '+')
+		    	write_utmp_wtmp("", ch->id, ch->pid, DEAD_PROCESS, NULL);
+		}
+	}
+
+  /*
+   *	Both rounds done; clean up the list.
+   */
+  sigemptyset(&nmask);
+  sigaddset(&nmask, SIGCHLD);
+  sigprocmask(SIG_BLOCK, &nmask, &omask);
+  for(ch = family; ch; ch = old) {
+	old = ch->next;
+	free(ch);
+  }
+  family = newFamily;
+  for(ch = family; ch; ch = ch->next) ch->new = NULL;
+  newFamily = NULL;
+  sigprocmask(SIG_SETMASK, &omask, NULL);
+
+#ifdef INITLVL
+  /*
+   *	Dispose of INITLVL file.
+   */
+  if (lstat(INITLVL, &st) >= 0 && S_ISLNK(st.st_mode)) {
+	/*
+	 *	INITLVL is a symbolic link, so just truncate the file.
+	 */
+	close(open(INITLVL, O_WRONLY|O_TRUNC));
+  } else {
+	/*
+	 *	Delete INITLVL file.
+	 */
+  	unlink(INITLVL);
+  }
+#endif
+#ifdef INITLVL2
+  /*
+   *	Dispose of INITLVL2 file.
+   */
+  if (lstat(INITLVL2, &st) >= 0 && S_ISLNK(st.st_mode)) {
+	/*
+	 *	INITLVL2 is a symbolic link, so just truncate the file.
+	 */
+	close(open(INITLVL2, O_WRONLY|O_TRUNC));
+  } else {
+	/*
+	 *	Delete INITLVL2 file.
+	 */
+  	unlink(INITLVL2);
+  }
+#endif
+}
+
+/*
+ *	Walk through the family list and start up children.
+ *	The entries that do not belong here at all are removed
+ *	from the list.
+ */
+static
+void start_if_needed(void)
+{
+	CHILD *ch;		/* Pointer to child */
+	int delete;		/* Delete this entry from list? */
+
+	INITDBG(L_VB, "Checking for children to start");
+
+	for(ch = family; ch; ch = ch->next) {
+
+#if DEBUG
+		if (ch->rlevel[0] == 'C') {
+			INITDBG(L_VB, "%s: flags %d", ch->process, ch->flags);
+		}
+#endif
+
+		/* Are we waiting for this process? Then quit here. */
+		if (ch->flags & WAITING) break;
+
+		/* Already running? OK, don't touch it */
+		if (ch->flags & RUNNING) continue;
+
+		/* See if we have to start it up */
+		delete = 1;
+		if (strchr(ch->rlevel, runlevel) ||
+		    ((ch->flags & DEMAND) && !strchr("#*Ss", runlevel))) {
+			startup(ch);
+			delete = 0;
+		}
+
+		if (delete) {
+			/* is this OK? */
+			ch->flags &= ~(RUNNING|WAITING);
+			if (!ISPOWER(ch->action) && ch->action != KBREQUEST)
+				ch->flags &= ~XECUTED;
+			ch->pid = 0;
+		} else
+			/* Do we have to wait for this process? */
+			if (ch->flags & WAITING) break;
+	}
+	/* Done. */
+}
+
+/*
+ *	Ask the user on the console for a runlevel
+ */
+static
+int ask_runlevel(void)
+{
+	const char	prompt[] = "\nEnter runlevel: ";
+	char		buf[8];
+	int		lvl = -1;
+	int		fd;
+
+	console_stty();
+	fd = console_open(O_RDWR|O_NOCTTY);
+
+	if (fd < 0) return('S');
+
+	while(!strchr("0123456789S", lvl)) {
+		safe_write(fd, prompt, sizeof(prompt) - 1);
+		if (read(fd, buf, sizeof(buf)) <= 0)
+			buf[0] = 0;
+  		if (buf[0] != 0 && (buf[1] == '\r' || buf[1] == '\n'))
+			lvl = buf[0];
+		if (islower(lvl)) lvl = toupper(lvl);
+	}
+	close(fd);
+	return lvl;
+}
+
+/*
+ *	Search the INITTAB file for the 'initdefault' field, with the default
+ *	runlevel. If this fails, ask the user to supply a runlevel.
+ */
+static
+int get_init_default(void)
+{
+	CHILD *ch;
+	int lvl = -1;
+	char *p;
+
+	/*
+	 *	Look for initdefault.
+	 */
+	for(ch = family; ch; ch = ch->next)
+		if (ch->action == INITDEFAULT) {
+			p = ch->rlevel;
+			while(*p) {
+				if (*p > lvl) lvl = *p;
+				p++;
+			}
+			break;
+		}
+	/*
+	 *	See if level is valid
+	 */
+	if (lvl > 0) {
+		if (islower(lvl)) lvl = toupper(lvl);
+		if (strchr("0123456789S", lvl) == NULL) {
+			initlog(L_VB,
+				"Initdefault level '%c' is invalid", lvl);
+			lvl = 0;
+		}
+	}
+	/*
+	 *	Ask for runlevel on console if needed.
+	 */
+	if (lvl <= 0) lvl = ask_runlevel();
+
+	/*
+	 *	Log the fact that we have a runlevel now.
+	 */
+        Write_Runlevel_Log(lvl);
+	return lvl;
+}
+
+
+/*
+ *	We got signaled.
+ *
+ *	Do actions for the new level. If we are compatible with
+ *	the "old" INITLVL and arg == 0, try to read the new
+ *	runlevel from that file first.
+ */
+static
+int read_level(int arg)
+{
+	CHILD		*ch;			/* Walk through list */
+	unsigned char	foo = 'X';		/* Contents of INITLVL */
+	int		ok = 1;
+#ifdef INITLVL
+	FILE		*fp;
+	struct stat	stt;
+	int		st;
+#endif
+
+	if (arg) foo = arg;
+
+#ifdef INITLVL
+	ok = 0;
+
+	if (arg == 0) {
+		fp = NULL;
+		if (stat(INITLVL, &stt) != 0 || stt.st_size != 0L)
+			fp = fopen(INITLVL, "r");
+#ifdef INITLVL2
+		if (fp == NULL &&
+		    (stat(INITLVL2, &stt) != 0 || stt.st_size != 0L))
+			fp = fopen(INITLVL2, "r");
+#endif
+		if (fp == NULL) {
+			/* INITLVL file empty or not there - act as 'init q' */
+			initlog(L_SY, "Re-reading inittab");
+  			return(runlevel);
+		}
+		ok = fscanf(fp, "%c %d", &foo, &st);
+		fclose(fp);
+	} else {
+		/* We go to the new runlevel passed as an argument. */
+		foo = arg;
+		ok = 1;
+	}
+	if (ok == 2) sleep_time = st;
+
+#endif /* INITLVL */
+
+	if (islower(foo)) foo = toupper(foo);
+	if (ok < 1 || ok > 2 || strchr("QS0123456789ABCU", foo) == NULL) {
+ 		initlog(L_VB, "bad runlevel: %c", foo);
+  		return runlevel;
+	}
+
+	/* Log this action */
+	switch(foo) {
+		case 'S':
+  			initlog(L_VB, "Going single user");
+			break;
+		case 'Q':
+			initlog(L_SY, "Re-reading inittab");
+			break;
+		case 'A':
+		case 'B':
+		case 'C':
+			initlog(L_SY,
+				"Activating demand-procedures for '%c'", foo);
+			break;
+		case 'U':
+			initlog(L_SY, "Trying to re-exec init");
+			return 'U';
+		default:
+		  	initlog(L_VB, "Switching to runlevel: %c", foo);
+	}
+
+	if (foo == 'Q') {
+#if defined(SIGINT_ONLYONCE) && (SIGINT_ONLYONCE == 1)
+		/* Re-enable signal from keyboard */
+		struct sigaction sa;
+		SETSIG(sa, SIGINT, signal_handler, 0);
+#endif
+		return runlevel;
+	}
+
+	/* Check if this is a runlevel a, b or c */
+	if (strchr("ABC", foo)) {
+		if (runlevel == 'S') return(runlevel);
+
+		/* Read inittab again first! */
+		read_inittab();
+
+  		/* Mark those special tasks */
+		for(ch = family; ch; ch = ch->next)
+			if (strchr(ch->rlevel, foo) != NULL ||
+			    strchr(ch->rlevel, tolower(foo)) != NULL) {
+				ch->flags |= DEMAND;
+				ch->flags &= ~XECUTED;
+				INITDBG(L_VB,
+					"Marking (%s) as ondemand, flags %d",
+					ch->id, ch->flags);
+			}
+  		return runlevel;
+	}
+
+	/* Store both the old and the new runlevel. */
+	wrote_utmp_rlevel = 0;
+	wrote_wtmp_rlevel = 0;
+	write_utmp_wtmp("runlevel", "~~", foo + 256*runlevel, RUN_LVL, "~");
+	thislevel = foo;
+	prevlevel = runlevel;
+        Write_Runlevel_Log(runlevel);
+	return foo;
+}
+
+
+/*
+ *	This procedure is called after every signal (SIGHUP, SIGALRM..)
+ *
+ *	Only clear the 'failing' flag if the process is sleeping
+ *	longer than 5 minutes, or inittab was read again due
+ *	to user interaction.
+ */
+static
+void fail_check(void)
+{
+	CHILD	*ch;			/* Pointer to child structure */
+	time_t	t;			/* System time */
+	time_t	next_alarm = 0;		/* When to set next alarm */
+
+	time(&t);
+
+	for(ch = family; ch; ch = ch->next) {
+
+		if (ch->flags & FAILING) {
+			/* Can we free this sucker? */
+			if (ch->tm + SLEEPTIME < t) {
+				ch->flags &= ~FAILING;
+				ch->count = 0;
+				ch->tm = 0;
+			} else {
+				/* No, we'll look again later */
+				if (next_alarm == 0 ||
+				    ch->tm + SLEEPTIME > next_alarm)
+					next_alarm = ch->tm + SLEEPTIME;
+			}
+		}
+	}
+	if (next_alarm) {
+		next_alarm -= t;
+		if (next_alarm < 1) next_alarm = 1;
+		alarm(next_alarm);
+	}
+}
+
+/* Set all 'Fail' timers to 0 */
+static
+void fail_cancel(void)
+{
+	CHILD *ch;
+
+	for(ch = family; ch; ch = ch->next) {
+		ch->count = 0;
+		ch->tm = 0;
+		ch->flags &= ~FAILING;
+	}
+}
+
+/*
+ *	Start up powerfail entries.
+ */
+static
+void do_power_fail(int pwrstat)
+{
+	CHILD *ch;
+
+	/*
+	 *	Tell powerwait & powerfail entries to start up
+	 */
+	for (ch = family; ch; ch = ch->next) {
+		if (pwrstat == 'O') {
+			/*
+		 	 *	The power is OK again.
+		 	 */
+			if (ch->action == POWEROKWAIT)
+				ch->flags &= ~XECUTED;
+		} else if (pwrstat == 'L') {
+			/*
+			 *	Low battery, shut down now.
+			 */
+			if (ch->action == POWERFAILNOW)
+				ch->flags &= ~XECUTED;
+		} else {
+			/*
+			 *	Power is failing, shutdown imminent
+			 */
+			if (ch->action == POWERFAIL || ch->action == POWERWAIT)
+				ch->flags &= ~XECUTED;
+		}
+	}
+}
+
+/*
+ *	Check for state-pipe presence
+ */
+static
+int check_pipe(int fd)
+{
+	struct timeval	t;
+	fd_set		s;
+	char		signature[8];
+
+	FD_ZERO(&s);
+	FD_SET(fd, &s);
+	t.tv_sec = t.tv_usec = 0;
+
+	if (select(fd+1, &s, NULL, NULL, &t) != 1)
+		return 0;
+	if (read(fd, signature, 8) != 8)
+		 return 0;
+	return strncmp(Signature, signature, 8) == 0;
+}
+
+/*
+ *	 Make a state-pipe.
+ */
+static
+int make_pipe(int fd)
+{
+	int fds[2];
+
+	if (pipe(fds)) {
+		initlog(L_VB, "pipe: %m");
+		return -1;
+	}
+	dup2(fds[0], fd);
+	close(fds[0]);
+	fcntl(fds[1], F_SETFD, 1);
+	fcntl(fd, F_SETFD, 0);
+	safe_write(fds[1], Signature, 8);
+
+	return fds[1];
+}
+
+/*
+ *	Attempt to re-exec.
+ *      Renaming to my_re_exec since re_exec is now a common function name
+ *      which conflicts.
+ */
+static
+void my_re_exec(void)
+{
+	CHILD		*ch;
+	sigset_t	mask, oldset;
+	pid_t		pid;
+	char		**env;
+	int		fd;
+
+	if (strchr("S0123456",runlevel) == NULL)
+		return;
+
+	/*
+	 *	Reset the alarm, and block all signals.
+	 */
+	alarm(0);
+	sigfillset(&mask);
+	sigprocmask(SIG_BLOCK, &mask, &oldset);
+
+	/*
+	 *	construct a pipe fd --> STATE_PIPE and write a signature
+	 */
+	if ((fd = make_pipe(STATE_PIPE)) < 0) {
+		sigprocmask(SIG_SETMASK, &oldset, NULL);
+		initlog(L_CO, "Attempt to re-exec failed");
+	}
+
+	fail_cancel();
+	if (pipe_fd >= 0) 
+          close(pipe_fd);
+   	pipe_fd = -1;
+	DELSET(got_signals, SIGCHLD);
+	DELSET(got_signals, SIGHUP);
+	DELSET(got_signals, SIGUSR1);
+	DELSET(got_signals, SIGUSR2);
+
+	/*
+	 *	That should be cleaned.
+	 */
+	for(ch = family; ch; ch = ch->next)
+	    if (ch->flags & ZOMBIE) {
+		INITDBG(L_VB, "Child died, PID= %d", ch->pid);
+		ch->flags &= ~(RUNNING|ZOMBIE|WAITING);
+		if (ch->process[0] != '+')
+			write_utmp_wtmp("", ch->id, ch->pid, DEAD_PROCESS, NULL);
+	    }
+
+	if ((pid = fork()) == 0) {
+		/*
+		 *	Child sends state information to the parent.
+		 */
+		send_state(fd);
+		exit(0);
+	}
+
+	/*
+	 *	The existing init process execs a new init binary.
+	 */
+	env = init_buildenv(0);
+	execle(myname, myname, "--init", NULL, env);
+
+	/*
+	 *	We shouldn't be here, something failed. 
+	 *	Close the state pipe, unblock signals and return.
+	 */
+	init_freeenv(env);
+	close(fd);
+	close(STATE_PIPE);
+	sigprocmask(SIG_SETMASK, &oldset, NULL);
+	initlog(L_CO, "Attempt to re-exec failed");
+}
+
+/*
+ *	Redo utmp/wtmp entries if required or requested
+ *	Check for written records and size of utmp
+ */
+static
+void redo_utmp_wtmp(void)
+{
+	struct stat ustat;
+	const int ret = stat(UTMP_FILE, &ustat);
+
+	if ((ret < 0) || (ustat.st_size == 0))
+		wrote_utmp_rlevel = wrote_utmp_reboot = 0;
+
+	if ((wrote_wtmp_reboot == 0) || (wrote_utmp_reboot == 0))
+		write_utmp_wtmp("reboot", "~~", 0, BOOT_TIME, "~");
+
+	if ((wrote_wtmp_rlevel == 0) || (wrote_utmp_rlevel == 0))
+		write_utmp_wtmp("runlevel", "~~", thislevel + 256 * prevlevel, RUN_LVL, "~");
+}
+
+/*
+ *	We got a change runlevel request through the
+ *	init.fifo. Process it.
+ */
+static
+void fifo_new_level(int level)
+{
+#if CHANGE_WAIT
+	CHILD	*ch;
+#endif
+	int	oldlevel;
+
+	if (level == runlevel) return;
+
+#if CHANGE_WAIT
+	/* Are we waiting for a child? */
+	for(ch = family; ch; ch = ch->next)
+		if (ch->flags & WAITING) break;
+	if (ch == NULL)
+#endif
+	{
+		/* We need to go into a new runlevel */
+		oldlevel = runlevel;
+		runlevel = read_level(level);
+		if (runlevel == 'U') {
+			runlevel = oldlevel;
+			my_re_exec();
+		} else {
+			if (oldlevel != 'S' && runlevel == 'S') console_stty();
+			if (runlevel == '6' || runlevel == '0' ||
+			    runlevel == '1') console_stty();
+			if (runlevel  > '1' && runlevel  < '6') redo_utmp_wtmp();
+			read_inittab();
+			fail_cancel();
+			setproctitle("init [%c]", (int)runlevel);
+		}
+	}
+        Write_Runlevel_Log(runlevel);
+}
+
+
+/*
+ *	Set/unset environment variables. The variables are
+ *	encoded as KEY=VAL\0KEY=VAL\0\0. With "=VAL" it means
+ *	setenv, without it means unsetenv.
+ */
+static
+void initcmd_setenv(char *data, int size)
+{
+	char		*env, *p, *e;
+	size_t		sz;
+	int		i, eq;
+
+	e = data + size;
+
+	while (*data && data < e) {
+		for (p = data; *p && p < e; p++)
+			;
+		if (*p) break;
+		env = data;
+		data = ++p;
+
+		/*
+		 *	We only allow INIT_* to be set.
+		 */
+		if (strncmp(env, "INIT_", 5) != 0)
+			continue;
+
+		sz = strcspn(env, "=");
+		eq = (env[sz] == '=');
+
+		/*initlog(L_SY, "init_setenv: %s, %d, %d", env, eq, sz);*/
+
+		/* Free existing vars. */
+		for (i = 0; i < NR_EXTRA_ENV; i++) {
+			if (extra_env[i] == NULL)
+				continue;
+			if (sz != strcspn(extra_env[i], "="))
+				continue;
+			if (strncmp(extra_env[i], env, sz) == 0) {
+				free(extra_env[i]);
+				extra_env[i] = NULL;
+			}
+		}
+
+		if (eq == 0)
+			continue;
+
+		/* Set new vars if needed. */
+		for (i = 0; i < NR_EXTRA_ENV; i++) {
+			if (extra_env[i] == NULL) {
+				extra_env[i] = istrdup(env);
+				break;
+			}
+		}
+	}
+}
+
+
+/*
+ *	Read from the init FIFO. Processes like telnetd and rlogind can
+ *	ask us to create login processes on their behalf.
+ */
+static
+void check_init_fifo(void)
+{
+  struct init_request	request;
+  struct timeval	tv;
+  struct stat		st, st2;
+  fd_set		fds;
+  int			n;
+  int			quit = 0;
+
+  /*
+   *	First, try to create /run/initctl if not present.
+   */
+  if (stat(INIT_FIFO, &st2) < 0 && errno == ENOENT)
+	(void)mkfifo(INIT_FIFO, 0600);
+
+  /*
+   *	If /run/initctl is open, stat the file to see if it
+   *	is still the _same_ inode.
+   */
+  if (pipe_fd >= 0) {
+	fstat(pipe_fd, &st);
+	if (stat(INIT_FIFO, &st2) < 0 ||
+	    st.st_dev != st2.st_dev ||
+	    st.st_ino != st2.st_ino) {
+		close(pipe_fd);
+		pipe_fd = -1;
+	}
+  }
+
+  /*
+   *	Now finally try to open /run/initctl if pipe_fd is -1
+   *    if it is -2, then we leave it closed
+   */
+  if (pipe_fd == -1) {
+	if ((pipe_fd = open(INIT_FIFO, O_RDWR|O_NONBLOCK)) >= 0) {
+		fstat(pipe_fd, &st);
+		if (!S_ISFIFO(st.st_mode)) {
+			initlog(L_VB, "%s is not a fifo", INIT_FIFO);
+			close(pipe_fd);
+			pipe_fd = -1;
+		}
+	}
+	if (pipe_fd >= 0) {
+		/*
+		 *	Don't use fd's 0, 1 or 2.
+		 */
+		(void) dup2(pipe_fd, PIPE_FD);
+		close(pipe_fd);
+		pipe_fd = PIPE_FD;
+
+		/*
+		 *	Return to caller - we'll be back later.
+		 */
+	}
+  }
+
+  /* Wait for data to appear, _if_ the pipe was opened. */
+  if (pipe_fd >= 0) { 
+     while(!quit) {
+
+	/* Do select, return on EINTR. */
+	FD_ZERO(&fds);
+	FD_SET(pipe_fd, &fds);
+	tv.tv_sec = 5;
+	tv.tv_usec = 0;
+	n = select(pipe_fd + 1, &fds, NULL, NULL, &tv);
+	if (n <= 0) {
+		if (n == 0 || errno == EINTR) return;
+		continue;
+	}
+
+	/* Read the data, return on EINTR. */
+	n = read(pipe_fd, &request, sizeof(request));
+	if (n == 0) {
+		/*
+		 *	End of file. This can't happen under Linux (because
+		 *	the pipe is opened O_RDWR - see select() in the
+		 *	kernel) but you never know...
+		 */
+		close(pipe_fd);
+		pipe_fd = -1;
+		return;
+	}
+	if (n <= 0) {
+		if (errno == EINTR) return;
+		initlog(L_VB, "error reading initrequest");
+		continue;
+	}
+
+	/*
+	 *	This is a convenient point to also try to
+	 *	find the console device or check if it changed.
+	 */
+	console_init();
+
+	/*
+	 *	Process request.
+	 */
+	if (request.magic != INIT_MAGIC || n != sizeof(request)) {
+		initlog(L_VB, "got bogus initrequest");
+		continue;
+	}
+	switch(request.cmd) {
+		case INIT_CMD_RUNLVL:
+			sleep_time = request.sleeptime;
+			fifo_new_level(request.runlevel);
+			quit = 1;
+			break;
+		case INIT_CMD_POWERFAIL:
+			sleep_time = request.sleeptime;
+			do_power_fail('F');
+			quit = 1;
+			break;
+		case INIT_CMD_POWERFAILNOW:
+			sleep_time = request.sleeptime;
+			do_power_fail('L');
+			quit = 1;
+			break;
+		case INIT_CMD_POWEROK:
+			sleep_time = request.sleeptime;
+			do_power_fail('O');
+			quit = 1;
+			break;
+		case INIT_CMD_SETENV:
+			initcmd_setenv(request.i.data, sizeof(request.i.data));
+			break;
+		default:
+			initlog(L_VB, "got unimplemented initrequest.");
+			break;
+	}   /* end of switch */
+    }       /* end of while loop not quitting */
+  }         /* end of if the pipe is open */
+  /*
+   *	We come here if the pipe couldn't be opened.
+   */
+  if (pipe_fd == -1) pause();
+
+}
+
+
+/*
+ *	This function is used in the transition
+ *	sysinit (-> single user) boot -> multi-user.
+ */
+static
+void boot_transitions()
+{
+  CHILD		*ch;
+  static int	newlevel = 0;
+  static int	warn = 1;
+  int		loglevel;
+  int		oldlevel;
+
+  /* Check if there is something to wait for! */
+  for( ch = family; ch; ch = ch->next )
+	if ((ch->flags & RUNNING) && ch->action != BOOT) break;
+     
+  if (ch == NULL) {
+	/* No processes left in this level, proceed to next level. */
+	loglevel = -1;
+	oldlevel = 'N';
+	switch(runlevel) {
+		case '#': /* SYSINIT -> BOOT */
+			INITDBG(L_VB, "SYSINIT -> BOOT");
+
+			/* Write a boot record. */
+			wrote_utmp_reboot = 0;
+			wrote_wtmp_reboot = 0;
+			write_utmp_wtmp("reboot", "~~", 0, BOOT_TIME, "~");
+
+  			/* Get our run level */
+  			newlevel = dfl_level ? dfl_level : get_init_default();
+			if (newlevel == 'S') {
+				runlevel = newlevel;
+				/* Not really 'S' but show anyway. */
+				setproctitle("init [S]");
+			} else
+				runlevel = '*';
+			break;
+		case '*': /* BOOT -> NORMAL */
+			INITDBG(L_VB, "BOOT -> NORMAL");
+			if (runlevel != newlevel)
+				loglevel = newlevel;
+			runlevel = newlevel;
+			did_boot = 1;
+			warn = 1;
+			break;
+		case 'S': /* Ended SU mode */
+		case 's':
+			INITDBG(L_VB, "END SU MODE");
+			newlevel = get_init_default();
+			if (!did_boot && newlevel != 'S')
+				runlevel = '*';
+			else {
+				if (runlevel != newlevel)
+					loglevel = newlevel;
+				runlevel = newlevel;
+				oldlevel = 'S';
+			}
+			warn = 1;
+			for(ch = family; ch; ch = ch->next)
+			    if (strcmp(ch->rlevel, "S") == 0)
+				ch->flags &= ~(FAILING|WAITING|XECUTED);
+			break;
+		default:
+			if (warn)
+			  initlog(L_VB,
+				"no more processes left in this runlevel");
+			warn = 0;
+			loglevel = -1;
+			if (got_signals == 0)
+				check_init_fifo();
+			break;
+	}
+	if (loglevel > 0) {
+		initlog(L_VB, "Entering runlevel: %c", runlevel);
+		wrote_utmp_rlevel = 0;
+		wrote_wtmp_rlevel = 0;
+		write_utmp_wtmp("runlevel", "~~", runlevel + 256 * oldlevel, RUN_LVL, "~");
+		thislevel = runlevel;
+		prevlevel = oldlevel;
+		setproctitle("init [%c]", (int)runlevel);
+	}
+        Write_Runlevel_Log(runlevel);
+  }
+}
+
+/*
+ *	Init got hit by a signal. See which signal it is,
+ *	and act accordingly.
+ */
+static
+void process_signals()
+{
+  CHILD		*ch;
+  int		pwrstat;
+  int		oldlevel;
+  int		fd;
+  char		c;
+
+  if (ISMEMBER(got_signals, SIGPWR)) {
+	INITDBG(L_VB, "got SIGPWR");
+	/* See _what_ kind of SIGPWR this is. */
+	pwrstat = 0;
+	if ((fd = open(PWRSTAT, O_RDONLY)) >= 0) {
+		if (read(fd, &c, 1) != 1)
+			c = 0;
+		pwrstat = c;
+		close(fd);
+		unlink(PWRSTAT);
+	} else if ((fd = open(PWRSTAT_OLD, O_RDONLY)) >= 0) {
+		/* Path changed 2010-03-20.  Look for the old path for a while. */
+		initlog(L_VB, "warning: found obsolete path %s, use %s instead",
+			PWRSTAT_OLD, PWRSTAT);
+		if (read(fd, &c, 1) != 1)
+			c = 0;
+		pwrstat = c;
+		close(fd);
+		unlink(PWRSTAT_OLD);
+        }
+	do_power_fail(pwrstat);
+	DELSET(got_signals, SIGPWR);
+  }
+
+  if (ISMEMBER(got_signals, SIGINT)) {
+#if defined(SIGINT_ONLYONCE) && (SIGINT_ONLYONCE == 1)
+	/* Ignore any further signal from keyboard */
+	struct sigaction sa;
+	SETSIG(sa, SIGINT, SIG_IGN, SA_RESTART);
+#endif
+	INITDBG(L_VB, "got SIGINT");
+	/* Tell ctrlaltdel entry to start up */
+	for(ch = family; ch; ch = ch->next)
+		if (ch->action == CTRLALTDEL)
+			ch->flags &= ~XECUTED;
+	DELSET(got_signals, SIGINT);
+  }
+
+  if (ISMEMBER(got_signals, SIGWINCH)) {
+	INITDBG(L_VB, "got SIGWINCH");
+	/* Tell kbrequest entry to start up */
+	for(ch = family; ch; ch = ch->next)
+		if (ch->action == KBREQUEST)
+			ch->flags &= ~XECUTED;
+	DELSET(got_signals, SIGWINCH);
+  }
+
+  if (ISMEMBER(got_signals, SIGALRM)) {
+	INITDBG(L_VB, "got SIGALRM");
+	/* The timer went off: check it out */
+	DELSET(got_signals, SIGALRM);
+  }
+
+  if (ISMEMBER(got_signals, SIGCHLD)) {
+	INITDBG(L_VB, "got SIGCHLD");
+	/* First set flag to 0 */
+	DELSET(got_signals, SIGCHLD);
+
+	/* See which child this was */
+	for(ch = family; ch; ch = ch->next)
+	    if (ch->flags & ZOMBIE) {
+		INITDBG(L_VB, "Child died, PID= %d", ch->pid);
+		ch->flags &= ~(RUNNING|ZOMBIE|WAITING);
+		if (ch->process[0] != '+')
+			write_utmp_wtmp("", ch->id, ch->pid, DEAD_PROCESS, NULL);
+	    }
+
+  }
+
+  if (ISMEMBER(got_signals, SIGHUP)) {
+	INITDBG(L_VB, "got SIGHUP");
+#if CHANGE_WAIT
+	/* Are we waiting for a child? */
+	for(ch = family; ch; ch = ch->next)
+		if (ch->flags & WAITING) break;
+	if (ch == NULL)
+#endif
+	{
+		/* We need to go into a new runlevel */
+		oldlevel = runlevel;
+#ifdef INITLVL
+		runlevel = read_level(0);
+#endif
+		if (runlevel == 'U') {
+			runlevel = oldlevel;
+			my_re_exec();
+		} else {
+			if (oldlevel != 'S' && runlevel == 'S') console_stty();
+			if (runlevel == '6' || runlevel == '0' ||
+			    runlevel == '1') console_stty();
+			read_inittab();
+			fail_cancel();
+			setproctitle("init [%c]", (int)runlevel);
+			DELSET(got_signals, SIGHUP);
+		}
+                Write_Runlevel_Log(runlevel);
+	}
+  }
+  if (ISMEMBER(got_signals, SIGUSR1)) {
+	/*
+	 *	SIGUSR1 means close and reopen /run/initctl
+	 */
+	INITDBG(L_VB, "got SIGUSR1");
+	if (pipe_fd)
+           close(pipe_fd);
+	pipe_fd = -1;
+	DELSET(got_signals, SIGUSR1);
+  }
+  else if (ISMEMBER(got_signals, SIGUSR2)) {
+       /* SIGUSR1 mean close the pipe and leave it closed */
+       INITDBG(L_VB, "got SIGUSR2");
+       if (pipe_fd)
+           close(pipe_fd);
+       pipe_fd = -2;
+       DELSET(got_signals, SIGUSR2);
+  }
+}
+
+/*
+ *	The main loop
+ */ 
+static
+void init_main(void)
+{
+  CHILD			*ch;
+  struct sigaction	sa;
+  sigset_t		sgt;
+  int			f, st;
+
+  if (!reload) {
+  
+#if INITDEBUG
+	/*
+	 * Fork so we can debug the init process.
+	 */
+	if ((f = fork()) > 0) {
+		static const char killmsg[] = "PRNT: init killed.\r\n";
+		pid_t rc;
+
+		while((rc = wait(&st)) != f)
+			if (rc < 0 && errno == ECHILD)
+				break;
+		safe_write(1, killmsg, sizeof(killmsg) - 1);
+		while(1) pause();
+	}
+#endif
+
+#ifdef __linux__
+	/*
+	 *	Tell the kernel to send us SIGINT when CTRL-ALT-DEL
+	 *	is pressed, and that we want to handle keyboard signals.
+	 */
+	init_reboot(BMAGIC_SOFT);
+	if ((f = open(VT_MASTER, O_RDWR | O_NOCTTY)) >= 0) {
+		(void) ioctl(f, KDSIGACCEPT, SIGWINCH);
+		close(f);
+	} else
+		(void) ioctl(0, KDSIGACCEPT, SIGWINCH);
+#endif
+
+	/*
+	 *	Ignore all signals.
+	 */
+	for(f = 1; f <= NSIG; f++)
+		SETSIG(sa, f, SIG_IGN, SA_RESTART);
+  }
+
+  SETSIG(sa, SIGALRM,  signal_handler, 0);
+  SETSIG(sa, SIGHUP,   signal_handler, 0);
+  SETSIG(sa, SIGINT,   signal_handler, 0);
+  SETSIG(sa, SIGCHLD,  chld_handler, SA_RESTART);
+  SETSIG(sa, SIGPWR,   signal_handler, 0);
+  SETSIG(sa, SIGWINCH, signal_handler, 0);
+  SETSIG(sa, SIGUSR1,  signal_handler, 0);
+  SETSIG(sa, SIGUSR2,  signal_handler, 0);
+  SETSIG(sa, SIGSTOP,  stop_handler, SA_RESTART);
+  SETSIG(sa, SIGTSTP,  stop_handler, SA_RESTART);
+  SETSIG(sa, SIGCONT,  cont_handler, SA_RESTART);
+  SETSIG(sa, SIGSEGV,  (void (*)(int))segv_handler, SA_RESTART);
+
+  console_init();
+
+  if (!reload) {
+	int fd;
+
+  	/* Close whatever files are open, and reset the console. */
+	close(0);
+	close(1);
+	close(2);
+  	console_stty();
+  	setsid();
+
+  	/*
+	 *	Set default PATH variable.
+	 */
+  	setenv("PATH", PATH_DEFAULT, 1 /* Overwrite */);
+
+  	/*
+	 *	Initialize /var/run/utmp (only works if /var is on
+	 *	root and mounted rw)
+	 */
+	if ((fd = open(UTMP_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0644)) >= 0)
+		close(fd);
+
+  	/*
+	 *	Say hello to the world
+	 */
+  	initlog(L_CO, bootmsg, "booting");
+
+  	/*
+	 *	See if we have to start an emergency shell.
+	 */
+	if (emerg_shell) {
+		pid_t rc;
+		SETSIG(sa, SIGCHLD, SIG_DFL, SA_RESTART);
+		if (spawn(&ch_emerg, &f) > 0) {
+			while((rc = wait(&st)) != f)
+				if (rc < 0 && errno == ECHILD)
+					break;
+		}
+  		SETSIG(sa, SIGCHLD,  chld_handler, SA_RESTART);
+  	}
+
+  	/*
+	 *	Start normal boot procedure.
+	 */
+  	runlevel = '#';
+  	read_inittab();
+  
+  } else {
+	/*
+	 *	Restart: unblock signals and let the show go on
+	 */
+	initlog(L_CO, bootmsg, "reloading");
+	sigfillset(&sgt);
+	sigprocmask(SIG_UNBLOCK, &sgt, NULL);
+
+  	/*
+	 *	Set default PATH variable.
+	 */
+  	setenv("PATH", PATH_DEFAULT, 0 /* Don't overwrite */);
+  }
+  start_if_needed();
+
+  while(1) {
+
+     /* See if we need to make the boot transitions. */
+     boot_transitions();
+     INITDBG(L_VB, "init_main: waiting..");
+
+     /* Check if there are processes to be waited on. */
+     for(ch = family; ch; ch = ch->next)
+	if ((ch->flags & RUNNING) && ch->action != BOOT) break;
+
+#if CHANGE_WAIT
+     /* Wait until we get hit by some signal. */
+     while (ch != NULL && got_signals == 0) {
+	if (ISMEMBER(got_signals, SIGHUP)) {
+		/* See if there are processes to be waited on. */
+		for(ch = family; ch; ch = ch->next)
+			if (ch->flags & WAITING) break;
+	}
+	if (ch != NULL) check_init_fifo();
+     }
+#else /* CHANGE_WAIT */
+     if (ch != NULL && got_signals == 0) check_init_fifo();
+#endif /* CHANGE_WAIT */
+
+     /* Check the 'failing' flags */
+     fail_check();
+
+     /* Process any signals. */
+     process_signals();
+
+     /* See what we need to start up (again) */
+     start_if_needed();
+  }
+  /*NOTREACHED*/
+}
+
+/*
+ * Tell the user about the syntax we expect.
+ */
+static
+void usage(char *s)
+{
+	fprintf(stderr, "Usage: %s {-e VAR[=VAL] | [-t SECONDS] {0|1|2|3|4|5|6|S|s|Q|q|A|a|B|b|C|c|U|u}}\n", s);
+	exit(1);
+}
+
+static
+int telinit(char *progname, int argc, char **argv)
+{
+#ifdef TELINIT_USES_INITLVL
+	FILE			*fp;
+#endif
+	struct init_request	request;
+	struct sigaction	sa;
+	int			f, fd, l;
+	char			*env = NULL;
+
+	memset(&request, 0, sizeof(request));
+	request.magic     = INIT_MAGIC;
+
+	while ((f = getopt(argc, argv, "t:e:")) != EOF) switch(f) {
+		case 't':
+			sleep_time = atoi(optarg);
+			break;
+		case 'e':
+			if (env == NULL)
+				env = request.i.data;
+			l = strlen(optarg);
+			if (env + l + 2 > request.i.data + sizeof(request.i.data)) {
+				fprintf(stderr, "%s: -e option data "
+					"too large\n", progname);
+				exit(1);
+			}
+			memcpy(env, optarg, l);
+			env += l;
+			*env++ = 0;
+			break;
+		default:
+			usage(progname);
+			break;
+	}
+
+	if (env) *env++ = 0;
+
+	if (env) {
+		if (argc != optind)
+			usage(progname);
+		request.cmd = INIT_CMD_SETENV;
+	} else {
+		if (argc - optind != 1 || strlen(argv[optind]) != 1)
+			usage(progname);
+		if (!strchr("0123456789SsQqAaBbCcUu", argv[optind][0]))
+			usage(progname);
+		request.cmd = INIT_CMD_RUNLVL;
+		request.runlevel  = argv[optind][0];
+		request.sleeptime = sleep_time;
+	}
+
+	/* Change to the root directory. */
+	if (0 != chdir("/"))
+		initlog(L_VB, "unable to chdir to /: %s",
+			strerror(errno));
+
+	/* Open the fifo and write a command. */
+	/* Make sure we don't hang on opening /run/initctl */
+	SETSIG(sa, SIGALRM, signal_handler, 0);
+	alarm(3);
+	if ((fd = open(INIT_FIFO, O_WRONLY)) >= 0) {
+		ssize_t p = 0;
+		size_t s  = sizeof(request);
+		void *ptr = &request;
+
+		while (s > 0) {
+			p = write(fd, ptr, s);
+			if (p < 0) {
+				if (errno == EINTR || errno == EAGAIN)
+					continue;
+				break;
+			}
+			ptr += p;
+			s -= p;
+		}
+		close(fd);
+		alarm(0);
+		return 0;
+	}
+
+#ifdef TELINIT_USES_INITLVL
+	if (request.cmd == INIT_CMD_RUNLVL) {
+		/* Fallthrough to the old method. */
+
+		/* Now write the new runlevel. */
+		if ((fp = fopen(INITLVL, "w")) == NULL) {
+			fprintf(stderr, "%s: cannot create %s\n",
+				progname, INITLVL);
+			exit(1);
+		}
+		fprintf(fp, "%s %d", argv[optind], sleep_time);
+		fclose(fp);
+
+		/* And tell init about the pending runlevel change. */
+		if (kill(INITPID, SIGHUP) < 0) perror(progname);
+
+		return 0;
+	}
+#endif
+
+	fprintf(stderr, "%s: ", progname);
+	if (ISMEMBER(got_signals, SIGALRM)) {
+		fprintf(stderr, "timeout opening/writing control channel %s\n",
+			INIT_FIFO);
+	} else {
+		perror(INIT_FIFO);
+	}
+	return 1;
+}
+
+/*
+ * Main entry for init and telinit.
+ */
+int main(int argc, char **argv)
+{
+	char			*p;
+	int			f;
+	int			isinit;
+#ifdef WITH_SELINUX
+	int			enforce = 0;
+#endif
+
+	/* Get my own name */
+	if ((p = strrchr(argv[0], '/')) != NULL)
+  		p++;
+	else
+  		p = argv[0];
+
+        if ( (argc == 2) && (! strcmp(argv[1], "--version") ) )
+        {
+           printf("SysV init version: %s\n\n", VERSION);
+           exit(0);
+        }
+
+	/* Common umask */
+	umask(umask(077) | 022);
+
+	/* Quick check */
+	if (geteuid() != 0) {
+		fprintf(stderr, "%s: must be superuser.\n", p);
+		exit(1);
+	}
+
+	/*
+	 *	Is this telinit or init ?
+	 */
+	isinit = (getpid() == 1);
+	for (f = 1; f < argc; f++) {
+		if (!strcmp(argv[f], "-i") || !strcmp(argv[f], "--init")) {
+			isinit = 1;
+			break;
+		}
+	}
+	if (!isinit) exit(telinit(p, argc, argv));
+
+	/*
+	 *	Check for re-exec
+	 */ 	
+	if (check_pipe(STATE_PIPE)) {
+
+		receive_state(STATE_PIPE);
+
+		myname = istrdup(argv[0]);
+		argv0 = argv[0];
+		maxproclen = 0;
+		for (f = 0; f < argc; f++)
+			maxproclen += strlen(argv[f]) + 1;
+		reload = 1;
+		setproctitle("init [%c]", (int)runlevel);
+
+		init_main();
+	}
+
+  	/* Check command line arguments */
+	maxproclen = strlen(argv[0]) + 1;
+  	for(f = 1; f < argc; f++) {
+		if (!strcmp(argv[f], "single") || !strcmp(argv[f], "-s"))
+			dfl_level = 'S';
+		else if (!strcmp(argv[f], "-a") || !strcmp(argv[f], "auto"))
+			putenv("AUTOBOOT=YES");
+		else if (!strcmp(argv[f], "-b") || !strcmp(argv[f],"emergency"))
+			emerg_shell = 1;
+		else if (!strcmp(argv[f], "-z")) {
+			/* Ignore -z xxx */
+			if (argv[f + 1]) f++;
+		} else if (strchr("0123456789sS", argv[f][0])
+			&& strlen(argv[f]) == 1)
+			dfl_level = argv[f][0];
+		/* "init u" in the very beginning makes no sense */
+		if (dfl_level == 's') dfl_level = 'S';
+		maxproclen += strlen(argv[f]) + 1;
+	}
+
+#ifdef WITH_SELINUX
+	if (getenv("SELINUX_INIT") == NULL) {
+         if (is_selinux_enabled() != 1) {
+	    if (selinux_init_load_policy(&enforce) == 0) {
+             putenv("SELINUX_INIT=YES");
+	      execv(myname, argv);
+	    } else {
+	      if (enforce > 0) {
+		/* SELinux in enforcing mode but load_policy failed */
+		/* At this point, we probably can't open /dev/console, so log() won't work */
+		fprintf(stderr,"Unable to load SELinux Policy. Machine is in enforcing mode. Halting now.\n");
+		exit(1);
+	      }
+	    }
+	  }
+	}
+#endif  
+	/* Start booting. */
+	argv0 = argv[0];
+	argv[1] = NULL;
+	setproctitle("init boot");
+	init_main();
+
+	/*NOTREACHED*/
+	return 0;
+}
Index: create-2.99-version-patch/sysvinit-2.99-new/src
===================================================================
--- create-2.99-version-patch/sysvinit-2.99-new/src	(nonexistent)
+++ create-2.99-version-patch/sysvinit-2.99-new/src	(revision 5)

Property changes on: create-2.99-version-patch/sysvinit-2.99-new/src
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: create-2.99-version-patch/sysvinit-2.99-new
===================================================================
--- create-2.99-version-patch/sysvinit-2.99-new	(nonexistent)
+++ create-2.99-version-patch/sysvinit-2.99-new	(revision 5)

Property changes on: create-2.99-version-patch/sysvinit-2.99-new
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: create-2.99-version-patch
===================================================================
--- create-2.99-version-patch	(nonexistent)
+++ create-2.99-version-patch	(revision 5)

Property changes on: create-2.99-version-patch
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: patches/README
===================================================================
--- patches/README	(nonexistent)
+++ patches/README	(revision 5)
@@ -0,0 +1,6 @@
+
+/* begin *
+
+   sysvinit-2.99-initctl.patch - should be applied before sysvinit-2.99-version.patch
+
+ * end */
Index: patches
===================================================================
--- patches	(nonexistent)
+++ patches	(revision 5)

Property changes on: patches
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: .
===================================================================
--- .	(nonexistent)
+++ .	(revision 5)

Property changes on: .
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~