[Pkg-sysvinit-commits] r1458 - in sysvinit-upstream/tags: . 2.87dsf 2.87dsf/doc 2.87dsf/man 2.87dsf/src

Petter Reinholdtsen pere at alioth.debian.org
Sun Jul 12 18:00:16 UTC 2009


Author: pere
Date: 2009-07-12 18:00:14 +0000 (Sun, 12 Jul 2009)
New Revision: 1458

Added:
   sysvinit-upstream/tags/2.87dsf/
   sysvinit-upstream/tags/2.87dsf/README
   sysvinit-upstream/tags/2.87dsf/doc/Changelog
   sysvinit-upstream/tags/2.87dsf/man/bootlogd.8
   sysvinit-upstream/tags/2.87dsf/man/killall5.8
   sysvinit-upstream/tags/2.87dsf/man/pidof.8
   sysvinit-upstream/tags/2.87dsf/man/shutdown.8
   sysvinit-upstream/tags/2.87dsf/src/bootlogd.c
   sysvinit-upstream/tags/2.87dsf/src/dowall.c
   sysvinit-upstream/tags/2.87dsf/src/halt.c
   sysvinit-upstream/tags/2.87dsf/src/hddown.c
   sysvinit-upstream/tags/2.87dsf/src/init.c
   sysvinit-upstream/tags/2.87dsf/src/init.h
   sysvinit-upstream/tags/2.87dsf/src/killall5.c
   sysvinit-upstream/tags/2.87dsf/src/last.c
   sysvinit-upstream/tags/2.87dsf/src/shutdown.c
   sysvinit-upstream/tags/2.87dsf/src/sulogin.c
Removed:
   sysvinit-upstream/tags/2.87dsf/README
   sysvinit-upstream/tags/2.87dsf/doc/Changelog
   sysvinit-upstream/tags/2.87dsf/man/bootlogd.8
   sysvinit-upstream/tags/2.87dsf/man/killall5.8
   sysvinit-upstream/tags/2.87dsf/man/pidof.8
   sysvinit-upstream/tags/2.87dsf/man/shutdown.8
   sysvinit-upstream/tags/2.87dsf/src/bootlogd.c
   sysvinit-upstream/tags/2.87dsf/src/dowall.c
   sysvinit-upstream/tags/2.87dsf/src/halt.c
   sysvinit-upstream/tags/2.87dsf/src/hddown.c
   sysvinit-upstream/tags/2.87dsf/src/init.c
   sysvinit-upstream/tags/2.87dsf/src/init.h
   sysvinit-upstream/tags/2.87dsf/src/killall5.c
   sysvinit-upstream/tags/2.87dsf/src/last.c
   sysvinit-upstream/tags/2.87dsf/src/shutdown.c
   sysvinit-upstream/tags/2.87dsf/src/sulogin.c
Log:
New release 2.87dsf.


Deleted: sysvinit-upstream/tags/2.87dsf/README
===================================================================
--- sysvinit-upstream/trunk/README	2009-07-10 21:51:19 UTC (rev 1428)
+++ sysvinit-upstream/tags/2.87dsf/README	2009-07-12 18:00:14 UTC (rev 1458)
@@ -1,7 +0,0 @@
-
-contrib		Unofficial stuff
-doc		Documentation, mostly obsolete
-man		Manual pages, not obsolete
-obsolete	Really obsolete stuff ;)
-src		Source code
-

Copied: sysvinit-upstream/tags/2.87dsf/README (from rev 1455, sysvinit-upstream/trunk/README)
===================================================================
--- sysvinit-upstream/tags/2.87dsf/README	                        (rev 0)
+++ sysvinit-upstream/tags/2.87dsf/README	2009-07-12 18:00:14 UTC (rev 1458)
@@ -0,0 +1,8 @@
+
+contrib		Unofficial stuff
+doc		Documentation, mostly obsolete
+man		Manual pages, not obsolete
+obsolete	Really obsolete stuff ;)
+src		Source code
+
+Send patches to initscripts-ng-devel at lists.alioth.debian.org.

Deleted: sysvinit-upstream/tags/2.87dsf/doc/Changelog
===================================================================
--- sysvinit-upstream/trunk/doc/Changelog	2009-07-10 21:51:19 UTC (rev 1428)
+++ sysvinit-upstream/tags/2.87dsf/doc/Changelog	2009-07-12 18:00:14 UTC (rev 1458)
@@ -1,591 +0,0 @@
-sysvinit (2.87dsf) world; urgency=low
-
-  * Fix typos and do minor updates in the manual pages.
-  * Correct section of mountpoint(1).
-  * Document -e and -t options for telinit in init(8).
-  * Update address of FSF in the COPYRIGHT file.
-  * Document in halt(8) that -n might not disable all syncing.
-    Patch by Bill Nottingham and Fedora
-  * Adjust output from "last -x".  In reboot lines, print endpoint
-    of uptime too.  In shutdown lines print downtimes rather than
-    the time between downs.  Fix typo in string compare in last.c.
-    Patch by Thomas Hood.
-  * Improve handling of IPv6 addresses in last.  Patch from Fedora.
-  * Document last options in usage information, previously only
-    mentioned in the manual page.
-  * Add new option -F to last, to output full date string instead
-    of the short form provided by default.  Patch from Olaf Dabrunz
-    and SuSe.
-  * Adjust build rules to make sure the installed binaries
-    are stripped.
-  * Increase the compiler warning level when building.
-  * Fix utmp/wtmp updating on 64-bit platforms.  Patch by Bill
-    Nottingham and Fedora.
-  * Avoid unchecked return value from malloc() in utmpdump.
-    Patch from Christian 'Dr. Disk' Hechelmann and Fedora.
-  * Make sure to use execle and no execl when passing environment to
-    the new process.  Patch from RedHat.
-  * Correct init to make sure the waiting status is preserved across
-    re-exec.  Patch from RedHat.
-  * Correct init to avoid race condition when starting programs during
-    boot.  Patch from SuSe.
-  * Allow 'telinit u' in runlevels 0 and 6.  Patch from Thomas Hood.
-  * Change install rules to make pidof an absolute symlink.  Patch from
-    Thomas Hood.
-  * Improve error message from init if fork() fail.  Patch found in Suse.
-  * Add support for SE Linux capability handling.  Patch from Manoj
-    Srivastava, adjusted to avoid aborting if SE policy was loaded in
-    the initrd with patch from Bill Nottingham and Fedora.
-  * Add -c option to pidof for only matching processes with the same
-    process root.  Ignore -c when not running as root.  Patch from
-    Thomas Woerner and Fedora.
-
- -- Petter Reinholdtsen <pere at debian.org>  Fri, 30 Jul 2004 14:14:58 +0200
-
-sysvinit (2.86) cistron; urgency=low
-
-  * Fixed up bootlogd to read /proc/cmdline. Also keep an internal
-    linebuffer to process \r, \t and ^H. It is becoming useable.
-  * Applied trivial OWL patches
-  * Block signals in syslog(), since syslog() is not re-entrant
-    (James Olin Oden <joden at malachi.lee.k12.nc.us>, redhat bug #97534)
-  * Minor adjustements so that sysvinit compiles on the Hurd 
-  * killall5 now skips kernel threads
-  * Inittab entries with both 'S' and other runlevels were broken.
-    Fix by Bryan Kadzban <bryan at kadzban.is-a-geek.net>
-  * Changed initreq.h to be more flexible and forwards-compatible.
-  * You can now through /dev/initctl set environment variables in
-    init that will be inherited by its children. For now, only
-    variables prefixed with INIT_ can be set and the maximum is
-    16 variables. There's also a length limit due to the size
-    of struct init_request, so it should be safe from abuse.
-  * Option -P and -H to shutdown set INIT_HALT=POWERDOWN and
-    INIT_HALT=HALT as environment variables as described above
-  * Add "mountpoint" utility.
-  * Slightly better algorithm in killall5.c:pidof()
-  * Added some patches from fedora-core (halt-usage, last -t,
-    sulogin-message, user-console)
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Fri, 30 Jul 2004 14:14:58 +0200
-
-sysvinit (2.85) cistron; urgency=low
-
-  * Add IPv6 support in last(1)
-  * Sulogin: even if the root password is empty, ask for a password-
-    otherwise there is no way to set a timeout.
-  * Removed support for ioctl.save.
-  * Turned of support for /etc/initrunlvl and /var/run/initrunlvl
-  * Fixed warts in dowall.c ("Dmitry V. Levin" <ldv at altlinux.org>)
-  * Fix init.c::spawn(). The "f" variable was used both as file descriptor
-    and waitpid(2) return code.  In certain circumstances, this leads to
-    TIOCSCTTY with wrong file descriptor (Vladimir N. Oleynik).
-  * Fix fd leak in sulogin (Dmitry V. Levin).
-  * More error checking in all wait() calling code (Dmitry V. Levin).
-  * Fix argv[] initialization in spawn() (Dmitry V. Levin).
-  * Change strncpy to strncat in most places (Dmitry V. Levin).
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Tue, 15 Apr 2003 16:37:57 +0200
-
-sysvinit (2.84) cistron; urgency=low
-
-  * Don't use /etc/initlvl interface for telinit; only use /dev/initctl,
-    and give a clear error when that fails.
-  * Add -i/--init command line flag to init - this tells init
-    'behave as system init even if you're not PID#1'. Useful for
-    testing in chroot/jail type environments.
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Tue, 27 Nov 2001 13:10:08 +0100
-
-sysvinit (2.83) cistron; urgency=low
-
-  * Fix bug in shutdown where it didn't check correctly for a
-    virtual console when checking /etc/shutdown.allow
-  * Fix race condition in waitpid() [Andrea Arcangeli]
-  * Call closelog() after openlog()/syslog() since recent libc's
-    keep the logging fd open and that is fd#0 aka stdin.
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Tue,  2 Oct 2001 23:27:06 +0200
-
-sysvinit (2.82) cistron; urgency=low
-
-  * Print out correct version number at startup.
-  * Fix spelling of initttab in init(8)
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Thu, 23 Aug 2001 17:50:44 +0200
-
-sysvinit (2.81) cistron; urgency=low
-
-  * Fix typo/bug in killall5/pidof, -o option failed to work since 2.79.
-    Reformatted source code to prevent this from happening again.
-  * shutdown.8: applied redhat manpage update
-  * sulogin: applied redhat sysvinit-2.78-sulogin-nologin.patch
-  * sulogin: applied redhat sysvinit-2.78-notty.patch
-  * sulogin: applied redhat sysvinit-2.78-sigint.patch
-
-sysvinit (2.80) cistron; urgency=low
-
-  * Grammar/spelling fixes in shutdown.c (Christian Steinrueck)
-  * Don't set controlling tty for non-(sysinit,boot,single) runlevels
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Thu, 26 Jul 2001 13:26:56 +0200
-
-sysvinit (2.79) cistron; urgency=low
-
-  * New upstream version
-  * several fixes to wall by Tim Robbins <fyre at box3n.gumbynet.org>
-  * Several extra boundary checks by Solar Designer
-  * Make /dev/console controlling tty
-  * Stricter checks on ownership of tty by mesg(1)
-  * Documented and restricted -n option to wall(1)
-  * Make it compile with glibc 2.2.2
-  * Document IO redirection in wall manpage (closes: #79491)
-  * Update README (closes: #85650)
-  * Fix init.8 manpage (closes:  #75268)
-  * Fix typo in halt(8) manpage (closes:  #67875)
-  * Check time argument of shutdown(8) for correctness (closes: #67825)
-  * Check for stale sessions in last(1) (Chris Wolf <cwolf at starclass.com>)
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Wed,  4 Jul 2001 15:04:36 +0200
-
-sysvinit (2.78-2) frozen unstable; urgency=high
-
-  * Change "booting" to "reloading" message at reload
-  * Add "-z xxx" dummy command line argument (closes: #54717)
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Fri, 11 Feb 2000 12:17:54 +0100
-
-sysvinit (2.78-1) unstable; urgency=low
-
-  * 2.78 will be the new upstream version, I'm skipping 2.77
-  * Shutdown now calls sync before switching the runlevel to 0 or 6,
-    or before unmounting filesystems if -n was used (closes: #46461)
-  * Some cosmetic changes to init.c (closes: #32079)
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Thu, 30 Dec 1999 20:40:23 +0100
-
-sysvinit (2.77-2) unstable; urgency=low
-
-  * Fix last -i option
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Tue,  5 Oct 1999 21:51:50 +0200
-
-sysvinit (2.77-1) unstable; urgency=low
-
-  * Write reboot record into utmp file as well to make rms happy
-  * Fork and dump core in / if SIGSEGV is received for debugging purposes
-  * Patch by Craig Sanders <cas at vicnet.net.au> for "last" -i option
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Wed,  4 Aug 1999 11:16:23 +0200
-
-sysvinit (2.76-4) unstable; urgency=low
-
-  * Change dowall.c to handle Unix98 ptys correctly
-  * Add comment in rcS about usage of setup.sh and unconfigured.sh
-  * Shutdown now removes nologin file just before calling telinit
-  * SEGV handler now tries to continue after sleep of 30 seconds.
-    On a 386-class processor it also prints out the value of EIP.
-  * Fix for racecondition in check_init_fifo() by Richard Gooch
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Sat,  8 May 1999 17:22:57 +0200
-
-sysvinit (2.76-3) frozen unstable; urgency=high
-
-  * Small bugfix to last.c courtesy of Danek Duvall <duvall at emufarm.ml.org>
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Tue, 12 Jan 1999 12:12:44 +0100
-
-sysvinit (2.76-1) frozen unstable; urgency=high
-
-  * Fix bug in check_pipe() which crashes init on the Alpha.
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Tue,  3 Nov 1998 11:09:13 +0100
-
-sysvinit (2.75-4) unstable; urgency=low
-
-  * Change sulogin password buffer to 128 characters.
-  * Don't print control characters in dowall.c
-  * Try to open getenv ("CONSOLE"), /dev/console and /dev/tty0 in order.
-    For backwards compatibility when you try to boot a 2.0.x kernel
-    with a linux > 2.1.70 /dev/console device.
-  * Change src/Makefile for non-debian systems (mainly, RedHat)
-  * Try to create /dev/initctl if not present; check every time to see
-    if the dev/ino of /dev/initctl has changed and re-open it. This should
-    help devfs a bit.
-  * Send SIGUSR1 to init at bootup to let it re-open /dev/initctl;
-    again in support of devfs.
-  * Moved pidof to /bin (it's only a link to killall5 anyway)
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Mon,  5 Oct 1998 14:03:14 +0200
-
-sysvinit (2.75-2) frozen unstable; urgency=medium
-
-  * Fix last.c again.
-  * Add check to see if /dev/initctl is really a FIFO
-  * In ifdown.c first down all shaper devices then the real devices
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Tue,  2 Jun 1998 22:43:01 +0200
-
-sysvinit (2.75-1) frozen unstable; urgency=low
-
-  * Rewrote last.c to be much more memory friendly and correct,
-    thanks to Nick Andrew <nick at zeta.org.au> and
-    David Parrish <dparrish at zeta.org.au>
-  * Fixes bugs:
-    #21616: sysvinit: sulogin thinks md5 root password is bad
-    #21765: sysvinit: Typo in `killall5.c'
-    #21775: sysvinit: sysvinit does not support MD5 hashed passwords
-    #21990: /usr/bin/last: unnecessary memset and off-by-one bug
-    #22084: sysvinit 2.74-4: SIGPWR missing on sparc
-    #21900: init, powerfail events, and shutdown.allow
-    #21702: init 0 does not work as expected...
-    #21728: sysvinit: Typo in `init.c'
-    #22363: sysvinit: discrepance btw. manpage and /sbin/init
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Tue, 19 May 1998 11:02:29 +0200
-
-sysvinit (2.74-4) frozen unstable; urgency=medium
-
-  * Add -o option to last to process libc5 utmp files.
-  * Buffer overflow fixed in init.c (not very serious; only exploitable
-    by root). Thanks to Chris Evans <chris at ferret.lmh.ox.ac.uk>
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Wed, 15 Apr 1998 17:04:33 +0200
-
-sysvinit (2.74-1) unstable; urgency=low
-
-  * Should compile with glibc 1.99 :)
-  * Change behaviour of reboot(1) and halt(1) so that the default when
-    the runlevel can't be determined is to call shutdown.
-  * Added re-exec patch from Al Viro (21 Feb 1998):
-        'U' flag added to telinit. It forces init to re-exec itself
-        (passing its state through exec, certainly).
-        May be useful for smoother (heh) upgrades.
-        24 Feb 1998, AV:
-        did_boot made global and added to state - thanks, Miquel.
-        Yet another file descriptors leak - close state pipe if
-        re_exec fails.
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Thu, 12 Mar 1998 17:42:46 +0100
-
-sysvinit (2.73-2) unstable; urgency=low
-
-  * Change _NSIG to NSIG for 2.1.x kernel includes.
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Thu,  8 Jan 1998 16:01:02 +0100
-
-sysvinit (2.73-1) unstable; urgency=low
-
-  * Use siginterrupt, now that system calls are restarted by default.
-    Main symptom was that the sulogin timeout didn't work but there
-    might have been more hidden problems.
-  * Kill process immidiately if turned off in inittab
-  * Fixed sulogin check on tty arg.
-  * Use strerror() instead of sys_errlist
-  * wall now supports a '-n' option to suppress [most of] the banner.
-    Debian doesn't use sysvinit's wall, but apparently Redhat does.
-  * Add '-F' (forcefsck) option to shutdown
-  * Close and reopen /dev/initctl on SIGUSR1 (mainly for a /dev in ram)
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Sat,  3 Jan 1998 16:32:39 +0100
-
-sysvinit (2.72-3) unstable; urgency=low
-
-  * Add extra fork() in dowall.c to avoid hanging in rare cases
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Wed, 22 Oct 1997 14:44:00 +0200
-
-sysvinit (2.72) unstable; urgency=low
-
-  * Applied manual page patches by Bill Hawes <whawes at star.net>.  Thanks Bill!
-  * Applied patches to the sample Slackware scripts by
-    "Jonathan I. Kamens" <jik at kamens.brookline.ma.us>
-  * Fix halt and reboot runlevels 0 & 6 check.
-  * Only say "no more processes left in runlevel x" once
-  * Fix race condition with SIGCHLD in spawn()
-    (thanks to Alon Ziv <alonz at CS.Technion.AC.IL>)
-  * Compress all manpages (missed 2)
-  * Compiled for libc6
-  * Added poweroff patch by Roderich Schupp <rsch at ExperTeam.de>
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Sun, 12 Oct 1997 17:20:17 +0200
-
-sysvinit (2.71-2) frozen unstable; urgency=low
-
-  * Print 2.71 instead of 2.70 on startup :)
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Mon, 5 May 1997 12:45:25 +0200
-
-sysvinit (2.71-1) frozen unstable; urgency=high
-
-  * Added code for updwtmp() in utmp.c for glibc (2.0.3)
-  * Fixed all programs to use functions from utmp.c and getutent()
-  * Do not try to clean up utmp in init itself (Bug#9022)
-  * Removed sync() from main loop.
-  * Hopefully fixes bug #8657 (shutdown signal handling)
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Sat, 26 Apr 1997 19:57:27 +0200
-
-sysvinit (2.70-1) unstable; urgency=low
-
-  * Respawn fix
-  * Removed StUdLy CaPs from source code
-  * Moved files in source archive around
-  * Fixes for glibc (utmp handling, signal handling).
-  * Fixed '-d' option to last (now also works without '-a').
-  * Added extra checking in last.c to prevent showing dead entries
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Fri, 7 Feb 1997 15:31:30 +0100
-
-sysvinit (2.69-1) frozen unstable; urgency=medium
-
-  * Fixed bug that can throw X in a loop (or any other app that reads from
-    /dev/tty0)
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Sun, 1 Dec 1996 15:32:24 +0100
-
-sysvinit (2.67-1) frozen unstable; urgency=high
-
-  * Fixes problem with /dev/console being controlling terminal of some
-    daemons
-  * Puts copyright file in the right place
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Fri, 15 Nov 1996 12:23:33 +0100
-
-sysvinit (2.66-1) unstable; urgency=medium
-
-  * Skipped 2.65. A development 2.65 got out by accident and is apparently
-    being used..
-  * Also compiles and runs with GNU libc (and on the Alpha)
-  * Fixed dowall.c not to exit when getpwuid() fails and uid == 0.
-  * Fixed init panic'ing on empty lines in /etc/inittab
-  * Changed default PATH to include /usr/local/sbin
-  * Set /dev/console as controlling terminal for sysinit,bootwait,wait,powerwait
-    This allows using ^C to interrupt some parts of eg the boot process.
-  * Remove old symlink in /var/log/initlvl; let init check both
-    /var/log and /etc itself.
-
- -- Miquel van Smoorenburg <miquels at cistron.nl>  Tue, 29 Oct 1996 13:46:54 +0100
-
-2.66    29-Oct-1996
-- Skipped 2.65. A development 2.65 got out by accident and is apparently
-  being used..
-- Fixed dowall.c not to exit when getpwuid() fails and uid == 0.
-- Fixed init panic'ing on empty lines in /etc/inittab
-- Changed default PATH to include /usr/local/sbin
-- Ported to Linux/Alpha and GNU libc.
-- Set /dev/console as controlling terminal for sysinit,bootwait,wait,powerwait.
-  This allows using ^C to interrupt some parts of eg the boot process.
-- Remove old symlink in /var/log/initlvl; let init check both
-  /var/log and /etc itself.
-
-2.64	28-Jun-1996
-- Init checks CONSOLE environment variable on startup (overrides /dev/console)
-- Init sets CONSOLE variable for all its children.
-- Wtmp(): when zeroing out old utmp entries, keep ut_id field
-- Wtmp(): try to re-use ut_id field if possible.
-- SetTerm(): only read from /etc/ioctl.save if written once.
-- Included start-stop-daemon, C version (source only).
-- Fixed wait() for the emergency shell.
-- killall5: ignore signal before doing kill(-1, pid).
-
-2.63    14-Jun-1996
-- Fixed preinst script for Debian
-- Fixed init.c to become init daemon if name is init.new
-- Fixed pidof to not return PIDs of shell scripts
-
-2.62-2	09-Jun-1996
-- Changed debian /etc/init.d/boot script to create a nologin file
-  at boot and to remove it just before going multiuser.
-
-2.62    31-May-1996
-- Decided to release a 2.62 version with a BIG WARNING about upgrading
-  init in it. Will send a patch to Linus for the linux/Documentation/Changes
-  file so that 2.62 or later is mentioned as the version to upgrade to.
-- Added docs for Slackware
-
-2.61-3  29-May-1996
-- Fixed debian/etc/init.d/network for the lo device.
-- Added "-xdev" to the cd /tmp && find in debian/etc/init.d/boot
-- Made remove time for files in /tmp configurable.
-
-2.61    29-Apr-1996
-- Changed /etc/init.d/boot script again
-- Fixed problem in init.c with trailing whitespace after entries in inittab
-- Fixed killall5 problems
-- Added manpage for lastb
-- Added SHELL= environment variable to sulogin
-- Fixed sulogin & shadow problems
-- Added timeout option to sulogin
-
-2.60-2  16-Apr-1996
-- Fixed sulogin (didn't work if root wasn't first entry in shadow file)
-- Fixed mesg for systems with "tty" group (such as Debian)
-- Fixed nsyslog() in killall5.c
-
-2.60   01-Apr-1996
-- Fixed race condition in init.c, resulting in hanging shutdowns.
-  Courtesy of Max Neunhoeffer <Max.Neunhoeffer at urz.uni-heidelberg.de>.
-- Fixed debian/etc/init.d/boot for swapon and mdadd
-- Added architecture to debian.control
-- Added manpages for rc.boot and rc.local
-- Updated inittab manpage for 4-character runlevel field
-- Added debian replaces for bsdutils < version_without_mesg
-- Fixed init.c so that it also works with kernels 1.3.81 and up
-
-2.59   10-Mar-1996
-- Init logs less to syslog (suspected to hang in syslog() or openlog() )
-- removed closelog() from init.c
-- removed time check of runlevel record in halt.
-- Added options to last to get hostname from ut_addr field
-- Added last and mesg to installation targets
-- rewrote /etc/init.d/boot a bit.
-
-2.58-2 04-Jan-1996
-- Changed etc/init.d/rc to do a stty onlcr
-- Added /var/log/initrunlvl symlink
-
-2.58-1 31-Dec-1995
-- Added the latest debian files.
-- Added support for 4-character id fields (if you have libc5).
-- Fixed pidof (in killall5) parsing of /proc/.../stat
-- Save restore GMT setting in /etc/init.d/boot
-
-2.57d 03-Dec-1995
-- Added sulogin
-- Added "-b" flag to init, gives a shell before
-  anything else (in case the startup scripts are screwed)
-- Moved fastboot to /fastboot
-- Folded in Debian patches.
-- Removed old scripts
-- Added debian /etc/directory.
-
-2.57c 08-Oct-1995
-- Changed over to init_request (with initreq.h)
-- Processes no longer killed when "process" field
-  changes, change takes effect after next respawn.
-
-2.57b xx-Aug-1995
-- Bugfix release for Debian and Slackware 3.0
-
-2.57a 10-Jul-1995
-- Fixed race condition init init.c wrt got_chld
-- Fixed one-off for malloc in killall5.c
-- Changed dowall.c
-- Console code: no relink to /dev/systty on CTRL-ALT-DEL)
-
-2.57 22-May-1995
-- Changed a few things here and there, didn't
-	 	  really document it :)
-
-2.55 17-Jan-1995
-- Added option to shutdown to run standalone.
-
-2.54 12-Jan-1995
-- Added GNU copyrigh to all *.[ch] files.
-- added /etc/initscript
-- reboot and halt now call shutdown in runlevels 1-5
-- Can run from read-only root (CDROM)
-
-2.53 10-Oct-1994
-- Renamed pidof to killall5, updated all scripts to
-  use killall5 instead of kill -1 ....
-- Rewrote scripts to use this, and some general changes.
-- Added SysV command line compatibility to shutdown.
-
-2.52 30-Aug-1994
-- Added `powerfailnow' keyword, for when UPS battery is low.
-- Updated `last'.
-- Fixed utmp handling (wrt. CLEAN_UTMP)
-TODO:
-* Make last compatible with GNU/BSD (long options?)
-* update powerd
-* remote SIGPWR broadcast? in powerd? (with priv. port)
-* remote shutdown
-
-2.50  14-Feb-1994
-- Ignores unknown command line arguments.
-- Modelled more after the "real" sysVinit
-- Lots of changes all over the place.
-  (like showing runlevel in "ps" listing, logging
-   runlevel into utmp file etc)
-- now using "reliable" signals instead of V7 style.
-- Updated all scripts. Examples are in two directories:
-  etc (normal) and etc-sysv (sysv style scripts).
-- runlevel 0 = halt, 1 = single user, 6 = reboot.
-- added support for serial console.
-- updated Propaganda, manpages.
-- added shutdown access control.
-
-2.4  24-May-93
-- Send out the official version into the world as
-  SysVinit-2.4.tar.z.
-
-2.4g 15-May-93
-- Changed init to really catch SIGPWR 'cause we
-  hooked up an UPS to the Linux machine. The
-  keyword for catching the TreeFingerSalute is
-  now "ctrlaltdel" instead of "power{wait,fail}".
-
-2.4a 22-Apr-93
-- Fixed last to reckognize BSD style wtmp logging.
-- Changed init to write wtmp records that are
-  SysV compliant but are also reckognized by the
-  BSD last. Added a '+' option to the 'process'
-  field of inittab, for getties that want to do
-  their own utmp/wtmp housekeeping (kludge!).
-- Now accepts a runlevel on the command line,
-  and reckognizes the 'auto' argument. (Sets the
-  environment variable AUTOBOOT to YES)
-
-2.2.3 24-Mar-93
-- Ripped out the 'leave' action. To difficult, and
-  unneeded.
-- Going single user now kills _all_ processes.
-- Added '-t secs' option to all commands.
-- This version is stable enough to post.
-
-2.2 02-Mar-93
-- Made wait()'s asynchronous
-- Changed whole thing to one big state machine
-- Now using 'pseudo levels' # & * for SYSINIT & BOOT
-- Added a new type of 'action', called leave. This
-  process will be executed when the system goes from a
-  runlevel specified in it's runlevel field to a 
-  level that's not. Nice to bring down NFS and the like.
-
-2.1 28-Jan-93
-- Fixed a bug with 'boot' and 'once'.
-- Check 'initdefault' for validity.
-- Reckognizes "single" as command line argument.
-- Retries execvp with 'sh -c exec ..' if command
-  is a shell script. (shouldn't execvp do this?)
-- Added patches to use syslog if defined.
-
-2.0 08-Dec-92
-- Rewrote the code totally, so started with a new
-  version number.
-- Dropped Minix support, this code now is Linux - specific.
-- With TEST switch on, this init & telinit can
-  run standalone for test purposes.
-
-1.3, 05-Jul-92
-- Got a 386, so installed Linux. Added 'soft' reboot
-  to be default under linux. Fixed some typos.
-
-1.2, 16-Jun-92
-- Bugreport from Michael Haardt ; removed deadlock
-  and added 'waitpid' instead of 'wait' for SYSV.
-
-1.1, 30-Apr-92
-- Read manual wrong: there is no 'action' field called
-  process, but all entries are of type process. Every
-  'process' get exec'ed by /bin/sh -c 'exec command'.
-- Rapidly respawning processes are caught in the act.
-- _SYSV support is really Linux support,
-  done by poe at daimi.aau.dk on 25-Mar-92.
-
- 1.0, 01-Feb-92
-- Initial version, very primitive for the Minix
-  operating system. Required some mods. to the
-  kernel.
-

Copied: sysvinit-upstream/tags/2.87dsf/doc/Changelog (from rev 1456, sysvinit-upstream/trunk/doc/Changelog)
===================================================================
--- sysvinit-upstream/tags/2.87dsf/doc/Changelog	                        (rev 0)
+++ sysvinit-upstream/tags/2.87dsf/doc/Changelog	2009-07-12 18:00:14 UTC (rev 1458)
@@ -0,0 +1,635 @@
+sysvinit (2.87dsf) world; urgency=low
+
+  * Fix typos and do minor updates in the manual pages.
+  * Correct section of mountpoint(1).
+  * Document -e and -t options for telinit in init(8).
+  * Update address of FSF in the COPYRIGHT file.
+  * Document in halt(8) that -n might not disable all syncing.
+    Patch by Bill Nottingham and Fedora
+  * Adjust output from "last -x".  In reboot lines, print endpoint
+    of uptime too.  In shutdown lines print downtimes rather than
+    the time between downs.  Fix typo in string compare in last.c.
+    Patch by Thomas Hood.
+  * Improve handling of IPv6 addresses in last.  Patch from Fedora.
+  * Document last options in usage information, previously only
+    mentioned in the manual page.
+  * Add new option -F to last, to output full date string instead
+    of the short form provided by default.  Patch from Olaf Dabrunz
+    and SuSe.
+  * Adjust build rules to make sure the installed binaries
+    are stripped.
+  * Increase the compiler warning level when building.
+  * Fix utmp/wtmp updating on 64-bit platforms.  Patch by Bill
+    Nottingham and Fedora.
+  * Avoid unchecked return value from malloc() in utmpdump.
+    Patch from Christian 'Dr. Disk' Hechelmann and Fedora.
+  * Make sure to use execle and no execl when passing environment to
+    the new process.  Patch from RedHat.
+  * Correct init to make sure the waiting status is preserved across
+    re-exec.  Patch from RedHat.
+  * Correct init to avoid race condition when starting programs during
+    boot.  Patch from SuSe.
+  * Allow 'telinit u' in runlevels 0 and 6.  Patch from Thomas Hood.
+  * Change install rules to make pidof an absolute symlink.  Patch from
+    Thomas Hood.
+  * Improve error message from init if fork() fail.  Patch found in Suse.
+  * Add support for SE Linux capability handling.  Patch from Manoj
+    Srivastava, adjusted to avoid aborting if SE policy was loaded in
+    the initrd with patch from Bill Nottingham and Fedora.
+  * Add -c option to pidof for only matching processes with the same
+    process root.  Ignore -c when not running as root.  Patch from
+    Thomas Woerner and Fedora.
+  * Adjust init to terminate argv0 with one 0 rather than two so that
+    process name can be one character longer.  Patch by Kir Kolyshkin.
+  * Make sure bootlogd exit with non-error exit code when forking of
+    the child successfully.
+  * Add bootlogd option -s to make it possible to control the use of
+    fdatasync().  Patch from Thomas Hood.
+  * Add bootlogd option -c to tell it to create the log file if it does
+    not exist.  Patch from Thomas Hood.
+  * Let bootlogd also look at ttyB* devices to work on HPPA.  Patch
+    from Thomas Hood.
+  * Change init to use setenv() instead of putenv, make sure the PATH
+    value is usable on re-exec.  Patch from Thomas Hood.
+  * Add usleep in killall5 after killing processes, to force the kernel
+    to reschedule.  Patch from SuSe.
+  * Modify pidof to not print empty line if no pid was found.
+  * Modify init and sulogin to fix emergency mode's tty, making sure ^C
+    and ^Z work when booting with 'emergency' kernel option.  Patch from
+    Samuel Thibault.
+  * Modify init to allow some time for failed opens to resolve themselves.
+    Patch from Bill Nottingham and Fedora.
+  * Modify init to shut down IDE, SCSI and SATA disks properly.  Patches
+    from Sebastian Reichelt, Werner Fink and SuSe.
+  * Modify wall to use UT_LINESIZE from <utmp.h> instead of hardcoded
+    string lengths.  Patch from SuSe.
+  * Change wall to make halt include hostname in output.
+  * Change killall to avoid killing init by mistake.  Patch from SuSe.
+  * Change killall5 to use the exit value to report if it found any
+    processes to kill.  Patch from Debian.
+  * Add option -o opmitpid to killall5, to make it possible to skip
+    some pids during shutdown.  Based on patch from Colin Watson and
+    Ubuntu.
+  * Add references between killall5 and pidof manual pages.  Patch from Debian.
+  * Modify killall to work better with user space file system, by
+    changing cwd to /proc when stopping and killing processes, and
+    avoiding stat() when the value isn't used.  Also, lock process
+    pages in memory to avoid paging when user processes are stopped.
+    Patch from Debian and Goswin von Brederlow with changes by Kel
+    Modderman.
+  * Change shutdown to only accept flags -H and -P with the -h flag,
+    and document this requirement in the manual page.
+  * Change reboot/halt to work properly when used as a login shell.
+    Patch by Dale R. Worley and Fedora.
+  * Let sulogin fall back to the staticly linked /bin/sash if both roots
+    shell and /bin/sh fail to execute.
+
+ -- Petter Reinholdtsen <pere at hungry.com>  Sun, 12 Jul 2009 19:58:10 +0200
+
+sysvinit (2.86) cistron; urgency=low
+
+  * Fixed up bootlogd to read /proc/cmdline. Also keep an internal
+    linebuffer to process \r, \t and ^H. It is becoming useable.
+  * Applied trivial OWL patches
+  * Block signals in syslog(), since syslog() is not re-entrant
+    (James Olin Oden <joden at malachi.lee.k12.nc.us>, redhat bug #97534)
+  * Minor adjustements so that sysvinit compiles on the Hurd 
+  * killall5 now skips kernel threads
+  * Inittab entries with both 'S' and other runlevels were broken.
+    Fix by Bryan Kadzban <bryan at kadzban.is-a-geek.net>
+  * Changed initreq.h to be more flexible and forwards-compatible.
+  * You can now through /dev/initctl set environment variables in
+    init that will be inherited by its children. For now, only
+    variables prefixed with INIT_ can be set and the maximum is
+    16 variables. There's also a length limit due to the size
+    of struct init_request, so it should be safe from abuse.
+  * Option -P and -H to shutdown set INIT_HALT=POWERDOWN and
+    INIT_HALT=HALT as environment variables as described above
+  * Add "mountpoint" utility.
+  * Slightly better algorithm in killall5.c:pidof()
+  * Added some patches from fedora-core (halt-usage, last -t,
+    sulogin-message, user-console)
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Fri, 30 Jul 2004 14:14:58 +0200
+
+sysvinit (2.85) cistron; urgency=low
+
+  * Add IPv6 support in last(1)
+  * Sulogin: even if the root password is empty, ask for a password-
+    otherwise there is no way to set a timeout.
+  * Removed support for ioctl.save.
+  * Turned of support for /etc/initrunlvl and /var/run/initrunlvl
+  * Fixed warts in dowall.c ("Dmitry V. Levin" <ldv at altlinux.org>)
+  * Fix init.c::spawn(). The "f" variable was used both as file descriptor
+    and waitpid(2) return code.  In certain circumstances, this leads to
+    TIOCSCTTY with wrong file descriptor (Vladimir N. Oleynik).
+  * Fix fd leak in sulogin (Dmitry V. Levin).
+  * More error checking in all wait() calling code (Dmitry V. Levin).
+  * Fix argv[] initialization in spawn() (Dmitry V. Levin).
+  * Change strncpy to strncat in most places (Dmitry V. Levin).
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Tue, 15 Apr 2003 16:37:57 +0200
+
+sysvinit (2.84) cistron; urgency=low
+
+  * Don't use /etc/initlvl interface for telinit; only use /dev/initctl,
+    and give a clear error when that fails.
+  * Add -i/--init command line flag to init - this tells init
+    'behave as system init even if you're not PID#1'. Useful for
+    testing in chroot/jail type environments.
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Tue, 27 Nov 2001 13:10:08 +0100
+
+sysvinit (2.83) cistron; urgency=low
+
+  * Fix bug in shutdown where it didn't check correctly for a
+    virtual console when checking /etc/shutdown.allow
+  * Fix race condition in waitpid() [Andrea Arcangeli]
+  * Call closelog() after openlog()/syslog() since recent libc's
+    keep the logging fd open and that is fd#0 aka stdin.
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Tue,  2 Oct 2001 23:27:06 +0200
+
+sysvinit (2.82) cistron; urgency=low
+
+  * Print out correct version number at startup.
+  * Fix spelling of initttab in init(8)
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Thu, 23 Aug 2001 17:50:44 +0200
+
+sysvinit (2.81) cistron; urgency=low
+
+  * Fix typo/bug in killall5/pidof, -o option failed to work since 2.79.
+    Reformatted source code to prevent this from happening again.
+  * shutdown.8: applied redhat manpage update
+  * sulogin: applied redhat sysvinit-2.78-sulogin-nologin.patch
+  * sulogin: applied redhat sysvinit-2.78-notty.patch
+  * sulogin: applied redhat sysvinit-2.78-sigint.patch
+
+sysvinit (2.80) cistron; urgency=low
+
+  * Grammar/spelling fixes in shutdown.c (Christian Steinrueck)
+  * Don't set controlling tty for non-(sysinit,boot,single) runlevels
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Thu, 26 Jul 2001 13:26:56 +0200
+
+sysvinit (2.79) cistron; urgency=low
+
+  * New upstream version
+  * several fixes to wall by Tim Robbins <fyre at box3n.gumbynet.org>
+  * Several extra boundary checks by Solar Designer
+  * Make /dev/console controlling tty
+  * Stricter checks on ownership of tty by mesg(1)
+  * Documented and restricted -n option to wall(1)
+  * Make it compile with glibc 2.2.2
+  * Document IO redirection in wall manpage (closes: #79491)
+  * Update README (closes: #85650)
+  * Fix init.8 manpage (closes:  #75268)
+  * Fix typo in halt(8) manpage (closes:  #67875)
+  * Check time argument of shutdown(8) for correctness (closes: #67825)
+  * Check for stale sessions in last(1) (Chris Wolf <cwolf at starclass.com>)
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Wed,  4 Jul 2001 15:04:36 +0200
+
+sysvinit (2.78-2) frozen unstable; urgency=high
+
+  * Change "booting" to "reloading" message at reload
+  * Add "-z xxx" dummy command line argument (closes: #54717)
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Fri, 11 Feb 2000 12:17:54 +0100
+
+sysvinit (2.78-1) unstable; urgency=low
+
+  * 2.78 will be the new upstream version, I'm skipping 2.77
+  * Shutdown now calls sync before switching the runlevel to 0 or 6,
+    or before unmounting filesystems if -n was used (closes: #46461)
+  * Some cosmetic changes to init.c (closes: #32079)
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Thu, 30 Dec 1999 20:40:23 +0100
+
+sysvinit (2.77-2) unstable; urgency=low
+
+  * Fix last -i option
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Tue,  5 Oct 1999 21:51:50 +0200
+
+sysvinit (2.77-1) unstable; urgency=low
+
+  * Write reboot record into utmp file as well to make rms happy
+  * Fork and dump core in / if SIGSEGV is received for debugging purposes
+  * Patch by Craig Sanders <cas at vicnet.net.au> for "last" -i option
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Wed,  4 Aug 1999 11:16:23 +0200
+
+sysvinit (2.76-4) unstable; urgency=low
+
+  * Change dowall.c to handle Unix98 ptys correctly
+  * Add comment in rcS about usage of setup.sh and unconfigured.sh
+  * Shutdown now removes nologin file just before calling telinit
+  * SEGV handler now tries to continue after sleep of 30 seconds.
+    On a 386-class processor it also prints out the value of EIP.
+  * Fix for racecondition in check_init_fifo() by Richard Gooch
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Sat,  8 May 1999 17:22:57 +0200
+
+sysvinit (2.76-3) frozen unstable; urgency=high
+
+  * Small bugfix to last.c courtesy of Danek Duvall <duvall at emufarm.ml.org>
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Tue, 12 Jan 1999 12:12:44 +0100
+
+sysvinit (2.76-1) frozen unstable; urgency=high
+
+  * Fix bug in check_pipe() which crashes init on the Alpha.
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Tue,  3 Nov 1998 11:09:13 +0100
+
+sysvinit (2.75-4) unstable; urgency=low
+
+  * Change sulogin password buffer to 128 characters.
+  * Don't print control characters in dowall.c
+  * Try to open getenv ("CONSOLE"), /dev/console and /dev/tty0 in order.
+    For backwards compatibility when you try to boot a 2.0.x kernel
+    with a linux > 2.1.70 /dev/console device.
+  * Change src/Makefile for non-debian systems (mainly, RedHat)
+  * Try to create /dev/initctl if not present; check every time to see
+    if the dev/ino of /dev/initctl has changed and re-open it. This should
+    help devfs a bit.
+  * Send SIGUSR1 to init at bootup to let it re-open /dev/initctl;
+    again in support of devfs.
+  * Moved pidof to /bin (it's only a link to killall5 anyway)
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Mon,  5 Oct 1998 14:03:14 +0200
+
+sysvinit (2.75-2) frozen unstable; urgency=medium
+
+  * Fix last.c again.
+  * Add check to see if /dev/initctl is really a FIFO
+  * In ifdown.c first down all shaper devices then the real devices
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Tue,  2 Jun 1998 22:43:01 +0200
+
+sysvinit (2.75-1) frozen unstable; urgency=low
+
+  * Rewrote last.c to be much more memory friendly and correct,
+    thanks to Nick Andrew <nick at zeta.org.au> and
+    David Parrish <dparrish at zeta.org.au>
+  * Fixes bugs:
+    #21616: sysvinit: sulogin thinks md5 root password is bad
+    #21765: sysvinit: Typo in `killall5.c'
+    #21775: sysvinit: sysvinit does not support MD5 hashed passwords
+    #21990: /usr/bin/last: unnecessary memset and off-by-one bug
+    #22084: sysvinit 2.74-4: SIGPWR missing on sparc
+    #21900: init, powerfail events, and shutdown.allow
+    #21702: init 0 does not work as expected...
+    #21728: sysvinit: Typo in `init.c'
+    #22363: sysvinit: discrepance btw. manpage and /sbin/init
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Tue, 19 May 1998 11:02:29 +0200
+
+sysvinit (2.74-4) frozen unstable; urgency=medium
+
+  * Add -o option to last to process libc5 utmp files.
+  * Buffer overflow fixed in init.c (not very serious; only exploitable
+    by root). Thanks to Chris Evans <chris at ferret.lmh.ox.ac.uk>
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Wed, 15 Apr 1998 17:04:33 +0200
+
+sysvinit (2.74-1) unstable; urgency=low
+
+  * Should compile with glibc 1.99 :)
+  * Change behaviour of reboot(1) and halt(1) so that the default when
+    the runlevel can't be determined is to call shutdown.
+  * Added re-exec patch from Al Viro (21 Feb 1998):
+        'U' flag added to telinit. It forces init to re-exec itself
+        (passing its state through exec, certainly).
+        May be useful for smoother (heh) upgrades.
+        24 Feb 1998, AV:
+        did_boot made global and added to state - thanks, Miquel.
+        Yet another file descriptors leak - close state pipe if
+        re_exec fails.
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Thu, 12 Mar 1998 17:42:46 +0100
+
+sysvinit (2.73-2) unstable; urgency=low
+
+  * Change _NSIG to NSIG for 2.1.x kernel includes.
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Thu,  8 Jan 1998 16:01:02 +0100
+
+sysvinit (2.73-1) unstable; urgency=low
+
+  * Use siginterrupt, now that system calls are restarted by default.
+    Main symptom was that the sulogin timeout didn't work but there
+    might have been more hidden problems.
+  * Kill process immidiately if turned off in inittab
+  * Fixed sulogin check on tty arg.
+  * Use strerror() instead of sys_errlist
+  * wall now supports a '-n' option to suppress [most of] the banner.
+    Debian doesn't use sysvinit's wall, but apparently Redhat does.
+  * Add '-F' (forcefsck) option to shutdown
+  * Close and reopen /dev/initctl on SIGUSR1 (mainly for a /dev in ram)
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Sat,  3 Jan 1998 16:32:39 +0100
+
+sysvinit (2.72-3) unstable; urgency=low
+
+  * Add extra fork() in dowall.c to avoid hanging in rare cases
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Wed, 22 Oct 1997 14:44:00 +0200
+
+sysvinit (2.72) unstable; urgency=low
+
+  * Applied manual page patches by Bill Hawes <whawes at star.net>.  Thanks Bill!
+  * Applied patches to the sample Slackware scripts by
+    "Jonathan I. Kamens" <jik at kamens.brookline.ma.us>
+  * Fix halt and reboot runlevels 0 & 6 check.
+  * Only say "no more processes left in runlevel x" once
+  * Fix race condition with SIGCHLD in spawn()
+    (thanks to Alon Ziv <alonz at CS.Technion.AC.IL>)
+  * Compress all manpages (missed 2)
+  * Compiled for libc6
+  * Added poweroff patch by Roderich Schupp <rsch at ExperTeam.de>
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Sun, 12 Oct 1997 17:20:17 +0200
+
+sysvinit (2.71-2) frozen unstable; urgency=low
+
+  * Print 2.71 instead of 2.70 on startup :)
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Mon, 5 May 1997 12:45:25 +0200
+
+sysvinit (2.71-1) frozen unstable; urgency=high
+
+  * Added code for updwtmp() in utmp.c for glibc (2.0.3)
+  * Fixed all programs to use functions from utmp.c and getutent()
+  * Do not try to clean up utmp in init itself (Bug#9022)
+  * Removed sync() from main loop.
+  * Hopefully fixes bug #8657 (shutdown signal handling)
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Sat, 26 Apr 1997 19:57:27 +0200
+
+sysvinit (2.70-1) unstable; urgency=low
+
+  * Respawn fix
+  * Removed StUdLy CaPs from source code
+  * Moved files in source archive around
+  * Fixes for glibc (utmp handling, signal handling).
+  * Fixed '-d' option to last (now also works without '-a').
+  * Added extra checking in last.c to prevent showing dead entries
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Fri, 7 Feb 1997 15:31:30 +0100
+
+sysvinit (2.69-1) frozen unstable; urgency=medium
+
+  * Fixed bug that can throw X in a loop (or any other app that reads from
+    /dev/tty0)
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Sun, 1 Dec 1996 15:32:24 +0100
+
+sysvinit (2.67-1) frozen unstable; urgency=high
+
+  * Fixes problem with /dev/console being controlling terminal of some
+    daemons
+  * Puts copyright file in the right place
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Fri, 15 Nov 1996 12:23:33 +0100
+
+sysvinit (2.66-1) unstable; urgency=medium
+
+  * Skipped 2.65. A development 2.65 got out by accident and is apparently
+    being used..
+  * Also compiles and runs with GNU libc (and on the Alpha)
+  * Fixed dowall.c not to exit when getpwuid() fails and uid == 0.
+  * Fixed init panic'ing on empty lines in /etc/inittab
+  * Changed default PATH to include /usr/local/sbin
+  * Set /dev/console as controlling terminal for sysinit,bootwait,wait,powerwait
+    This allows using ^C to interrupt some parts of eg the boot process.
+  * Remove old symlink in /var/log/initlvl; let init check both
+    /var/log and /etc itself.
+
+ -- Miquel van Smoorenburg <miquels at cistron.nl>  Tue, 29 Oct 1996 13:46:54 +0100
+
+2.66    29-Oct-1996
+- Skipped 2.65. A development 2.65 got out by accident and is apparently
+  being used..
+- Fixed dowall.c not to exit when getpwuid() fails and uid == 0.
+- Fixed init panic'ing on empty lines in /etc/inittab
+- Changed default PATH to include /usr/local/sbin
+- Ported to Linux/Alpha and GNU libc.
+- Set /dev/console as controlling terminal for sysinit,bootwait,wait,powerwait.
+  This allows using ^C to interrupt some parts of eg the boot process.
+- Remove old symlink in /var/log/initlvl; let init check both
+  /var/log and /etc itself.
+
+2.64	28-Jun-1996
+- Init checks CONSOLE environment variable on startup (overrides /dev/console)
+- Init sets CONSOLE variable for all its children.
+- Wtmp(): when zeroing out old utmp entries, keep ut_id field
+- Wtmp(): try to re-use ut_id field if possible.
+- SetTerm(): only read from /etc/ioctl.save if written once.
+- Included start-stop-daemon, C version (source only).
+- Fixed wait() for the emergency shell.
+- killall5: ignore signal before doing kill(-1, pid).
+
+2.63    14-Jun-1996
+- Fixed preinst script for Debian
+- Fixed init.c to become init daemon if name is init.new
+- Fixed pidof to not return PIDs of shell scripts
+
+2.62-2	09-Jun-1996
+- Changed debian /etc/init.d/boot script to create a nologin file
+  at boot and to remove it just before going multiuser.
+
+2.62    31-May-1996
+- Decided to release a 2.62 version with a BIG WARNING about upgrading
+  init in it. Will send a patch to Linus for the linux/Documentation/Changes
+  file so that 2.62 or later is mentioned as the version to upgrade to.
+- Added docs for Slackware
+
+2.61-3  29-May-1996
+- Fixed debian/etc/init.d/network for the lo device.
+- Added "-xdev" to the cd /tmp && find in debian/etc/init.d/boot
+- Made remove time for files in /tmp configurable.
+
+2.61    29-Apr-1996
+- Changed /etc/init.d/boot script again
+- Fixed problem in init.c with trailing whitespace after entries in inittab
+- Fixed killall5 problems
+- Added manpage for lastb
+- Added SHELL= environment variable to sulogin
+- Fixed sulogin & shadow problems
+- Added timeout option to sulogin
+
+2.60-2  16-Apr-1996
+- Fixed sulogin (didn't work if root wasn't first entry in shadow file)
+- Fixed mesg for systems with "tty" group (such as Debian)
+- Fixed nsyslog() in killall5.c
+
+2.60   01-Apr-1996
+- Fixed race condition in init.c, resulting in hanging shutdowns.
+  Courtesy of Max Neunhoeffer <Max.Neunhoeffer at urz.uni-heidelberg.de>.
+- Fixed debian/etc/init.d/boot for swapon and mdadd
+- Added architecture to debian.control
+- Added manpages for rc.boot and rc.local
+- Updated inittab manpage for 4-character runlevel field
+- Added debian replaces for bsdutils < version_without_mesg
+- Fixed init.c so that it also works with kernels 1.3.81 and up
+
+2.59   10-Mar-1996
+- Init logs less to syslog (suspected to hang in syslog() or openlog() )
+- removed closelog() from init.c
+- removed time check of runlevel record in halt.
+- Added options to last to get hostname from ut_addr field
+- Added last and mesg to installation targets
+- rewrote /etc/init.d/boot a bit.
+
+2.58-2 04-Jan-1996
+- Changed etc/init.d/rc to do a stty onlcr
+- Added /var/log/initrunlvl symlink
+
+2.58-1 31-Dec-1995
+- Added the latest debian files.
+- Added support for 4-character id fields (if you have libc5).
+- Fixed pidof (in killall5) parsing of /proc/.../stat
+- Save restore GMT setting in /etc/init.d/boot
+
+2.57d 03-Dec-1995
+- Added sulogin
+- Added "-b" flag to init, gives a shell before
+  anything else (in case the startup scripts are screwed)
+- Moved fastboot to /fastboot
+- Folded in Debian patches.
+- Removed old scripts
+- Added debian /etc/directory.
+
+2.57c 08-Oct-1995
+- Changed over to init_request (with initreq.h)
+- Processes no longer killed when "process" field
+  changes, change takes effect after next respawn.
+
+2.57b xx-Aug-1995
+- Bugfix release for Debian and Slackware 3.0
+
+2.57a 10-Jul-1995
+- Fixed race condition init init.c wrt got_chld
+- Fixed one-off for malloc in killall5.c
+- Changed dowall.c
+- Console code: no relink to /dev/systty on CTRL-ALT-DEL)
+
+2.57 22-May-1995
+- Changed a few things here and there, didn't
+	 	  really document it :)
+
+2.55 17-Jan-1995
+- Added option to shutdown to run standalone.
+
+2.54 12-Jan-1995
+- Added GNU copyrigh to all *.[ch] files.
+- added /etc/initscript
+- reboot and halt now call shutdown in runlevels 1-5
+- Can run from read-only root (CDROM)
+
+2.53 10-Oct-1994
+- Renamed pidof to killall5, updated all scripts to
+  use killall5 instead of kill -1 ....
+- Rewrote scripts to use this, and some general changes.
+- Added SysV command line compatibility to shutdown.
+
+2.52 30-Aug-1994
+- Added `powerfailnow' keyword, for when UPS battery is low.
+- Updated `last'.
+- Fixed utmp handling (wrt. CLEAN_UTMP)
+TODO:
+* Make last compatible with GNU/BSD (long options?)
+* update powerd
+* remote SIGPWR broadcast? in powerd? (with priv. port)
+* remote shutdown
+
+2.50  14-Feb-1994
+- Ignores unknown command line arguments.
+- Modelled more after the "real" sysVinit
+- Lots of changes all over the place.
+  (like showing runlevel in "ps" listing, logging
+   runlevel into utmp file etc)
+- now using "reliable" signals instead of V7 style.
+- Updated all scripts. Examples are in two directories:
+  etc (normal) and etc-sysv (sysv style scripts).
+- runlevel 0 = halt, 1 = single user, 6 = reboot.
+- added support for serial console.
+- updated Propaganda, manpages.
+- added shutdown access control.
+
+2.4  24-May-93
+- Send out the official version into the world as
+  SysVinit-2.4.tar.z.
+
+2.4g 15-May-93
+- Changed init to really catch SIGPWR 'cause we
+  hooked up an UPS to the Linux machine. The
+  keyword for catching the TreeFingerSalute is
+  now "ctrlaltdel" instead of "power{wait,fail}".
+
+2.4a 22-Apr-93
+- Fixed last to reckognize BSD style wtmp logging.
+- Changed init to write wtmp records that are
+  SysV compliant but are also reckognized by the
+  BSD last. Added a '+' option to the 'process'
+  field of inittab, for getties that want to do
+  their own utmp/wtmp housekeeping (kludge!).
+- Now accepts a runlevel on the command line,
+  and reckognizes the 'auto' argument. (Sets the
+  environment variable AUTOBOOT to YES)
+
+2.2.3 24-Mar-93
+- Ripped out the 'leave' action. To difficult, and
+  unneeded.
+- Going single user now kills _all_ processes.
+- Added '-t secs' option to all commands.
+- This version is stable enough to post.
+
+2.2 02-Mar-93
+- Made wait()'s asynchronous
+- Changed whole thing to one big state machine
+- Now using 'pseudo levels' # & * for SYSINIT & BOOT
+- Added a new type of 'action', called leave. This
+  process will be executed when the system goes from a
+  runlevel specified in it's runlevel field to a 
+  level that's not. Nice to bring down NFS and the like.
+
+2.1 28-Jan-93
+- Fixed a bug with 'boot' and 'once'.
+- Check 'initdefault' for validity.
+- Reckognizes "single" as command line argument.
+- Retries execvp with 'sh -c exec ..' if command
+  is a shell script. (shouldn't execvp do this?)
+- Added patches to use syslog if defined.
+
+2.0 08-Dec-92
+- Rewrote the code totally, so started with a new
+  version number.
+- Dropped Minix support, this code now is Linux - specific.
+- With TEST switch on, this init & telinit can
+  run standalone for test purposes.
+
+1.3, 05-Jul-92
+- Got a 386, so installed Linux. Added 'soft' reboot
+  to be default under linux. Fixed some typos.
+
+1.2, 16-Jun-92
+- Bugreport from Michael Haardt ; removed deadlock
+  and added 'waitpid' instead of 'wait' for SYSV.
+
+1.1, 30-Apr-92
+- Read manual wrong: there is no 'action' field called
+  process, but all entries are of type process. Every
+  'process' get exec'ed by /bin/sh -c 'exec command'.
+- Rapidly respawning processes are caught in the act.
+- _SYSV support is really Linux support,
+  done by poe at daimi.aau.dk on 25-Mar-92.
+
+ 1.0, 01-Feb-92
+- Initial version, very primitive for the Minix
+  operating system. Required some mods. to the
+  kernel.
+

Deleted: sysvinit-upstream/tags/2.87dsf/man/bootlogd.8
===================================================================
--- sysvinit-upstream/trunk/man/bootlogd.8	2009-07-10 21:51:19 UTC (rev 1428)
+++ sysvinit-upstream/tags/2.87dsf/man/bootlogd.8	2009-07-12 18:00:14 UTC (rev 1458)
@@ -1,41 +0,0 @@
-.TH BOOTLOGD 8 "Jul 21, 2003" "" "Linux System Administrator's Manual"
-.SH NAME
-bootlogd \- record boot messages
-.SH SYNOPSIS
-.B /sbin/bootlogd
-.RB [ \-d ]
-.RB [ \-r ]
-.RB [ \-v ]
-.RB [ " -l logfile " ]
-.RB [ " -p pidfile " ]
-.SH DESCRIPTION
-\fBBootlogd\fP runs in the background and copies all strings sent to the
-\fI/dev/console\fP device to a logfile. If the logfile is not accessible,
-the messages will be kept in memory until it is.
-.SH OPTIONS
-.IP \fB\-d\fP
-Do not fork and run in the background.
-.IP \fB\-r\fP
-If there is an existing logfile called \fIlogfile\fP rename it to
-\fIlogfile~\fP unless \fIlogfile~\fP already exists.
-.IP \fB\-v\fP
-Show version.
-.IP "\fB\-l\fP \fIlogfile\fP"
-Log to this logfile. The default is \fI/var/log/boot\fP.
-.IP "\fB\-p\fP \fIpidfile\fP"
-Put process-id in this file. The default is no pidfile.
-.SH BUGS
-Bootlogd works by redirecting the console output from the console device.
-(Consequently \fBbootlogd\fP requires PTY support in the kernel configuration.)
-It copies that output to the real console device and to a log file.
-There is no standard way of ascertaining the real console device
-if you have a new-style \fI/dev/console\fP device (major 5, minor 1)
-so \fBbootlogd\fP parses the kernel command line looking for
-\fBconsole=...\fP lines and deduces the real console device from that.
-If that syntax is ever changed by the kernel, or a console type is used that
-\fBbootlogd\fP does not know about then \fBbootlogd\fP will not work.
-
-.SH AUTHOR
-Miquel van Smoorenburg, miquels at cistron.nl
-.SH "SEE ALSO"
-.BR dmesg (8)

Copied: sysvinit-upstream/tags/2.87dsf/man/bootlogd.8 (from rev 1432, sysvinit-upstream/trunk/man/bootlogd.8)
===================================================================
--- sysvinit-upstream/tags/2.87dsf/man/bootlogd.8	                        (rev 0)
+++ sysvinit-upstream/tags/2.87dsf/man/bootlogd.8	2009-07-12 18:00:14 UTC (rev 1458)
@@ -0,0 +1,55 @@
+.TH BOOTLOGD 8 "Jul 21, 2003" "" "Linux System Administrator's Manual"
+.SH NAME
+bootlogd \- record boot messages
+.SH SYNOPSIS
+.B /sbin/bootlogd
+.RB [ \-c ]
+.RB [ \-d ]
+.RB [ \-r ]
+.RB [ \-s ]
+.RB [ \-v ]
+.RB [ " -l logfile " ]
+.RB [ " -p pidfile " ]
+.SH DESCRIPTION
+\fBBootlogd\fP runs in the background and copies all strings sent to the
+\fI/dev/console\fP device to a logfile. If the logfile is not accessible,
+the messages will be kept in memory until it is.
+.SH OPTIONS
+.IP \fB\-d\fP
+Do not fork and run in the background.
+.IP \fB\-c\fP
+Attempt to write to the logfile even if it does not yet exist.
+Without this option,
+.B bootlogd
+will wait for the logfile to appear before attempting to write to it.
+This behavior prevents bootlogd from creating logfiles under mount points.
+.IP \fB\-r\fP
+If there is an existing logfile called \fIlogfile\fP rename it to
+\fIlogfile~\fP unless \fIlogfile~\fP already exists.
+.IP \fB\-s\fP
+Ensure that the data is written to the file after each line by calling
+.BR fdatasync (3).
+This will slow down a
+.BR fsck (8)
+process running in parallel.
+.IP \fB\-v\fP
+Show version.
+.IP "\fB\-l\fP \fIlogfile\fP"
+Log to this logfile. The default is \fI/var/log/boot\fP.
+.IP "\fB\-p\fP \fIpidfile\fP"
+Put process-id in this file. The default is no pidfile.
+.SH BUGS
+Bootlogd works by redirecting the console output from the console device.
+(Consequently \fBbootlogd\fP requires PTY support in the kernel configuration.)
+It copies that output to the real console device and to a log file.
+There is no standard way of ascertaining the real console device
+if you have a new-style \fI/dev/console\fP device (major 5, minor 1)
+so \fBbootlogd\fP parses the kernel command line looking for
+\fBconsole=...\fP lines and deduces the real console device from that.
+If that syntax is ever changed by the kernel, or a console type is used that
+\fBbootlogd\fP does not know about then \fBbootlogd\fP will not work.
+
+.SH AUTHOR
+Miquel van Smoorenburg, miquels at cistron.nl
+.SH "SEE ALSO"
+.BR dmesg (8),  fdatasync (3).

Deleted: sysvinit-upstream/tags/2.87dsf/man/killall5.8
===================================================================
--- sysvinit-upstream/trunk/man/killall5.8	2009-07-10 21:51:19 UTC (rev 1428)
+++ sysvinit-upstream/tags/2.87dsf/man/killall5.8	2009-07-12 18:00:14 UTC (rev 1458)
@@ -1,17 +0,0 @@
-.TH KILLALL5 8 "04 Nov 2003" "" "Linux System Administrator's Manual"
-.SH NAME
-killall5 -- send a signal to all processes.
-.SH SYNOPSIS
-.B killall5
-.RB -signalnumber
-.SH DESCRIPTION
-.B killall5
-is the SystemV killall command. It sends a signal to all processes except
-kernel threads and the processes in its own session, so it won't kill
-the shell that is running the script it was called from. Its primary
-(only) use is in the \fBrc\fP scripts found in the /etc/init.d directory.
-.SH SEE ALSO
-.BR halt (8),
-.BR reboot (8)
-.SH AUTHOR
-Miquel van Smoorenburg, miquels at cistron.nl

Copied: sysvinit-upstream/tags/2.87dsf/man/killall5.8 (from rev 1449, sysvinit-upstream/trunk/man/killall5.8)
===================================================================
--- sysvinit-upstream/tags/2.87dsf/man/killall5.8	                        (rev 0)
+++ sysvinit-upstream/tags/2.87dsf/man/killall5.8	2009-07-12 18:00:14 UTC (rev 1458)
@@ -0,0 +1,32 @@
+.TH KILLALL5 8 "04 Nov 2003" "" "Linux System Administrator's Manual"
+.SH NAME
+killall5 -- send a signal to all processes.
+.SH SYNOPSIS
+.B killall5
+.RB -signalnumber
+.RB [ \-o
+.IR omitpid ]
+.RB [ \-o
+.IR omitpid.. ]
+.SH DESCRIPTION
+.B killall5
+is the SystemV killall command. It sends a signal to all processes except
+kernel threads and the processes in its own session, so it won't kill
+the shell that is running the script it was called from. Its primary
+(only) use is in the \fBrc\fP scripts found in the /etc/init.d directory.
+.SH OPTIONS
+.IP "-o \fIomitpid\fP"
+Tells \fIkillall5\fP to omit processes with that process id.
+.SH NOTES
+\fIkillall5\fP can also be invoked as pidof, which is simply a
+(symbolic) link to the \fIkillall5\fP program.
+.SH EXIT STATUS
+The program return zero if it killed processes.  It return 2 if no
+process were killed, and 1 if it was unable to find any processes
+(/proc/ is missing).
+.SH SEE ALSO
+.BR halt (8),
+.BR reboot (8),
+.BR pidof (8)
+.SH AUTHOR
+Miquel van Smoorenburg, miquels at cistron.nl

Deleted: sysvinit-upstream/tags/2.87dsf/man/pidof.8
===================================================================
--- sysvinit-upstream/trunk/man/pidof.8	2009-07-10 21:51:19 UTC (rev 1428)
+++ sysvinit-upstream/tags/2.87dsf/man/pidof.8	2009-07-12 18:00:14 UTC (rev 1458)
@@ -1,60 +0,0 @@
-.TH PIDOF 8 "01 Sep 1998" "" "Linux System Administrator's Manual"
-.SH NAME
-pidof -- find the process ID of a running program.
-.SH SYNOPSIS
-.B pidof
-.RB [ \-s ]
-.RB [ \-c ]
-.RB [ \-x ]
-.RB [ \-o
-.IR omitpid ]
-.RB [ \-o
-.IR omitpid.. ]
-.B program
-.RB [ program.. ]
-.SH DESCRIPTION
-.B Pidof
-finds the process id's (pids) of the named programs. It prints those
-id's on the standard output. This program is on some systems used in
-run-level change scripts, especially when the system has a
-\fISystem-V\fP like \fIrc\fP structure. In that case these scripts are
-located in /etc/rc?.d, where ? is the runlevel. If the system has
-a
-.B start-stop-daemon
-(8) program that should be used instead.
-.SH OPTIONS
-.IP -s
-Single shot - this instructs the program to only return one \fIpid\fP.
-.IP -c
-Only return process ids that are running with the same root directory.
-This option is ignored for non-root users, as they will be unable to check
-the current root directory of processes they do not own.
-.IP -x
-Scripts too - this causes the program to also return process id's of
-shells running the named scripts.
-.IP "-o \fIomitpid\fP"
-Tells \fIpidof\fP to omit processes with that process id. The special
-pid \fB%PPID\fP can be used to name the parent process of the \fIpidof\fP
-program, in other words the calling shell or shell script.
-.SH "EXIT STATUS"
-.TP
-.B 0
-At least one program was found with the requested name.
-.TP
-.B 1
-No program was found with the requested name.
-.SH NOTES
-\fIpidof\fP is actually the same program as \fIkillall5\fP;
-the program behaves according to the name under which it is called.
-.PP
-When \fIpidof\fP is invoked with a full pathname to the program it
-should find the pid of, it is reasonably safe. Otherwise it is possible
-that it returns pids of running programs that happen to have the same name
-as the program you're after but are actually other programs.
-.SH SEE ALSO
-.BR shutdown (8),
-.BR init (8),
-.BR halt (8),
-.BR reboot (8)
-.SH AUTHOR
-Miquel van Smoorenburg, miquels at cistron.nl

Copied: sysvinit-upstream/tags/2.87dsf/man/pidof.8 (from rev 1449, sysvinit-upstream/trunk/man/pidof.8)
===================================================================
--- sysvinit-upstream/tags/2.87dsf/man/pidof.8	                        (rev 0)
+++ sysvinit-upstream/tags/2.87dsf/man/pidof.8	2009-07-12 18:00:14 UTC (rev 1458)
@@ -0,0 +1,61 @@
+.TH PIDOF 8 "01 Sep 1998" "" "Linux System Administrator's Manual"
+.SH NAME
+pidof -- find the process ID of a running program.
+.SH SYNOPSIS
+.B pidof
+.RB [ \-s ]
+.RB [ \-c ]
+.RB [ \-x ]
+.RB [ \-o
+.IR omitpid ]
+.RB [ \-o
+.IR omitpid.. ]
+.B program
+.RB [ program.. ]
+.SH DESCRIPTION
+.B Pidof
+finds the process id's (pids) of the named programs. It prints those
+id's on the standard output. This program is on some systems used in
+run-level change scripts, especially when the system has a
+\fISystem-V\fP like \fIrc\fP structure. In that case these scripts are
+located in /etc/rc?.d, where ? is the runlevel. If the system has
+a
+.B start-stop-daemon
+(8) program that should be used instead.
+.SH OPTIONS
+.IP -s
+Single shot - this instructs the program to only return one \fIpid\fP.
+.IP -c
+Only return process ids that are running with the same root directory.
+This option is ignored for non-root users, as they will be unable to check
+the current root directory of processes they do not own.
+.IP -x
+Scripts too - this causes the program to also return process id's of
+shells running the named scripts.
+.IP "-o \fIomitpid\fP"
+Tells \fIpidof\fP to omit processes with that process id. The special
+pid \fB%PPID\fP can be used to name the parent process of the \fIpidof\fP
+program, in other words the calling shell or shell script.
+.SH "EXIT STATUS"
+.TP
+.B 0
+At least one program was found with the requested name.
+.TP
+.B 1
+No program was found with the requested name.
+.SH NOTES
+\fIpidof\fP is actually the same program as \fIkillall5\fP;
+the program behaves according to the name under which it is called.
+.PP
+When \fIpidof\fP is invoked with a full pathname to the program it
+should find the pid of, it is reasonably safe. Otherwise it is possible
+that it returns pids of running programs that happen to have the same name
+as the program you're after but are actually other programs.
+.SH SEE ALSO
+.BR shutdown (8),
+.BR init (8),
+.BR halt (8),
+.BR reboot (8),
+.BR killall5 (8)
+.SH AUTHOR
+Miquel van Smoorenburg, miquels at cistron.nl

Deleted: sysvinit-upstream/tags/2.87dsf/man/shutdown.8
===================================================================
--- sysvinit-upstream/trunk/man/shutdown.8	2009-07-10 21:51:19 UTC (rev 1428)
+++ sysvinit-upstream/tags/2.87dsf/man/shutdown.8	2009-07-12 18:00:14 UTC (rev 1458)
@@ -1,197 +0,0 @@
-.\"{{{}}}
-.\"{{{  Title
-.TH SHUTDOWN 8 "November 12, 2003" "" "Linux System Administrator's Manual"
-.\"}}}
-.\"{{{  Name
-.SH NAME
-shutdown \- bring the system down
-.\"}}}
-.\"{{{  Synopsis
-.SH SYNOPSIS
-.B /sbin/shutdown
-.RB [ \-t
-.IR sec ]
-.RB [ \-arkhncfFHP ]
-.I time
-.RI [ warning-message ]
-.\"}}}
-.\"{{{  Description
-.SH DESCRIPTION
-\fBshutdown\fP brings the system down in a secure way.  All logged-in users are
-notified that the system is going down, and \fBlogin\fP(1) is blocked.
-It is possible to shut the system down immediately or after a specified delay.
-All processes are first notified that the system is going down by the
-signal \s-2SIGTERM\s0.  This gives programs like \fBvi\fP(1)
-the time to save the file being edited, 
-mail and news processing programs a chance to exit cleanly, etc. 
-\fBshutdown\fP does its job by signalling the \fBinit\fP process, 
-asking it to change the runlevel.
-Runlevel \fB0\fP is used to halt the system, runlevel \fB6\fP is used
-to reboot the system, and runlevel \fB1\fP is used to put to system into
-a state where administrative tasks can be performed; this is the default
-if neither the \fI-h\fP or \fI-r\fP flag is given to \fBshutdown\fP.
-To see which actions are taken on halt or reboot see the appropriate
-entries for these runlevels in the file \fI/etc/inittab\fP.
-.\"}}}
-.\"{{{  Options
-.SH OPTIONS
-.\"{{{  -a
-.IP "\fB\-a\fP
-Use \fB/etc/shutdown.allow\fP.
-.\"}}}
-.\"{{{  -t sec
-.IP "\fB\-t\fP \fIsec\fP"
-Tell \fBinit\fP(8) to wait \fIsec\fP seconds between sending processes the 
-warning and the kill signal, before changing to another runlevel.
-.\"}}}
-.\"{{{  -k
-.IP \fB\-k\fP
-Don't really shutdown; only send the warning messages to everybody.
-.\"}}}
-.\"{{{  -r
-.IP \fB\-r\fP
-Reboot after shutdown.
-.\"}}}
-.\"{{{  -h
-.IP \fB\-h\fP
-Halt or power off after shutdown.
-.\"}}}
-.\"{{{  -H
-.IP \fB\-H\fP
-Halt action is to halt or drop into boot monitor on systems that
-support it.
-.\"}}}
-.\"{{{  -P
-.IP \fB\-P\fP
-Halt action is to turn off the power.
-.\"}}}
-.\"{{{  -n
-.IP \fB\-n\fP
-[DEPRECATED] Don't call \fBinit\fP(8) to do the shutdown but do it ourself.
-The use of this option is discouraged, and its results are not always what
-you'd expect.
-.\"}}}
-.\"{{{  -f
-.IP \fB\-f\fP
-Skip fsck on reboot.
-.\"}}}
-.\"{{{  -F
-.IP \fB\-F\fP
-Force fsck on reboot.
-.\"}}}
-.\"{{{  -c
-.IP \fB\-c\fP
-Cancel an already running shutdown. With this option it is of course
-not possible to give the \fBtime\fP argument, but you can enter a
-explanatory message on the command line that will be sent to all users.
-.\"}}}
-.\"{{{  time
-.IP \fItime\fP
-When to shutdown.
-.\"}}}
-.\"{{{  warning-message
-.IP \fIwarning-message\fP
-Message to send to all users.
-.\"}}}
-.PP
-The \fItime\fP argument can have different formats.  First, it can be an
-absolute time in the format \fIhh:mm\fP, in which \fIhh\fP is the hour
-(1 or 2 digits) and \fImm\fP is the minute of the hour (in two digits).
-Second, it can be in the format \fB+\fP\fIm\fP, in which \fIm\fP is the
-number of minutes to wait.  The word \fBnow\fP is an alias for \fB+0\fP.
-.PP
-If shutdown is called with a delay, it will create the advisory file
-.I /etc/nologin
-which causes programs such as \fIlogin(1)\fP to not allow new user
-logins. This file is created five minutes before the shutdown sequence
-starts. Shutdown removes this file if it is stopped before it
-can signal init (i.e. it is cancelled or something goes wrong).
-It also removes it before calling init to change the runlevel.
-.PP
-The \fB\-f\fP flag means `reboot fast'.  This only creates an advisory
-file \fI/fastboot\fP which can be tested by the system when it comes
-up again.  The boot rc file can test if this file is present, and decide not 
-to run \fBfsck\fP(1) since the system has been shut down in the proper way.  
-After that, the boot process should remove \fI/fastboot\fP.
-.PP
-The \fB\-F\fP flag means `force fsck'.  This only creates an advisory
-file \fI/forcefsck\fP which can be tested by the system when it comes
-up again.  The boot rc file can test if this file is present, and decide
-to run \fBfsck\fP(1) with a special `force' flag so that even properly
-unmounted file systems get checked.
-After that, the boot process should remove \fI/forcefsck\fP.
-.PP
-The \fB-n\fP flag causes \fBshutdown\fP not to call \fBinit\fP, 
-but to kill all running processes itself. 
-\fBshutdown\fP will then turn off quota, accounting, and swapping
-and unmount all file systems.
-.\"}}}
-.\"{{{  Files
-.SH ACCESS CONTROL
-\fBshutdown\fP can be called from \fBinit\fP(8) when the magic keys
-\fBCTRL-ALT-DEL\fP are pressed, by creating an appropriate entry in
-\fI/etc/inittab\fP. This means that everyone who has physical access
-to the console keyboard can shut the system down. To prevent this,
-\fBshutdown\fP can check to see if an authorized user is logged in on
-one of the virtual consoles. If \fBshutdown\fP is called with the \fB-a\fP
-argument (add this to the invocation of shutdown in /etc/inittab),
-it checks to see if the file \fI/etc/shutdown.allow\fP is present.
-It then compares the login names in that file with the list of people
-that are logged in on a virtual console (from \fI/var/run/utmp\fP). Only
-if one of those authorized users \fBor root\fP is logged in, it will
-proceed. Otherwise it will write the message
-.sp 1
-.nf
-\fBshutdown: no authorized users logged in\fP
-.fi
-.sp 1
-to the (physical) system console. The format of \fI/etc/shutdown.allow\fP
-is one user name per line. Empty lines and comment lines (prefixed by a
-\fB#\fP) are allowed. Currently there is a limit of 32 users in this file.
-.sp 1
-Note that if \fI/etc/shutdown.allow\fP is not present, the \fB-a\fP
-argument is ignored.
-.SH HALT OR POWEROFF
-The \fB-H\fP option just sets the \fIinit\fP environment variable
-\fIINIT_HALT\fP to \fIHALT\fP, and the \fB-P\fP option just sets
-that variable to \fIPOWEROFF\fP. The shutdown script that calls
-\fBhalt\fP(8) as the last thing in the shutdown sequence should
-check these environment variables and call \fBhalt\fP(8) with
-the right options for these options to actually have any effect.
-Debian 3.1 (sarge) supports this.
-.SH FILES
-.nf
-/fastboot
-/etc/inittab
-/etc/init.d/halt
-/etc/init.d/reboot
-/etc/shutdown.allow
-.fi
-.\"}}}
-.SH NOTES
-A lot of users forget to give the \fItime\fP argument
-and are then puzzled by the error message \fBshutdown\fP produces. The
-\fItime\fP argument is mandatory; in 90 percent of all cases this argument
-will be the word \fBnow\fP.
-.PP
-Init can only capture CTRL-ALT-DEL and start shutdown in console mode.
-If the system is running the X window System, the X server processes
-all key strokes. Some X11 environments make it possible to capture
-CTRL-ALT-DEL, but what exactly is done with that event depends on
-that environment.
-.PP
-Shutdown wasn't designed to be run setuid. /etc/shutdown.allow is
-not used to find out who is executing shutdown, it ONLY checks who
-is currently logged in on (one of the) console(s).
-.\"{{{  Author
-.SH AUTHOR
-Miquel van Smoorenburg, miquels at cistron.nl
-.\"}}}
-.\"{{{  See also
-.SH "SEE ALSO"
-.BR fsck (8),
-.BR init (8),
-.BR halt (8),
-.BR poweroff (8),
-.BR reboot (8)
-.\"}}}

Copied: sysvinit-upstream/tags/2.87dsf/man/shutdown.8 (from rev 1451, sysvinit-upstream/trunk/man/shutdown.8)
===================================================================
--- sysvinit-upstream/tags/2.87dsf/man/shutdown.8	                        (rev 0)
+++ sysvinit-upstream/tags/2.87dsf/man/shutdown.8	2009-07-12 18:00:14 UTC (rev 1458)
@@ -0,0 +1,197 @@
+.\"{{{}}}
+.\"{{{  Title
+.TH SHUTDOWN 8 "November 12, 2003" "" "Linux System Administrator's Manual"
+.\"}}}
+.\"{{{  Name
+.SH NAME
+shutdown \- bring the system down
+.\"}}}
+.\"{{{  Synopsis
+.SH SYNOPSIS
+.B /sbin/shutdown
+.RB [ \-t
+.IR sec ]
+.RB [ \-arkhncfFHP ]
+.I time
+.RI [ warning-message ]
+.\"}}}
+.\"{{{  Description
+.SH DESCRIPTION
+\fBshutdown\fP brings the system down in a secure way.  All logged-in users are
+notified that the system is going down, and \fBlogin\fP(1) is blocked.
+It is possible to shut the system down immediately or after a specified delay.
+All processes are first notified that the system is going down by the
+signal \s-2SIGTERM\s0.  This gives programs like \fBvi\fP(1)
+the time to save the file being edited, 
+mail and news processing programs a chance to exit cleanly, etc. 
+\fBshutdown\fP does its job by signalling the \fBinit\fP process, 
+asking it to change the runlevel.
+Runlevel \fB0\fP is used to halt the system, runlevel \fB6\fP is used
+to reboot the system, and runlevel \fB1\fP is used to put to system into
+a state where administrative tasks can be performed; this is the default
+if neither the \fI-h\fP or \fI-r\fP flag is given to \fBshutdown\fP.
+To see which actions are taken on halt or reboot see the appropriate
+entries for these runlevels in the file \fI/etc/inittab\fP.
+.\"}}}
+.\"{{{  Options
+.SH OPTIONS
+.\"{{{  -a
+.IP "\fB\-a\fP
+Use \fB/etc/shutdown.allow\fP.
+.\"}}}
+.\"{{{  -t sec
+.IP "\fB\-t\fP \fIsec\fP"
+Tell \fBinit\fP(8) to wait \fIsec\fP seconds between sending processes the 
+warning and the kill signal, before changing to another runlevel.
+.\"}}}
+.\"{{{  -k
+.IP \fB\-k\fP
+Don't really shutdown; only send the warning messages to everybody.
+.\"}}}
+.\"{{{  -r
+.IP \fB\-r\fP
+Reboot after shutdown.
+.\"}}}
+.\"{{{  -h
+.IP \fB\-h\fP
+Halt or power off after shutdown.
+.\"}}}
+.\"{{{  -H
+.IP \fB\-H\fP
+Modifier to the -h flag.  Halt action is to halt or drop into boot
+monitor on systems that support it.  Must be used with the -h flag.
+.\"}}}
+.\"{{{  -P
+.IP \fB\-P\fP
+Halt action is to turn off the power.
+.\"}}}
+.\"{{{  -n
+.IP \fB\-n\fP
+[DEPRECATED] Don't call \fBinit\fP(8) to do the shutdown but do it ourself.
+The use of this option is discouraged, and its results are not always what
+you'd expect.
+.\"}}}
+.\"{{{  -f
+.IP \fB\-f\fP
+Skip fsck on reboot.
+.\"}}}
+.\"{{{  -F
+.IP \fB\-F\fP
+Force fsck on reboot.
+.\"}}}
+.\"{{{  -c
+.IP \fB\-c\fP
+Cancel an already running shutdown. With this option it is of course
+not possible to give the \fBtime\fP argument, but you can enter a
+explanatory message on the command line that will be sent to all users.
+.\"}}}
+.\"{{{  time
+.IP \fItime\fP
+When to shutdown.
+.\"}}}
+.\"{{{  warning-message
+.IP \fIwarning-message\fP
+Message to send to all users.
+.\"}}}
+.PP
+The \fItime\fP argument can have different formats.  First, it can be an
+absolute time in the format \fIhh:mm\fP, in which \fIhh\fP is the hour
+(1 or 2 digits) and \fImm\fP is the minute of the hour (in two digits).
+Second, it can be in the format \fB+\fP\fIm\fP, in which \fIm\fP is the
+number of minutes to wait.  The word \fBnow\fP is an alias for \fB+0\fP.
+.PP
+If shutdown is called with a delay, it will create the advisory file
+.I /etc/nologin
+which causes programs such as \fIlogin(1)\fP to not allow new user
+logins. This file is created five minutes before the shutdown sequence
+starts. Shutdown removes this file if it is stopped before it
+can signal init (i.e. it is cancelled or something goes wrong).
+It also removes it before calling init to change the runlevel.
+.PP
+The \fB\-f\fP flag means `reboot fast'.  This only creates an advisory
+file \fI/fastboot\fP which can be tested by the system when it comes
+up again.  The boot rc file can test if this file is present, and decide not 
+to run \fBfsck\fP(1) since the system has been shut down in the proper way.  
+After that, the boot process should remove \fI/fastboot\fP.
+.PP
+The \fB\-F\fP flag means `force fsck'.  This only creates an advisory
+file \fI/forcefsck\fP which can be tested by the system when it comes
+up again.  The boot rc file can test if this file is present, and decide
+to run \fBfsck\fP(1) with a special `force' flag so that even properly
+unmounted file systems get checked.
+After that, the boot process should remove \fI/forcefsck\fP.
+.PP
+The \fB-n\fP flag causes \fBshutdown\fP not to call \fBinit\fP, 
+but to kill all running processes itself. 
+\fBshutdown\fP will then turn off quota, accounting, and swapping
+and unmount all file systems.
+.\"}}}
+.\"{{{  Files
+.SH ACCESS CONTROL
+\fBshutdown\fP can be called from \fBinit\fP(8) when the magic keys
+\fBCTRL-ALT-DEL\fP are pressed, by creating an appropriate entry in
+\fI/etc/inittab\fP. This means that everyone who has physical access
+to the console keyboard can shut the system down. To prevent this,
+\fBshutdown\fP can check to see if an authorized user is logged in on
+one of the virtual consoles. If \fBshutdown\fP is called with the \fB-a\fP
+argument (add this to the invocation of shutdown in /etc/inittab),
+it checks to see if the file \fI/etc/shutdown.allow\fP is present.
+It then compares the login names in that file with the list of people
+that are logged in on a virtual console (from \fI/var/run/utmp\fP). Only
+if one of those authorized users \fBor root\fP is logged in, it will
+proceed. Otherwise it will write the message
+.sp 1
+.nf
+\fBshutdown: no authorized users logged in\fP
+.fi
+.sp 1
+to the (physical) system console. The format of \fI/etc/shutdown.allow\fP
+is one user name per line. Empty lines and comment lines (prefixed by a
+\fB#\fP) are allowed. Currently there is a limit of 32 users in this file.
+.sp 1
+Note that if \fI/etc/shutdown.allow\fP is not present, the \fB-a\fP
+argument is ignored.
+.SH HALT OR POWEROFF
+The \fB-H\fP option just sets the \fIinit\fP environment variable
+\fIINIT_HALT\fP to \fIHALT\fP, and the \fB-P\fP option just sets
+that variable to \fIPOWEROFF\fP. The shutdown script that calls
+\fBhalt\fP(8) as the last thing in the shutdown sequence should
+check these environment variables and call \fBhalt\fP(8) with
+the right options for these options to actually have any effect.
+Debian 3.1 (sarge) supports this.
+.SH FILES
+.nf
+/fastboot
+/etc/inittab
+/etc/init.d/halt
+/etc/init.d/reboot
+/etc/shutdown.allow
+.fi
+.\"}}}
+.SH NOTES
+A lot of users forget to give the \fItime\fP argument
+and are then puzzled by the error message \fBshutdown\fP produces. The
+\fItime\fP argument is mandatory; in 90 percent of all cases this argument
+will be the word \fBnow\fP.
+.PP
+Init can only capture CTRL-ALT-DEL and start shutdown in console mode.
+If the system is running the X window System, the X server processes
+all key strokes. Some X11 environments make it possible to capture
+CTRL-ALT-DEL, but what exactly is done with that event depends on
+that environment.
+.PP
+Shutdown wasn't designed to be run setuid. /etc/shutdown.allow is
+not used to find out who is executing shutdown, it ONLY checks who
+is currently logged in on (one of the) console(s).
+.\"{{{  Author
+.SH AUTHOR
+Miquel van Smoorenburg, miquels at cistron.nl
+.\"}}}
+.\"{{{  See also
+.SH "SEE ALSO"
+.BR fsck (8),
+.BR init (8),
+.BR halt (8),
+.BR poweroff (8),
+.BR reboot (8)
+.\"}}}

Deleted: sysvinit-upstream/tags/2.87dsf/src/bootlogd.c
===================================================================
--- sysvinit-upstream/trunk/src/bootlogd.c	2009-07-10 21:51:19 UTC (rev 1428)
+++ sysvinit-upstream/tags/2.87dsf/src/bootlogd.c	2009-07-12 18:00:14 UTC (rev 1458)
@@ -1,626 +0,0 @@
-/*
- * bootlogd.c	Store output from the console during bootup into a file.
- *		The file is usually located on the /var partition, and
- *		gets written (and fsynced) as soon as possible.
- *
- * Version:	@(#)bootlogd  2.86pre  12-Jan-2004  miquels at cistron.nl
- *
- * Bugs:	Uses openpty(), only available in glibc. Sorry.
- *
- *		This file is part of the sysvinit suite,
- *		Copyright 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.
- *
- *				*NOTE* *NOTE* *NOTE*
- *			This is a PROOF OF CONCEPT IMPLEMENTATION
- *
- *		I have bigger plans for Debian, but for now
- *		this has to do ;)
- *
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/utsname.h>
-#include <time.h>
-#include <stdio.h>
-#include <errno.h>
-#include <malloc.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <signal.h>
-#include <getopt.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <pty.h>
-#include <ctype.h>
-#ifdef __linux__
-#include <sys/mount.h>
-#endif
-
-char *Version = "@(#) bootlogd 2.86 03-Jun-2004 miquels at cistron.nl";
-
-#define LOGFILE	"/var/log/boot"
-
-char ringbuf[32768];
-char *endptr = ringbuf + sizeof(ringbuf);
-char *inptr  = ringbuf;
-char *outptr = ringbuf;
-
-int got_signal = 0;
-int didnl = 1;
-
-struct line {
-	char buf[256];
-	int pos;
-} line;
-
-/*
- *	Console devices as listed on the kernel command line and
- *	the mapping to actual devices in /dev
- */
-struct consdev {
-	char	*cmdline;
-	char	*dev1;
-	char	*dev2;
-} consdev[] = {
-	{ "ttySC",	"/dev/ttySC%s",		"/dev/ttsc/%s"	},
-	{ "ttyS",	"/dev/ttyS%s",		"/dev/tts/%s"	},
-	{ "tty",	"/dev/tty%s",		"/dev/vc/%s"	},
-	{ "hvc",	"/dev/hvc%s",		"/dev/hvc/%s"	},
-	{ NULL,		NULL,			NULL		},
-};
-
-/*
- *	Devices to try as console if not found on kernel command line.
- *	Tried from left to right (as opposed to kernel cmdline).
- */
-char *defcons[] = { "tty0", "hvc0", "ttyS0", "ttySC0", NULL };
-
-/*
- *	Catch signals.
- */
-void handler(int sig)
-{
-	got_signal = sig;
-}
-
-
-/*
- *	Scan /dev and find the device name.
- *	Side-effect: directory is changed to /dev
- *
- *	FIXME: scan subdirectories for devfs support ?
- */
-int findtty(char *res, int rlen, dev_t dev)
-{
-	DIR		*dir;
-	struct dirent	*ent;
-	struct stat	st;
-	int		r = 0;
-
-	if (chdir("/dev") < 0 || (dir = opendir(".")) == NULL) {
-		perror("bootlogd: /dev");
-		return -1;
-	}
-	while ((ent = readdir(dir)) != NULL) {
-		if (lstat(ent->d_name, &st) != 0)
-			continue;
-		if (!S_ISCHR(st.st_mode))
-			continue;
-		if (st.st_rdev == dev) {
-			break;
-		}
-	}
-	if (ent == NULL) {
-		fprintf(stderr, "bootlogd: cannot find console device "
-			"%d:%d in /dev\n", major(dev), minor(dev));
-		r = -1;
-	} else if (strlen(ent->d_name) + 5 >= rlen) {
-		fprintf(stderr, "bootlogd: console device name too long\n");
-		r = -1;
-	} else
-		snprintf(res, rlen, "/dev/%s", ent->d_name);
-	closedir(dir);
-
-	return r;
-}
-
-/*
- *	For some reason, openpty() in glibc sometimes doesn't
- *	work at boot-time. It must be a bug with old-style pty
- *	names, as new-style (/dev/pts) is not available at that
- *	point. So, we find a pty/tty pair ourself if openpty()
- *	fails for whatever reason.
- */
-int findpty(int *master, int *slave, char *name)
-{
-	char	pty[16];
-	char	tty[16];
-	int	i, j;
-	int	found;
-
-	if (openpty(master, slave, name, NULL, NULL) >= 0)
-		return 0;
-
-	found = 0;
-
-	for (i = 'p'; i <= 'z'; i++) {
-		for (j = '0'; j <= 'f'; j++) {
-			if (j == '9' + 1) j = 'a';
-			sprintf(pty, "/dev/pty%c%c", i, j);
-			sprintf(tty, "/dev/tty%c%c", i, j);
-			if ((*master = open(pty, O_RDWR|O_NOCTTY)) >= 0) {
-				*slave = open(tty, O_RDWR|O_NOCTTY);
-				if (*slave >= 0) {
-					found = 1;
-					break;
-				}
-			}
-		}
-		if (found) break;
-	}
-	if (found < 0) return -1;
-
-	if (name) strcpy(name, tty);
-
-	return 0;
-}
-/*
- *	See if a console taken from the kernel command line maps
- *	to a character device we know about, and if we can open it.
- */
-int isconsole(char *s, char *res, int rlen)
-{
-	struct consdev	*c;
-	int		l, sl, i, fd;
-	char		*p, *q;
-
-	sl = strlen(s);
-
-	for (c = consdev; c->cmdline; c++) {
-		l = strlen(c->cmdline);
-		if (sl <= l) continue;
-		p = s + l;
-		if (strncmp(s, c->cmdline, l) != 0 || !isdigit(*p))
-			continue;
-		for (i = 0; i < 2; i++) {
-			snprintf(res, rlen, i ? c->dev1 : c->dev2, p);
-			if ((q = strchr(res, ',')) != NULL) *q = 0;
-			if ((fd = open(res, O_RDONLY|O_NONBLOCK)) >= 0) {
-				close(fd);
-				return 1;
-			}
-		}
-	}
-	return 0;
-}
-
-/*
- *	Find out the _real_ console. Assume that stdin is connected to
- *	the console device (/dev/console).
- */
-int consolename(char *res, int rlen)
-{
-#ifdef TIOCGDEV
-	unsigned int	kdev;
-#endif
-	struct stat	st, st2;
-	char		buf[256];
-	char		*p;
-	int		didmount = 0;
-	int		n, r;
-	int		fd;
-
-	fstat(0, &st);
-	if (major(st.st_rdev) != 5 || minor(st.st_rdev) != 1) {
-		/*
-		 *	Old kernel, can find real device easily.
-		 */
-		return findtty(res, rlen, st.st_rdev);
-	}
-
-#ifdef TIOCGDEV
-	if (ioctl(0, TIOCGDEV, &kdev) == 0)
-		return findtty(res, rlen, (dev_t)kdev);
-	if (errno != ENOIOCTLCMD) return -1;
-#endif
-
-#ifdef __linux__
-	/*
-	 *	Read /proc/cmdline.
-	 */
-	stat("/", &st);
-	if (stat("/proc", &st2) < 0) {
-		perror("bootlogd: /proc");
-		return -1;
-	}
-	if (st.st_dev == st2.st_dev) {
-		if (mount("proc", "/proc", "proc", 0, NULL) < 0) {
-			perror("bootlogd: mount /proc");
-			return -1;
-		}
-		didmount = 1;
-	}
-
-	n = 0;
-	r = -1;
-	if ((fd = open("/proc/cmdline", O_RDONLY)) < 0) {
-		perror("bootlogd: /proc/cmdline");
-	} else {
-		buf[0] = 0;
-		if ((n = read(fd, buf, sizeof(buf) - 1)) >= 0)
-			r = 0;
-		else
-			perror("bootlogd: /proc/cmdline");
-		close(fd);
-	}
-	if (didmount) umount("/proc");
-
-	if (r < 0) return r;
-
-	/*
-	 *	OK, so find console= in /proc/cmdline.
-	 *	Parse in reverse, opening as we go.
-	 *
-	 *	Valid console devices: ttySC, ttyS, tty, hvc.
-	 */
-	p = buf + n;
-	*p-- = 0;
-	r = -1;
-	while (p >= buf) {
-		if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
-			*p-- = 0;
-			continue;
-		}
-		if (strncmp(p, "console=", 8) == 0 &&
-		    isconsole(p + 8, res, rlen)) {
-			r = 0;
-			break;
-		}
-		p--;
-	}
-
-	if (r == 0) return r;
-#endif
-
-	/*
-	 *	Okay, no console on the command line -
-	 *	guess the default console.
-	 */
-	for (n = 0; defcons[n]; n++)
-		if (isconsole(defcons[n], res, rlen))
-			return 0;
-
-	fprintf(stderr, "bootlogd: cannot deduce real console device\n");
-
-	return -1;
-}
-
-
-/*
- *	Write data and make sure it's on disk.
- */
-void writelog(FILE *fp, unsigned char *ptr, int len)
-{
-	time_t		t;
-	char		*s;
-	char		tmp[8];
-	int		olen = len;
-	int		dosync = 0;
-	int		tlen;
-
-	while (len > 0) {
-		tmp[0] = 0;
-		if (didnl) {
-			time(&t);
-			s = ctime(&t);
-			fprintf(fp, "%.24s: ", s);
-			didnl = 0;
-		}
-		switch (*ptr) {
-			case 27: /* ESC */
-				strcpy(tmp, "^[");
-				break;
-			case '\r':
-				line.pos = 0;
-				break;
-			case 8: /* ^H */
-				if (line.pos > 0) line.pos--;
-				break;
-			case '\n':
-				didnl = 1;
-				dosync = 1;
-				break;
-			case '\t':
-				line.pos += (line.pos / 8 + 1) * 8;
-				if (line.pos >= sizeof(line.buf))
-					line.pos = sizeof(line.buf) - 1;
-				break;
-			case  32 ... 127:
-			case 161 ... 255:
-				tmp[0] = *ptr;
-				tmp[1] = 0;
-				break;
-			default:
-				sprintf(tmp, "\\%03o", *ptr);
-				break;
-		}
-		ptr++;
-		len--;
-
-		tlen = strlen(tmp);
-		if (tlen && (line.pos + tlen < sizeof(line.buf))) {
-			memcpy(line.buf + line.pos, tmp, tlen);
-			line.pos += tlen;
-		}
-		if (didnl) {
-			fprintf(fp, "%s\n", line.buf);
-			memset(&line, 0, sizeof(line));
-		}
-	}
-
-	if (dosync) {
-		fflush(fp);
-		fdatasync(fileno(fp));
-	}
-
-	outptr += olen;
-	if (outptr >= endptr)
-		outptr = ringbuf;
-
-}
-
-
-/*
- *	Print usage message and exit.
- */
-void usage(void)
-{
-	fprintf(stderr, "Usage: bootlogd [-v] [-r] [-d] [-p pidfile] [-l logfile]\n");
-	exit(1);
-}
-
-int open_nb(char *buf)
-{
-	int	fd, n;
-
-	if ((fd = open(buf, O_WRONLY|O_NONBLOCK|O_NOCTTY)) < 0)
-		return -1;
-	n = fcntl(fd, F_GETFL);
-	n &= ~(O_NONBLOCK);
-	fcntl(fd, F_SETFL, n);
-
-	return fd;
-}
-
-/*
- *	We got a write error on the real console. If its an EIO,
- *	somebody hung up our filedescriptor, so try to re-open it.
- */
-int write_err(int pts, int realfd, char *realcons, int e)
-{
-	int	fd;
-
-	if (e != EIO) {
-werr:
-		close(pts);
-		fprintf(stderr, "bootlogd: writing to console: %s\n",
-			strerror(e));
-		return -1;
-	}
-	close(realfd);
-	if ((fd = open_nb(realcons)) < 0)
-		goto werr;
-
-	return fd;
-}
-
-int main(int argc, char **argv)
-{
-	FILE		*fp;
-	struct timeval	tv;
-	fd_set		fds;
-	char		buf[1024];
-	char		realcons[1024];
-	char		*p;
-	char		*logfile;
-	char		*pidfile;
-	int		rotate;
-	int		dontfork;
-	int		ptm, pts;
-	int		realfd;
-	int		n, m, i;
-	int		todo;
-
-	fp = NULL;
-	logfile = LOGFILE;
-	pidfile = NULL;
-	rotate = 0;
-	dontfork = 0;
-
-	while ((i = getopt(argc, argv, "dl:p:rv")) != EOF) switch(i) {
-		case 'l':
-			logfile = optarg;
-			break;
-		case 'r':
-			rotate = 1;
-			break;
-		case 'v':
-			printf("%s\n", Version);
-			exit(0);
-			break;
-		case 'p':
-			pidfile = optarg;
-			break;
-		case 'd':
-			dontfork = 1;
-			break;
-		default:
-			usage();
-			break;
-	}
-	if (optind < argc) usage();
-
-	signal(SIGTERM, handler);
-	signal(SIGQUIT, handler);
-	signal(SIGINT,  handler);
-	signal(SIGTTIN,  SIG_IGN);
-	signal(SIGTTOU,  SIG_IGN);
-	signal(SIGTSTP,  SIG_IGN);
-
-	/*
-	 *	Open console device directly.
-	 */
-	if (consolename(realcons, sizeof(realcons)) < 0)
-		return 1;
-
-	if (strcmp(realcons, "/dev/tty0") == 0)
-		strcpy(realcons, "/dev/tty1");
-	if (strcmp(realcons, "/dev/vc/0") == 0)
-		strcpy(realcons, "/dev/vc/1");
-
-	if ((realfd = open_nb(realcons)) < 0) {
-		fprintf(stderr, "bootlogd: %s: %s\n", buf, strerror(errno));
-		return 1;
-	}
-
-	/*
-	 *	Grab a pty, and redirect console messages to it.
-	 */
-	ptm = -1;
-	pts = -1;
-	buf[0] = 0;
-	if (findpty(&ptm, &pts, buf) < 0) {
-		fprintf(stderr,
-			"bootlogd: cannot allocate pseudo tty: %s\n",
-			strerror(errno));
-		return 1;
-	}
-
-	(void)ioctl(0, TIOCCONS, NULL);
-#if 1
-	/* Work around bug in 2.1/2.2 kernels. Fixed in 2.2.13 and 2.3.18 */
-	if ((n = open("/dev/tty0", O_RDWR)) >= 0) {
-		(void)ioctl(n, TIOCCONS, NULL);
-		close(n);
-	}
-#endif
-	if (ioctl(pts, TIOCCONS, NULL) < 0) {
-		fprintf(stderr, "bootlogd: ioctl(%s, TIOCCONS): %s\n",
-			buf, strerror(errno));
-		return 1;
-	}
-
-	/*
-	 *	Fork and write pidfile if needed.
-	 */
-	if (!dontfork) {
-		if (fork())
-			exit(1);
-		setsid();
-	}
-	if (pidfile) {
-		unlink(pidfile);
-		if ((fp = fopen(pidfile, "w")) != NULL) {
-			fprintf(fp, "%d\n", (int)getpid());
-			fclose(fp);
-		}
-		fp = NULL;
-	}
-
-	/*
-	 *	Read the console messages from the pty, and write
-	 *	to the real console and the logfile.
-	 */
-	while (!got_signal) {
-
-		/*
-		 *	We timeout after 5 seconds if we still need to
-		 *	open the logfile. There might be buffered messages
-		 *	we want to write.
-		 */
-		tv.tv_sec = 0;
-		tv.tv_usec = 500000;
-		FD_ZERO(&fds);
-		FD_SET(ptm, &fds);
-		if (select(ptm + 1, &fds, NULL, NULL, &tv) == 1) {
-			/*
-			 *	See how much space there is left, read.
-			 */
-			if ((n = read(ptm, inptr, endptr - inptr)) >= 0) {
-				/*
-				 *	Write data (in chunks if needed)
-				 *	to the real output device.
-				 */
-				m = n;
-				p = inptr;
-				while (m > 0) {
-					i = write(realfd, p, m);
-					if (i >= 0) {
-						m -= i;
-						p += i;
-						continue;
-					}
-					/*
-					 *	Handle EIO (somebody hung
-					 *	up our filedescriptor)
-					 */
-					realfd = write_err(pts, realfd,
-						realcons, errno);
-					if (realfd >= 0) continue;
-					got_signal = 1; /* Not really */
-					break;
-				}
-
-				/*
-				 *	Increment buffer position. Handle
-				 *	wraps, and also drag output pointer
-				 *	along if we cross it.
-				 */
-				inptr += n;
-				if (inptr - n < outptr && inptr > outptr)
-					outptr = inptr;
-				if (inptr >= endptr)
-					inptr = ringbuf;
-				if (outptr >= endptr)
-					outptr = ringbuf;
-			}
-		}
-
-		/*
-		 *	Perhaps we need to open the logfile.
-		 */
-		if (fp == NULL && rotate && access(logfile, F_OK) == 0) {
-			snprintf(buf, sizeof(buf), "%s~", logfile);
-			rename(logfile, buf);
-		}
-		if (fp == NULL)
-			fp = fopen(logfile, "a");
-		if (inptr >= outptr)
-			todo = inptr - outptr;
-		else
-			todo = endptr - outptr;
-		if (fp && todo)
-			writelog(fp, outptr, todo);
-	}
-
-	if (fp) {
-		if (!didnl) fputc('\n', fp);
-		fclose(fp);
-	}
-
-	close(pts);
-	close(ptm);
-	close(realfd);
-
-	return 0;
-}
-

Copied: sysvinit-upstream/tags/2.87dsf/src/bootlogd.c (from rev 1433, sysvinit-upstream/trunk/src/bootlogd.c)
===================================================================
--- sysvinit-upstream/tags/2.87dsf/src/bootlogd.c	                        (rev 0)
+++ sysvinit-upstream/tags/2.87dsf/src/bootlogd.c	2009-07-12 18:00:14 UTC (rev 1458)
@@ -0,0 +1,648 @@
+/*
+ * bootlogd.c	Store output from the console during bootup into a file.
+ *		The file is usually located on the /var partition, and
+ *		gets written (and fsynced) as soon as possible.
+ *
+ * Version:	@(#)bootlogd  2.86pre  12-Jan-2004  miquels at cistron.nl
+ *
+ * Bugs:	Uses openpty(), only available in glibc. Sorry.
+ *
+ *		This file is part of the sysvinit suite,
+ *		Copyright 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.
+ *
+ *				*NOTE* *NOTE* *NOTE*
+ *			This is a PROOF OF CONCEPT IMPLEMENTATION
+ *
+ *		I have bigger plans for Debian, but for now
+ *		this has to do ;)
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/utsname.h>
+#include <time.h>
+#include <stdio.h>
+#include <errno.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <getopt.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <pty.h>
+#include <ctype.h>
+#ifdef __linux__
+#include <sys/mount.h>
+#endif
+
+char *Version = "@(#) bootlogd 2.86 03-Jun-2004 miquels at cistron.nl";
+
+#define LOGFILE	"/var/log/boot"
+
+char ringbuf[32768];
+char *endptr = ringbuf + sizeof(ringbuf);
+char *inptr  = ringbuf;
+char *outptr = ringbuf;
+
+int got_signal = 0;
+int didnl = 1;
+int createlogfile = 0;
+int syncalot = 0;
+
+struct line {
+	char buf[256];
+	int pos;
+} line;
+
+/*
+ *	Console devices as listed on the kernel command line and
+ *	the mapping to actual devices in /dev
+ */
+struct consdev {
+	char	*cmdline;
+	char	*dev1;
+	char	*dev2;
+} consdev[] = {
+	{ "ttyB",	"/dev/ttyB%s",		NULL		},
+	{ "ttySC",	"/dev/ttySC%s",		"/dev/ttsc/%s"	},
+	{ "ttyS",	"/dev/ttyS%s",		"/dev/tts/%s"	},
+	{ "tty",	"/dev/tty%s",		"/dev/vc/%s"	},
+	{ "hvc",	"/dev/hvc%s",		"/dev/hvc/%s"	},
+	{ NULL,		NULL,			NULL		},
+};
+
+/*
+ *	Devices to try as console if not found on kernel command line.
+ *	Tried from left to right (as opposed to kernel cmdline).
+ */
+char *defcons[] = { "tty0", "hvc0", "ttyS0", "ttySC0", "ttyB0", NULL };
+
+/*
+ *	Catch signals.
+ */
+void handler(int sig)
+{
+	got_signal = sig;
+}
+
+
+/*
+ *	Scan /dev and find the device name.
+ *	Side-effect: directory is changed to /dev
+ *
+ *	FIXME: scan subdirectories for devfs support ?
+ */
+int findtty(char *res, int rlen, dev_t dev)
+{
+	DIR		*dir;
+	struct dirent	*ent;
+	struct stat	st;
+	int		r = 0;
+
+	if (chdir("/dev") < 0 || (dir = opendir(".")) == NULL) {
+		perror("bootlogd: /dev");
+		return -1;
+	}
+	while ((ent = readdir(dir)) != NULL) {
+		if (lstat(ent->d_name, &st) != 0)
+			continue;
+		if (!S_ISCHR(st.st_mode))
+			continue;
+		if (st.st_rdev == dev) {
+			break;
+		}
+	}
+	if (ent == NULL) {
+		fprintf(stderr, "bootlogd: cannot find console device "
+			"%d:%d in /dev\n", major(dev), minor(dev));
+		r = -1;
+	} else if (strlen(ent->d_name) + 5 >= rlen) {
+		fprintf(stderr, "bootlogd: console device name too long\n");
+		r = -1;
+	} else
+		snprintf(res, rlen, "/dev/%s", ent->d_name);
+	closedir(dir);
+
+	return r;
+}
+
+/*
+ *	For some reason, openpty() in glibc sometimes doesn't
+ *	work at boot-time. It must be a bug with old-style pty
+ *	names, as new-style (/dev/pts) is not available at that
+ *	point. So, we find a pty/tty pair ourself if openpty()
+ *	fails for whatever reason.
+ */
+int findpty(int *master, int *slave, char *name)
+{
+	char	pty[16];
+	char	tty[16];
+	int	i, j;
+	int	found;
+
+	if (openpty(master, slave, name, NULL, NULL) >= 0)
+		return 0;
+
+	found = 0;
+
+	for (i = 'p'; i <= 'z'; i++) {
+		for (j = '0'; j <= 'f'; j++) {
+			if (j == '9' + 1) j = 'a';
+			sprintf(pty, "/dev/pty%c%c", i, j);
+			sprintf(tty, "/dev/tty%c%c", i, j);
+			if ((*master = open(pty, O_RDWR|O_NOCTTY)) >= 0) {
+				*slave = open(tty, O_RDWR|O_NOCTTY);
+				if (*slave >= 0) {
+					found = 1;
+					break;
+				}
+			}
+		}
+		if (found) break;
+	}
+	if (found < 0) return -1;
+
+	if (name) strcpy(name, tty);
+
+	return 0;
+}
+/*
+ *	See if a console taken from the kernel command line maps
+ *	to a character device we know about, and if we can open it.
+ */
+int isconsole(char *s, char *res, int rlen)
+{
+	struct consdev	*c;
+	int		l, sl, i, fd;
+	char		*p, *q;
+
+	sl = strlen(s);
+
+	for (c = consdev; c->cmdline; c++) {
+		l = strlen(c->cmdline);
+		if (sl <= l) continue;
+		p = s + l;
+		if (strncmp(s, c->cmdline, l) != 0 || !isdigit(*p))
+			continue;
+		for (i = 0; i < 2; i++) {
+			snprintf(res, rlen, i ? c->dev1 : c->dev2, p);
+			if ((q = strchr(res, ',')) != NULL) *q = 0;
+			if ((fd = open(res, O_RDONLY|O_NONBLOCK)) >= 0) {
+				close(fd);
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+/*
+ *	Find out the _real_ console. Assume that stdin is connected to
+ *	the console device (/dev/console).
+ */
+int consolename(char *res, int rlen)
+{
+#ifdef TIOCGDEV
+	unsigned int	kdev;
+#endif
+	struct stat	st, st2;
+	char		buf[256];
+	char		*p;
+	int		didmount = 0;
+	int		n, r;
+	int		fd;
+
+	fstat(0, &st);
+	if (major(st.st_rdev) != 5 || minor(st.st_rdev) != 1) {
+		/*
+		 *	Old kernel, can find real device easily.
+		 */
+		return findtty(res, rlen, st.st_rdev);
+	}
+
+#ifdef TIOCGDEV
+	if (ioctl(0, TIOCGDEV, &kdev) == 0)
+		return findtty(res, rlen, (dev_t)kdev);
+	if (errno != ENOIOCTLCMD) return -1;
+#endif
+
+#ifdef __linux__
+	/*
+	 *	Read /proc/cmdline.
+	 */
+	stat("/", &st);
+	if (stat("/proc", &st2) < 0) {
+		perror("bootlogd: /proc");
+		return -1;
+	}
+	if (st.st_dev == st2.st_dev) {
+		if (mount("proc", "/proc", "proc", 0, NULL) < 0) {
+			perror("bootlogd: mount /proc");
+			return -1;
+		}
+		didmount = 1;
+	}
+
+	n = 0;
+	r = -1;
+	if ((fd = open("/proc/cmdline", O_RDONLY)) < 0) {
+		perror("bootlogd: /proc/cmdline");
+	} else {
+		buf[0] = 0;
+		if ((n = read(fd, buf, sizeof(buf) - 1)) >= 0)
+			r = 0;
+		else
+			perror("bootlogd: /proc/cmdline");
+		close(fd);
+	}
+	if (didmount) umount("/proc");
+
+	if (r < 0) return r;
+
+	/*
+	 *	OK, so find console= in /proc/cmdline.
+	 *	Parse in reverse, opening as we go.
+	 */
+	p = buf + n;
+	*p-- = 0;
+	r = -1;
+	while (p >= buf) {
+		if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+			*p-- = 0;
+			continue;
+		}
+		if (strncmp(p, "console=", 8) == 0 &&
+		    isconsole(p + 8, res, rlen)) {
+			r = 0;
+			break;
+		}
+		p--;
+	}
+
+	if (r == 0) return r;
+#endif
+
+	/*
+	 *	Okay, no console on the command line -
+	 *	guess the default console.
+	 */
+	for (n = 0; defcons[n]; n++)
+		if (isconsole(defcons[n], res, rlen))
+			return 0;
+
+	fprintf(stderr, "bootlogd: cannot deduce real console device\n");
+
+	return -1;
+}
+
+
+/*
+ *	Write data and make sure it's on disk.
+ */
+void writelog(FILE *fp, unsigned char *ptr, int len)
+{
+	time_t		t;
+	char		*s;
+	char		tmp[8];
+	int		olen = len;
+	int		dosync = 0;
+	int		tlen;
+
+	while (len > 0) {
+		tmp[0] = 0;
+		if (didnl) {
+			time(&t);
+			s = ctime(&t);
+			fprintf(fp, "%.24s: ", s);
+			didnl = 0;
+		}
+		switch (*ptr) {
+			case 27: /* ESC */
+				strcpy(tmp, "^[");
+				break;
+			case '\r':
+				line.pos = 0;
+				break;
+			case 8: /* ^H */
+				if (line.pos > 0) line.pos--;
+				break;
+			case '\n':
+				didnl = 1;
+				dosync = syncalot;
+				break;
+			case '\t':
+				line.pos += (line.pos / 8 + 1) * 8;
+				if (line.pos >= sizeof(line.buf))
+					line.pos = sizeof(line.buf) - 1;
+				break;
+			case  32 ... 127:
+			case 161 ... 255:
+				tmp[0] = *ptr;
+				tmp[1] = 0;
+				break;
+			default:
+				sprintf(tmp, "\\%03o", *ptr);
+				break;
+		}
+		ptr++;
+		len--;
+
+		tlen = strlen(tmp);
+		if (tlen && (line.pos + tlen < sizeof(line.buf))) {
+			memcpy(line.buf + line.pos, tmp, tlen);
+			line.pos += tlen;
+		}
+		if (didnl) {
+			fprintf(fp, "%s\n", line.buf);
+			memset(&line, 0, sizeof(line));
+		}
+	}
+
+	if (dosync) {
+		fflush(fp);
+		fdatasync(fileno(fp));
+	}
+
+	outptr += olen;
+	if (outptr >= endptr)
+		outptr = ringbuf;
+
+}
+
+
+/*
+ *	Print usage message and exit.
+ */
+void usage(void)
+{
+	fprintf(stderr, "Usage: bootlogd [-v] [-r] [-d] [-s] [-c] [-p pidfile] [-l logfile]\n");
+	exit(1);
+}
+
+int open_nb(char *buf)
+{
+	int	fd, n;
+
+	if ((fd = open(buf, O_WRONLY|O_NONBLOCK|O_NOCTTY)) < 0)
+		return -1;
+	n = fcntl(fd, F_GETFL);
+	n &= ~(O_NONBLOCK);
+	fcntl(fd, F_SETFL, n);
+
+	return fd;
+}
+
+/*
+ *	We got a write error on the real console. If its an EIO,
+ *	somebody hung up our filedescriptor, so try to re-open it.
+ */
+int write_err(int pts, int realfd, char *realcons, int e)
+{
+	int	fd;
+
+	if (e != EIO) {
+werr:
+		close(pts);
+		fprintf(stderr, "bootlogd: writing to console: %s\n",
+			strerror(e));
+		return -1;
+	}
+	close(realfd);
+	if ((fd = open_nb(realcons)) < 0)
+		goto werr;
+
+	return fd;
+}
+
+int main(int argc, char **argv)
+{
+	FILE		*fp;
+	struct timeval	tv;
+	fd_set		fds;
+	char		buf[1024];
+	char		realcons[1024];
+	char		*p;
+	char		*logfile;
+	char		*pidfile;
+	int		rotate;
+	int		dontfork;
+	int		ptm, pts;
+	int		realfd;
+	int		n, m, i;
+	int		todo;
+
+	fp = NULL;
+	logfile = LOGFILE;
+	pidfile = NULL;
+	rotate = 0;
+	dontfork = 0;
+
+	while ((i = getopt(argc, argv, "cdsl:p:rv")) != EOF) switch(i) {
+		case 'l':
+			logfile = optarg;
+			break;
+		case 'r':
+			rotate = 1;
+			break;
+		case 'v':
+			printf("%s\n", Version);
+			exit(0);
+			break;
+		case 'p':
+			pidfile = optarg;
+			break;
+		case 'c':
+			createlogfile = 1;
+			break;
+		case 'd':
+			dontfork = 1;
+			break;
+		case 's':
+			syncalot = 1;
+			break;
+		default:
+			usage();
+			break;
+	}
+	if (optind < argc) usage();
+
+	signal(SIGTERM, handler);
+	signal(SIGQUIT, handler);
+	signal(SIGINT,  handler);
+	signal(SIGTTIN,  SIG_IGN);
+	signal(SIGTTOU,  SIG_IGN);
+	signal(SIGTSTP,  SIG_IGN);
+
+	/*
+	 *	Open console device directly.
+	 */
+	if (consolename(realcons, sizeof(realcons)) < 0)
+		return 1;
+
+	if (strcmp(realcons, "/dev/tty0") == 0)
+		strcpy(realcons, "/dev/tty1");
+	if (strcmp(realcons, "/dev/vc/0") == 0)
+		strcpy(realcons, "/dev/vc/1");
+
+	if ((realfd = open_nb(realcons)) < 0) {
+		fprintf(stderr, "bootlogd: %s: %s\n", buf, strerror(errno));
+		return 1;
+	}
+
+	/*
+	 *	Grab a pty, and redirect console messages to it.
+	 */
+	ptm = -1;
+	pts = -1;
+	buf[0] = 0;
+	if (findpty(&ptm, &pts, buf) < 0) {
+		fprintf(stderr,
+			"bootlogd: cannot allocate pseudo tty: %s\n",
+			strerror(errno));
+		return 1;
+	}
+
+	(void)ioctl(0, TIOCCONS, NULL);
+#if 1
+	/* Work around bug in 2.1/2.2 kernels. Fixed in 2.2.13 and 2.3.18 */
+	if ((n = open("/dev/tty0", O_RDWR)) >= 0) {
+		(void)ioctl(n, TIOCCONS, NULL);
+		close(n);
+	}
+#endif
+	if (ioctl(pts, TIOCCONS, NULL) < 0) {
+		fprintf(stderr, "bootlogd: ioctl(%s, TIOCCONS): %s\n",
+			buf, strerror(errno));
+		return 1;
+	}
+
+	/*
+	 *	Fork and write pidfile if needed.
+	 */
+	if (!dontfork) {
+		pid_t child_pid = fork();
+		switch (child_pid) {
+		case -1: /* I am parent and the attempt to create a child failed */
+			fprintf(stderr, "bootlogd: fork failed: %s\n",
+				strerror(errno));
+			exit(1);
+			break;
+		case 0: /* I am the child */
+			break;
+		default: /* I am parent and got child's pid */
+			exit(0);
+			break;
+		}
+		setsid();
+	}
+	if (pidfile) {
+		unlink(pidfile);
+		if ((fp = fopen(pidfile, "w")) != NULL) {
+			fprintf(fp, "%d\n", (int)getpid());
+			fclose(fp);
+		}
+		fp = NULL;
+	}
+
+	/*
+	 *	Read the console messages from the pty, and write
+	 *	to the real console and the logfile.
+	 */
+	while (!got_signal) {
+
+		/*
+		 *	We timeout after 5 seconds if we still need to
+		 *	open the logfile. There might be buffered messages
+		 *	we want to write.
+		 */
+		tv.tv_sec = 0;
+		tv.tv_usec = 500000;
+		FD_ZERO(&fds);
+		FD_SET(ptm, &fds);
+		if (select(ptm + 1, &fds, NULL, NULL, &tv) == 1) {
+			/*
+			 *	See how much space there is left, read.
+			 */
+			if ((n = read(ptm, inptr, endptr - inptr)) >= 0) {
+				/*
+				 *	Write data (in chunks if needed)
+				 *	to the real output device.
+				 */
+				m = n;
+				p = inptr;
+				while (m > 0) {
+					i = write(realfd, p, m);
+					if (i >= 0) {
+						m -= i;
+						p += i;
+						continue;
+					}
+					/*
+					 *	Handle EIO (somebody hung
+					 *	up our filedescriptor)
+					 */
+					realfd = write_err(pts, realfd,
+						realcons, errno);
+					if (realfd >= 0) continue;
+					got_signal = 1; /* Not really */
+					break;
+				}
+
+				/*
+				 *	Increment buffer position. Handle
+				 *	wraps, and also drag output pointer
+				 *	along if we cross it.
+				 */
+				inptr += n;
+				if (inptr - n < outptr && inptr > outptr)
+					outptr = inptr;
+				if (inptr >= endptr)
+					inptr = ringbuf;
+				if (outptr >= endptr)
+					outptr = ringbuf;
+			}
+		}
+
+		/*
+		 *	Perhaps we need to open the logfile.
+		 */
+		if (fp == NULL && access(logfile, F_OK) == 0) {
+			if (rotate) {
+				snprintf(buf, sizeof(buf), "%s~", logfile);
+				rename(logfile, buf);
+			}
+			fp = fopen(logfile, "a");
+		}
+		if (fp == NULL && createlogfile)
+			fp = fopen(logfile, "a");
+
+		if (inptr >= outptr)
+			todo = inptr - outptr;
+		else
+			todo = endptr - outptr;
+		if (fp && todo)
+			writelog(fp, outptr, todo);
+	}
+
+	if (fp) {
+		if (!didnl) fputc('\n', fp);
+		fclose(fp);
+	}
+
+	close(pts);
+	close(ptm);
+	close(realfd);
+
+	return 0;
+}
+

Deleted: sysvinit-upstream/tags/2.87dsf/src/dowall.c
===================================================================
--- sysvinit-upstream/trunk/src/dowall.c	2009-07-10 21:51:19 UTC (rev 1428)
+++ sysvinit-upstream/tags/2.87dsf/src/dowall.c	2009-07-12 18:00:14 UTC (rev 1458)
@@ -1,216 +0,0 @@
-/*
- * dowall.c	Write to all users on the system.
- *
- * Author:	Miquel van Smoorenburg, miquels at cistron.nl
- * 
- * Version:	@(#)dowall.c  2.85-5  02-Jul-2003  miquels at cistron.nl
- *
- *		This file is part of the sysvinit suite,
- *		Copyright 1991-2003 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.
- */
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/sysmacros.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <utmp.h>
-#include <pwd.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <setjmp.h>
-
-static sigjmp_buf jbuf;
-
-/*
- *	Alarm handler
- */
-/*ARGSUSED*/
-static void handler(int arg)
-{
-	siglongjmp(jbuf, 1);
-}
-
-
-/*
- *	Print a text, escape all characters not in Latin-1.
- */
-static void feputs(char *line, FILE *fp)
-{
-	unsigned char		*p;
-
-	for (p = (unsigned char *)line; *p; p++) {
-		if (strchr("\t\r\n", *p) ||
-		    (*p >= 32 && *p <= 127) || (*p >= 160)) {
-			fputc(*p, fp);
-		} else {
-			fprintf(fp, "^%c", (*p & 0x1f) + 'A' - 1);
-		}
-	}
-	fflush(fp);
-}
-
-
-static void getuidtty(char **userp, char **ttyp)
-{
-	struct passwd 		*pwd;
-	uid_t			uid;
-	char			*tty;
-	static char		uidbuf[32];
-	static char		ttynm[32];
-	static int		init = 0;
-
-	if (!init) {
-
-		uid = getuid();
-		if ((pwd = getpwuid(uid)) != NULL) {
-			uidbuf[0] = 0;
-			strncat(uidbuf, pwd->pw_name, sizeof(uidbuf) - 1);
-		} else {
-			sprintf(uidbuf, uid ? "uid %d" : "root", (int)uid);
-		}
-
-		if ((tty = ttyname(0)) != NULL) {
-			if (strncmp(tty, "/dev/", 5) == 0)
-				tty += 5;
-			sprintf(ttynm, "(%.28s) ", tty);	
-		} else
-			ttynm[0] = 0;
-		init++;
-	}
-
-	*userp = uidbuf;
-	*ttyp  = ttynm;
-}
-
-/*
- *	Check whether given filename looks like tty device.
- */
-static int file_isatty(const char *fname)
-{
-	struct stat		st;
-	int			major;
-
-	if (stat(fname, &st) < 0)
-		return 0;
-
-	if (st.st_nlink != 1 || !S_ISCHR(st.st_mode))
-		return 0;
-
-	/*
-	 *	It would be an impossible task to list all major/minors
-	 *	of tty devices here, so we just exclude the obvious
-	 *	majors of which just opening has side-effects:
-	 *	printers and tapes.
-	 */
-	major = major(st.st_dev);
-	if (major == 1 || major == 2 || major == 6 || major == 9 ||
-	    major == 12 || major == 16 || major == 21 || major == 27 ||
-	    major == 37 || major == 96 || major == 97 || major == 206 ||
-	    major == 230) return 0;
-
-	return 1;
-}
-
-/*
- *	Wall function.
- */
-void wall(char *text, int fromshutdown, int remote)
-{
-	FILE			*tp;
-	struct sigaction	sa;
-	struct utmp		*utmp;
-	time_t			t;
-	char			term[UT_LINESIZE+6];
-	char			line[81];
-	char			*date, *p;
-	char			*user, *tty;
-	int			fd, flags;
-
-	/*
-	 *	Make sure tp and fd aren't in a register. Some versions
-	 *	of gcc clobber those after longjmp (or so I understand).
-	 */
-	(void) &tp;
-	(void) &fd;
-
-	getuidtty(&user, &tty);
-
-	/* Get the time */
-	time(&t);
-	date = ctime(&t);
-	for(p = date; *p && *p != '\n'; p++)
-		;
-	*p = 0;
-	
-	if (remote) {
-		snprintf(line, sizeof(line),
-			"\007\r\nRemote broadcast message (%s):\r\n\r\n",
-			date);
-	} else {
-		snprintf(line, sizeof(line),
-			"\007\r\nBroadcast message from %s %s(%s):\r\n\r\n",
-			user, tty, date);
-	}
-
-	/*
-	 *	Fork to avoid us hanging in a write()
-	 */
-	if (fork() != 0)
-		return;
-	
-	memset(&sa, 0, sizeof(sa));
-	sa.sa_handler = handler;
-	sa.sa_flags = 0;
-	sigemptyset(&sa.sa_mask);
-	sigaction(SIGALRM, &sa, NULL);
-
-	setutent();
-
-	while ((utmp = getutent()) != NULL) {
-		if(utmp->ut_type != USER_PROCESS ||
-		   utmp->ut_user[0] == 0) continue;
-		if (strncmp(utmp->ut_line, "/dev/", 5) == 0) {
-			term[0] = 0;
-			strncat(term, utmp->ut_line, UT_LINESIZE);
-		} else
-			snprintf(term, sizeof(term), "/dev/%.*s",
-				UT_LINESIZE, utmp->ut_line);
-		if (strstr(term, "/../")) continue;
-
-		fd = -1;
-		tp = NULL;
-
-		/*
-		 *	Open it non-delay
-		 */
-		if (sigsetjmp(jbuf, 1) == 0) {
-			alarm(2);
-			flags = O_WRONLY|O_NDELAY|O_NOCTTY;
-			if (file_isatty(term) &&
-			    (fd = open(term, flags)) >= 0) {
-				if (isatty(fd) &&
-				    (tp = fdopen(fd, "w")) != NULL) {
-					fputs(line, tp);
-					feputs(text, tp);
-					fflush(tp);
-				}
-			}
-		}
-		alarm(0);
-		if (fd >= 0) close(fd);
-		if (tp != NULL) fclose(tp);
-	}
-	endutent();
-
-	exit(0);
-}
-

Copied: sysvinit-upstream/tags/2.87dsf/src/dowall.c (from rev 1445, sysvinit-upstream/trunk/src/dowall.c)
===================================================================
--- sysvinit-upstream/tags/2.87dsf/src/dowall.c	                        (rev 0)
+++ sysvinit-upstream/tags/2.87dsf/src/dowall.c	2009-07-12 18:00:14 UTC (rev 1458)
@@ -0,0 +1,227 @@
+/*
+ * dowall.c	Write to all users on the system.
+ *
+ * Author:	Miquel van Smoorenburg, miquels at cistron.nl
+ * 
+ * Version:	@(#)dowall.c  2.85-5  02-Jul-2003  miquels at cistron.nl
+ *
+ *		This file is part of the sysvinit suite,
+ *		Copyright 1991-2003 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.
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <utmp.h>
+#include <pwd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <setjmp.h>
+
+static sigjmp_buf jbuf;
+
+/*
+ *	Alarm handler
+ */
+/*ARGSUSED*/
+static void handler(int arg)
+{
+	siglongjmp(jbuf, 1);
+}
+
+
+/*
+ *	Print a text, escape all characters not in Latin-1.
+ */
+static void feputs(char *line, FILE *fp)
+{
+	unsigned char		*p;
+
+	for (p = (unsigned char *)line; *p; p++) {
+		if (strchr("\t\r\n", *p) ||
+		    (*p >= 32 && *p <= 127) || (*p >= 160)) {
+			fputc(*p, fp);
+		} else {
+			fprintf(fp, "^%c", (*p & 0x1f) + 'A' - 1);
+		}
+	}
+	fflush(fp);
+}
+
+
+static void getuidtty(char **userp, char **ttyp)
+{
+	struct passwd 		*pwd;
+	uid_t			uid;
+	char			*tty;
+	static char		uidbuf[32];
+	static char		ttynm[UT_LINESIZE + 4];
+	static int		init = 0;
+
+	if (!init) {
+
+		uid = getuid();
+		if ((pwd = getpwuid(uid)) != NULL) {
+			uidbuf[0] = 0;
+			strncat(uidbuf, pwd->pw_name, sizeof(uidbuf) - 1);
+		} else {
+			sprintf(uidbuf, uid ? "uid %d" : "root", (int)uid);
+		}
+
+		if ((tty = ttyname(0)) != NULL) {
+			if (strncmp(tty, "/dev/", 5) == 0)
+				tty += 5;
+			sprintf(ttynm, "(%.28s) ", tty);	
+		} else
+			ttynm[0] = 0;
+		init++;
+	}
+
+	*userp = uidbuf;
+	*ttyp  = ttynm;
+}
+
+/*
+ *	Check whether given filename looks like tty device.
+ */
+static int file_isatty(const char *fname)
+{
+	struct stat		st;
+	int			major;
+
+	if (stat(fname, &st) < 0)
+		return 0;
+
+	if (st.st_nlink != 1 || !S_ISCHR(st.st_mode))
+		return 0;
+
+	/*
+	 *	It would be an impossible task to list all major/minors
+	 *	of tty devices here, so we just exclude the obvious
+	 *	majors of which just opening has side-effects:
+	 *	printers and tapes.
+	 */
+	major = major(st.st_dev);
+	if (major == 1 || major == 2 || major == 6 || major == 9 ||
+	    major == 12 || major == 16 || major == 21 || major == 27 ||
+	    major == 37 || major == 96 || major == 97 || major == 206 ||
+	    major == 230) return 0;
+
+	return 1;
+}
+
+/*
+ *	Wall function.
+ */
+void wall(char *text, int fromshutdown, int remote)
+{
+	FILE			*tp;
+	struct sigaction	sa;
+	struct utmp		*utmp;
+	time_t			t;
+	char			term[UT_LINESIZE+6];
+	char			line[81];
+	char                    hostname[256]; /* HOST_NAME_MAX+1 */
+	char			*date, *p;
+	char			*user, *tty;
+	int			fd, flags;
+
+	/*
+	 *	Make sure tp and fd aren't in a register. Some versions
+	 *	of gcc clobber those after longjmp (or so I understand).
+	 */
+	(void) &tp;
+	(void) &fd;
+
+	getuidtty(&user, &tty);
+
+	/* Get and report current hostname, to make it easier to find
+	   out which machine is being shut down. */
+	if (0 != gethostname(hostname, sizeof(hostname))) {
+		strncpy(hostname, "[unknown]", sizeof(hostname)-1);
+	}
+	/* If hostname is truncated, it is unspecified if the string
+	   is null terminated or not.  Make sure we know it is null
+	   terminated. */
+	hostname[sizeof(hostname)-1] = 0;
+
+	/* Get the time */
+	time(&t);
+	date = ctime(&t);
+	for(p = date; *p && *p != '\n'; p++)
+		;
+	*p = 0;
+	
+	if (remote) {
+		snprintf(line, sizeof(line),
+			"\007\r\nRemote broadcast message (%s):\r\n\r\n",
+			date);
+	} else {
+		snprintf(line, sizeof(line),
+			"\007\r\nBroadcast message from %s@%s %s(%s):\r\n\r\n",
+			user, hostname, tty, date);
+	}
+
+	/*
+	 *	Fork to avoid us hanging in a write()
+	 */
+	if (fork() != 0)
+		return;
+	
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = handler;
+	sa.sa_flags = 0;
+	sigemptyset(&sa.sa_mask);
+	sigaction(SIGALRM, &sa, NULL);
+
+	setutent();
+
+	while ((utmp = getutent()) != NULL) {
+		if(utmp->ut_type != USER_PROCESS ||
+		   utmp->ut_user[0] == 0) continue;
+		if (strncmp(utmp->ut_line, "/dev/", 5) == 0) {
+			term[0] = 0;
+			strncat(term, utmp->ut_line, sizeof(term)-1);
+		} else
+			snprintf(term, sizeof(term), "/dev/%.*s",
+				UT_LINESIZE, utmp->ut_line);
+		if (strstr(term, "/../")) continue;
+
+		fd = -1;
+		tp = NULL;
+
+		/*
+		 *	Open it non-delay
+		 */
+		if (sigsetjmp(jbuf, 1) == 0) {
+			alarm(2);
+			flags = O_WRONLY|O_NDELAY|O_NOCTTY;
+			if (file_isatty(term) &&
+			    (fd = open(term, flags)) >= 0) {
+				if (isatty(fd) &&
+				    (tp = fdopen(fd, "w")) != NULL) {
+					fputs(line, tp);
+					feputs(text, tp);
+					fflush(tp);
+				}
+			}
+		}
+		alarm(0);
+		if (fd >= 0) close(fd);
+		if (tp != NULL) fclose(tp);
+	}
+	endutent();
+
+	exit(0);
+}
+

Deleted: sysvinit-upstream/tags/2.87dsf/src/halt.c
===================================================================
--- sysvinit-upstream/trunk/src/halt.c	2009-07-10 21:51:19 UTC (rev 1428)
+++ sysvinit-upstream/tags/2.87dsf/src/halt.c	2009-07-12 18:00:14 UTC (rev 1458)
@@ -1,301 +0,0 @@
-/*
- * Halt		Stop the system running.
- *		It re-enables CTRL-ALT-DEL, so that a hard reboot can
- *		be done. If called as reboot, it will reboot the system.
- *
- *		If the system is not in runlevel 0 or 6, halt will just
- *		execute a "shutdown -h" to halt the system, and reboot will
- *		execute an "shutdown -r". This is for compatibility with
- *		sysvinit 2.4.
- *
- * Usage:	halt [-n] [-w] [-d] [-f] [-h] [-i] [-p]
- *		-n: don't sync before halting the system
- *		-w: only write a wtmp reboot record and exit.
- *		-d: don't write a wtmp record.
- *		-f: force halt/reboot, don't call shutdown.
- *		-h: put harddisks in standby mode
- *		-i: shut down all network interfaces.
- *		-p: power down the system (if possible, otherwise halt).
- *
- *		Reboot and halt are both this program. Reboot
- *		is just a link to halt. Invoking the program
- *		as poweroff implies the -p option.
- *
- * Author:	Miquel van Smoorenburg, miquels at cistron.nl
- *
- * Version:	2.86,  30-Jul-2004
- *
- *		This file is part of the sysvinit suite,
- *		Copyright 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.
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <stdlib.h>
-#include <utmp.h>
-#include <fcntl.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/times.h>
-#include <time.h>
-#include <signal.h>
-#include <stdio.h>
-#include <getopt.h>
-#include "reboot.h"
-
-char *Version = "@(#)halt  2.86  31-Jul-2004 miquels at cistron.nl";
-char *progname;
-
-#define KERNEL_MONITOR	1 /* If halt() puts you into the kernel monitor. */
-#define RUNLVL_PICKY	0 /* Be picky about the runlevel */
-
-extern int ifdown(void);
-extern int hddown(void);
-extern void write_wtmp(char *user, char *id, int pid, int type, char *line);
-
-/*
- *	Send usage message.
- */
-void usage(void)
-{
-	fprintf(stderr, "usage: %s [-n] [-w] [-d] [-f] [-h] [-i]%s\n",
-		progname, strcmp(progname, "halt") ? "" : " [-p]");
-	fprintf(stderr, "\t-n: don't sync before halting the system\n");
-	fprintf(stderr, "\t-w: only write a wtmp reboot record and exit.\n");
-	fprintf(stderr, "\t-d: don't write a wtmp record.\n");
-	fprintf(stderr, "\t-f: force halt/reboot, don't call shutdown.\n");
-	fprintf(stderr, "\t-h: put harddisks in standby mode.\n");
-	fprintf(stderr, "\t-i: shut down all network interfaces.\n");
-	if (!strcmp(progname, "halt"))
-		fprintf(stderr, "\t-p: power down the system (if possible, otherwise halt).\n");
-	exit(1);
-}
-
-/*
- *	See if we were started directly from init.
- *	Get the runlevel from /var/run/utmp or the environment.
- */
-int get_runlevel(void)
-{
-	struct utmp *ut;
-	char *r;
-#if RUNLVL_PICKY
-	time_t boottime;
-#endif
-
-	/*
-	 *	First see if we were started directly from init.
-	 */
-	if (getenv("INIT_VERSION") && (r = getenv("RUNLEVEL")) != NULL)
-		return *r;
-
-	/*
-	 *	Hmm, failed - read runlevel from /var/run/utmp..
-	 */
-#if RUNLVL_PICKY
-	/*
-	 *	Get boottime from the kernel.
-	 */
-	time(&boottime);
-	boottime -= (times(NULL) / HZ);
-#endif
-
-	/*
-	 *	Find runlevel in utmp.
-	 */
-	setutent();
-	while ((ut = getutent()) != NULL) {
-#if RUNLVL_PICKY
-		/*
-		 *	Only accept value if it's from after boottime.
-		 */
-		if (ut->ut_type == RUN_LVL && ut->ut_time > boottime)
-			return (ut->ut_pid & 255);
-#else
-		if (ut->ut_type == RUN_LVL)
-			return (ut->ut_pid & 255);
-#endif
-	}
-	endutent();
-
-	/* This should not happen but warn the user! */
-	fprintf(stderr, "WARNING: could not determine runlevel"
-		" - doing soft %s\n", progname);
-	fprintf(stderr, "  (it's better to use shutdown instead of %s"
-		" from the command line)\n", progname);
-
-	return -1;
-}
-
-/*
- *	Switch to another runlevel.
- */
-void do_shutdown(char *fl, char *tm)
-{
-	char *args[8];
-	int i = 0;
-
-	args[i++] = "shutdown";
-	args[i++] = fl;
-	if (tm) {
-		args[i++] = "-t";
-		args[i++] = tm;
-	}
-	args[i++] = "now";
-	args[i++] = NULL;
-
-	execv("/sbin/shutdown", args);
-	execv("/etc/shutdown", args);
-	execv("/bin/shutdown", args);
-
-	perror("shutdown");
-	exit(1);
-}
-
-/*
- *	Main program.
- *	Write a wtmp entry and reboot cq. halt.
- */
-int main(int argc, char **argv)
-{
-	int do_reboot = 0;
-	int do_sync = 1;
-	int do_wtmp = 1;
-	int do_nothing = 0;
-	int do_hard = 0;
-	int do_ifdown = 0;
-	int do_hddown = 0;
-	int do_poweroff = 0;
-	int c;
-	char *tm = NULL;
-
-	/*
-	 *	Find out who we are
-	 */
-	if ((progname = strrchr(argv[0], '/')) != NULL)
-		progname++;
-	else
-		progname = argv[0];
-
-	if (!strcmp(progname, "reboot")) do_reboot = 1;
-	if (!strcmp(progname, "poweroff")) do_poweroff = 1;
-
-	/*
-	 *	Get flags
-	 */
-	while((c = getopt(argc, argv, ":ihdfnpwt:")) != EOF) {
-		switch(c) {
-			case 'n':
-				do_sync = 0;
-				do_wtmp = 0;
-				break;
-			case 'w':
-				do_nothing = 1;
-				break;
-			case 'd':
-				do_wtmp = 0;
-				break;
-			case 'f':
-				do_hard = 1;
-				break;
-			case 'i':
-				do_ifdown = 1;
-				break;
-			case 'h':
-				do_hddown = 1;
-				break;
-			case 'p':
-				do_poweroff = 1;
-				break;
-			case 't':
-				tm = optarg;
-				break;
-			default:
-				usage();
-		}
-	 }
-	if (argc != optind) usage();
-
-	if (geteuid() != 0) {
-		fprintf(stderr, "%s: must be superuser.\n", progname);
-		exit(1);
-	}
-
-	(void)chdir("/");
-
-	if (!do_hard && !do_nothing) {
-		/*
-		 *	See if we are in runlevel 0 or 6.
-		 */
-		c = get_runlevel();
-		if (c != '0' && c != '6')
-			do_shutdown(do_reboot ? "-r" : "-h", tm);
-	}
-
-	/*
-	 *	Record the fact that we're going down
-	 */
-	if (do_wtmp)
-		write_wtmp("shutdown", "~~", 0, RUN_LVL, "~~");
-
-	/*
-	 *	Exit if all we wanted to do was write a wtmp record.
-	 */
-	if (do_nothing && !do_hddown && !do_ifdown) exit(0);
-
-	if (do_sync) {
-		sync();
-		sleep(2);
-	}
-
-	if (do_ifdown)
-		(void)ifdown();
-
-	if (do_hddown)
-		(void)hddown();
-
-	if (do_nothing) exit(0);
-
-	if (do_reboot) {
-		init_reboot(BMAGIC_REBOOT);
-	} else {
-		/*
-		 *	Turn on hard reboot, CTRL-ALT-DEL will reboot now
-		 */
-#ifdef BMAGIC_HARD
-		init_reboot(BMAGIC_HARD);
-#endif
-
-		/*
-		 *	Stop init; it is insensitive to the signals sent
-		 *	by the kernel.
-		 */
-		kill(1, SIGTSTP);
-
-		/*
-		 *	Halt or poweroff.
-		 */
-		if (do_poweroff)
-			init_reboot(BMAGIC_POWEROFF);
-		/*
-		 *	Fallthrough if failed.
-		 */
-		init_reboot(BMAGIC_HALT);
-	}
-
-	/*
-	 *	If we return, we (c)ontinued from the kernel monitor.
-	 */
-#ifdef BMAGIC_SOFT
-	init_reboot(BMAGIC_SOFT);
-#endif
-	kill(1, SIGCONT);
-
-	exit(0);
-}

Copied: sysvinit-upstream/tags/2.87dsf/src/halt.c (from rev 1452, sysvinit-upstream/trunk/src/halt.c)
===================================================================
--- sysvinit-upstream/tags/2.87dsf/src/halt.c	                        (rev 0)
+++ sysvinit-upstream/tags/2.87dsf/src/halt.c	2009-07-12 18:00:14 UTC (rev 1458)
@@ -0,0 +1,303 @@
+/*
+ * Halt		Stop the system running.
+ *		It re-enables CTRL-ALT-DEL, so that a hard reboot can
+ *		be done. If called as reboot, it will reboot the system.
+ *
+ *		If the system is not in runlevel 0 or 6, halt will just
+ *		execute a "shutdown -h" to halt the system, and reboot will
+ *		execute an "shutdown -r". This is for compatibility with
+ *		sysvinit 2.4.
+ *
+ * Usage:	halt [-n] [-w] [-d] [-f] [-h] [-i] [-p]
+ *		-n: don't sync before halting the system
+ *		-w: only write a wtmp reboot record and exit.
+ *		-d: don't write a wtmp record.
+ *		-f: force halt/reboot, don't call shutdown.
+ *		-h: put harddisks in standby mode
+ *		-i: shut down all network interfaces.
+ *		-p: power down the system (if possible, otherwise halt).
+ *
+ *		Reboot and halt are both this program. Reboot
+ *		is just a link to halt. Invoking the program
+ *		as poweroff implies the -p option.
+ *
+ * Author:	Miquel van Smoorenburg, miquels at cistron.nl
+ *
+ * Version:	2.86,  30-Jul-2004
+ *
+ *		This file is part of the sysvinit suite,
+ *		Copyright 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.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <utmp.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/times.h>
+#include <time.h>
+#include <signal.h>
+#include <stdio.h>
+#include <getopt.h>
+#include "reboot.h"
+
+char *Version = "@(#)halt  2.86  31-Jul-2004 miquels at cistron.nl";
+char *progname;
+
+#define KERNEL_MONITOR	1 /* If halt() puts you into the kernel monitor. */
+#define RUNLVL_PICKY	0 /* Be picky about the runlevel */
+
+extern int ifdown(void);
+extern int hddown(void);
+extern void write_wtmp(char *user, char *id, int pid, int type, char *line);
+
+/*
+ *	Send usage message.
+ */
+void usage(void)
+{
+	fprintf(stderr, "usage: %s [-n] [-w] [-d] [-f] [-h] [-i]%s\n",
+		progname, strcmp(progname, "halt") ? "" : " [-p]");
+	fprintf(stderr, "\t-n: don't sync before halting the system\n");
+	fprintf(stderr, "\t-w: only write a wtmp reboot record and exit.\n");
+	fprintf(stderr, "\t-d: don't write a wtmp record.\n");
+	fprintf(stderr, "\t-f: force halt/reboot, don't call shutdown.\n");
+	fprintf(stderr, "\t-h: put harddisks in standby mode.\n");
+	fprintf(stderr, "\t-i: shut down all network interfaces.\n");
+	if (!strcmp(progname, "halt"))
+		fprintf(stderr, "\t-p: power down the system (if possible, otherwise halt).\n");
+	exit(1);
+}
+
+/*
+ *	See if we were started directly from init.
+ *	Get the runlevel from /var/run/utmp or the environment.
+ */
+int get_runlevel(void)
+{
+	struct utmp *ut;
+	char *r;
+#if RUNLVL_PICKY
+	time_t boottime;
+#endif
+
+	/*
+	 *	First see if we were started directly from init.
+	 */
+	if (getenv("INIT_VERSION") && (r = getenv("RUNLEVEL")) != NULL)
+		return *r;
+
+	/*
+	 *	Hmm, failed - read runlevel from /var/run/utmp..
+	 */
+#if RUNLVL_PICKY
+	/*
+	 *	Get boottime from the kernel.
+	 */
+	time(&boottime);
+	boottime -= (times(NULL) / HZ);
+#endif
+
+	/*
+	 *	Find runlevel in utmp.
+	 */
+	setutent();
+	while ((ut = getutent()) != NULL) {
+#if RUNLVL_PICKY
+		/*
+		 *	Only accept value if it's from after boottime.
+		 */
+		if (ut->ut_type == RUN_LVL && ut->ut_time > boottime)
+			return (ut->ut_pid & 255);
+#else
+		if (ut->ut_type == RUN_LVL)
+			return (ut->ut_pid & 255);
+#endif
+	}
+	endutent();
+
+	/* This should not happen but warn the user! */
+	fprintf(stderr, "WARNING: could not determine runlevel"
+		" - doing soft %s\n", progname);
+	fprintf(stderr, "  (it's better to use shutdown instead of %s"
+		" from the command line)\n", progname);
+
+	return -1;
+}
+
+/*
+ *	Switch to another runlevel.
+ */
+void do_shutdown(char *fl, char *tm)
+{
+	char *args[8];
+	int i = 0;
+
+	args[i++] = "shutdown";
+	args[i++] = fl;
+	if (tm) {
+		args[i++] = "-t";
+		args[i++] = tm;
+	}
+	args[i++] = "now";
+	args[i++] = NULL;
+
+	execv("/sbin/shutdown", args);
+	execv("/etc/shutdown", args);
+	execv("/bin/shutdown", args);
+
+	perror("shutdown");
+	exit(1);
+}
+
+/*
+ *	Main program.
+ *	Write a wtmp entry and reboot cq. halt.
+ */
+int main(int argc, char **argv)
+{
+	int do_reboot = 0;
+	int do_sync = 1;
+	int do_wtmp = 1;
+	int do_nothing = 0;
+	int do_hard = 0;
+	int do_ifdown = 0;
+	int do_hddown = 0;
+	int do_poweroff = 0;
+	int c;
+	char *tm = NULL;
+
+	/*
+	 *	Find out who we are
+	 */
+	/* Remove dash passed on in argv[0] when used as login shell. */
+	if (argv[0][0] == '-') argv[0]++;
+	if ((progname = strrchr(argv[0], '/')) != NULL)
+		progname++;
+	else
+		progname = argv[0];
+
+	if (!strcmp(progname, "reboot")) do_reboot = 1;
+	if (!strcmp(progname, "poweroff")) do_poweroff = 1;
+
+	/*
+	 *	Get flags
+	 */
+	while((c = getopt(argc, argv, ":ihdfnpwt:")) != EOF) {
+		switch(c) {
+			case 'n':
+				do_sync = 0;
+				do_wtmp = 0;
+				break;
+			case 'w':
+				do_nothing = 1;
+				break;
+			case 'd':
+				do_wtmp = 0;
+				break;
+			case 'f':
+				do_hard = 1;
+				break;
+			case 'i':
+				do_ifdown = 1;
+				break;
+			case 'h':
+				do_hddown = 1;
+				break;
+			case 'p':
+				do_poweroff = 1;
+				break;
+			case 't':
+				tm = optarg;
+				break;
+			default:
+				usage();
+		}
+	 }
+	if (argc != optind) usage();
+
+	if (geteuid() != 0) {
+		fprintf(stderr, "%s: must be superuser.\n", progname);
+		exit(1);
+	}
+
+	(void)chdir("/");
+
+	if (!do_hard && !do_nothing) {
+		/*
+		 *	See if we are in runlevel 0 or 6.
+		 */
+		c = get_runlevel();
+		if (c != '0' && c != '6')
+			do_shutdown(do_reboot ? "-r" : "-h", tm);
+	}
+
+	/*
+	 *	Record the fact that we're going down
+	 */
+	if (do_wtmp)
+		write_wtmp("shutdown", "~~", 0, RUN_LVL, "~~");
+
+	/*
+	 *	Exit if all we wanted to do was write a wtmp record.
+	 */
+	if (do_nothing && !do_hddown && !do_ifdown) exit(0);
+
+	if (do_sync) {
+		sync();
+		sleep(2);
+	}
+
+	if (do_ifdown)
+		(void)ifdown();
+
+	if (do_hddown)
+		(void)hddown();
+
+	if (do_nothing) exit(0);
+
+	if (do_reboot) {
+		init_reboot(BMAGIC_REBOOT);
+	} else {
+		/*
+		 *	Turn on hard reboot, CTRL-ALT-DEL will reboot now
+		 */
+#ifdef BMAGIC_HARD
+		init_reboot(BMAGIC_HARD);
+#endif
+
+		/*
+		 *	Stop init; it is insensitive to the signals sent
+		 *	by the kernel.
+		 */
+		kill(1, SIGTSTP);
+
+		/*
+		 *	Halt or poweroff.
+		 */
+		if (do_poweroff)
+			init_reboot(BMAGIC_POWEROFF);
+		/*
+		 *	Fallthrough if failed.
+		 */
+		init_reboot(BMAGIC_HALT);
+	}
+
+	/*
+	 *	If we return, we (c)ontinued from the kernel monitor.
+	 */
+#ifdef BMAGIC_SOFT
+	init_reboot(BMAGIC_SOFT);
+#endif
+	kill(1, SIGCONT);
+
+	exit(0);
+}

Deleted: sysvinit-upstream/tags/2.87dsf/src/hddown.c
===================================================================
--- sysvinit-upstream/trunk/src/hddown.c	2009-07-10 21:51:19 UTC (rev 1428)
+++ sysvinit-upstream/tags/2.87dsf/src/hddown.c	2009-07-12 18:00:14 UTC (rev 1458)
@@ -1,123 +0,0 @@
-/*
- * hddown.c	Find all disks on the system and
- *		shut them down.
- *
- */
-char *v_hddown = "@(#)hddown.c  1.02  22-Apr-2003  miquels at cistron.nl";
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <time.h>
-#include <string.h>
-#include <fcntl.h>
-#include <dirent.h>
-
-#ifdef __linux__
-
-#include <sys/ioctl.h>
-#include <linux/hdreg.h>
-
-#define MAX_DISKS	64
-#define PROC_IDE	"/proc/ide"
-#define DEV_BASE	"/dev"
-
-/*
- *	Find all IDE disks through /proc.
- */
-static int find_idedisks(char **dev, int maxdev)
-{
-	DIR *dd;
-	FILE *fp;
-	struct dirent *d;
-	char buf[256];
-	int i = 0;
-
-	if ((dd = opendir(PROC_IDE)) == NULL)
-		return -1;
-
-	while ((d = readdir(dd)) != NULL) {
-		if (strncmp(d->d_name, "hd", 2) != 0)
-			continue;
-		buf[0] = 0;
-		snprintf(buf, sizeof(buf), PROC_IDE "/%s/media", d->d_name);
-		if ((fp = fopen(buf, "r")) == NULL)
-			continue;
-		if (fgets(buf, sizeof(buf), fp) == 0 ||
-		    strcmp(buf, "disk\n") != 0) {
-			fclose(fp);
-			continue;
-		}
-		fclose(fp);
-		snprintf(buf, sizeof(buf), DEV_BASE "/%s", d->d_name);
-		dev[i++] = strdup(buf);
-		if (i >= maxdev)
-			break;
-	}
-	closedir(dd);
-	if (i < maxdev) dev[i] = NULL;
-
-	return 0;
-}
-
-/*
- *	Put an IDE disk in standby mode.
- *	Code stolen from hdparm.c
- */
-static int do_standby_idedisk(char *device)
-{
-#ifndef WIN_STANDBYNOW1
-#define WIN_STANDBYNOW1 0xE0
-#endif
-#ifndef WIN_STANDBYNOW2
-#define WIN_STANDBYNOW2 0x94
-#endif
-	unsigned char args1[4] = {WIN_STANDBYNOW1,0,0,0};
-	unsigned char args2[4] = {WIN_STANDBYNOW2,0,0,0};
-	int fd;
-
-	if ((fd = open(device, O_RDWR)) < 0)
-		return -1;
-
-	if (ioctl(fd, HDIO_DRIVE_CMD, &args1) &&
-	    ioctl(fd, HDIO_DRIVE_CMD, &args2))
-		return -1;
-
-	return 0;
-}
-
-/*
- *	First find all IDE disks, then put them in standby mode.
- *	This has the side-effect of flushing the writecache,
- *	which is exactly what we want on poweroff.
- */
-int hddown(void)
-{
-	char *disks[MAX_DISKS+1];
-	int i;
-
-	if (find_idedisks(disks, MAX_DISKS) < 0)
-		return -1;
-
-	for (i = 0; disks[i] && i < MAX_DISKS; i++)
-		do_standby_idedisk(disks[i]);
-
-	return 0;
-}
-
-#else /* __linux__ */
-
-int hddown(void)
-{
-	return 0;
-}
-
-#endif /* __linux__ */
-
-#ifdef STANDALONE
-int main(int argc, char **argv)
-{
-	return (hddown() == 0);
-}
-#endif
-

Copied: sysvinit-upstream/tags/2.87dsf/src/hddown.c (from rev 1443, sysvinit-upstream/trunk/src/hddown.c)
===================================================================
--- sysvinit-upstream/tags/2.87dsf/src/hddown.c	                        (rev 0)
+++ sysvinit-upstream/tags/2.87dsf/src/hddown.c	2009-07-12 18:00:14 UTC (rev 1458)
@@ -0,0 +1,496 @@
+/*
+ * hddown.c	Find all disks on the system and
+ *		shut them down.
+ *
+ */
+char *v_hddown = "@(#)hddown.c  1.02  22-Apr-2003  miquels at cistron.nl";
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <string.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#ifdef __linux__
+
+#include <sys/ioctl.h>
+#include <linux/hdreg.h>
+
+#define USE_SYSFS
+#ifdef USE_SYSFS
+/*
+ * sysfs part	Find all disks on the system, list out IDE and unmanaged
+ *		SATA disks, flush the cache of those and shut them down.
+ * Author:	Werner Fink <werner at suse.de>, 2007/06/12
+ *
+ */
+#include <limits.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#ifdef WORDS_BIGENDIAN
+#include <byteswap.h>
+#endif
+
+#define SYS_BLK		"/sys/block"
+#define SYS_CLASS	"/sys/class/scsi_disk"
+#define DEV_BASE	"/dev"
+#define ISSPACE(c)	(((c)==' ')||((c)=='\n')||((c)=='\t')||((c)=='\v')||((c)=='\r')||((c)=='\f'))
+
+/* Used in flush_cache_ext(), compare with <linux/hdreg.h> */
+#define IDBYTES		512
+#define MASK_EXT	0xE000		/* Bit 15 shall be zero, bit 14 shall be one, bit 13 flush cache ext */
+#define TEST_EXT	0x6000
+
+/* Maybe set in list_disks() and used in do_standby_idedisk() */
+#define DISK_IS_IDE	0x00000001
+#define DISK_IS_SATA	0x00000002
+#define DISK_EXTFLUSH	0x00000004
+
+static char *strstrip(char *str);
+static FILE *hdopen(const char* const format, const char* const name);
+static int flush_cache_ext(const char *device);
+
+/*
+ *	Find all disks through /sys/block.
+ */
+static char *list_disks(DIR* blk, unsigned int* flags)
+{
+	struct dirent *d;
+
+	while ((d = readdir(blk))) {
+		*flags = 0;
+		if (d->d_name[1] == 'd' && (d->d_name[0] == 'h' || d->d_name[0] == 's')) {
+			char buf[NAME_MAX+1], lnk[NAME_MAX+1], *ptr;
+			struct stat st;
+			FILE *fp;
+			int ret;
+
+			fp = hdopen(SYS_BLK "/%s/removable", d->d_name);
+			if ((long)fp <= 0) {
+				if ((long)fp < 0)
+					goto empty;	/* error */
+				continue;		/* no entry `removable' */
+			}
+
+			ret = getc(fp);
+			fclose(fp);
+
+			if (ret != '0')
+				continue;		/* not a hard disk */
+
+			if (d->d_name[0] == 'h') {
+				(*flags) |= DISK_IS_IDE;
+				if ((ret = flush_cache_ext(d->d_name))) {
+					if (ret < 0)
+						goto empty;
+					(*flags) |= DISK_EXTFLUSH;
+				}
+				break;			/* old IDE disk not managed by kernel, out here */
+			}
+
+			ret = snprintf(buf, sizeof(buf), SYS_BLK "/%s/device", d->d_name);
+			if ((ret >= sizeof(buf)) || (ret < 0))
+				goto empty;		/* error */
+
+			ret = readlink(buf, lnk, sizeof(lnk));
+			if (ret >= sizeof(lnk))
+				goto empty;		/* error */
+			if (ret < 0) {
+				if (errno != ENOENT)
+					goto empty;	/* error */
+				continue;		/* no entry `device' */
+			}
+			lnk[ret] = '\0';
+
+			ptr = basename(lnk);
+			if (!ptr || !*ptr)
+				continue;		/* should not happen */
+
+			ret = snprintf(buf, sizeof(buf), SYS_CLASS "/%s/manage_start_stop", ptr);
+			if ((ret >= sizeof(buf)) || (ret < 0))
+				goto empty;		/* error */
+
+			ret = stat(buf, &st);
+			if (ret == 0)
+				continue;		/* disk found but managed by kernel */
+
+			if (errno != ENOENT)
+				goto empty;		/* error */
+
+			fp = hdopen(SYS_BLK "/%s/device/vendor", d->d_name);
+			if ((long)fp <= 0) {
+				if ((long)fp < 0)
+					goto empty;	/* error */
+				continue;		/* no entry `device/vendor' */
+			}
+
+			ptr = fgets(buf, sizeof(buf), fp);
+			fclose(fp);
+			if (ptr == (char*)0)
+				continue;		/* should not happen */
+
+			ptr = strstrip(buf);
+			if (*ptr == '\0')
+				continue;		/* should not happen */
+
+			if (strncmp(buf, "ATA", sizeof(buf)))
+				continue;		/* no SATA but a real SCSI disk */
+
+			(*flags) |= (DISK_IS_IDE|DISK_IS_SATA);
+			if ((ret = flush_cache_ext(d->d_name))) {
+				if (ret < 0)
+					goto empty;
+				(*flags) |= DISK_EXTFLUSH;
+			}
+			break;				/* new SATA disk to shutdown, out here */
+		}
+	}
+	if (d == (struct dirent*)0)
+		goto empty;
+	return d->d_name;
+empty:
+	return (char*)0;
+}
+
+/*
+ *	Put an disk in standby mode.
+ *	Code stolen from hdparm.c
+ */
+static int do_standby_idedisk(char *device, unsigned int flags)
+{
+#ifndef WIN_STANDBYNOW1
+#define WIN_STANDBYNOW1		0xE0
+#endif
+#ifndef WIN_STANDBYNOW2
+#define WIN_STANDBYNOW2		0x94
+#endif
+#ifndef WIN_FLUSH_CACHE_EXT
+#define WIN_FLUSH_CACHE_EXT	0xEA
+#endif
+#ifndef WIN_FLUSH_CACHE
+#define WIN_FLUSH_CACHE		0xE7
+#endif
+	unsigned char flush1[4] = {WIN_FLUSH_CACHE_EXT,0,0,0};
+	unsigned char flush2[4] = {WIN_FLUSH_CACHE,0,0,0};
+	unsigned char stdby1[4] = {WIN_STANDBYNOW1,0,0,0};
+	unsigned char stdby2[4] = {WIN_STANDBYNOW2,0,0,0};
+	char buf[NAME_MAX+1];
+	int fd, ret;
+
+	ret = snprintf(buf, sizeof(buf), DEV_BASE "/%s", device);
+	if ((ret >= sizeof(buf)) || (ret < 0))
+		return -1;
+
+	if ((fd = open(buf, O_RDWR)) < 0)
+		return -1;
+
+	switch (flags & DISK_EXTFLUSH) {
+	case DISK_EXTFLUSH:
+		if (ioctl(fd, HDIO_DRIVE_CMD, &flush1) == 0)
+			break;
+		/* Extend flush rejected, try standard flush */
+	default:
+		ioctl(fd, HDIO_DRIVE_CMD, &flush2);
+		break;
+	}
+
+	ret = ioctl(fd, HDIO_DRIVE_CMD, &stdby1) &&
+	      ioctl(fd, HDIO_DRIVE_CMD, &stdby2);
+	close(fd);
+
+	if (ret)
+		return -1;
+	return 0;
+}
+
+/*
+ *	List all disks and put them in standby mode.
+ *	This has the side-effect of flushing the writecache,
+ *	which is exactly what we want on poweroff.
+ */
+int hddown(void)
+{
+	unsigned int flags;
+	char *disk;
+	DIR *blk;
+
+	if ((blk = opendir(SYS_BLK)) == (DIR*)0)
+		return -1;
+
+	while ((disk = list_disks(blk, &flags)))
+		do_standby_idedisk(disk, flags);
+
+	return closedir(blk);
+}
+
+/*
+ * Strip off trailing white spaces
+ */
+static char *strstrip(char *str)
+{
+	const size_t len = strlen(str);
+	if (len) {
+		char* end = str + len - 1;
+		while ((end != str) && ISSPACE(*end))
+			end--;
+		*(end + 1) = '\0';			/* remove trailing white spaces */
+	}
+	return str;
+}
+
+/*
+ * Open a sysfs file without getting a controlling tty
+ * and return FILE* pointer.
+ */
+static FILE *hdopen(const char* const format, const char* const name)
+{
+	char buf[NAME_MAX+1];
+	FILE *fp = (FILE*)-1;
+	int fd, ret;
+	
+	ret = snprintf(buf, sizeof(buf), format, name);
+	if ((ret >= sizeof(buf)) || (ret < 0))
+		goto error;		/* error */
+
+	fd = open(buf, O_RDONLY|O_NOCTTY);
+	if (fd < 0) {
+		if (errno != ENOENT)
+			goto error;	/* error */
+		fp = (FILE*)0;
+		goto error;		/* no entry `removable' */
+	}
+
+	fp = fdopen(fd, "r");
+	if (fp == (FILE*)0)
+		close(fd);		/* should not happen */
+error:
+	return fp;
+}
+
+/*
+ * Check IDE/(S)ATA hard disk identity for
+ * the FLUSH CACHE EXT bit set.
+ */
+static int flush_cache_ext(const char *device)
+{
+#ifndef WIN_IDENTIFY
+#define WIN_IDENTIFY		0xEC
+#endif
+	unsigned char args[4+IDBYTES];
+	unsigned short *id = (unsigned short*)(&args[4]);
+	char buf[NAME_MAX+1], *ptr;
+	int fd = -1, ret = 0;
+	FILE *fp;
+
+	fp = hdopen(SYS_BLK "/%s/size", device);
+	if ((long)fp <= 0) {
+		if ((long)fp < 0)
+			return -1;	/* error */
+		goto out;		/* no entry `size' */
+	}
+
+	ptr = fgets(buf, sizeof(buf), fp);
+	fclose(fp);
+	if (ptr == (char*)0)
+		goto out;		/* should not happen */
+
+	ptr = strstrip(buf);
+	if (*ptr == '\0')
+		goto out;		/* should not happen */
+
+	if ((size_t)atoll(buf) < (1<<28))
+		goto out;		/* small disk */
+		
+	ret = snprintf(buf, sizeof(buf), DEV_BASE "/%s", device);
+	if ((ret >= sizeof(buf)) || (ret < 0))
+		return -1;		/* error */
+
+	if ((fd = open(buf, O_RDONLY|O_NONBLOCK)) < 0)
+		goto out;
+
+	memset(&args[0], 0, sizeof(args));
+	args[0] = WIN_IDENTIFY;
+	args[3] = 1;
+	if (ioctl(fd, HDIO_DRIVE_CMD, &args))
+		goto out;
+#ifdef WORDS_BIGENDIAN
+# if 0
+	{
+		const unsigned short *end = id + IDBYTES/2;
+		const unsigned short *from = id;
+		unsigned short *to = id;
+
+		while (from < end)
+			*to++ = bswap_16(*from++);
+	}
+# else
+	id[83] = bswap_16(id[83]);
+# endif
+#endif
+	if ((id[83] & MASK_EXT) == TEST_EXT)
+		ret = 1;
+out:
+	if (fd >= 0)
+		close(fd);
+	return ret;
+}
+#else /* ! USE_SYSFS */
+#define MAX_DISKS	64
+#define PROC_IDE	"/proc/ide"
+#define DEV_BASE	"/dev"
+
+/*
+ *	Find all IDE disks through /proc.
+ */
+static int find_idedisks(const char **dev, int maxdev, int *count)
+{
+	DIR *dd;
+	FILE *fp;
+	struct dirent *d;
+	char buf[256];
+
+	if ((dd = opendir(PROC_IDE)) == NULL)
+		return -1;
+
+	while (*count < maxdev && (d = readdir(dd)) != NULL) {
+		if (strncmp(d->d_name, "hd", 2) != 0)
+			continue;
+		buf[0] = 0;
+		snprintf(buf, sizeof(buf), PROC_IDE "/%s/media", d->d_name);
+		if ((fp = fopen(buf, "r")) == NULL)
+			continue;
+		if (fgets(buf, sizeof(buf), fp) == 0 ||
+		    strcmp(buf, "disk\n") != 0) {
+			fclose(fp);
+			continue;
+		}
+		fclose(fp);
+		snprintf(buf, sizeof(buf), DEV_BASE "/%s", d->d_name);
+		dev[(*count)++] = strdup(buf);
+	}
+	closedir(dd);
+
+	return 0;
+}
+
+/*
+ *	Find all SCSI/SATA disks.
+ */
+static int find_scsidisks(const char **dev, int maxdev, int *count)
+{
+	if (*count < maxdev) dev[(*count)++] = DEV_BASE "/sda";
+	if (*count < maxdev) dev[(*count)++] = DEV_BASE "/sdb";
+	if (*count < maxdev) dev[(*count)++] = DEV_BASE "/sdc";
+	if (*count < maxdev) dev[(*count)++] = DEV_BASE "/sdd";
+	if (*count < maxdev) dev[(*count)++] = DEV_BASE "/sde";
+	if (*count < maxdev) dev[(*count)++] = DEV_BASE "/sdf";
+	if (*count < maxdev) dev[(*count)++] = DEV_BASE "/sdg";
+	if (*count < maxdev) dev[(*count)++] = DEV_BASE "/sdh";
+
+	return 0;
+}
+
+/*
+ *	Open the device node of a disk.
+ */
+static int open_disk(const char *device)
+{
+	return open(device, O_RDWR);
+}
+
+/*
+ *	Open device nodes of all disks, and store the file descriptors in fds.
+ *	This has to be done in advance because accessing the device nodes
+ *	might cause a disk to spin back up.
+ */
+static int open_disks(const char **disks, int *fds, int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		fds[i] = open_disk(disks[i]);
+
+	return 0;
+}
+
+/*
+ *	Put an IDE/SCSI/SATA disk in standby mode.
+ *	Code stolen from hdparm.c
+ */
+static int do_standby_disk(int fd)
+{
+#ifndef WIN_STANDBYNOW1
+#define WIN_STANDBYNOW1 0xE0
+#endif
+#ifndef WIN_STANDBYNOW2
+#define WIN_STANDBYNOW2 0x94
+#endif
+	unsigned char args1[4] = {WIN_STANDBYNOW1,0,0,0};
+	unsigned char args2[4] = {WIN_STANDBYNOW2,0,0,0};
+
+	if (fd < 0)
+		return -1;
+
+	if (ioctl(fd, HDIO_DRIVE_CMD, &args1) &&
+	    ioctl(fd, HDIO_DRIVE_CMD, &args2))
+		return -1;
+
+	return 0;
+}
+
+/*
+ *	Put all specified disks in standby mode.
+ */
+static int do_standby_disks(const int *fds, int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		do_standby_disk(fds[i]);
+
+	return 0;
+}
+
+/*
+ *	First find all IDE/SCSI/SATA disks, then put them in standby mode.
+ *	This has the side-effect of flushing the writecache,
+ *	which is exactly what we want on poweroff.
+ */
+int hddown(void)
+{
+	const char *disks[MAX_DISKS];
+	int fds[MAX_DISKS];
+	int count = 0;
+	int result1, result2;
+
+	result1 = find_idedisks(disks, MAX_DISKS, &count);
+	result2 = find_scsidisks(disks, MAX_DISKS, &count);
+
+	open_disks(disks, fds, count);
+	do_standby_disks(fds, count);
+
+	return (result1 ? result1 : result2);
+}
+#endif /* ! USE_SYSFS */
+#else /* __linux__ */
+
+int hddown(void)
+{
+	return 0;
+}
+
+#endif /* __linux__ */
+
+#ifdef STANDALONE
+int main(int argc, char **argv)
+{
+	return (hddown() == 0);
+}
+#endif
+

Deleted: sysvinit-upstream/tags/2.87dsf/src/init.c
===================================================================
--- sysvinit-upstream/trunk/src/init.c	2009-07-10 21:51:19 UTC (rev 1428)
+++ sysvinit-upstream/tags/2.87dsf/src/init.c	2009-07-12 18:00:14 UTC (rev 1458)
@@ -1,2697 +0,0 @@
-/*
- * Init		A System-V Init Clone.
- *
- * Usage:	/sbin/init
- *		     init [0123456SsQqAaBbCc]
- *		  telinit [0123456SsQqAaBbCc]
- *
- * Version:	@(#)init.c  2.86  30-Jul-2004  miquels at cistron.nl
- */
-#define VERSION "2.86"
-#define DATE    "31-Jul-2004"
-/*
- *		This file is part of the sysvinit suite,
- *		Copyright 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.
- *
- */
-
-#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>
-#include <utmp.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <sys/syslog.h>
-#include <sys/time.h>
-
-#ifdef WITH_SELINUX
-#include <selinux/selinux.h>
-#endif
-
-
-#ifdef __i386__
-#  if (__GLIBC__ >= 2)
-     /* GNU libc 2.x */
-#    define STACK_DEBUG 1
-#    if (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
-       /* Only glibc 2.0 needs this */
-#      include <sigcontext.h>
-#    endif
-#  endif
-#endif
-
-#include "init.h"
-#include "initreq.h"
-#include "paths.h"
-#include "reboot.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 { \
-			sa.sa_handler = fun; \
-			sa.sa_flags = flags; \
-			sigemptyset(&sa.sa_mask); \
-			sigaction(sig, &sa, NULL); \
-		} while(0)
-
-/* Version information */
-char *Version = "@(#) init " VERSION "  " DATE "  miquels at 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 */
-	0, 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 sltime = 5;			/* 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 *user_console = NULL;	/* User console device */
-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="/sbin/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	},
-  { "",	   	   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];
-
-
-/*
- *	Sleep a number of seconds.
- *
- *	This only works correctly because the linux select updates
- *	the elapsed time in the struct timeval passed to select!
- */
-void do_sleep(int sec)
-{
-	struct timeval tv;
-
-	tv.tv_sec = sec;
-	tv.tv_usec = 0;
-
-	while(select(0, NULL, NULL, NULL, &tv) < 0 && errno == EINTR)
-		;
-}
-
-
-/*
- *	Non-failing allocation routines (init cannot fail).
- */
-void *imalloc(size_t size)
-{
-	void	*m;
-
-	while ((m = malloc(size)) == NULL) {
-		initlog(L_VB, "out of memory");
-		do_sleep(5);
-	}
-	memset(m, 0, size);
-	return m;
-}
-
-
-char *istrdup(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.
- */
-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", sltime);
-	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.
- *	FIXME: why not use fgets() ?
- */
-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 {
-		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:
-				fscanf(f, "%c\n", &runlevel);
-				break;
-			case D_THISLEVEL:
-				fscanf(f, "%c\n", &thislevel);
-				break;
-			case D_PREVLEVEL:
-				fscanf(f, "%c\n", &prevlevel);
-				break;
-			case D_GOTSIGN:
-				fscanf(f, "%u\n", &got_signals);
-				break;
-			case D_WROTE_WTMP_REBOOT:
-				fscanf(f, "%d\n", &wrote_wtmp_reboot);
-				break;
-			case D_WROTE_UTMP_REBOOT:
-				fscanf(f, "%d\n", &wrote_utmp_reboot);
-				break;
-			case D_SLTIME:
-				fscanf(f, "%d\n", &sltime);
-				break;
-			case D_DIDBOOT:
-				fscanf(f, "%d\n", &did_boot);
-				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:
-			fscanf(f, "%d\n", &(p->pid));
-			break;
-		case C_EXS:
-			fscanf(f, "%u\n", &(p->exstat));
-			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
- */
-int receive_state(int fd)
-{
-	FILE	*f;
-	char	old_version[256];
-	CHILD	**pp;
-
-	f = fdopen(fd, "r");
-
- 	if (get_cmd(f) != C_VER)
-		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__
-__attribute__ ((format (printf, 1, 2)))
-#endif
-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 > 2) {
-		memset(argv0, 0, maxproclen);
-		strncpy(argv0, buf, maxproclen - 2);
-	}
-
-	return len;
-}
-
-/*
- *	Set console_dev to a working console.
- */
-void console_init(void)
-{
-	int fd;
-	int tried_devcons = 0;
-	int tried_vtmaster = 0;
-	char *s;
-
-	if (user_console) {
-		console_dev = user_console;
-	} else 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.
- */
-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;
-
-	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)
- */
-void signal_handler(int sig)
-{
-	ADDSET(got_signals, sig);
-}
-
-/*
- *	SIGCHLD: one of our children has died.
- */
-void chld_handler()
-{
-	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
- */
-void cont_handler()
-{
-	got_cont = 1;
-}
-
-/*
- *	Fork and dump core in /.
- */
-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);
-	chdir("/");
-
-	signal(SIGSEGV, SIG_DFL);
-	raise(SIGSEGV);
-	sigdelset(&mask, SIGSEGV);
-	sigprocmask(SIG_SETMASK, &mask, NULL);
-
-	do_sleep(5);
-	exit(0);
-}
-
-/*
- *	OOPS: segmentation violation!
- *	If we have the info, print where it occured.
- *	Then sleep 30 seconds and try to continue.
- */
-#if defined(STACK_DEBUG) && defined(__linux__)
-void segv_handler(int sig, struct sigcontext ctx)
-{
-	char	*p = "";
-	int	saved_errno = errno;
-
-	if ((void *)ctx.eip >= (void *)do_sleep &&
-	    (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_sleep(30);
-	errno = saved_errno;
-}
-#else
-void segv_handler()
-{
-	int	saved_errno = errno;
-
-	initlog(L_VB,
-		"PANIC: segmentation violation! sleeping for 30 seconds.");
-	coredump();
-	do_sleep(30);
-	errno = saved_errno;
-}
-#endif
-
-/*
- *	The SIGSTOP & SIGTSTP handler
- */
-void stop_handler()
-{
-	int	saved_errno = errno;
-
-	got_cont = 0;
-	while(!got_cont) pause();
-	got_cont = 0;
-	errno = saved_errno;
-}
-
-/*
- *	Set terminal settings to reasonable defaults
- */
-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;
-	}
-
-	(void) tcgetattr(fd, &tty);
-
-	tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD;
-	tty.c_cflag |= HUPCL|CLOCAL|CREAD;
-
-	tty.c_cc[VINTR]  = 3;	/* ctrl('c') */
-	tty.c_cc[VQUIT]  = 28;	/* ctrl('\\') */
-	tty.c_cc[VERASE] = 127;
-	tty.c_cc[VKILL]  = 24;	/* ctrl('x') */
-	tty.c_cc[VEOF]   = 4;	/* ctrl('d') */
-	tty.c_cc[VTIME]  = 0;
-	tty.c_cc[VMIN]   = 1;
-	tty.c_cc[VSTART] = 17;	/* ctrl('q') */
-	tty.c_cc[VSTOP]  = 19;	/* ctrl('s') */
-	tty.c_cc[VSUSP]  = 26;	/* ctrl('z') */
-
-	/*
-	 *	Set pre and post processing
-	 */
-	tty.c_iflag = IGNPAR|ICRNL|IXON|IXANY;
-	tty.c_oflag = OPOST|ONLCR;
-	tty.c_lflag = ISIG|ICANON|ECHO|ECHOCTL|ECHOPRT|ECHOKE;
-
-	/*
-	 *	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);
-}
-
-/*
- *	Print to the system console
- */
-void print(char *s)
-{
-	int fd;
-
-	if ((fd = console_open(O_WRONLY|O_NOCTTY|O_NDELAY)) >= 0) {
-		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");
-	}
-}
-
-
-/*
- *	Build a new environment for execve().
- */
-char **init_buildenv(int child)
-{
-	char		i_lvl[] = "RUNLEVEL=x";
-	char		i_prev[] = "PREVLEVEL=x";
-	char		i_cons[32];
-	char		**e;
-	int		n, i;
-
-	for (n = 0; environ[n]; n++)
-		;
-	n += NR_EXTRA_ENV + 8;
-	e = calloc(n, sizeof(char *));
-
-	for (n = 0; environ[n]; n++)
-		e[n] = istrdup(environ[n]);
-
-	for (i = 0; i < NR_EXTRA_ENV; i++)
-		if (extra_env[i])
-			e[n++] = istrdup(extra_env[i]);
-
-	if (child) {
-		snprintf(i_cons, sizeof(i_cons), "CONSOLE=%s", console_dev);
-		i_lvl[9]   = thislevel;
-		i_prev[10] = prevlevel;
-		e[n++] = istrdup(i_lvl);
-		e[n++] = istrdup(i_prev);
-		e[n++] = istrdup(i_cons);
-		e[n++] = istrdup(E_VERSION);
-	}
-
-	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.
- *
- */
-int spawn(CHILD *ch, int *res)
-{
-  char *args[16];		/* Argv array */
-  char buf[136];		/* Line buffer */
-  int f, st, rc;		/* 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);
-
-  		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) {
-			/*
-			 *	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 ((f = console_open(O_RDWR|O_NOCTTY)) >= 0) {
-				/* Take over controlling tty by force */
-				(void)ioctl(f, TIOCSCTTY, 1);
-  				dup(f);
-  				dup(f);
-			}
-			SETSIG(sa, SIGCHLD, SIG_DFL, SA_RESTART);
-			if ((pid = fork()) < 0) {
-  				initlog(L_VB, "cannot fork: %s",
-					strerror(errno));
-				exit(1);
-			}
-			if (pid > 0) {
-				/*
-				 *	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(f);
-				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(f, 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 {
-			setsid();
-			if ((f = console_open(O_RDWR|O_NOCTTY)) < 0) {
-				initlog(L_VB, "open(%s): %s", console_dev,
-					strerror(errno));
-				f = open("/dev/null", O_RDWR);
-			}
-			dup(f);
-			dup(f);
-		}
-
-  		/* 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]);
-  		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_sleep(5);
-		continue;
-	}
-	return(pid);
-  }
-}
-
-/*
- *	Start a child running!
- */
-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;
-		case KBREQUEST:
-		case BOOT:
-		case POWERFAIL:
-		case ONCE:
-			if (ch->flags & XECUTED) break;
-		case ONDEMAND:
-		case RESPAWN:
-  			ch->flags |= RUNNING;
-  			if (spawn(ch, &(ch->pid)) < 0) break;
-			/*
-			 *	Do NOT log if process field starts with '+'
-			 *	FIXME: that's for compatibility with *very*
-			 *	old getties - probably it can be taken out.
-			 */
-  			if (ch->process[0] != '+')
-				write_utmp_wtmp("", ch->id, ch->pid,
-					INIT_PROCESS, "");
-  			break;
-	}
-}
-
-
-/*
- *	Read the inittab file.
- */
-void read_inittab(void)
-{
-  FILE		*fp;			/* The INITTAB file */
-  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 = 0;		/* Ready yet? */
-
-#if DEBUG
-  if (newFamily != NULL) {
-	INITDBG(L_VB, "PANIC newFamily != NULL");
-	exit(1);
-  }
-  INITDBG(L_VB, "Reading inittab");
-#endif
-
-  /*
-   *	Open INITTAB and real line by line.
-   */
-  if ((fp = fopen(INITTAB, "r")) == NULL)
-	initlog(L_VB, "No inittab file found");
-
-  while(!done) {
-	/*
-	 *	Add single user shell entry at the end.
-	 */
-	if (fp == NULL || fgets(buf, sizeof(buf), fp) == NULL) {
-		done = 1;
-		/*
-		 *	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;
-	}
-	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");
-	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 < 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);
-
-  /*
-   *	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 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 the KILL signal");
-			kill(-(ch->pid), SIGKILL);
-			break;
-	}
-	talk = 0;
-	
-    }
-    /*
-     *	See if we have to wait 5 seconds
-     */
-    if (foundOne && round == 0) {
-	/*
-	 *	Yup, but check every second if we still have children.
-	 */
-	for(f = 0; f < sltime; 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_sleep(1);
-	}
-    }
-  }
-
-  /*
-   *	Now give all processes the chance to die and collect exit statuses.
-   */
-  if (foundOne) do_sleep(1);
-  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.
- */
-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) {
-			/* FIXME: 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
- */
-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)) {
-  		write(fd, prompt, sizeof(prompt) - 1);
-		buf[0] = 0;
-  		read(fd, buf, sizeof(buf));
-  		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.
- */
-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.
-	 */
-	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.
- */
-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) sltime = 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') 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. */
-	write_utmp_wtmp("runlevel", "~~", foo + 256*runlevel, RUN_LVL, "~");
-	thislevel = foo;
-	prevlevel = 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.
- */
-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 */
-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.
- */
-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
- */
-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.
- */
-int make_pipe(int fd)
-{
-	int fds[2];
-
-	pipe(fds);
-	dup2(fds[0], fd);
-	close(fds[0]);
-	fcntl(fds[1], F_SETFD, 1);
-	fcntl(fd, F_SETFD, 0);
-	write(fds[1], Signature, 8);
-
-	return fds[1];
-}
-
-/*
- *	Attempt to re-exec.
- */
-void 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
-	 */
-	fd = make_pipe(STATE_PIPE);
-
-	/* 
-	 * It's a backup day today, so I'm pissed off.  Being a BOFH, however, 
-	 * does have it's advantages...
-	 */
-	fail_cancel();
-	close(pipe_fd);
-	pipe_fd = -1;
-	DELSET(got_signals, SIGCHLD);
-	DELSET(got_signals, SIGHUP);
-	DELSET(got_signals, SIGUSR1);
-
-	/*
-	 *	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. 
-	 *	Bitch, close the state pipe, unblock signals and return.
-	 */
-	close(fd);
-	close(STATE_PIPE);
-	sigprocmask(SIG_SETMASK, &oldset, NULL);
-	init_freeenv(env);
-	initlog(L_CO, "Attempt to re-exec failed");
-}
-
-
-/*
- *	We got a change runlevel request through the
- *	init.fifo. Process it.
- */
-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;
-			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]", 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.
- */
-void initcmd_setenv(char *data, int size)
-{
-	char		*env, *p, *e, *eq;
-	int		i, sz;
-
-	e = data + size;
-
-	while (*data && data < e) {
-		eq = NULL;
-		for (p = data; *p && p < e; p++)
-			if (*p == '=') eq = p;
-		if (*p) break;
-		env = data;
-		data = ++p;
-
-		sz = eq ? (eq - env) : (p - env);
-
-		/*initlog(L_SY, "init_setenv: %s, %s, %d", env, eq, sz);*/
-
-		/*
-		 *	We only allow INIT_* to be set.
-		 */
-		if (strncmp(env, "INIT_", 5) != 0)
-			continue;
-
-		/* Free existing vars. */
-		for (i = 0; i < NR_EXTRA_ENV; i++) {
-			if (extra_env[i] == NULL) continue;
-			if (!strncmp(extra_env[i], env, sz) &&
-			    extra_env[i][sz] == '=') {
-				free(extra_env[i]);
-				extra_env[i] = NULL;
-			}
-		}
-
-		/* Set new vars if needed. */
-		if (eq == NULL) continue;
-		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.
- *
- *	FIXME:	this needs to be finished. NOT that it is buggy, but we need
- *		to add the telnetd/rlogind stuff so people can start using it.
- *		Maybe move to using an AF_UNIX socket so we can use
- *		the 2.2 kernel credential stuff to see who we're talking to.
- *	
- */
-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 < 0) {
-	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:
-			sltime = request.sleeptime;
-			fifo_new_level(request.runlevel);
-			quit = 1;
-			break;
-		case INIT_CMD_POWERFAIL:
-			sltime = request.sleeptime;
-			do_power_fail('F');
-			quit = 1;
-			break;
-		case INIT_CMD_POWERFAILNOW:
-			sltime = request.sleeptime;
-			do_power_fail('L');
-			quit = 1;
-			break;
-		case INIT_CMD_POWEROK:
-			sltime = request.sleeptime;
-			do_power_fail('O');
-			quit = 1;
-			break;
-		case INIT_CMD_SETENV:
-			initcmd_setenv(request.i.data, sizeof(request.i.data));
-			break;
-		case INIT_CMD_CHANGECONS:
-			if (user_console) {
-				free(user_console);
-				user_console = NULL;
-			}
-			if (!request.i.bsd.reserved[0])
-				user_console = NULL;
-			else
-				user_console = strdup(request.i.bsd.reserved);
-			console_init();
-			quit = 1;
-			break;
-		default:
-			initlog(L_VB, "got unimplemented initrequest.");
-			break;
-	}
-  }
-
-  /*
-   *	We come here if the pipe couldn't be opened.
-   */
-  if (pipe_fd < 0) pause();
-
-}
-
-
-/*
- *	This function is used in the transition
- *	sysinit (-> single user) boot -> multi-user.
- */
-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);
-		write_utmp_wtmp("runlevel", "~~", runlevel + 256 * oldlevel, RUN_LVL, "~");
-		thislevel = runlevel;
-		prevlevel = oldlevel;
-		setproctitle("init [%c]", runlevel);
-	}
-  }
-}
-
-/*
- *	Init got hit by a signal. See which signal it is,
- *	and act accordingly.
- */
-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) {
-		c = 0;
-		read(fd, &c, 1);
-		pwrstat = c;
-		close(fd);
-		unlink(PWRSTAT);
-	}
-	do_power_fail(pwrstat);
-	DELSET(got_signals, SIGPWR);
-  }
-
-  if (ISMEMBER(got_signals, SIGINT)) {
-	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;
-			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]", runlevel);
-			DELSET(got_signals, SIGHUP);
-		}
-	}
-  }
-  if (ISMEMBER(got_signals, SIGUSR1)) {
-	/*
-	 *	SIGUSR1 means close and reopen /dev/initctl
-	 */
-	INITDBG(L_VB, "got SIGUSR1");
-	close(pipe_fd);
-	pipe_fd = -1;
-	DELSET(got_signals, SIGUSR1);
-  }
-}
-
-/*
- *	The main loop
- */ 
-int init_main()
-{
-  CHILD			*ch;
-  struct sigaction	sa;
-  sigset_t		sgt;
-  pid_t			rc;
-  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;
-		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, 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) {
-
-  	/* Close whatever files are open, and reset the console. */
-	close(0);
-	close(1);
-	close(2);
-  	console_stty();
-  	setsid();
-
-  	/*
-	 *	Set default PATH variable.
-	 */
-  	putenv(PATH_DFL);
-
-  	/*
-	 *	Initialize /var/run/utmp (only works if /var is on
-	 *	root and mounted rw)
-	 */
-  	(void) close(open(UTMP_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0644));
-
-  	/*
-	 *	Say hello to the world
-	 */
-  	initlog(L_CO, bootmsg, "booting");
-
-  	/*
-	 *	See if we have to start an emergency shell.
-	 */
-	if (emerg_shell) {
-		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);
-  }
-  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.
- */
-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);
-}
-
-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':
-			sltime = 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  = env ? 0 : argv[optind][0];
-		request.sleeptime = sltime;
-	}
-
-	/* 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 &&
-	    write(fd, &request, sizeof(request)) == sizeof(request)) {
-		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], sltime);
-		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;
-	int			enforce = 0;
-
-	/* Get my own name */
-	if ((p = strrchr(argv[0], '/')) != NULL)
-  		p++;
-	else
-  		p = argv[0];
-	umask(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]",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 && !is_selinux_enabled()) {
-	  putenv("SELINUX_INIT=YES");
-	  if (selinux_init_load_policy(&enforce) == 0 ) {
-	    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(dfl_level);
-
-	/*NOTREACHED*/
-	return 0;
-}

Copied: sysvinit-upstream/tags/2.87dsf/src/init.c (from rev 1454, sysvinit-upstream/trunk/src/init.c)
===================================================================
--- sysvinit-upstream/tags/2.87dsf/src/init.c	                        (rev 0)
+++ sysvinit-upstream/tags/2.87dsf/src/init.c	2009-07-12 18:00:14 UTC (rev 1458)
@@ -0,0 +1,2705 @@
+/*
+ * Init		A System-V Init Clone.
+ *
+ * Usage:	/sbin/init
+ *		     init [0123456SsQqAaBbCc]
+ *		  telinit [0123456SsQqAaBbCc]
+ *
+ * Version:	@(#)init.c  2.86  30-Jul-2004  miquels at cistron.nl
+ */
+#define VERSION "2.86"
+#define DATE    "31-Jul-2004"
+/*
+ *		This file is part of the sysvinit suite,
+ *		Copyright 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.
+ *
+ */
+
+#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>
+#include <utmp.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <sys/syslog.h>
+#include <sys/time.h>
+
+#ifdef WITH_SELINUX
+#include <selinux/selinux.h>
+#endif
+
+
+#ifdef __i386__
+#  if (__GLIBC__ >= 2)
+     /* GNU libc 2.x */
+#    define STACK_DEBUG 1
+#    if (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
+       /* Only glibc 2.0 needs this */
+#      include <sigcontext.h>
+#    endif
+#  endif
+#endif
+
+#include "init.h"
+#include "initreq.h"
+#include "paths.h"
+#include "reboot.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 { \
+			sa.sa_handler = fun; \
+			sa.sa_flags = flags; \
+			sigemptyset(&sa.sa_mask); \
+			sigaction(sig, &sa, NULL); \
+		} while(0)
+
+/* Version information */
+char *Version = "@(#) init " VERSION "  " DATE "  miquels at 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 sltime = 5;			/* 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 *user_console = NULL;	/* User console device */
+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="/sbin/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	},
+  { "",	   	   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];
+
+
+/*
+ *	Sleep a number of seconds.
+ *
+ *	This only works correctly because the linux select updates
+ *	the elapsed time in the struct timeval passed to select!
+ */
+void do_sleep(int sec)
+{
+	struct timeval tv;
+
+	tv.tv_sec = sec;
+	tv.tv_usec = 0;
+
+	while(select(0, NULL, NULL, NULL, &tv) < 0 && errno == EINTR)
+		;
+}
+
+
+/*
+ *	Non-failing allocation routines (init cannot fail).
+ */
+void *imalloc(size_t size)
+{
+	void	*m;
+
+	while ((m = malloc(size)) == NULL) {
+		initlog(L_VB, "out of memory");
+		do_sleep(5);
+	}
+	memset(m, 0, size);
+	return m;
+}
+
+
+char *istrdup(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.
+ */
+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", sltime);
+	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.
+ *	FIXME: why not use fgets() ?
+ */
+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 {
+		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:
+				fscanf(f, "%c\n", &runlevel);
+				break;
+			case D_THISLEVEL:
+				fscanf(f, "%c\n", &thislevel);
+				break;
+			case D_PREVLEVEL:
+				fscanf(f, "%c\n", &prevlevel);
+				break;
+			case D_GOTSIGN:
+				fscanf(f, "%u\n", &got_signals);
+				break;
+			case D_WROTE_WTMP_REBOOT:
+				fscanf(f, "%d\n", &wrote_wtmp_reboot);
+				break;
+			case D_WROTE_UTMP_REBOOT:
+				fscanf(f, "%d\n", &wrote_utmp_reboot);
+				break;
+			case D_SLTIME:
+				fscanf(f, "%d\n", &sltime);
+				break;
+			case D_DIDBOOT:
+				fscanf(f, "%d\n", &did_boot);
+				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:
+			fscanf(f, "%d\n", &(p->pid));
+			break;
+		case C_EXS:
+			fscanf(f, "%u\n", &(p->exstat));
+			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
+ */
+int receive_state(int fd)
+{
+	FILE	*f;
+	char	old_version[256];
+	CHILD	**pp;
+
+	f = fdopen(fd, "r");
+
+ 	if (get_cmd(f) != C_VER)
+		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__
+__attribute__ ((format (printf, 1, 2)))
+#endif
+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;
+}
+
+/*
+ *	Set console_dev to a working console.
+ */
+void console_init(void)
+{
+	int fd;
+	int tried_devcons = 0;
+	int tried_vtmaster = 0;
+	char *s;
+
+	if (user_console) {
+		console_dev = user_console;
+	} else 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.
+ */
+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(100);
+	}
+
+	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)
+ */
+void signal_handler(int sig)
+{
+	ADDSET(got_signals, sig);
+}
+
+/*
+ *	SIGCHLD: one of our children has died.
+ */
+void chld_handler()
+{
+	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
+ */
+void cont_handler()
+{
+	got_cont = 1;
+}
+
+/*
+ *	Fork and dump core in /.
+ */
+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);
+	chdir("/");
+
+	signal(SIGSEGV, SIG_DFL);
+	raise(SIGSEGV);
+	sigdelset(&mask, SIGSEGV);
+	sigprocmask(SIG_SETMASK, &mask, NULL);
+
+	do_sleep(5);
+	exit(0);
+}
+
+/*
+ *	OOPS: segmentation violation!
+ *	If we have the info, print where it occured.
+ *	Then sleep 30 seconds and try to continue.
+ */
+#if defined(STACK_DEBUG) && defined(__linux__)
+void segv_handler(int sig, struct sigcontext ctx)
+{
+	char	*p = "";
+	int	saved_errno = errno;
+
+	if ((void *)ctx.eip >= (void *)do_sleep &&
+	    (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_sleep(30);
+	errno = saved_errno;
+}
+#else
+void segv_handler()
+{
+	int	saved_errno = errno;
+
+	initlog(L_VB,
+		"PANIC: segmentation violation! sleeping for 30 seconds.");
+	coredump();
+	do_sleep(30);
+	errno = saved_errno;
+}
+#endif
+
+/*
+ *	The SIGSTOP & SIGTSTP handler
+ */
+void stop_handler()
+{
+	int	saved_errno = errno;
+
+	got_cont = 0;
+	while(!got_cont) pause();
+	got_cont = 0;
+	errno = saved_errno;
+}
+
+/*
+ *	Set terminal settings to reasonable defaults
+ */
+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;
+	}
+
+	(void) tcgetattr(fd, &tty);
+
+	tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD;
+	tty.c_cflag |= HUPCL|CLOCAL|CREAD;
+
+	tty.c_cc[VINTR]  = 3;	/* ctrl('c') */
+	tty.c_cc[VQUIT]  = 28;	/* ctrl('\\') */
+	tty.c_cc[VERASE] = 127;
+	tty.c_cc[VKILL]  = 24;	/* ctrl('x') */
+	tty.c_cc[VEOF]   = 4;	/* ctrl('d') */
+	tty.c_cc[VTIME]  = 0;
+	tty.c_cc[VMIN]   = 1;
+	tty.c_cc[VSTART] = 17;	/* ctrl('q') */
+	tty.c_cc[VSTOP]  = 19;	/* ctrl('s') */
+	tty.c_cc[VSUSP]  = 26;	/* ctrl('z') */
+
+	/*
+	 *	Set pre and post processing
+	 */
+	tty.c_iflag = IGNPAR|ICRNL|IXON|IXANY;
+	tty.c_oflag = OPOST|ONLCR;
+	tty.c_lflag = ISIG|ICANON|ECHO|ECHOCTL|ECHOPRT|ECHOKE;
+
+	/*
+	 *	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);
+}
+
+/*
+ *	Print to the system console
+ */
+void print(char *s)
+{
+	int fd;
+
+	if ((fd = console_open(O_WRONLY|O_NOCTTY|O_NDELAY)) >= 0) {
+		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");
+	}
+}
+
+
+/*
+ *	Build a new environment for execve().
+ */
+char **init_buildenv(int child)
+{
+	char		i_lvl[] = "RUNLEVEL=x";
+	char		i_prev[] = "PREVLEVEL=x";
+	char		i_cons[32];
+	char		**e;
+	int		n, i;
+
+	for (n = 0; environ[n]; n++)
+		;
+	n += NR_EXTRA_ENV + 8;
+	e = calloc(n, sizeof(char *));
+
+	for (n = 0; environ[n]; n++)
+		e[n] = istrdup(environ[n]);
+
+	for (i = 0; i < NR_EXTRA_ENV; i++)
+		if (extra_env[i])
+			e[n++] = istrdup(extra_env[i]);
+
+	if (child) {
+		snprintf(i_cons, sizeof(i_cons), "CONSOLE=%s", console_dev);
+		i_lvl[9]   = thislevel;
+		i_prev[10] = prevlevel;
+		e[n++] = istrdup(i_lvl);
+		e[n++] = istrdup(i_prev);
+		e[n++] = istrdup(i_cons);
+		e[n++] = istrdup(E_VERSION);
+	}
+
+	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.
+ *
+ */
+int spawn(CHILD *ch, int *res)
+{
+  char *args[16];		/* Argv array */
+  char buf[136];		/* Line buffer */
+  int f, st, rc;		/* 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);
+
+  		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) {
+			/*
+			 *	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 ((f = console_open(O_RDWR|O_NOCTTY)) >= 0) {
+				/* Take over controlling tty by force */
+				(void)ioctl(f, TIOCSCTTY, 1);
+  				dup(f);
+  				dup(f);
+			}
+			SETSIG(sa, SIGCHLD, SIG_DFL, SA_RESTART);
+			if ((pid = fork()) < 0) {
+  				initlog(L_VB, "cannot fork: %s",
+					strerror(errno));
+				exit(1);
+			}
+			if (pid > 0) {
+				/*
+				 *	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(f);
+				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(f, 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 {
+			setsid();
+			if ((f = console_open(O_RDWR|O_NOCTTY)) < 0) {
+				initlog(L_VB, "open(%s): %s", console_dev,
+					strerror(errno));
+				f = open("/dev/null", O_RDWR);
+			}
+			dup(f);
+			dup(f);
+		}
+
+  		/* 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]);
+  		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_sleep(5);
+		continue;
+	}
+	return(pid);
+  }
+}
+
+/*
+ *	Start a child running!
+ */
+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;
+		case KBREQUEST:
+		case BOOT:
+		case POWERFAIL:
+		case ONCE:
+			if (ch->flags & XECUTED) break;
+		case ONDEMAND:
+		case RESPAWN:
+  			ch->flags |= RUNNING;
+  			if (spawn(ch, &(ch->pid)) < 0) break;
+			/*
+			 *	Do NOT log if process field starts with '+'
+			 *	FIXME: that's for compatibility with *very*
+			 *	old getties - probably it can be taken out.
+			 */
+  			if (ch->process[0] != '+')
+				write_utmp_wtmp("", ch->id, ch->pid,
+					INIT_PROCESS, "");
+  			break;
+	}
+}
+
+
+/*
+ *	Read the inittab file.
+ */
+void read_inittab(void)
+{
+  FILE		*fp;			/* The INITTAB file */
+  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 = 0;		/* Ready yet? */
+
+#if DEBUG
+  if (newFamily != NULL) {
+	INITDBG(L_VB, "PANIC newFamily != NULL");
+	exit(1);
+  }
+  INITDBG(L_VB, "Reading inittab");
+#endif
+
+  /*
+   *	Open INITTAB and real line by line.
+   */
+  if ((fp = fopen(INITTAB, "r")) == NULL)
+	initlog(L_VB, "No inittab file found");
+
+  while(!done) {
+	/*
+	 *	Add single user shell entry at the end.
+	 */
+	if (fp == NULL || fgets(buf, sizeof(buf), fp) == NULL) {
+		done = 1;
+		/*
+		 *	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;
+	}
+	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");
+	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 < 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);
+
+  /*
+   *	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 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 the KILL signal");
+			kill(-(ch->pid), SIGKILL);
+			break;
+	}
+	talk = 0;
+	
+    }
+    /*
+     *	See if we have to wait 5 seconds
+     */
+    if (foundOne && round == 0) {
+	/*
+	 *	Yup, but check every second if we still have children.
+	 */
+	for(f = 0; f < sltime; 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_sleep(1);
+	}
+    }
+  }
+
+  /*
+   *	Now give all processes the chance to die and collect exit statuses.
+   */
+  if (foundOne) do_sleep(1);
+  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.
+ */
+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) {
+			/* FIXME: 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
+ */
+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)) {
+  		write(fd, prompt, sizeof(prompt) - 1);
+		buf[0] = 0;
+  		read(fd, buf, sizeof(buf));
+  		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.
+ */
+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.
+	 */
+	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.
+ */
+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) sltime = 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') 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. */
+	write_utmp_wtmp("runlevel", "~~", foo + 256*runlevel, RUN_LVL, "~");
+	thislevel = foo;
+	prevlevel = 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.
+ */
+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 */
+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.
+ */
+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
+ */
+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.
+ */
+int make_pipe(int fd)
+{
+	int fds[2];
+
+	pipe(fds);
+	dup2(fds[0], fd);
+	close(fds[0]);
+	fcntl(fds[1], F_SETFD, 1);
+	fcntl(fd, F_SETFD, 0);
+	write(fds[1], Signature, 8);
+
+	return fds[1];
+}
+
+/*
+ *	Attempt to re-exec.
+ */
+void 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
+	 */
+	fd = make_pipe(STATE_PIPE);
+
+	/* 
+	 * It's a backup day today, so I'm pissed off.  Being a BOFH, however, 
+	 * does have it's advantages...
+	 */
+	fail_cancel();
+	close(pipe_fd);
+	pipe_fd = -1;
+	DELSET(got_signals, SIGCHLD);
+	DELSET(got_signals, SIGHUP);
+	DELSET(got_signals, SIGUSR1);
+
+	/*
+	 *	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. 
+	 *	Bitch, close the state pipe, unblock signals and return.
+	 */
+	close(fd);
+	close(STATE_PIPE);
+	sigprocmask(SIG_SETMASK, &oldset, NULL);
+	init_freeenv(env);
+	initlog(L_CO, "Attempt to re-exec failed");
+}
+
+
+/*
+ *	We got a change runlevel request through the
+ *	init.fifo. Process it.
+ */
+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;
+			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]", 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.
+ */
+void initcmd_setenv(char *data, int size)
+{
+	char		*env, *p, *e, *eq;
+	int		i, sz;
+
+	e = data + size;
+
+	while (*data && data < e) {
+		eq = NULL;
+		for (p = data; *p && p < e; p++)
+			if (*p == '=') eq = p;
+		if (*p) break;
+		env = data;
+		data = ++p;
+
+		sz = eq ? (eq - env) : (p - env);
+
+		/*initlog(L_SY, "init_setenv: %s, %s, %d", env, eq, sz);*/
+
+		/*
+		 *	We only allow INIT_* to be set.
+		 */
+		if (strncmp(env, "INIT_", 5) != 0)
+			continue;
+
+		/* Free existing vars. */
+		for (i = 0; i < NR_EXTRA_ENV; i++) {
+			if (extra_env[i] == NULL) continue;
+			if (!strncmp(extra_env[i], env, sz) &&
+			    extra_env[i][sz] == '=') {
+				free(extra_env[i]);
+				extra_env[i] = NULL;
+			}
+		}
+
+		/* Set new vars if needed. */
+		if (eq == NULL) continue;
+		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.
+ *
+ *	FIXME:	this needs to be finished. NOT that it is buggy, but we need
+ *		to add the telnetd/rlogind stuff so people can start using it.
+ *		Maybe move to using an AF_UNIX socket so we can use
+ *		the 2.2 kernel credential stuff to see who we're talking to.
+ *	
+ */
+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 < 0) {
+	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:
+			sltime = request.sleeptime;
+			fifo_new_level(request.runlevel);
+			quit = 1;
+			break;
+		case INIT_CMD_POWERFAIL:
+			sltime = request.sleeptime;
+			do_power_fail('F');
+			quit = 1;
+			break;
+		case INIT_CMD_POWERFAILNOW:
+			sltime = request.sleeptime;
+			do_power_fail('L');
+			quit = 1;
+			break;
+		case INIT_CMD_POWEROK:
+			sltime = request.sleeptime;
+			do_power_fail('O');
+			quit = 1;
+			break;
+		case INIT_CMD_SETENV:
+			initcmd_setenv(request.i.data, sizeof(request.i.data));
+			break;
+		case INIT_CMD_CHANGECONS:
+			if (user_console) {
+				free(user_console);
+				user_console = NULL;
+			}
+			if (!request.i.bsd.reserved[0])
+				user_console = NULL;
+			else
+				user_console = strdup(request.i.bsd.reserved);
+			console_init();
+			quit = 1;
+			break;
+		default:
+			initlog(L_VB, "got unimplemented initrequest.");
+			break;
+	}
+  }
+
+  /*
+   *	We come here if the pipe couldn't be opened.
+   */
+  if (pipe_fd < 0) pause();
+
+}
+
+
+/*
+ *	This function is used in the transition
+ *	sysinit (-> single user) boot -> multi-user.
+ */
+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);
+		write_utmp_wtmp("runlevel", "~~", runlevel + 256 * oldlevel, RUN_LVL, "~");
+		thislevel = runlevel;
+		prevlevel = oldlevel;
+		setproctitle("init [%c]", runlevel);
+	}
+  }
+}
+
+/*
+ *	Init got hit by a signal. See which signal it is,
+ *	and act accordingly.
+ */
+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) {
+		c = 0;
+		read(fd, &c, 1);
+		pwrstat = c;
+		close(fd);
+		unlink(PWRSTAT);
+	}
+	do_power_fail(pwrstat);
+	DELSET(got_signals, SIGPWR);
+  }
+
+  if (ISMEMBER(got_signals, SIGINT)) {
+	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;
+			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]", runlevel);
+			DELSET(got_signals, SIGHUP);
+		}
+	}
+  }
+  if (ISMEMBER(got_signals, SIGUSR1)) {
+	/*
+	 *	SIGUSR1 means close and reopen /dev/initctl
+	 */
+	INITDBG(L_VB, "got SIGUSR1");
+	close(pipe_fd);
+	pipe_fd = -1;
+	DELSET(got_signals, SIGUSR1);
+  }
+}
+
+/*
+ *	The main loop
+ */ 
+int init_main()
+{
+  CHILD			*ch;
+  struct sigaction	sa;
+  sigset_t		sgt;
+  pid_t			rc;
+  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;
+		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, 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) {
+
+  	/* 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)
+	 */
+  	(void) close(open(UTMP_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0644));
+
+  	/*
+	 *	Say hello to the world
+	 */
+  	initlog(L_CO, bootmsg, "booting");
+
+  	/*
+	 *	See if we have to start an emergency shell.
+	 */
+	if (emerg_shell) {
+		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.
+ */
+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);
+}
+
+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':
+			sltime = 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  = env ? 0 : argv[optind][0];
+		request.sleeptime = sltime;
+	}
+
+	/* 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 &&
+	    write(fd, &request, sizeof(request)) == sizeof(request)) {
+		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], sltime);
+		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;
+	int			enforce = 0;
+
+	/* Get my own name */
+	if ((p = strrchr(argv[0], '/')) != NULL)
+  		p++;
+	else
+  		p = argv[0];
+	umask(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]",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 && !is_selinux_enabled()) {
+	  putenv("SELINUX_INIT=YES");
+	  if (selinux_init_load_policy(&enforce) == 0 ) {
+	    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(dfl_level);
+
+	/*NOTREACHED*/
+	return 0;
+}

Deleted: sysvinit-upstream/tags/2.87dsf/src/init.h
===================================================================
--- sysvinit-upstream/trunk/src/init.h	2009-07-10 21:51:19 UTC (rev 1428)
+++ sysvinit-upstream/tags/2.87dsf/src/init.h	2009-07-12 18:00:14 UTC (rev 1458)
@@ -1,123 +0,0 @@
-/*
- * init.h	Several defines and declarations to be
- *		included by all modules of the init program.
- *
- * Version:	@(#)init.h  2.85-5  02-Jul-2003  miquels at cistron.nl
- *
- */
-
-/* Standard configuration */
-#define CHANGE_WAIT 0			/* Change runlevel while
-					   waiting for a process to exit? */
-/* Debug and test modes */
-#define DEBUG	   0			/* Debug code off */
-#define INITDEBUG  0			/* Fork at startup to debug init. */
-
-/* Some constants */
-#define INITPID	   1			/* pid of first process */
-#define PIPE_FD    10			/* Fileno of initfifo. */
-#define STATE_PIPE 11			/* used to pass state through exec */
-
-/* Failsafe configuration */
-#define MAXSPAWN   10			/* Max times respawned in.. */
-#define TESTTIME   120			/* this much seconds */
-#define SLEEPTIME  300			/* Disable time */
-
-/* Default path inherited by every child. */
-#define PATH_DFL   "PATH=/bin:/usr/bin:/sbin:/usr/sbin"
-
-
-/* Prototypes. */
-void write_utmp_wtmp(char *user, char *id, int pid, int type, char *line);
-void write_wtmp(char *user, char *id, int pid, int type, char *line);
-#ifdef __GNUC__
-__attribute__ ((format (printf, 2, 3)))
-#endif
-void initlog(int loglevel, char *fmt, ...);
-void set_term(int how);
-void print(char *fmt);
-
-#if DEBUG
-#  define INITDBG(level, fmt, args...) initlog(level, fmt, ##args)
-#else
-#  define INITDBG(level, fmt, args...)
-#endif
-
-/* Actions to be taken by init */
-#define RESPAWN			1
-#define WAIT			2
-#define ONCE			3
-#define	BOOT			4
-#define BOOTWAIT		5
-#define POWERFAIL		6
-#define POWERWAIT		7
-#define POWEROKWAIT		8
-#define CTRLALTDEL		9
-#define OFF		       10
-#define	ONDEMAND	       11
-#define	INITDEFAULT	       12
-#define SYSINIT		       13
-#define POWERFAILNOW           14
-#define KBREQUEST               15
-
-/* Information about a process in the in-core inittab */
-typedef struct _child_ {
-  int flags;			/* Status of this entry */
-  int exstat;			/* Exit status of process */
-  int pid;			/* Pid of this process */
-  time_t tm;			/* When respawned last */
-  int count;			/* Times respawned in the last 2 minutes */
-  char id[8];			/* Inittab id (must be unique) */
-  char rlevel[12];		/* run levels */
-  int action;			/* what to do (see list below) */
-  char process[128];		/* The command line */
-  struct _child_ *new;		/* New entry (after inittab re-read) */
-  struct _child_ *next;		/* For the linked list */
-} CHILD;
-
-/* Values for the 'flags' field */
-#define RUNNING			2	/* Process is still running */
-#define KILLME			4	/* Kill this process */
-#define DEMAND			8	/* "runlevels" a b c */
-#define FAILING			16	/* process respawns rapidly */
-#define WAITING			32	/* We're waiting for this process */
-#define ZOMBIE			64	/* This process is already dead */
-#define XECUTED		128	/* Set if spawned once or more times */
-
-/* Log levels. */
-#define L_CO	1		/* Log on the console. */
-#define L_SY	2		/* Log with syslog() */
-#define L_VB	(L_CO|L_SY)	/* Log with both. */
-
-#ifndef NO_PROCESS
-#  define NO_PROCESS 0
-#endif
-
-/*
- *	Global variables.
- */
-extern CHILD *family;
-extern int wrote_wtmp_reboot;
-extern int wrote_utmp_reboot;
-
-/* Tokens in state parser */
-#define C_VER		1
-#define	C_END		2
-#define C_REC		3
-#define	C_EOR		4
-#define	C_LEV		5
-#define C_FLAG		6
-#define	C_ACTION	7
-#define C_PROCESS	8
-#define C_PID		9
-#define C_EXS	       10
-#define C_EOF          -1
-#define D_RUNLEVEL     -2
-#define D_THISLEVEL    -3
-#define D_PREVLEVEL    -4
-#define D_GOTSIGN      -5
-#define D_WROTE_WTMP_REBOOT -6
-#define D_WROTE_UTMP_REBOOT -7
-#define D_SLTIME       -8
-#define D_DIDBOOT      -9
-

Copied: sysvinit-upstream/tags/2.87dsf/src/init.h (from rev 1434, sysvinit-upstream/trunk/src/init.h)
===================================================================
--- sysvinit-upstream/tags/2.87dsf/src/init.h	                        (rev 0)
+++ sysvinit-upstream/tags/2.87dsf/src/init.h	2009-07-12 18:00:14 UTC (rev 1458)
@@ -0,0 +1,123 @@
+/*
+ * init.h	Several defines and declarations to be
+ *		included by all modules of the init program.
+ *
+ * Version:	@(#)init.h  2.85-5  02-Jul-2003  miquels at cistron.nl
+ *
+ */
+
+/* Standard configuration */
+#define CHANGE_WAIT 0			/* Change runlevel while
+					   waiting for a process to exit? */
+/* Debug and test modes */
+#define DEBUG	   0			/* Debug code off */
+#define INITDEBUG  0			/* Fork at startup to debug init. */
+
+/* Some constants */
+#define INITPID	   1			/* pid of first process */
+#define PIPE_FD    10			/* Fileno of initfifo. */
+#define STATE_PIPE 11			/* used to pass state through exec */
+
+/* Failsafe configuration */
+#define MAXSPAWN   10			/* Max times respawned in.. */
+#define TESTTIME   120			/* this much seconds */
+#define SLEEPTIME  300			/* Disable time */
+
+/* Default path inherited by every child. */
+#define PATH_DEFAULT   "/sbin:/usr/sbin:/bin:/usr/bin"
+
+
+/* Prototypes. */
+void write_utmp_wtmp(char *user, char *id, int pid, int type, char *line);
+void write_wtmp(char *user, char *id, int pid, int type, char *line);
+#ifdef __GNUC__
+__attribute__ ((format (printf, 2, 3)))
+#endif
+void initlog(int loglevel, char *fmt, ...);
+void set_term(int how);
+void print(char *fmt);
+
+#if DEBUG
+#  define INITDBG(level, fmt, args...) initlog(level, fmt, ##args)
+#else
+#  define INITDBG(level, fmt, args...)
+#endif
+
+/* Actions to be taken by init */
+#define RESPAWN			1
+#define WAIT			2
+#define ONCE			3
+#define	BOOT			4
+#define BOOTWAIT		5
+#define POWERFAIL		6
+#define POWERWAIT		7
+#define POWEROKWAIT		8
+#define CTRLALTDEL		9
+#define OFF		       10
+#define	ONDEMAND	       11
+#define	INITDEFAULT	       12
+#define SYSINIT		       13
+#define POWERFAILNOW           14
+#define KBREQUEST               15
+
+/* Information about a process in the in-core inittab */
+typedef struct _child_ {
+  int flags;			/* Status of this entry */
+  int exstat;			/* Exit status of process */
+  int pid;			/* Pid of this process */
+  time_t tm;			/* When respawned last */
+  int count;			/* Times respawned in the last 2 minutes */
+  char id[8];			/* Inittab id (must be unique) */
+  char rlevel[12];		/* run levels */
+  int action;			/* what to do (see list below) */
+  char process[128];		/* The command line */
+  struct _child_ *new;		/* New entry (after inittab re-read) */
+  struct _child_ *next;		/* For the linked list */
+} CHILD;
+
+/* Values for the 'flags' field */
+#define RUNNING			2	/* Process is still running */
+#define KILLME			4	/* Kill this process */
+#define DEMAND			8	/* "runlevels" a b c */
+#define FAILING			16	/* process respawns rapidly */
+#define WAITING			32	/* We're waiting for this process */
+#define ZOMBIE			64	/* This process is already dead */
+#define XECUTED		128	/* Set if spawned once or more times */
+
+/* Log levels. */
+#define L_CO	1		/* Log on the console. */
+#define L_SY	2		/* Log with syslog() */
+#define L_VB	(L_CO|L_SY)	/* Log with both. */
+
+#ifndef NO_PROCESS
+#  define NO_PROCESS 0
+#endif
+
+/*
+ *	Global variables.
+ */
+extern CHILD *family;
+extern int wrote_wtmp_reboot;
+extern int wrote_utmp_reboot;
+
+/* Tokens in state parser */
+#define C_VER		1
+#define	C_END		2
+#define C_REC		3
+#define	C_EOR		4
+#define	C_LEV		5
+#define C_FLAG		6
+#define	C_ACTION	7
+#define C_PROCESS	8
+#define C_PID		9
+#define C_EXS	       10
+#define C_EOF          -1
+#define D_RUNLEVEL     -2
+#define D_THISLEVEL    -3
+#define D_PREVLEVEL    -4
+#define D_GOTSIGN      -5
+#define D_WROTE_WTMP_REBOOT -6
+#define D_WROTE_UTMP_REBOOT -7
+#define D_SLTIME       -8
+#define D_DIDBOOT      -9
+

Deleted: sysvinit-upstream/tags/2.87dsf/src/killall5.c
===================================================================
--- sysvinit-upstream/trunk/src/killall5.c	2009-07-10 21:51:19 UTC (rev 1428)
+++ sysvinit-upstream/tags/2.87dsf/src/killall5.c	2009-07-12 18:00:14 UTC (rev 1458)
@@ -1,648 +0,0 @@
-/*
- * kilall5.c	Kill all processes except processes that have the
- *		same session id, so that the shell that called us
- *		won't be killed. Typically used in shutdown scripts.
- *
- * pidof.c	Tries to get the pid of the process[es] named.
- *
- * Version:	2.86 30-Jul-2004 MvS
- *
- * Usage:	killall5 [-][signal]
- *		pidof [-s] [-o omitpid [-o omitpid]] program [program..]
- *
- * Authors:	Miquel van Smoorenburg, miquels at cistron.nl
- *
- *		Riku Meskanen, <mesrik at jyu.fi>
- *		- return all running pids of given program name
- *		- single shot '-s' option for backwards combatibility
- *		- omit pid '-o' option and %PPID (parent pid metavariable)
- *		- syslog() only if not a connected to controlling terminal
- *		- swapped out programs pids are caught now
- *
- *		This file is part of the sysvinit suite,
- *		Copyright 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.
- */
-#include <sys/types.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <signal.h>
-#include <dirent.h>
-#include <syslog.h>
-#include <getopt.h>
-#include <stdarg.h>
-
-char *Version = "@(#)killall5 2.86 31-Jul-2004 miquels at cistron.nl";
-
-#define STATNAMELEN	15
-
-/* Info about a process. */
-typedef struct proc {
-	char *argv0;		/* Name as found out from argv[0] */
-	char *argv0base;	/* `basename argv[1]`		  */
-	char *argv1;		/* Name as found out from argv[1] */
-	char *argv1base;	/* `basename argv[1]`		  */
-	char *statname;		/* the statname without braces    */
-	ino_t ino;		/* Inode number			  */
-	dev_t dev;		/* Device it is on		  */
-	pid_t pid;		/* Process ID.			  */
-	int sid;		/* Session ID.			  */
-	int kernel;		/* Kernel thread or zombie.	  */
-	struct proc *next;	/* Pointer to next struct. 	  */
-} PROC;
-
-/* pid queue */
-
-typedef struct pidq {
-	PROC		*proc;
-	struct pidq	*next;
-} PIDQ;
-
-typedef struct {
-	PIDQ		*head;
-	PIDQ		*tail;
-	PIDQ		*next;
-} PIDQ_HEAD;
-
-/* List of processes. */
-PROC *plist;
-
-/* Did we stop all processes ? */
-int sent_sigstop;
-
-int scripts_too = 0;
-
-char *progname;	/* the name of the running program */
-#ifdef __GNUC__
-__attribute__ ((format (printf, 2, 3)))
-#endif
-void nsyslog(int pri, char *fmt, ...);
-
-/*
- *	Malloc space, barf if out of memory.
- */
-void *xmalloc(int bytes)
-{
-	void *p;
-
-	if ((p = malloc(bytes)) == NULL) {
-		if (sent_sigstop) kill(-1, SIGCONT);
-		nsyslog(LOG_ERR, "out of memory");
-		exit(1);
-	}
-	return p;
-}
-
-/*
- *	See if the proc filesystem is there. Mount if needed.
- */
-int mount_proc(void)
-{
-	struct stat	st;
-	char		*args[] = { "mount", "-t", "proc", "proc", "/proc", 0 };
-	pid_t		pid, rc;
-	int		wst;
-	int		did_mount = 0;
-
-	/* Stat /proc/version to see if /proc is mounted. */
-	if (stat("/proc/version", &st) < 0 && errno == ENOENT) {
-
-		/* It's not there, so mount it. */
-		if ((pid = fork()) < 0) {
-			nsyslog(LOG_ERR, "cannot fork");
-			exit(1);
-		}
-		if (pid == 0) {
-			/* Try a few mount binaries. */
-			execv("/sbin/mount", args);
-			execv("/bin/mount", args);
-
-			/* Okay, I give up. */
-			nsyslog(LOG_ERR, "cannot execute mount");
-			exit(1);
-		}
-		/* Wait for child. */
-		while ((rc = wait(&wst)) != pid)
-			if (rc < 0 && errno == ECHILD)
-				break;
-		if (rc != pid || WEXITSTATUS(wst) != 0)
-			nsyslog(LOG_ERR, "mount returned non-zero exit status");
-
-		did_mount = 1;
-	}
-
-	/* See if mount succeeded. */
-	if (stat("/proc/version", &st) < 0) {
-		if (errno == ENOENT)
-			nsyslog(LOG_ERR, "/proc not mounted, failed to mount.");
-		else
-			nsyslog(LOG_ERR, "/proc unavailable.");
-		exit(1);
-	}
-
-	return did_mount;
-}
-
-int readarg(FILE *fp, char *buf, int sz)
-{
-	int		c = 0, f = 0;
-
-	while (f < (sz-1) && (c = fgetc(fp)) != EOF && c)
-		buf[f++] = c;
-	buf[f] = 0;
-
-	return (c == EOF && f == 0) ? c : f;
-}
-
-/*
- *	Read the proc filesystem.
- */
-int readproc()
-{
-	DIR		*dir;
-	FILE		*fp;
-	PROC		*p, *n;
-	struct dirent	*d;
-	struct stat	st;
-	char		path[256];
-	char		buf[256];
-	char		*s, *q;
-	unsigned long	startcode, endcode;
-	int		pid, f;
-
-	/* Open the /proc directory. */
-	if ((dir = opendir("/proc")) == NULL) {
-		nsyslog(LOG_ERR, "cannot opendir(/proc)");
-		return -1;
-	}
-
-	/* Free the already existing process list. */
-	n = plist;
-	for (p = plist; n; p = n) {
-		n = p->next;
-		if (p->argv0) free(p->argv0);
-		if (p->argv1) free(p->argv1);
-		free(p);
-	}
-	plist = NULL;
-
-	/* Walk through the directory. */
-	while ((d = readdir(dir)) != NULL) {
-
-		/* See if this is a process */
-		if ((pid = atoi(d->d_name)) == 0) continue;
-
-		/* Get a PROC struct . */
-		p = (PROC *)xmalloc(sizeof(PROC));
-		memset(p, 0, sizeof(PROC));
-
-		/* Open the status file. */
-		snprintf(path, sizeof(path), "/proc/%s/stat", d->d_name);
-
-		/* Read SID & statname from it. */
- 		if ((fp = fopen(path, "r")) != NULL) {
-			buf[0] = 0;
-			fgets(buf, sizeof(buf), fp);
-
-			/* See if name starts with '(' */
-			s = buf;
-			while (*s != ' ') s++;
-			s++;
-			if (*s == '(') {
-				/* Read program name. */
-				q = strrchr(buf, ')');
-				if (q == NULL) {
-					p->sid = 0;
-					nsyslog(LOG_ERR,
-					"can't get program name from %s\n",
-						path);
-					free(p);
-					continue;
-				}
-				s++;
-			} else {
-				q = s;
-				while (*q != ' ') q++;
-			}
-			*q++ = 0;
-			while (*q == ' ') q++;
-			p->statname = (char *)xmalloc(strlen(s)+1);
-			strcpy(p->statname, s);
-
-			/* Get session, startcode, endcode. */
-			startcode = endcode = 0;
-			if (sscanf(q, 	"%*c %*d %*d %d %*d %*d %*u %*u "
-					"%*u %*u %*u %*u %*u %*d %*d "
-					"%*d %*d %*d %*d %*u %*u %*d "
-					"%*u %lu %lu",
-					&p->sid, &startcode, &endcode) != 3) {
-				p->sid = 0;
-				nsyslog(LOG_ERR, "can't read sid from %s\n",
-					path);
-				free(p);
-				continue;
-			}
-			if (startcode == 0 && endcode == 0)
-				p->kernel = 1;
-			fclose(fp);
-		} else {
-			/* Process disappeared.. */
-			free(p);
-			continue;
-		}
-
-		snprintf(path, sizeof(path), "/proc/%s/cmdline", d->d_name);
-		if ((fp = fopen(path, "r")) != NULL) {
-
-			/* Now read argv[0] */
-			f = readarg(fp, buf, sizeof(buf));
-
-			if (buf[0]) {
-				/* Store the name into malloced memory. */
-				p->argv0 = (char *)xmalloc(f + 1);
-				strcpy(p->argv0, buf);
-
-				/* Get a pointer to the basename. */
-				p->argv0base = strrchr(p->argv0, '/');
-				if (p->argv0base != NULL)
-					p->argv0base++;
-				else
-					p->argv0base = p->argv0;
-			}
-
-			/* And read argv[1] */
-			while ((f = readarg(fp, buf, sizeof(buf))) != EOF)
-				if (buf[0] != '-') break;
-
-			if (buf[0]) {
-				/* Store the name into malloced memory. */
-				p->argv1 = (char *)xmalloc(f + 1);
-				strcpy(p->argv1, buf);
-
-				/* Get a pointer to the basename. */
-				p->argv1base = strrchr(p->argv1, '/');
-				if (p->argv1base != NULL)
-					p->argv1base++;
-				else
-					p->argv1base = p->argv1;
-			}
-
-			fclose(fp);
-
-		} else {
-			/* Process disappeared.. */
-			free(p);
-			continue;
-		}
-
-		/* Try to stat the executable. */
-		snprintf(path, sizeof(path), "/proc/%s/exe", d->d_name);
-		if (stat(path, &st) == 0) {
-			p->dev = st.st_dev;
-			p->ino = st.st_ino;
-		}
-
-		/* Link it into the list. */
-		p->next = plist;
-		plist = p;
-		p->pid = pid;
-	}
-	closedir(dir);
-
-	/* Done. */
-	return 0;
-}
-
-PIDQ_HEAD *init_pid_q(PIDQ_HEAD *q)
-{
-	q->head =  q->next = q->tail = NULL;
-	return q;
-}
-
-int empty_q(PIDQ_HEAD *q)
-{
-	return (q->head == NULL);
-}
-
-int add_pid_to_q(PIDQ_HEAD *q, PROC *p)
-{
-	PIDQ *tmp;
-
-	tmp = (PIDQ *)xmalloc(sizeof(PIDQ));
-
-	tmp->proc = p;
-	tmp->next = NULL;
-
-	if (empty_q(q)) {
-		q->head = tmp;
-		q->tail  = tmp;
-	} else {
-		q->tail->next = tmp;
-		q->tail = tmp;
-	}
-	return 0;
-}
-
-PROC *get_next_from_pid_q(PIDQ_HEAD *q)
-{
-	PROC		*p;
-	PIDQ		*tmp = q->head;
-
-	if (!empty_q(q)) {
-		p = q->head->proc;
-		q->head = tmp->next;
-		free(tmp);
-		return p;
-	}
-
-	return NULL;
-}
-
-/* Try to get the process ID of a given process. */
-PIDQ_HEAD *pidof(char *prog)
-{
-	PROC		*p;
-	PIDQ_HEAD	*q;
-	struct stat	st;
-	char		*s;
-	int		dostat = 0;
-	int		foundone = 0;
-	int		ok = 0;
-
-	/* Try to stat the executable. */
-	if (prog[0] == '/' && stat(prog, &st) == 0) dostat++;
-
-	/* Get basename of program. */
-	if ((s = strrchr(prog, '/')) == NULL)
-		s = prog;
-	else
-		s++;
-
-	q = (PIDQ_HEAD *)xmalloc(sizeof(PIDQ_HEAD));
-	q = init_pid_q(q);
-
-	/* First try to find a match based on dev/ino pair. */
-	if (dostat) {
-		for (p = plist; p; p = p->next) {
-			if (p->dev == st.st_dev && p->ino == st.st_ino) {
-				add_pid_to_q(q, p);
-				foundone++;
-			}
-		}
-	}
-
-	/* If we didn't find a match based on dev/ino, try the name. */
-	if (!foundone) for (p = plist; p; p = p->next) {
-		ok = 0;
-
-		/* Compare name (both basename and full path) */
-		ok += (p->argv0 && strcmp(p->argv0, prog) == 0);
-		ok += (p->argv0 && strcmp(p->argv0base, s) == 0);
-
-		/* For scripts, compare argv[1] as well. */
-		if (scripts_too && p->argv1 &&
-		    !strncmp(p->statname, p->argv1base, STATNAMELEN)) {
-			ok += (strcmp(p->argv1, prog) == 0);
-			ok += (strcmp(p->argv1base, s) == 0);
-		}
-
-		/*
-		 *	if we have a space in argv0, process probably
-		 *	used setproctitle so try statname.
-		 */
-		if (strlen(s) <= STATNAMELEN &&
-		    (p->argv0 == NULL ||
-		     p->argv0[0] == 0 ||
-		     strchr(p->argv0, ' '))) {
-			ok += (strcmp(p->statname, s) == 0);
-		}
-		if (ok) add_pid_to_q(q, p);
-	}
-
-	 return q;
-}
-
-/* Give usage message and exit. */
-void usage(void)
-{
-	nsyslog(LOG_ERR, "only one argument, a signal number, allowed");
-	closelog();
-	exit(1);
-}
-
-/* write to syslog file if not open terminal */
-#ifdef __GNUC__
-__attribute__ ((format (printf, 2, 3)))
-#endif
-void nsyslog(int pri, char *fmt, ...)
-{
-	va_list  args;
-
-	va_start(args, fmt);
-
-	if (ttyname(0) == NULL) {
-		vsyslog(pri, fmt, args);
-	} else {
-		fprintf(stderr, "%s: ",progname);
-		vfprintf(stderr, fmt, args);
-		fprintf(stderr, "\n");
-	}
-
-	va_end(args);
-}
-
-#define PIDOF_SINGLE	0x01
-#define PIDOF_OMIT	0x02
-
-#define PIDOF_OMITSZ	5
-
-/*
- *	Pidof functionality.
- */
-int main_pidof(int argc, char **argv)
-{
-	PIDQ_HEAD	*q;
-	PROC		*p;
-	pid_t		opid[PIDOF_OMITSZ], spid;
-	int		f;
-	int		first = 1;
-	int		i, oind, opt, flags = 0;
-	int		chroot_check = 0;
-	struct stat	st;
-	char		tmp[512];
-
-	for (oind = PIDOF_OMITSZ-1; oind > 0; oind--)
-		opid[oind] = 0;
-	opterr = 0;
-
-	while ((opt = getopt(argc,argv,"hco:sx")) != EOF) switch (opt) {
-		case '?':
-			nsyslog(LOG_ERR,"invalid options on command line!\n");
-			closelog();
-			exit(1);
-		case 'c':
-			if (geteuid() == 0) chroot_check = 1;
-			break;
-		case 'o':
-			if (oind >= PIDOF_OMITSZ -1) {
-				nsyslog(LOG_ERR,"omit pid buffer size %d "
-					"exceeded!\n", PIDOF_OMITSZ);
-				closelog();
-				exit(1);
-			}
-			if (strcmp("%PPID",optarg) == 0)
-				opid[oind] = getppid();
-			else if ((opid[oind] = atoi(optarg)) < 1) {
-				nsyslog(LOG_ERR,
-					"illegal omit pid value (%s)!\n",
-					optarg);
-				closelog();
-				exit(1);
-			}
-			oind++;
-			flags |= PIDOF_OMIT;
-			break;
-		case 's':
-			flags |= PIDOF_SINGLE;
-			break;
-		case 'x':
-			scripts_too++;
-			break;
-		default:
-			/* Nothing */
-			break;
-	}
-	argc -= optind;
-	argv += optind;
-
-	/* Check if we are in a chroot */
-	if (chroot_check) {
-		snprintf(tmp, 512, "/proc/%d/root", getpid());
-		if (stat(tmp, &st) < 0) {
-			nsyslog(LOG_ERR, "stat failed for %s!\n", tmp);
-			closelog();
-			exit(1);
-		}
-	}
-
-	/* Print out process-ID's one by one. */
-	readproc();
-	for(f = 0; f < argc; f++) {
-		if ((q = pidof(argv[f])) != NULL) {
-			spid = 0;
-			while ((p = get_next_from_pid_q(q))) {
-				if (flags & PIDOF_OMIT) {
-					for (i = 0; i < oind; i++)
-						if (opid[i] == p->pid)
-							break;
-					/*
-					 *	On a match, continue with
-					 *	the for loop above.
-					 */
-					if (i < oind)
-						continue;
-				}
-				if (flags & PIDOF_SINGLE) {
-					if (spid)
-						continue;
-					else
-						spid = 1;
-				}
-				if (chroot_check) {
-					struct stat st2;
-					snprintf(tmp, 512, "/proc/%d/root",
-						 p->pid);
-					if (stat(tmp, &st2) < 0 ||
-					    st.st_dev != st2.st_dev ||
-					    st.st_ino != st2.st_ino) {
-						continue;
-					}
-				}
-				if (!first)
-					printf(" ");
-				printf("%d", p->pid);
-				first = 0;
-			}
-		}
-	}
-	printf("\n");
-	closelog();
-	return(first ? 1 : 0);
-}
-
-
-
-/* Main for either killall or pidof. */
-int main(int argc, char **argv)
-{
-	PROC		*p;
-	int		pid, sid = -1;
-	int		sig = SIGKILL;
-
-	/* Get program name. */
-	if ((progname = strrchr(argv[0], '/')) == NULL)
-		progname = argv[0];
-	else
-		progname++;
-
-	/* Now connect to syslog. */
-	openlog(progname, LOG_CONS|LOG_PID, LOG_DAEMON);
-
-	/* Were we called as 'pidof' ? */
-	if (strcmp(progname, "pidof") == 0)
-		return main_pidof(argc, argv);
-
-	/* Right, so we are "killall". */
-	if (argc > 1) {
-		if (argc != 2) usage();
-		if (argv[1][0] == '-') (argv[1])++;
-		if ((sig = atoi(argv[1])) <= 0 || sig > 31) usage();
-	}
-
-	/* First get the /proc filesystem online. */
-	mount_proc();
-
-	/*
-	 *	Ignoring SIGKILL and SIGSTOP do not make sense, but
-	 *	someday kill(-1, sig) might kill ourself if we don't
-	 *	do this. This certainly is a valid concern for SIGTERM-
-	 *	Linux 2.1 might send the calling process the signal too.
-	 */
-	signal(SIGTERM, SIG_IGN);
-	signal(SIGSTOP, SIG_IGN);
-	signal(SIGKILL, SIG_IGN);
-
-	/* Now stop all processes. */
-	kill(-1, SIGSTOP);
-	sent_sigstop = 1;
-
-	/* Read /proc filesystem */
-	if (readproc() < 0) {
-		kill(-1, SIGCONT);
-		exit(1);
-	}
-
-	/* Now kill all processes except our session. */
-	sid = (int)getsid(0);
-	pid = (int)getpid();
-	for (p = plist; p; p = p->next)
-		if (p->pid != pid && p->sid != sid && !p->kernel)
-			kill(p->pid, sig);
-
-	/* And let them continue. */
-	kill(-1, SIGCONT);
-
-	/* Done. */
-	closelog();
-
-	return 0;
-}

Copied: sysvinit-upstream/tags/2.87dsf/src/killall5.c (from rev 1450, sysvinit-upstream/trunk/src/killall5.c)
===================================================================
--- sysvinit-upstream/tags/2.87dsf/src/killall5.c	                        (rev 0)
+++ sysvinit-upstream/tags/2.87dsf/src/killall5.c	2009-07-12 18:00:14 UTC (rev 1458)
@@ -0,0 +1,732 @@
+/*
+ * kilall5.c	Kill all processes except processes that have the
+ *		same session id, so that the shell that called us
+ *		won't be killed. Typically used in shutdown scripts.
+ *
+ * pidof.c	Tries to get the pid of the process[es] named.
+ *
+ * Version:	2.86 30-Jul-2004 MvS
+ *
+ * Usage:	killall5 [-][signal]
+ *		pidof [-s] [-o omitpid [-o omitpid]] program [program..]
+ *
+ * Authors:	Miquel van Smoorenburg, miquels at cistron.nl
+ *
+ *		Riku Meskanen, <mesrik at jyu.fi>
+ *		- return all running pids of given program name
+ *		- single shot '-s' option for backwards combatibility
+ *		- omit pid '-o' option and %PPID (parent pid metavariable)
+ *		- syslog() only if not a connected to controlling terminal
+ *		- swapped out programs pids are caught now
+ *
+ *		This file is part of the sysvinit suite,
+ *		Copyright 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.
+ */
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <dirent.h>
+#include <syslog.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <sys/mman.h>
+
+char *Version = "@(#)killall5 2.86 31-Jul-2004 miquels at cistron.nl";
+
+#define STATNAMELEN	15
+#define DO_STAT 1
+#define NO_STAT 0
+
+/* Info about a process. */
+typedef struct proc {
+	char *argv0;		/* Name as found out from argv[0] */
+	char *argv0base;	/* `basename argv[1]`		  */
+	char *argv1;		/* Name as found out from argv[1] */
+	char *argv1base;	/* `basename argv[1]`		  */
+	char *statname;		/* the statname without braces    */
+	ino_t ino;		/* Inode number			  */
+	dev_t dev;		/* Device it is on		  */
+	pid_t pid;		/* Process ID.			  */
+	int sid;		/* Session ID.			  */
+	int kernel;		/* Kernel thread or zombie.	  */
+	struct proc *next;	/* Pointer to next struct. 	  */
+} PROC;
+
+/* pid queue */
+
+typedef struct pidq {
+	PROC		*proc;
+	struct pidq	*next;
+} PIDQ;
+
+typedef struct {
+	PIDQ		*head;
+	PIDQ		*tail;
+	PIDQ		*next;
+} PIDQ_HEAD;
+
+/* List of processes. */
+PROC *plist;
+
+/* Did we stop all processes ? */
+int sent_sigstop;
+
+int scripts_too = 0;
+
+char *progname;	/* the name of the running program */
+#ifdef __GNUC__
+__attribute__ ((format (printf, 2, 3)))
+#endif
+void nsyslog(int pri, char *fmt, ...);
+
+/*
+ *	Malloc space, barf if out of memory.
+ */
+void *xmalloc(int bytes)
+{
+	void *p;
+
+	if ((p = malloc(bytes)) == NULL) {
+		if (sent_sigstop) kill(-1, SIGCONT);
+		nsyslog(LOG_ERR, "out of memory");
+		exit(1);
+	}
+	return p;
+}
+
+/*
+ *	See if the proc filesystem is there. Mount if needed.
+ */
+int mount_proc(void)
+{
+	struct stat	st;
+	char		*args[] = { "mount", "-t", "proc", "proc", "/proc", 0 };
+	pid_t		pid, rc;
+	int		wst;
+	int		did_mount = 0;
+
+	/* Stat /proc/version to see if /proc is mounted. */
+	if (stat("/proc/version", &st) < 0 && errno == ENOENT) {
+
+		/* It's not there, so mount it. */
+		if ((pid = fork()) < 0) {
+			nsyslog(LOG_ERR, "cannot fork");
+			exit(1);
+		}
+		if (pid == 0) {
+			/* Try a few mount binaries. */
+			execv("/sbin/mount", args);
+			execv("/bin/mount", args);
+
+			/* Okay, I give up. */
+			nsyslog(LOG_ERR, "cannot execute mount");
+			exit(1);
+		}
+		/* Wait for child. */
+		while ((rc = wait(&wst)) != pid)
+			if (rc < 0 && errno == ECHILD)
+				break;
+		if (rc != pid || WEXITSTATUS(wst) != 0)
+			nsyslog(LOG_ERR, "mount returned non-zero exit status");
+
+		did_mount = 1;
+	}
+
+	/* See if mount succeeded. */
+	if (stat("/proc/version", &st) < 0) {
+		if (errno == ENOENT)
+			nsyslog(LOG_ERR, "/proc not mounted, failed to mount.");
+		else
+			nsyslog(LOG_ERR, "/proc unavailable.");
+		exit(1);
+	}
+
+	return did_mount;
+}
+
+int readarg(FILE *fp, char *buf, int sz)
+{
+	int		c = 0, f = 0;
+
+	while (f < (sz-1) && (c = fgetc(fp)) != EOF && c)
+		buf[f++] = c;
+	buf[f] = 0;
+
+	return (c == EOF && f == 0) ? c : f;
+}
+
+/*
+ *	Read the proc filesystem.
+ *	CWD must be /proc to avoid problems if / is affected by the killing (ie depend on fuse).
+ */
+int readproc(int do_stat)
+{
+	DIR		*dir;
+	FILE		*fp;
+	PROC		*p, *n;
+	struct dirent	*d;
+	struct stat	st;
+	char		path[256];
+	char		buf[256];
+	char		*s, *q;
+	unsigned long	startcode, endcode;
+	int		pid, f;
+
+	/* Open the /proc directory. */
+	if (chdir("/proc") == -1) {
+		nsyslog(LOG_ERR, "chdir /proc failed");
+		return -1;
+	}
+	if ((dir = opendir(".")) == NULL) {
+		nsyslog(LOG_ERR, "cannot opendir(/proc)");
+		return -1;
+	}
+
+	/* Free the already existing process list. */
+	n = plist;
+	for (p = plist; n; p = n) {
+		n = p->next;
+		if (p->argv0) free(p->argv0);
+		if (p->argv1) free(p->argv1);
+		free(p);
+	}
+	plist = NULL;
+
+	/* Walk through the directory. */
+	while ((d = readdir(dir)) != NULL) {
+
+		/* See if this is a process */
+		if ((pid = atoi(d->d_name)) == 0) continue;
+
+		/* Get a PROC struct . */
+		p = (PROC *)xmalloc(sizeof(PROC));
+		memset(p, 0, sizeof(PROC));
+
+		/* Open the status file. */
+		snprintf(path, sizeof(path), "%s/stat", d->d_name);
+
+		/* Read SID & statname from it. */
+		if ((fp = fopen(path, "r")) != NULL) {
+			buf[0] = 0;
+			fgets(buf, sizeof(buf), fp);
+
+			/* See if name starts with '(' */
+			s = buf;
+			while (*s != ' ') s++;
+			s++;
+			if (*s == '(') {
+				/* Read program name. */
+				q = strrchr(buf, ')');
+				if (q == NULL) {
+					p->sid = 0;
+					nsyslog(LOG_ERR,
+					"can't get program name from /proc/%s\n",
+						path);
+					free(p);
+					continue;
+				}
+				s++;
+			} else {
+				q = s;
+				while (*q != ' ') q++;
+			}
+			*q++ = 0;
+			while (*q == ' ') q++;
+			p->statname = (char *)xmalloc(strlen(s)+1);
+			strcpy(p->statname, s);
+
+			/* Get session, startcode, endcode. */
+			startcode = endcode = 0;
+			if (sscanf(q, 	"%*c %*d %*d %d %*d %*d %*u %*u "
+					"%*u %*u %*u %*u %*u %*d %*d "
+					"%*d %*d %*d %*d %*u %*u %*d "
+					"%*u %lu %lu",
+					&p->sid, &startcode, &endcode) != 3) {
+				p->sid = 0;
+				nsyslog(LOG_ERR, "can't read sid from %s\n",
+					path);
+				free(p);
+				continue;
+			}
+			if (startcode == 0 && endcode == 0)
+				p->kernel = 1;
+			fclose(fp);
+		} else {
+			/* Process disappeared.. */
+			free(p);
+			continue;
+		}
+
+		snprintf(path, sizeof(path), "%s/cmdline", d->d_name);
+		if ((fp = fopen(path, "r")) != NULL) {
+
+			/* Now read argv[0] */
+			f = readarg(fp, buf, sizeof(buf));
+
+			if (buf[0]) {
+				/* Store the name into malloced memory. */
+				p->argv0 = (char *)xmalloc(f + 1);
+				strcpy(p->argv0, buf);
+
+				/* Get a pointer to the basename. */
+				p->argv0base = strrchr(p->argv0, '/');
+				if (p->argv0base != NULL)
+					p->argv0base++;
+				else
+					p->argv0base = p->argv0;
+			}
+
+			/* And read argv[1] */
+			while ((f = readarg(fp, buf, sizeof(buf))) != EOF)
+				if (buf[0] != '-') break;
+
+			if (buf[0]) {
+				/* Store the name into malloced memory. */
+				p->argv1 = (char *)xmalloc(f + 1);
+				strcpy(p->argv1, buf);
+
+				/* Get a pointer to the basename. */
+				p->argv1base = strrchr(p->argv1, '/');
+				if (p->argv1base != NULL)
+					p->argv1base++;
+				else
+					p->argv1base = p->argv1;
+			}
+
+			fclose(fp);
+
+		} else {
+			/* Process disappeared.. */
+			free(p);
+			continue;
+		}
+
+		/* Try to stat the executable. */
+		snprintf(path, sizeof(path), "/proc/%s/exe", d->d_name);
+		if (do_stat && stat(path, &st) == 0) {
+			p->dev = st.st_dev;
+			p->ino = st.st_ino;
+		}
+
+		/* Link it into the list. */
+		p->next = plist;
+		plist = p;
+		p->pid = pid;
+	}
+	closedir(dir);
+
+	/* Done. */
+	return 0;
+}
+
+PIDQ_HEAD *init_pid_q(PIDQ_HEAD *q)
+{
+	q->head =  q->next = q->tail = NULL;
+	return q;
+}
+
+int empty_q(PIDQ_HEAD *q)
+{
+	return (q->head == NULL);
+}
+
+int add_pid_to_q(PIDQ_HEAD *q, PROC *p)
+{
+	PIDQ *tmp;
+
+	tmp = (PIDQ *)xmalloc(sizeof(PIDQ));
+
+	tmp->proc = p;
+	tmp->next = NULL;
+
+	if (empty_q(q)) {
+		q->head = tmp;
+		q->tail  = tmp;
+	} else {
+		q->tail->next = tmp;
+		q->tail = tmp;
+	}
+	return 0;
+}
+
+PROC *get_next_from_pid_q(PIDQ_HEAD *q)
+{
+	PROC		*p;
+	PIDQ		*tmp = q->head;
+
+	if (!empty_q(q)) {
+		p = q->head->proc;
+		q->head = tmp->next;
+		free(tmp);
+		return p;
+	}
+
+	return NULL;
+}
+
+/* Try to get the process ID of a given process. */
+PIDQ_HEAD *pidof(char *prog)
+{
+	PROC		*p;
+	PIDQ_HEAD	*q;
+	struct stat	st;
+	char		*s;
+	int		dostat = 0;
+	int		foundone = 0;
+	int		ok = 0;
+
+	if (! prog)
+		return NULL;
+
+	/* Get basename of program. */
+	if ((s = strrchr(prog, '/')) == NULL)
+		s = prog;
+	else
+		s++;
+
+	if (! *s)
+		return NULL;
+
+	q = (PIDQ_HEAD *)xmalloc(sizeof(PIDQ_HEAD));
+	q = init_pid_q(q);
+
+	/* Try to stat the executable. */
+	if (prog[0] == '/' && stat(prog, &st) == 0)
+		dostat++;
+
+	/* First try to find a match based on dev/ino pair. */
+	if (dostat) {
+		for (p = plist; p; p = p->next) {
+			if (p->dev == st.st_dev && p->ino == st.st_ino) {
+				add_pid_to_q(q, p);
+				foundone++;
+			}
+		}
+	}
+
+	/* If we didn't find a match based on dev/ino, try the name. */
+	if (!foundone) for (p = plist; p; p = p->next) {
+		ok = 0;
+
+		/*             matching        nonmatching
+		 * proc name   prog name       prog name
+		 * ---         -----------     ------------
+		 *   b         b, p/b, q/b
+		 * p/b         b, p/b          q/b
+		 *
+		 * Algorithm: Match if:
+		 *    cmd = arg
+		 * or cmd = base(arg)
+		 * or base(cmd) = arg
+		 *
+		 * Specifically, do not match just because base(cmd) = base(arg)
+		 * as was done in earlier versions of this program, since this
+		 * allows /aaa/foo to match /bbb/foo .
+		 */
+		ok |=
+			(p->argv0 && strcmp(p->argv0, prog) == 0)
+			|| (p->argv0 && s != prog && strcmp(p->argv0, s) == 0)
+			|| (p->argv0base && strcmp(p->argv0base, prog) == 0);
+
+		/* For scripts, compare argv[1] as well. */
+		if (
+			scripts_too && p->statname && p->argv1base
+			&& !strncmp(p->statname, p->argv1base, STATNAMELEN)
+		) {
+			ok |=
+				(p->argv1 && strcmp(p->argv1, prog) == 0)
+				|| (p->argv1 && s != prog && strcmp(p->argv1, s) == 0)
+				|| (p->argv1base && strcmp(p->argv1base, prog) == 0);
+		}
+
+		/*
+		 *	if we have a space in argv0, process probably
+		 *	used setproctitle so try statname.
+		 */
+		if (strlen(s) <= STATNAMELEN &&
+		    (p->argv0 == NULL ||
+		     p->argv0[0] == 0 ||
+		     strchr(p->argv0, ' '))) {
+			ok |= (strcmp(p->statname, s) == 0);
+		}
+		if (ok) add_pid_to_q(q, p);
+	}
+
+	 return q;
+}
+
+/* Give usage message and exit. */
+void usage(void)
+{
+	nsyslog(LOG_ERR, "only one argument, a signal number, allowed");
+	closelog();
+	exit(1);
+}
+
+/* write to syslog file if not open terminal */
+#ifdef __GNUC__
+__attribute__ ((format (printf, 2, 3)))
+#endif
+void nsyslog(int pri, char *fmt, ...)
+{
+	va_list  args;
+
+	va_start(args, fmt);
+
+	if (ttyname(0) == NULL) {
+		vsyslog(pri, fmt, args);
+	} else {
+		fprintf(stderr, "%s: ",progname);
+		vfprintf(stderr, fmt, args);
+		fprintf(stderr, "\n");
+	}
+
+	va_end(args);
+}
+
+#define PIDOF_SINGLE	0x01
+#define PIDOF_OMIT	0x02
+
+#define PIDOF_OMITSZ	5
+
+/*
+ *	Pidof functionality.
+ */
+int main_pidof(int argc, char **argv)
+{
+	PIDQ_HEAD	*q;
+	PROC		*p;
+	pid_t		opid[PIDOF_OMITSZ], spid;
+	int		f;
+	int		first = 1;
+	int		i, oind, opt, flags = 0;
+	int		chroot_check = 0;
+	struct stat	st;
+	char		tmp[512];
+
+	for (oind = PIDOF_OMITSZ-1; oind > 0; oind--)
+		opid[oind] = 0;
+	opterr = 0;
+
+	while ((opt = getopt(argc,argv,"hco:sx")) != EOF) switch (opt) {
+		case '?':
+			nsyslog(LOG_ERR,"invalid options on command line!\n");
+			closelog();
+			exit(1);
+		case 'c':
+			if (geteuid() == 0) chroot_check = 1;
+			break;
+		case 'o':
+			if (oind >= PIDOF_OMITSZ -1) {
+				nsyslog(LOG_ERR,"omit pid buffer size %d "
+					"exceeded!\n", PIDOF_OMITSZ);
+				closelog();
+				exit(1);
+			}
+			if (strcmp("%PPID",optarg) == 0)
+				opid[oind] = getppid();
+			else if ((opid[oind] = atoi(optarg)) < 1) {
+				nsyslog(LOG_ERR,
+					"illegal omit pid value (%s)!\n",
+					optarg);
+				closelog();
+				exit(1);
+			}
+			oind++;
+			flags |= PIDOF_OMIT;
+			break;
+		case 's':
+			flags |= PIDOF_SINGLE;
+			break;
+		case 'x':
+			scripts_too++;
+			break;
+		default:
+			/* Nothing */
+			break;
+	}
+	argc -= optind;
+	argv += optind;
+
+	/* Check if we are in a chroot */
+	if (chroot_check) {
+		snprintf(tmp, 512, "/proc/%d/root", getpid());
+		if (stat(tmp, &st) < 0) {
+			nsyslog(LOG_ERR, "stat failed for %s!\n", tmp);
+			closelog();
+			exit(1);
+		}
+	}
+
+	/* Print out process-ID's one by one. */
+	readproc(DO_STAT);
+	for(f = 0; f < argc; f++) {
+		if ((q = pidof(argv[f])) != NULL) {
+			spid = 0;
+			while ((p = get_next_from_pid_q(q))) {
+				if (flags & PIDOF_OMIT) {
+					for (i = 0; i < oind; i++)
+						if (opid[i] == p->pid)
+							break;
+					/*
+					 *	On a match, continue with
+					 *	the for loop above.
+					 */
+					if (i < oind)
+						continue;
+				}
+				if (flags & PIDOF_SINGLE) {
+					if (spid)
+						continue;
+					else
+						spid = 1;
+				}
+				if (chroot_check) {
+					struct stat st2;
+					snprintf(tmp, 512, "/proc/%d/root",
+						 p->pid);
+					if (stat(tmp, &st2) < 0 ||
+					    st.st_dev != st2.st_dev ||
+					    st.st_ino != st2.st_ino) {
+						continue;
+					}
+				}
+				if (!first)
+					printf(" ");
+				printf("%d", p->pid);
+				first = 0;
+			}
+		}
+	}
+	if (!first)
+		printf("\n");
+	closelog();
+	return(first ? 1 : 0);
+}
+
+
+
+#define KILLALL_OMITSZ	16
+
+/* Main for either killall or pidof. */
+int main(int argc, char **argv)
+{
+	PROC		*p;
+	int		pid, sid = -1;
+	pid_t		opid[KILLALL_OMITSZ];
+	int		i, oind, omit = 0;
+	int		sig = SIGKILL;
+
+	/* return non-zero if no process was killed */
+	int		retval = 2;
+
+	/* Get program name. */
+	if ((progname = strrchr(argv[0], '/')) == NULL)
+		progname = argv[0];
+	else
+		progname++;
+
+	/* Now connect to syslog. */
+	openlog(progname, LOG_CONS|LOG_PID, LOG_DAEMON);
+
+	/* Were we called as 'pidof' ? */
+	if (strcmp(progname, "pidof") == 0)
+		return main_pidof(argc, argv);
+
+	/* Right, so we are "killall". */
+	for (oind = KILLALL_OMITSZ-1; oind > 0; oind--)
+		opid[oind] = 0;
+
+	if (argc > 1) {
+		for (i = 1; i < argc; i++) {
+			if (argv[i][0] == '-') (argv[i])++;
+			if (argv[i][0] == 'o') {
+				if (++i >= argc) usage();
+				if (oind >= KILLALL_OMITSZ -1) {
+					nsyslog(LOG_ERR,"omit pid buffer size "
+						"%d exceeded!\n",
+						KILLALL_OMITSZ);
+					closelog();
+					exit(1);
+				}
+				if ((opid[oind] = atoi(argv[i])) < 1) {
+					nsyslog(LOG_ERR,
+						"illegal omit pid value "
+						"(%s)!\n", argv[i]);
+					closelog();
+					exit(1);
+				}
+				oind++;
+				omit = 1;
+			}
+			else if ((sig = atoi(argv[1])) <= 0 || sig > 31)
+				usage();
+		}
+	}
+
+	/* First get the /proc filesystem online. */
+	mount_proc();
+
+	/*
+	 *	Ignoring SIGKILL and SIGSTOP do not make sense, but
+	 *	someday kill(-1, sig) might kill ourself if we don't
+	 *	do this. This certainly is a valid concern for SIGTERM-
+	 *	Linux 2.1 might send the calling process the signal too.
+	 */
+	signal(SIGTERM, SIG_IGN);
+	signal(SIGSTOP, SIG_IGN);
+	signal(SIGKILL, SIG_IGN);
+
+	/* lock us into memory */
+	mlockall(MCL_CURRENT | MCL_FUTURE);
+
+	/* Now stop all processes. */
+	kill(-1, SIGSTOP);
+	sent_sigstop = 1;
+
+	/* Read /proc filesystem */
+	if (readproc(NO_STAT) < 0) {
+		kill(-1, SIGCONT);
+		return(1);
+	}
+
+	/* Now kill all processes except init (pid 1) and our session. */
+	sid = (int)getsid(0);
+	pid = (int)getpid();
+	for (p = plist; p; p = p->next) {
+		if (p->pid == 1 || p->pid == pid || p->sid == sid || p->kernel)
+			continue;
+		if (omit) {
+			for (i = 0; i < oind; i++)
+				if (opid[i] == p->pid)
+					break;
+			/* On a match, continue with the for loop above. */
+			if (i < oind)
+				continue;
+		}
+		kill(p->pid, sig);
+		retval = 0;
+	}
+
+	/* And let them continue. */
+	kill(-1, SIGCONT);
+
+	/* Done. */
+	closelog();
+
+	/* Force the kernel to run the scheduler */
+	usleep(1);
+
+	return retval;
+}

Deleted: sysvinit-upstream/tags/2.87dsf/src/last.c
===================================================================
--- sysvinit-upstream/trunk/src/last.c	2009-07-10 21:51:19 UTC (rev 1428)
+++ sysvinit-upstream/tags/2.87dsf/src/last.c	2009-07-12 18:00:14 UTC (rev 1458)
@@ -1,900 +0,0 @@
-/*
- * last.c	Re-implementation of the 'last' command, this time
- *		for Linux. Yes I know there is BSD last, but I
- *		just felt like writing this. No thanks :-).
- *		Also, this version gives lots more info (especially with -x)
- *
- * Author:	Miquel van Smoorenburg, miquels at cistron.nl
- *
- * Version:	@(#)last  2.85  30-Jul-2004  miquels at cistron.nl
- *
- *		This file is part of the sysvinit suite,
- *		Copyright 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.
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/fcntl.h>
-#include <time.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <utmp.h>
-#include <errno.h>
-#include <malloc.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <signal.h>
-#include <getopt.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <arpa/inet.h>
-#include "oldutmp.h"
-
-#ifndef SHUTDOWN_TIME
-#  define SHUTDOWN_TIME 254
-#endif
-
-char *Version = "@(#) last 2.85 31-Apr-2004 miquels";
-
-#define CHOP_DOMAIN	0	/* Define to chop off local domainname. */
-#define NEW_UTMP	1	/* Fancy & fast utmp read code. */
-#define UCHUNKSIZE	16384	/* How much we read at once. */
-
-/* Double linked list of struct utmp's */
-struct utmplist {
-  struct utmp ut;
-  struct utmplist *next;
-  struct utmplist *prev;
-};
-struct utmplist *utmplist = NULL;
-
-/* Types of listing */
-#define R_CRASH		1 /* No logout record, system boot in between */
-#define R_DOWN		2 /* System brought down in decent way */
-#define R_NORMAL	3 /* Normal */
-#define R_NOW		4 /* Still logged in */
-#define R_REBOOT	5 /* Reboot record. */
-#define R_PHANTOM	6 /* No logout record but session is stale. */
-#define R_TIMECHANGE	7 /* NEW_TIME or OLD_TIME */
-
-/* Global variables */
-int maxrecs = 0;	/* Maximum number of records to list. */
-int recsdone = 0;	/* Number of records listed */
-int showhost = 1;	/* Show hostname too? */
-int altlist = 0;	/* Show hostname at the end. */
-int usedns = 0;		/* Use DNS to lookup the hostname. */
-int useip = 0;		/* Print IP address in number format */
-int fulltime = 0;	/* Print full dates and times */
-int oldfmt = 0;		/* Use old libc5 format? */
-char **show = NULL;	/* What do they want us to show */
-char *ufile;		/* Filename of this file */
-time_t lastdate;	/* Last date we've seen */
-char *progname;		/* Name of this program */
-#if CHOP_DOMAIN
-char hostname[256];	/* For gethostbyname() */
-char *domainname;	/* Our domainname. */
-#endif
-
-/*
- *	Convert old utmp format to new.
- */
-void uconv(struct oldutmp *oldut, struct utmp *utn)
-{
-	memset(utn, 0, sizeof(struct utmp));
-	utn->ut_type = oldut->ut_type;
-	utn->ut_pid  = oldut->ut_pid;
-	utn->ut_time = oldut->ut_oldtime;
-	utn->ut_addr = oldut->ut_oldaddr;
-	strncpy(utn->ut_line, oldut->ut_line, OLD_LINESIZE);
-	strncpy(utn->ut_user, oldut->ut_user, OLD_NAMESIZE);
-	strncpy(utn->ut_host, oldut->ut_host, OLD_HOSTSIZE);
-}
-
-#if NEW_UTMP
-/*
- *	Read one utmp entry, return in new format.
- *	Automatically reposition file pointer.
- */
-int uread(FILE *fp, struct utmp *u, int *quit)
-{
-	static int utsize;
-	static char buf[UCHUNKSIZE];
-	char tmp[1024];
-	static off_t fpos;
-	static int bpos;
-	struct oldutmp uto;
-	int r;
-	off_t o;
-
-	if (quit == NULL && u != NULL) {
-		/*
-		 *	Normal read.
-		 */
-		if (oldfmt) {
-			r = fread(&uto, sizeof(uto), 1, fp);
-			uconv(&uto, u);
-		} else
-			r = fread(u, sizeof(struct utmp), 1, fp);
-		return r;
-	}
-
-	if (u == NULL) {
-		/*
-		 *	Initialize and position.
-		 */
-		utsize = oldfmt ? sizeof(uto) : sizeof(struct utmp);
-		fseeko(fp, 0, SEEK_END);
-		fpos = ftello(fp);
-		if (fpos == 0)
-			return 0;
-		o = ((fpos - 1) / UCHUNKSIZE) * UCHUNKSIZE;
-		if (fseeko(fp, o, SEEK_SET) < 0) {
-			fprintf(stderr, "%s: seek failed!\n", progname);
-			return 0;
-		}
-		bpos = (int)(fpos - o);
-		if (fread(buf, bpos, 1, fp) != 1) {
-			fprintf(stderr, "%s: read failed!\n", progname);
-			return 0;
-		}
-		fpos = o;
-		return 1;
-	}
-
-	/*
-	 *	Read one struct. From the buffer if possible.
-	 */
-	bpos -= utsize;
-	if (bpos >= 0) {
-		if (oldfmt)
-			uconv((struct oldutmp *)(buf + bpos), u);
-		else
-			memcpy(u, buf + bpos, sizeof(struct utmp));
-		return 1;
-	}
-
-	/*
-	 *	Oops we went "below" the buffer. We should be able to
-	 *	seek back UCHUNKSIZE bytes.
-	 */
-	fpos -= UCHUNKSIZE;
-	if (fpos < 0)
-		return 0;
-
-	/*
-	 *	Copy whatever is left in the buffer.
-	 */
-	memcpy(tmp + (-bpos), buf, utsize + bpos);
-	if (fseeko(fp, fpos, SEEK_SET) < 0) {
-		perror("fseek");
-		return 0;
-	}
-
-	/*
-	 *	Read another UCHUNKSIZE bytes.
-	 */
-	if (fread(buf, UCHUNKSIZE, 1, fp) != 1) {
-		perror("fread");
-		return 0;
-	}
-
-	/*
-	 *	The end of the UCHUNKSIZE byte buffer should be the first
-	 *	few bytes of the current struct utmp.
-	 */
-	memcpy(tmp, buf + UCHUNKSIZE + bpos, -bpos);
-	bpos += UCHUNKSIZE;
-
-	if (oldfmt)
-		uconv((struct oldutmp *)tmp, u);
-	else
-		memcpy(u, tmp, sizeof(struct utmp));
-
-	return 1;
-}
-
-#else /* NEW_UTMP */
-
-/*
- *	Read one utmp entry, return in new format.
- *	Automatically reposition file pointer.
- */
-int uread(FILE *fp, struct utmp *u, int *quit)
-{
-	struct oldutmp uto;
-	off_t r;
-
-	if (u == NULL) {
-		r = oldfmt ? sizeof(struct oldutmp) : sizeof(struct utmp);
-		fseek(fp, -1 * r, SEEK_END);
-		return 1;
-	}
-
-	if (!oldfmt) {
-		r = fread(u, sizeof(struct utmp), 1, fp);
-		if (r == 1) {
-			if (fseeko(fp, -2 * sizeof(struct utmp), SEEK_CUR) < 0)
-				if (quit) *quit = 1;
-		}
-		return r;
-	}
-	r = fread(&uto, sizeof(struct oldutmp), 1, fp);
-	if (r == 1) {
-		if (fseeko(fp, -2 * sizeof(struct oldutmp), SEEK_CUR) < 0)
-			if (quit) *quit = 1;
-		uconv(&uto, u);
-	}
-
-	return r;
-}
-#endif
-
-/*
- *	Try to be smart about the location of the BTMP file
- */
-#ifndef BTMP_FILE
-#define BTMP_FILE getbtmp()
-char *getbtmp()
-{
-	static char btmp[128];
-	char *p;
-
-	strcpy(btmp, WTMP_FILE);
-	if ((p = strrchr(btmp, '/')) == NULL)
-		p = btmp;
-	else
-		p++;
-	*p = 0;
-	strcat(btmp, "btmp");
-	return btmp;
-}
-#endif
-
-/*
- *	Print a short date.
- */
-char *showdate()
-{
-	char *s = ctime(&lastdate);
-	s[16] = 0;
-	return s;
-}
-
-/*
- *	SIGINT handler
- */
-void int_handler()
-{
-	printf("Interrupted %s\n", showdate());
-	exit(1);
-}
-
-/*
- *	SIGQUIT handler
- */
-void quit_handler()
-{
-	printf("Interrupted %s\n", showdate());
-	signal(SIGQUIT, quit_handler);
-}
-
-/*
- *	Get the basename of a filename
- */
-char *mybasename(char *s)
-{
-	char *p;
-
-	if ((p = strrchr(s, '/')) != NULL)
-		p++;
-	else
-		p = s;
-	return p;
-}
-
-/*
- *	Lookup a host with DNS.
- */
-int dns_lookup(char *result, int size, int useip, int32_t *a)
-{
-	struct sockaddr_in	sin;
-	struct sockaddr_in6	sin6;
-	struct sockaddr		*sa;
-	int			salen, flags;
-	unsigned int		topnibble;
-	unsigned int		azero = 0, sitelocal = 0;
-	int			mapped = 0;
-
-	flags = useip ? NI_NUMERICHOST : 0;
-
-	/*
-	 *	IPv4 or IPv6 ? We use 2 heuristics:
-	 *	1. Current IPv6 range uses 2000-3fff or fec0-feff.
-	 *	   Outside of that is illegal and must be IPv4.
-	 *	2. If last 3 bytes are 0, must be IPv4
-	 *	3. If IPv6 in IPv4, handle as IPv4
-	 *
-	 *	Ugly.
-	 */
-	if (a[0] == 0 && a[1] == 0 && a[2] == htonl (0xffff))
-		mapped = 1;
-	topnibble = ntohl((unsigned int)a[0]) >> 28;
-
-	azero = ntohl((unsigned int)a[0]) >> 16;
-	sitelocal = (azero >= 0xfec0 && azero <= 0xfeff) ? 1 : 0;
-	
-	if (((topnibble < 2 || topnibble > 3) && (!sitelocal)) || mapped ||
-	    (a[1] == 0 && a[2] == 0 && a[3] == 0)) {
-		/* IPv4 */
-		sin.sin_family = AF_INET;
-		sin.sin_port = 0;
-		sin.sin_addr.s_addr = mapped ? a[3] : a[0];
-		sa = (struct sockaddr *)&sin;
-		salen = sizeof(sin);
-	} else {
-		/* IPv6 */
-		memset(&sin6, 0, sizeof(sin6));
-		sin6.sin6_family = AF_INET6;
-		sin6.sin6_port = 0;
-		memcpy(sin6.sin6_addr.s6_addr, a, 16);
-		sa = (struct sockaddr *)&sin6;
-		salen = sizeof(sin6);
-	}
-
-	return getnameinfo(sa, salen, result, size, NULL, 0, flags);
-}
-
-/*
- *	Show one line of information on screen
- */
-int list(struct utmp *p, time_t t, int what)
-{
-	time_t		secs, tmp;
-	char		logintime[32];
-	char		logouttime[32];
-	char		length[32];
-	char		final[128];
-	char		utline[UT_LINESIZE+1];
-	char		domain[256];
-	char		*s, **walk;
-	int		mins, hours, days;
-	int		r, len;
-
-	/*
-	 *	uucp and ftp have special-type entries
-	 */
-	utline[0] = 0;
-	strncat(utline, p->ut_line, UT_LINESIZE);
-	if (strncmp(utline, "ftp", 3) == 0 && isdigit(utline[3]))
-		utline[3] = 0;
-	if (strncmp(utline, "uucp", 4) == 0 && isdigit(utline[4]))
-		utline[4] = 0;
-
-	/*
-	 *	Is this something we wanna show?
-	 */
-	if (show) {
-		for (walk = show; *walk; walk++) {
-			if (strncmp(p->ut_name, *walk, UT_NAMESIZE) == 0 ||
-			    strcmp(utline, *walk) == 0 ||
-			    (strncmp(utline, "tty", 3) == 0 &&
-			     strcmp(utline + 3, *walk) == 0)) break;
-		}
-		if (*walk == NULL) return 0;
-	}
-
-	/*
-	 *	Calculate times
-	 */
-	tmp = (time_t)p->ut_time;
-	strcpy(logintime, ctime(&tmp));
-	if (fulltime)
-		sprintf(logouttime, "- %s", ctime(&t));
-	else {
-		logintime[16] = 0;
-		sprintf(logouttime, "- %s", ctime(&t) + 11);
-		logouttime[7] = 0;
-	}
-	secs = t - p->ut_time;
-	mins  = (secs / 60) % 60;
-	hours = (secs / 3600) % 24;
-	days  = secs / 86400;
-	if (days)
-		sprintf(length, "(%d+%02d:%02d)", days, hours, mins);
-	else
-		sprintf(length, " (%02d:%02d)", hours, mins);
-
-	switch(what) {
-		case R_CRASH:
-			sprintf(logouttime, "- crash");
-			break;
-		case R_DOWN:
-			sprintf(logouttime, "- down ");
-			break;
-		case R_NOW:
-			length[0] = 0;
-			if (fulltime)
-				sprintf(logouttime, "  still logged in");
-			else {
-				sprintf(logouttime, "  still");
-				sprintf(length, "logged in");
-			}
-			break;
-		case R_PHANTOM:
-			length[0] = 0;
-			if (fulltime)
-				sprintf(logouttime, "  gone - no logout");
-			else {
-				sprintf(logouttime, "   gone");
-				sprintf(length, "- no logout");
-			}
-			break;
-		case R_REBOOT:
-			break;
-		case R_TIMECHANGE:
-			logouttime[0] = 0;
-			length[0] = 0;
-			break;
-		case R_NORMAL:
-			break;
- 	}
-
-	/*
-	 *	Look up host with DNS if needed.
-	 */
-	r = -1;
-	if (usedns || useip)
-		r = dns_lookup(domain, sizeof(domain), useip, p->ut_addr_v6);
-	if (r < 0) {
-		len = UT_HOSTSIZE;
-		if (len >= sizeof(domain)) len = sizeof(domain) - 1;
-		domain[0] = 0;
-		strncat(domain, p->ut_host, len);
-	}
-
-	if (showhost) {
-#if CHOP_DOMAIN
-		/*
-		 *	See if this is in our domain.
-		 */
-		if (!usedns && (s = strchr(p->ut_host, '.')) != NULL &&
-		     strcmp(s + 1, domainname) == 0) *s = 0;
-#endif
-		if (!altlist) {
-			snprintf(final, sizeof(final),
-				fulltime ?
-				"%-8.8s %-12.12s %-16.16s %-24.24s %-26.26s %-12.12s\n" :
-				"%-8.8s %-12.12s %-16.16s %-16.16s %-7.7s %-12.12s\n",
-				p->ut_name, utline,
-				domain, logintime, logouttime, length);
-		} else {
-			snprintf(final, sizeof(final), 
-				fulltime ?
-				"%-8.8s %-12.12s %-24.24s %-26.26s %-12.12s %s\n" :
-				"%-8.8s %-12.12s %-16.16s %-7.7s %-12.12s %s\n",
-				p->ut_name, utline,
-				logintime, logouttime, length, domain);
-		}
-	} else
-		snprintf(final, sizeof(final),
-			fulltime ?
-			"%-8.8s %-12.12s %-24.24s %-26.26s %-12.12s\n" :
-			"%-8.8s %-12.12s %-16.16s %-7.7s %-12.12s\n",
-			p->ut_name, utline,
-			logintime, logouttime, length);
-
-	/*
-	 *	Print out "final" string safely.
-	 */
-	for (s = final; *s; s++) {
-		if (*s == '\n' || (*s >= 32 && (unsigned char)*s <= 126))
-			putchar(*s);
-		else
-			putchar('*');
-	}
-
-	recsdone++;
-	if (maxrecs && recsdone >= maxrecs)
-		return 1;
-
-	return 0;
-}
-
-
-/*
- *	show usage
- */
-void usage(char *s)
-{
-	fprintf(stderr, "Usage: %s [-num | -n num] [-f file] "
-			"[-t YYYYMMDDHHMMSS] "
-			"[-R] [-adioxF] [username..] [tty..]\n", s);
-	exit(1);
-}
-
-time_t parsetm(char *ts)
-{
-	struct tm	u = {0}, origu;
-	time_t		tm;
-
-	if (sscanf(ts, "%4d%2d%2d%2d%2d%2d", &u.tm_year,
-	    &u.tm_mon, &u.tm_mday, &u.tm_hour, &u.tm_min,
-	    &u.tm_sec) != 6)
-		return (time_t)-1;
-
-	u.tm_year -= 1900;
-	u.tm_mon -= 1;
-	u.tm_isdst = -1;
-
-	origu = u;
-
-	if ((tm = mktime(&u)) == (time_t)-1)
-		return tm;
-
-	/*
-	 *	Unfortunately mktime() is much more forgiving than
-	 *	it should be.  For example, it'll gladly accept
-	 *	"30" as a valid month number.  This behavior is by
-	 *	design, but we don't like it, so we want to detect
-	 *	it and complain.
-	 */
-	if (u.tm_year != origu.tm_year ||
-	    u.tm_mon != origu.tm_mon ||
-	    u.tm_mday != origu.tm_mday ||
-	    u.tm_hour != origu.tm_hour ||
-	    u.tm_min != origu.tm_min ||
-	    u.tm_sec != origu.tm_sec)
-		return (time_t)-1;
-
-	return tm;
-}
-
-int main(int argc, char **argv)
-{
-  FILE *fp;		/* Filepointer of wtmp file */
-
-  struct utmp ut;	/* Current utmp entry */
-  struct utmp oldut;	/* Old utmp entry to check for duplicates */
-  struct utmplist *p;	/* Pointer into utmplist */
-  struct utmplist *next;/* Pointer into utmplist */
-
-  time_t lastboot = 0;  /* Last boottime */
-  time_t lastrch = 0;	/* Last run level change */
-  time_t lastdown;	/* Last downtime */
-  time_t begintime;	/* When wtmp begins */
-  int whydown = 0;	/* Why we went down: crash or shutdown */
-
-  int c, x;		/* Scratch */
-  struct stat st;	/* To stat the [uw]tmp file */
-  int quit = 0;		/* Flag */
-  int down = 0;		/* Down flag */
-  int lastb = 0;	/* Is this 'lastb' ? */
-  int extended = 0;	/* Lots of info. */
-  char *altufile = NULL;/* Alternate wtmp */
-
-  time_t until = 0;	/* at what time to stop parsing the file */
-
-  progname = mybasename(argv[0]);
-
-  /* Process the arguments. */
-  while((c = getopt(argc, argv, "f:n:RxadFiot:0123456789")) != EOF)
-    switch(c) {
-	case 'R':
-		showhost = 0;
-		break;
-	case 'x':
-		extended = 1;
-		break;
-	case 'n':
-		maxrecs = atoi(optarg);
-		break;
-	case 'o':
-		oldfmt = 1;
-		break;
-	case 'f':
-		if((altufile = malloc(strlen(optarg)+1)) == NULL) {
-			fprintf(stderr, "%s: out of memory\n",
-				progname);
-			exit(1);
-		}
-		strcpy(altufile, optarg);
-		break;
-	case 'd':
-		usedns++;
-		break;
-	case 'i':
-		useip++;
-		break;
-	case 'a':
-		altlist++;
-		break;
-	case 'F':
-		fulltime++;
-		break;
-	case 't':
-		if ((until = parsetm(optarg)) == (time_t)-1) {
-			fprintf(stderr, "%s: Invalid time value \"%s\"\n",
-				progname, optarg);
-			usage(progname);
-		}
-		break;
-	case '0': case '1': case '2': case '3': case '4':
-	case '5': case '6': case '7': case '8': case '9':
-		maxrecs = 10*maxrecs + c - '0';
-		break;
-	default:
-		usage(progname);
-		break;
-    }
-  if (optind < argc) show = argv + optind;
-
-  /*
-   *	Which file do we want to read?
-   */
-  if (strcmp(progname, "lastb") == 0) {
-	ufile = BTMP_FILE;
-	lastb = 1;
-  } else
-	ufile = WTMP_FILE;
-  if (altufile)
-	ufile = altufile;
-  time(&lastdown);
-  lastrch = lastdown;
-
-  /*
-   *	Fill in 'lastdate'
-   */
-  lastdate = lastdown;
-
-#if CHOP_DOMAIN
-  /*
-   *	Find out domainname.
-   *
-   *	This doesn't work on modern systems, where only a DNS
-   *	lookup of the result from hostname() will get you the domainname.
-   *	Remember that domainname() is the NIS domainname, not DNS.
-   *	So basically this whole piece of code is bullshit.
-   */
-  hostname[0] = 0;
-  (void) gethostname(hostname, sizeof(hostname));
-  if ((domainname = strchr(hostname, '.')) != NULL) domainname++;
-  if (domainname == NULL || domainname[0] == 0) {
-	hostname[0] = 0;
-	(void) getdomainname(hostname, sizeof(hostname));
-	hostname[sizeof(hostname) - 1] = 0;
-	domainname = hostname;
-	if (strcmp(domainname, "(none)") == 0 || domainname[0] == 0)
-		domainname = NULL;
-  }
-#endif
-
-  /*
-   *	Install signal handlers
-   */
-  signal(SIGINT, int_handler);
-  signal(SIGQUIT, quit_handler);
-
-  /*
-   *	Open the utmp file
-   */
-  if ((fp = fopen(ufile, "r")) == NULL) {
-	x = errno;
-	fprintf(stderr, "%s: %s: %s\n", progname, ufile, strerror(errno));
-	if (altufile == NULL && x == ENOENT)
-		fprintf(stderr, "Perhaps this file was removed by the "
-			"operator to prevent logging %s info.\n", progname);
-	exit(1);
-  }
-
-  /*
-   *	Optimize the buffer size.
-   */
-  setvbuf(fp, NULL, _IOFBF, UCHUNKSIZE);
-
-  /*
-   *	Read first structure to capture the time field
-   */
-  if (uread(fp, &ut, NULL) == 1)
-	begintime = ut.ut_time;
-  else {
-  	fstat(fileno(fp), &st);
-	begintime = st.st_ctime;
-	quit = 1;
-  }
-
-  /*
-   *	Go to end of file minus one structure
-   *	and/or initialize utmp reading code.
-   */
-  uread(fp, NULL, NULL);
-
-  /*
-   *	Read struct after struct backwards from the file.
-   */
-  while(!quit) {
-
-	if (uread(fp, &ut, &quit) != 1)
-		break;
-
-	if (until && until < ut.ut_time)
-		continue;
-
-	if (memcmp(&ut, &oldut, sizeof(struct utmp)) == 0) continue;
-	memcpy(&oldut, &ut, sizeof(struct utmp));
-	lastdate = ut.ut_time;
-
-  	if (lastb) {
-  		quit = list(&ut, ut.ut_time, R_NORMAL);
-  		continue;
-  	}
-
-	/*
-	 *	Set ut_type to the correct type.
-	 */
-	if (strncmp(ut.ut_line, "~", 1) == 0) {
-		if (strncmp(ut.ut_user, "shutdown", 8) == 0)
-			ut.ut_type = SHUTDOWN_TIME;
-		else if (strncmp(ut.ut_user, "reboot", 6) == 0)
-			ut.ut_type = BOOT_TIME;
-		else if (strncmp(ut.ut_user, "runlevel", 8) == 0)
-			ut.ut_type = RUN_LVL;
-	}
-#if 1 /*def COMPAT*/
-	/*
-	 *	For stupid old applications that don't fill in
-	 *	ut_type correctly.
-	 */
-	else {
-		if (ut.ut_type != DEAD_PROCESS &&
-		    ut.ut_name[0] && ut.ut_line[0] &&
-		    strcmp(ut.ut_name, "LOGIN") != 0)
-			ut.ut_type = USER_PROCESS;
-		/*
-		 *	Even worse, applications that write ghost
-		 *	entries: ut_type set to USER_PROCESS but
-		 *	empty ut_name...
-		 */
-		if (ut.ut_name[0] == 0)
-			ut.ut_type = DEAD_PROCESS;
-
-		/*
-		 *	Clock changes.
-		 */
-		if (strcmp(ut.ut_name, "date") == 0) {
-			if (ut.ut_line[0] == '|') ut.ut_type = OLD_TIME;
-			if (ut.ut_line[0] == '{') ut.ut_type = NEW_TIME;
-		}
-	}
-#endif
-
-	switch (ut.ut_type) {
-		case SHUTDOWN_TIME:
-			if (extended) {
-				strcpy(ut.ut_line, "system down");
-				quit = list(&ut, lastboot, R_NORMAL);
-			}
-			lastdown = lastrch = ut.ut_time;
-			down = 1;
-			break;
-		case OLD_TIME:
-		case NEW_TIME:
-			if (extended) {
-				strcpy(ut.ut_line,
-				ut.ut_type == NEW_TIME ? "new time" :
-					"old time");
-				quit = list(&ut, lastdown, R_TIMECHANGE);
-			}
-			break;
-		case BOOT_TIME:
-			strcpy(ut.ut_line, "system boot");
-			quit = list(&ut, lastdown, R_REBOOT);
-			lastboot = ut.ut_time;
-			down = 1;
-			break;
-		case RUN_LVL:
-			x = ut.ut_pid & 255;
-			if (extended) {
-				sprintf(ut.ut_line, "(to lvl %c)", x);
-				quit = list(&ut, lastrch, R_NORMAL);
-			}
-			if (x == '0' || x == '6') {
-				lastdown = ut.ut_time;
-				down = 1;
-				ut.ut_type = SHUTDOWN_TIME;
-			}
-			lastrch = ut.ut_time;
-			break;
-
-		case USER_PROCESS:
-			/*
-			 *	This was a login - show the first matching
-			 *	logout record and delete all records with
-			 *	the same ut_line.
-			 */
-			c = 0;
-			for (p = utmplist; p; p = next) {
-				next = p->next;
-				if (strncmp(p->ut.ut_line, ut.ut_line,
-				    UT_LINESIZE) == 0) {
-					/* Show it */
-					if (c == 0) {
-						quit = list(&ut, p->ut.ut_time,
-							R_NORMAL);
-						c = 1;
-					}
-					if (p->next) p->next->prev = p->prev;
-					if (p->prev)
-						p->prev->next = p->next;
-					else
-						utmplist = p->next;
-					free(p);
-				}
-			}
-			/*
-			 *	Not found? Then crashed, down, still
-			 *	logged in, or missing logout record.
-			 */
-			if (c == 0) {
-				if (lastboot == 0) {
-					c = R_NOW;
-					/* Is process still alive? */
-					if (ut.ut_pid > 0 &&
-					    kill(ut.ut_pid, 0) != 0 &&
-					    errno == ESRCH)
-						c = R_PHANTOM;
-				} else
-					c = whydown;
-				quit = list(&ut, lastboot, c);
-			}
-			/* FALLTHRU */
-
-		case DEAD_PROCESS:
-			/*
-			 *	Just store the data if it is
-			 *	interesting enough.
-			 */
-			if (ut.ut_line[0] == 0)
-				break;
-			if ((p = malloc(sizeof(struct utmplist))) == NULL) {
-				fprintf(stderr, "%s: out of memory\n",
-					progname);
-				exit(1);
-			}
-			memcpy(&p->ut, &ut, sizeof(struct utmp));
-			p->next  = utmplist;
-			p->prev  = NULL;
-			if (utmplist) utmplist->prev = p;
-			utmplist = p;
-			break;
-
-	}
-	/*
-	 *	If we saw a shutdown/reboot record we can remove
-	 *	the entire current utmplist.
-	 */
-	if (down) {
-		lastboot = ut.ut_time;
-		whydown = (ut.ut_type == SHUTDOWN_TIME) ? R_DOWN : R_CRASH;
-		for (p = utmplist; p; p = next) {
-			next = p->next;
-			free(p);
-		}
-		utmplist = NULL;
-		down = 0;
-	}
-  }
-  printf("\n%s begins %s", mybasename(ufile), ctime(&begintime));
-
-  fclose(fp);
-
-  /*
-   *	Should we free memory here? Nah. This is not NT :)
-   */
-  return 0;
-}

Copied: sysvinit-upstream/tags/2.87dsf/src/last.c (from rev 1454, sysvinit-upstream/trunk/src/last.c)
===================================================================
--- sysvinit-upstream/tags/2.87dsf/src/last.c	                        (rev 0)
+++ sysvinit-upstream/tags/2.87dsf/src/last.c	2009-07-12 18:00:14 UTC (rev 1458)
@@ -0,0 +1,902 @@
+/*
+ * last.c	Re-implementation of the 'last' command, this time
+ *		for Linux. Yes I know there is BSD last, but I
+ *		just felt like writing this. No thanks :-).
+ *		Also, this version gives lots more info (especially with -x)
+ *
+ * Author:	Miquel van Smoorenburg, miquels at cistron.nl
+ *
+ * Version:	@(#)last  2.85  30-Jul-2004  miquels at cistron.nl
+ *
+ *		This file is part of the sysvinit suite,
+ *		Copyright 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.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#include <time.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <utmp.h>
+#include <errno.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <getopt.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include "oldutmp.h"
+
+#ifndef SHUTDOWN_TIME
+#  define SHUTDOWN_TIME 254
+#endif
+
+char *Version = "@(#) last 2.85 31-Apr-2004 miquels";
+
+#define CHOP_DOMAIN	0	/* Define to chop off local domainname. */
+#define NEW_UTMP	1	/* Fancy & fast utmp read code. */
+#define UCHUNKSIZE	16384	/* How much we read at once. */
+
+/* Double linked list of struct utmp's */
+struct utmplist {
+  struct utmp ut;
+  struct utmplist *next;
+  struct utmplist *prev;
+};
+struct utmplist *utmplist = NULL;
+
+/* Types of listing */
+#define R_CRASH		1 /* No logout record, system boot in between */
+#define R_DOWN		2 /* System brought down in decent way */
+#define R_NORMAL	3 /* Normal */
+#define R_NOW		4 /* Still logged in */
+#define R_REBOOT	5 /* Reboot record. */
+#define R_PHANTOM	6 /* No logout record but session is stale. */
+#define R_TIMECHANGE	7 /* NEW_TIME or OLD_TIME */
+
+/* Global variables */
+int maxrecs = 0;	/* Maximum number of records to list. */
+int recsdone = 0;	/* Number of records listed */
+int showhost = 1;	/* Show hostname too? */
+int altlist = 0;	/* Show hostname at the end. */
+int usedns = 0;		/* Use DNS to lookup the hostname. */
+int useip = 0;		/* Print IP address in number format */
+int fulltime = 0;	/* Print full dates and times */
+int oldfmt = 0;		/* Use old libc5 format? */
+char **show = NULL;	/* What do they want us to show */
+char *ufile;		/* Filename of this file */
+time_t lastdate;	/* Last date we've seen */
+char *progname;		/* Name of this program */
+#if CHOP_DOMAIN
+char hostname[256];	/* For gethostbyname() */
+char *domainname;	/* Our domainname. */
+#endif
+
+/*
+ *	Convert old utmp format to new.
+ */
+void uconv(struct oldutmp *oldut, struct utmp *utn)
+{
+	memset(utn, 0, sizeof(struct utmp));
+	utn->ut_type = oldut->ut_type;
+	utn->ut_pid  = oldut->ut_pid;
+	utn->ut_time = oldut->ut_oldtime;
+	utn->ut_addr = oldut->ut_oldaddr;
+	strncpy(utn->ut_line, oldut->ut_line, OLD_LINESIZE);
+	strncpy(utn->ut_user, oldut->ut_user, OLD_NAMESIZE);
+	strncpy(utn->ut_host, oldut->ut_host, OLD_HOSTSIZE);
+}
+
+#if NEW_UTMP
+/*
+ *	Read one utmp entry, return in new format.
+ *	Automatically reposition file pointer.
+ */
+int uread(FILE *fp, struct utmp *u, int *quit)
+{
+	static int utsize;
+	static char buf[UCHUNKSIZE];
+	char tmp[1024];
+	static off_t fpos;
+	static int bpos;
+	struct oldutmp uto;
+	int r;
+	off_t o;
+
+	if (quit == NULL && u != NULL) {
+		/*
+		 *	Normal read.
+		 */
+		if (oldfmt) {
+			r = fread(&uto, sizeof(uto), 1, fp);
+			uconv(&uto, u);
+		} else
+			r = fread(u, sizeof(struct utmp), 1, fp);
+		return r;
+	}
+
+	if (u == NULL) {
+		/*
+		 *	Initialize and position.
+		 */
+		utsize = oldfmt ? sizeof(uto) : sizeof(struct utmp);
+		fseeko(fp, 0, SEEK_END);
+		fpos = ftello(fp);
+		if (fpos == 0)
+			return 0;
+		o = ((fpos - 1) / UCHUNKSIZE) * UCHUNKSIZE;
+		if (fseeko(fp, o, SEEK_SET) < 0) {
+			fprintf(stderr, "%s: seek failed!\n", progname);
+			return 0;
+		}
+		bpos = (int)(fpos - o);
+		if (fread(buf, bpos, 1, fp) != 1) {
+			fprintf(stderr, "%s: read failed!\n", progname);
+			return 0;
+		}
+		fpos = o;
+		return 1;
+	}
+
+	/*
+	 *	Read one struct. From the buffer if possible.
+	 */
+	bpos -= utsize;
+	if (bpos >= 0) {
+		if (oldfmt)
+			uconv((struct oldutmp *)(buf + bpos), u);
+		else
+			memcpy(u, buf + bpos, sizeof(struct utmp));
+		return 1;
+	}
+
+	/*
+	 *	Oops we went "below" the buffer. We should be able to
+	 *	seek back UCHUNKSIZE bytes.
+	 */
+	fpos -= UCHUNKSIZE;
+	if (fpos < 0)
+		return 0;
+
+	/*
+	 *	Copy whatever is left in the buffer.
+	 */
+	memcpy(tmp + (-bpos), buf, utsize + bpos);
+	if (fseeko(fp, fpos, SEEK_SET) < 0) {
+		perror("fseek");
+		return 0;
+	}
+
+	/*
+	 *	Read another UCHUNKSIZE bytes.
+	 */
+	if (fread(buf, UCHUNKSIZE, 1, fp) != 1) {
+		perror("fread");
+		return 0;
+	}
+
+	/*
+	 *	The end of the UCHUNKSIZE byte buffer should be the first
+	 *	few bytes of the current struct utmp.
+	 */
+	memcpy(tmp, buf + UCHUNKSIZE + bpos, -bpos);
+	bpos += UCHUNKSIZE;
+
+	if (oldfmt)
+		uconv((struct oldutmp *)tmp, u);
+	else
+		memcpy(u, tmp, sizeof(struct utmp));
+
+	return 1;
+}
+
+#else /* NEW_UTMP */
+
+/*
+ *	Read one utmp entry, return in new format.
+ *	Automatically reposition file pointer.
+ */
+int uread(FILE *fp, struct utmp *u, int *quit)
+{
+	struct oldutmp uto;
+	off_t r;
+
+	if (u == NULL) {
+		r = oldfmt ? sizeof(struct oldutmp) : sizeof(struct utmp);
+		fseek(fp, -1 * r, SEEK_END);
+		return 1;
+	}
+
+	if (!oldfmt) {
+		r = fread(u, sizeof(struct utmp), 1, fp);
+		if (r == 1) {
+			if (fseeko(fp, -2 * sizeof(struct utmp), SEEK_CUR) < 0)
+				if (quit) *quit = 1;
+		}
+		return r;
+	}
+	r = fread(&uto, sizeof(struct oldutmp), 1, fp);
+	if (r == 1) {
+		if (fseeko(fp, -2 * sizeof(struct oldutmp), SEEK_CUR) < 0)
+			if (quit) *quit = 1;
+		uconv(&uto, u);
+	}
+
+	return r;
+}
+#endif
+
+/*
+ *	Try to be smart about the location of the BTMP file
+ */
+#ifndef BTMP_FILE
+#define BTMP_FILE getbtmp()
+char *getbtmp()
+{
+	static char btmp[128];
+	char *p;
+
+	strcpy(btmp, WTMP_FILE);
+	if ((p = strrchr(btmp, '/')) == NULL)
+		p = btmp;
+	else
+		p++;
+	*p = 0;
+	strcat(btmp, "btmp");
+	return btmp;
+}
+#endif
+
+/*
+ *	Print a short date.
+ */
+char *showdate()
+{
+	char *s = ctime(&lastdate);
+	s[16] = 0;
+	return s;
+}
+
+/*
+ *	SIGINT handler
+ */
+void int_handler()
+{
+	printf("Interrupted %s\n", showdate());
+	exit(1);
+}
+
+/*
+ *	SIGQUIT handler
+ */
+void quit_handler()
+{
+	printf("Interrupted %s\n", showdate());
+	signal(SIGQUIT, quit_handler);
+}
+
+/*
+ *	Get the basename of a filename
+ */
+char *mybasename(char *s)
+{
+	char *p;
+
+	if ((p = strrchr(s, '/')) != NULL)
+		p++;
+	else
+		p = s;
+	return p;
+}
+
+/*
+ *	Lookup a host with DNS.
+ */
+int dns_lookup(char *result, int size, int useip, int32_t *a)
+{
+	struct sockaddr_in	sin;
+	struct sockaddr_in6	sin6;
+	struct sockaddr		*sa;
+	int			salen, flags;
+	unsigned int		topnibble;
+	unsigned int		azero = 0, sitelocal = 0;
+	int			mapped = 0;
+
+	flags = useip ? NI_NUMERICHOST : 0;
+
+	/*
+	 *	IPv4 or IPv6 ? We use 2 heuristics:
+	 *	1. Current IPv6 range uses 2000-3fff or fec0-feff.
+	 *	   Outside of that is illegal and must be IPv4.
+	 *	2. If last 3 bytes are 0, must be IPv4
+	 *	3. If IPv6 in IPv4, handle as IPv4
+	 *
+	 *	Ugly.
+	 */
+	if (a[0] == 0 && a[1] == 0 && a[2] == htonl (0xffff))
+		mapped = 1;
+	topnibble = ntohl((unsigned int)a[0]) >> 28;
+
+	azero = ntohl((unsigned int)a[0]) >> 16;
+	sitelocal = (azero >= 0xfec0 && azero <= 0xfeff) ? 1 : 0;
+	
+	if (((topnibble < 2 || topnibble > 3) && (!sitelocal)) || mapped ||
+	    (a[1] == 0 && a[2] == 0 && a[3] == 0)) {
+		/* IPv4 */
+		sin.sin_family = AF_INET;
+		sin.sin_port = 0;
+		sin.sin_addr.s_addr = mapped ? a[3] : a[0];
+		sa = (struct sockaddr *)&sin;
+		salen = sizeof(sin);
+	} else {
+		/* IPv6 */
+		memset(&sin6, 0, sizeof(sin6));
+		sin6.sin6_family = AF_INET6;
+		sin6.sin6_port = 0;
+		memcpy(sin6.sin6_addr.s6_addr, a, 16);
+		sa = (struct sockaddr *)&sin6;
+		salen = sizeof(sin6);
+	}
+
+	return getnameinfo(sa, salen, result, size, NULL, 0, flags);
+}
+
+/*
+ *	Show one line of information on screen
+ */
+int list(struct utmp *p, time_t t, int what)
+{
+	time_t		secs, tmp;
+	char		logintime[32];
+	char		logouttime[32];
+	char		length[32];
+	char		final[128];
+	char		utline[UT_LINESIZE+1];
+	char		domain[256];
+	char		*s, **walk;
+	int		mins, hours, days;
+	int		r, len;
+
+	/*
+	 *	uucp and ftp have special-type entries
+	 */
+	utline[0] = 0;
+	strncat(utline, p->ut_line, UT_LINESIZE);
+	if (strncmp(utline, "ftp", 3) == 0 && isdigit(utline[3]))
+		utline[3] = 0;
+	if (strncmp(utline, "uucp", 4) == 0 && isdigit(utline[4]))
+		utline[4] = 0;
+
+	/*
+	 *	Is this something we wanna show?
+	 */
+	if (show) {
+		for (walk = show; *walk; walk++) {
+			if (strncmp(p->ut_name, *walk, UT_NAMESIZE) == 0 ||
+			    strcmp(utline, *walk) == 0 ||
+			    (strncmp(utline, "tty", 3) == 0 &&
+			     strcmp(utline + 3, *walk) == 0)) break;
+		}
+		if (*walk == NULL) return 0;
+	}
+
+	/*
+	 *	Calculate times
+	 */
+	tmp = (time_t)p->ut_time;
+	strcpy(logintime, ctime(&tmp));
+	if (fulltime)
+		sprintf(logouttime, "- %s", ctime(&t));
+	else {
+		logintime[16] = 0;
+		sprintf(logouttime, "- %s", ctime(&t) + 11);
+		logouttime[7] = 0;
+	}
+	secs = t - p->ut_time;
+	mins  = (secs / 60) % 60;
+	hours = (secs / 3600) % 24;
+	days  = secs / 86400;
+	if (days)
+		sprintf(length, "(%d+%02d:%02d)", days, hours, mins);
+	else
+		sprintf(length, " (%02d:%02d)", hours, mins);
+
+	switch(what) {
+		case R_CRASH:
+			sprintf(logouttime, "- crash");
+			break;
+		case R_DOWN:
+			sprintf(logouttime, "- down ");
+			break;
+		case R_NOW:
+			length[0] = 0;
+			if (fulltime)
+				sprintf(logouttime, "  still logged in");
+			else {
+				sprintf(logouttime, "  still");
+				sprintf(length, "logged in");
+			}
+			break;
+		case R_PHANTOM:
+			length[0] = 0;
+			if (fulltime)
+				sprintf(logouttime, "  gone - no logout");
+			else {
+				sprintf(logouttime, "   gone");
+				sprintf(length, "- no logout");
+			}
+			break;
+		case R_REBOOT:
+			break;
+		case R_TIMECHANGE:
+			logouttime[0] = 0;
+			length[0] = 0;
+			break;
+		case R_NORMAL:
+			break;
+ 	}
+
+	/*
+	 *	Look up host with DNS if needed.
+	 */
+	r = -1;
+	if (usedns || useip)
+		r = dns_lookup(domain, sizeof(domain), useip, p->ut_addr_v6);
+	if (r < 0) {
+		len = UT_HOSTSIZE;
+		if (len >= sizeof(domain)) len = sizeof(domain) - 1;
+		domain[0] = 0;
+		strncat(domain, p->ut_host, len);
+	}
+
+	if (showhost) {
+#if CHOP_DOMAIN
+		/*
+		 *	See if this is in our domain.
+		 */
+		if (!usedns && (s = strchr(p->ut_host, '.')) != NULL &&
+		     strcmp(s + 1, domainname) == 0) *s = 0;
+#endif
+		if (!altlist) {
+			snprintf(final, sizeof(final),
+				fulltime ?
+				"%-8.8s %-12.12s %-16.16s %-24.24s %-26.26s %-12.12s\n" :
+				"%-8.8s %-12.12s %-16.16s %-16.16s %-7.7s %-12.12s\n",
+				p->ut_name, utline,
+				domain, logintime, logouttime, length);
+		} else {
+			snprintf(final, sizeof(final), 
+				fulltime ?
+				"%-8.8s %-12.12s %-24.24s %-26.26s %-12.12s %s\n" :
+				"%-8.8s %-12.12s %-16.16s %-7.7s %-12.12s %s\n",
+				p->ut_name, utline,
+				logintime, logouttime, length, domain);
+		}
+	} else
+		snprintf(final, sizeof(final),
+			fulltime ?
+			"%-8.8s %-12.12s %-24.24s %-26.26s %-12.12s\n" :
+			"%-8.8s %-12.12s %-16.16s %-7.7s %-12.12s\n",
+			p->ut_name, utline,
+			logintime, logouttime, length);
+
+	/*
+	 *	Print out "final" string safely.
+	 */
+	for (s = final; *s; s++) {
+		if (*s == '\n' || (*s >= 32 && (unsigned char)*s <= 126))
+			putchar(*s);
+		else
+			putchar('*');
+	}
+
+	recsdone++;
+	if (maxrecs && recsdone >= maxrecs)
+		return 1;
+
+	return 0;
+}
+
+
+/*
+ *	show usage
+ */
+void usage(char *s)
+{
+	fprintf(stderr, "Usage: %s [-num | -n num] [-f file] "
+			"[-t YYYYMMDDHHMMSS] "
+			"[-R] [-adioxF] [username..] [tty..]\n", s);
+	exit(1);
+}
+
+time_t parsetm(char *ts)
+{
+	struct tm	u, origu;
+	time_t		tm;
+
+	memset(&tm, 0, sizeof(tm));
+
+	if (sscanf(ts, "%4d%2d%2d%2d%2d%2d", &u.tm_year,
+	    &u.tm_mon, &u.tm_mday, &u.tm_hour, &u.tm_min,
+	    &u.tm_sec) != 6)
+		return (time_t)-1;
+
+	u.tm_year -= 1900;
+	u.tm_mon -= 1;
+	u.tm_isdst = -1;
+
+	origu = u;
+
+	if ((tm = mktime(&u)) == (time_t)-1)
+		return tm;
+
+	/*
+	 *	Unfortunately mktime() is much more forgiving than
+	 *	it should be.  For example, it'll gladly accept
+	 *	"30" as a valid month number.  This behavior is by
+	 *	design, but we don't like it, so we want to detect
+	 *	it and complain.
+	 */
+	if (u.tm_year != origu.tm_year ||
+	    u.tm_mon != origu.tm_mon ||
+	    u.tm_mday != origu.tm_mday ||
+	    u.tm_hour != origu.tm_hour ||
+	    u.tm_min != origu.tm_min ||
+	    u.tm_sec != origu.tm_sec)
+		return (time_t)-1;
+
+	return tm;
+}
+
+int main(int argc, char **argv)
+{
+  FILE *fp;		/* Filepointer of wtmp file */
+
+  struct utmp ut;	/* Current utmp entry */
+  struct utmp oldut;	/* Old utmp entry to check for duplicates */
+  struct utmplist *p;	/* Pointer into utmplist */
+  struct utmplist *next;/* Pointer into utmplist */
+
+  time_t lastboot = 0;  /* Last boottime */
+  time_t lastrch = 0;	/* Last run level change */
+  time_t lastdown;	/* Last downtime */
+  time_t begintime;	/* When wtmp begins */
+  int whydown = 0;	/* Why we went down: crash or shutdown */
+
+  int c, x;		/* Scratch */
+  struct stat st;	/* To stat the [uw]tmp file */
+  int quit = 0;		/* Flag */
+  int down = 0;		/* Down flag */
+  int lastb = 0;	/* Is this 'lastb' ? */
+  int extended = 0;	/* Lots of info. */
+  char *altufile = NULL;/* Alternate wtmp */
+
+  time_t until = 0;	/* at what time to stop parsing the file */
+
+  progname = mybasename(argv[0]);
+
+  /* Process the arguments. */
+  while((c = getopt(argc, argv, "f:n:RxadFiot:0123456789")) != EOF)
+    switch(c) {
+	case 'R':
+		showhost = 0;
+		break;
+	case 'x':
+		extended = 1;
+		break;
+	case 'n':
+		maxrecs = atoi(optarg);
+		break;
+	case 'o':
+		oldfmt = 1;
+		break;
+	case 'f':
+		if((altufile = malloc(strlen(optarg)+1)) == NULL) {
+			fprintf(stderr, "%s: out of memory\n",
+				progname);
+			exit(1);
+		}
+		strcpy(altufile, optarg);
+		break;
+	case 'd':
+		usedns++;
+		break;
+	case 'i':
+		useip++;
+		break;
+	case 'a':
+		altlist++;
+		break;
+	case 'F':
+		fulltime++;
+		break;
+	case 't':
+		if ((until = parsetm(optarg)) == (time_t)-1) {
+			fprintf(stderr, "%s: Invalid time value \"%s\"\n",
+				progname, optarg);
+			usage(progname);
+		}
+		break;
+	case '0': case '1': case '2': case '3': case '4':
+	case '5': case '6': case '7': case '8': case '9':
+		maxrecs = 10*maxrecs + c - '0';
+		break;
+	default:
+		usage(progname);
+		break;
+    }
+  if (optind < argc) show = argv + optind;
+
+  /*
+   *	Which file do we want to read?
+   */
+  if (strcmp(progname, "lastb") == 0) {
+	ufile = BTMP_FILE;
+	lastb = 1;
+  } else
+	ufile = WTMP_FILE;
+  if (altufile)
+	ufile = altufile;
+  time(&lastdown);
+  lastrch = lastdown;
+
+  /*
+   *	Fill in 'lastdate'
+   */
+  lastdate = lastdown;
+
+#if CHOP_DOMAIN
+  /*
+   *	Find out domainname.
+   *
+   *	This doesn't work on modern systems, where only a DNS
+   *	lookup of the result from hostname() will get you the domainname.
+   *	Remember that domainname() is the NIS domainname, not DNS.
+   *	So basically this whole piece of code is bullshit.
+   */
+  hostname[0] = 0;
+  (void) gethostname(hostname, sizeof(hostname));
+  if ((domainname = strchr(hostname, '.')) != NULL) domainname++;
+  if (domainname == NULL || domainname[0] == 0) {
+	hostname[0] = 0;
+	(void) getdomainname(hostname, sizeof(hostname));
+	hostname[sizeof(hostname) - 1] = 0;
+	domainname = hostname;
+	if (strcmp(domainname, "(none)") == 0 || domainname[0] == 0)
+		domainname = NULL;
+  }
+#endif
+
+  /*
+   *	Install signal handlers
+   */
+  signal(SIGINT, int_handler);
+  signal(SIGQUIT, quit_handler);
+
+  /*
+   *	Open the utmp file
+   */
+  if ((fp = fopen(ufile, "r")) == NULL) {
+	x = errno;
+	fprintf(stderr, "%s: %s: %s\n", progname, ufile, strerror(errno));
+	if (altufile == NULL && x == ENOENT)
+		fprintf(stderr, "Perhaps this file was removed by the "
+			"operator to prevent logging %s info.\n", progname);
+	exit(1);
+  }
+
+  /*
+   *	Optimize the buffer size.
+   */
+  setvbuf(fp, NULL, _IOFBF, UCHUNKSIZE);
+
+  /*
+   *	Read first structure to capture the time field
+   */
+  if (uread(fp, &ut, NULL) == 1)
+	begintime = ut.ut_time;
+  else {
+  	fstat(fileno(fp), &st);
+	begintime = st.st_ctime;
+	quit = 1;
+  }
+
+  /*
+   *	Go to end of file minus one structure
+   *	and/or initialize utmp reading code.
+   */
+  uread(fp, NULL, NULL);
+
+  /*
+   *	Read struct after struct backwards from the file.
+   */
+  while(!quit) {
+
+	if (uread(fp, &ut, &quit) != 1)
+		break;
+
+	if (until && until < ut.ut_time)
+		continue;
+
+	if (memcmp(&ut, &oldut, sizeof(struct utmp)) == 0) continue;
+	memcpy(&oldut, &ut, sizeof(struct utmp));
+	lastdate = ut.ut_time;
+
+  	if (lastb) {
+  		quit = list(&ut, ut.ut_time, R_NORMAL);
+  		continue;
+  	}
+
+	/*
+	 *	Set ut_type to the correct type.
+	 */
+	if (strncmp(ut.ut_line, "~", 1) == 0) {
+		if (strncmp(ut.ut_user, "shutdown", 8) == 0)
+			ut.ut_type = SHUTDOWN_TIME;
+		else if (strncmp(ut.ut_user, "reboot", 6) == 0)
+			ut.ut_type = BOOT_TIME;
+		else if (strncmp(ut.ut_user, "runlevel", 8) == 0)
+			ut.ut_type = RUN_LVL;
+	}
+#if 1 /*def COMPAT*/
+	/*
+	 *	For stupid old applications that don't fill in
+	 *	ut_type correctly.
+	 */
+	else {
+		if (ut.ut_type != DEAD_PROCESS &&
+		    ut.ut_name[0] && ut.ut_line[0] &&
+		    strcmp(ut.ut_name, "LOGIN") != 0)
+			ut.ut_type = USER_PROCESS;
+		/*
+		 *	Even worse, applications that write ghost
+		 *	entries: ut_type set to USER_PROCESS but
+		 *	empty ut_name...
+		 */
+		if (ut.ut_name[0] == 0)
+			ut.ut_type = DEAD_PROCESS;
+
+		/*
+		 *	Clock changes.
+		 */
+		if (strcmp(ut.ut_name, "date") == 0) {
+			if (ut.ut_line[0] == '|') ut.ut_type = OLD_TIME;
+			if (ut.ut_line[0] == '{') ut.ut_type = NEW_TIME;
+		}
+	}
+#endif
+
+	switch (ut.ut_type) {
+		case SHUTDOWN_TIME:
+			if (extended) {
+				strcpy(ut.ut_line, "system down");
+				quit = list(&ut, lastboot, R_NORMAL);
+			}
+			lastdown = lastrch = ut.ut_time;
+			down = 1;
+			break;
+		case OLD_TIME:
+		case NEW_TIME:
+			if (extended) {
+				strcpy(ut.ut_line,
+				ut.ut_type == NEW_TIME ? "new time" :
+					"old time");
+				quit = list(&ut, lastdown, R_TIMECHANGE);
+			}
+			break;
+		case BOOT_TIME:
+			strcpy(ut.ut_line, "system boot");
+			quit = list(&ut, lastdown, R_REBOOT);
+			lastboot = ut.ut_time;
+			down = 1;
+			break;
+		case RUN_LVL:
+			x = ut.ut_pid & 255;
+			if (extended) {
+				sprintf(ut.ut_line, "(to lvl %c)", x);
+				quit = list(&ut, lastrch, R_NORMAL);
+			}
+			if (x == '0' || x == '6') {
+				lastdown = ut.ut_time;
+				down = 1;
+				ut.ut_type = SHUTDOWN_TIME;
+			}
+			lastrch = ut.ut_time;
+			break;
+
+		case USER_PROCESS:
+			/*
+			 *	This was a login - show the first matching
+			 *	logout record and delete all records with
+			 *	the same ut_line.
+			 */
+			c = 0;
+			for (p = utmplist; p; p = next) {
+				next = p->next;
+				if (strncmp(p->ut.ut_line, ut.ut_line,
+				    UT_LINESIZE) == 0) {
+					/* Show it */
+					if (c == 0) {
+						quit = list(&ut, p->ut.ut_time,
+							R_NORMAL);
+						c = 1;
+					}
+					if (p->next) p->next->prev = p->prev;
+					if (p->prev)
+						p->prev->next = p->next;
+					else
+						utmplist = p->next;
+					free(p);
+				}
+			}
+			/*
+			 *	Not found? Then crashed, down, still
+			 *	logged in, or missing logout record.
+			 */
+			if (c == 0) {
+				if (lastboot == 0) {
+					c = R_NOW;
+					/* Is process still alive? */
+					if (ut.ut_pid > 0 &&
+					    kill(ut.ut_pid, 0) != 0 &&
+					    errno == ESRCH)
+						c = R_PHANTOM;
+				} else
+					c = whydown;
+				quit = list(&ut, lastboot, c);
+			}
+			/* FALLTHRU */
+
+		case DEAD_PROCESS:
+			/*
+			 *	Just store the data if it is
+			 *	interesting enough.
+			 */
+			if (ut.ut_line[0] == 0)
+				break;
+			if ((p = malloc(sizeof(struct utmplist))) == NULL) {
+				fprintf(stderr, "%s: out of memory\n",
+					progname);
+				exit(1);
+			}
+			memcpy(&p->ut, &ut, sizeof(struct utmp));
+			p->next  = utmplist;
+			p->prev  = NULL;
+			if (utmplist) utmplist->prev = p;
+			utmplist = p;
+			break;
+
+	}
+	/*
+	 *	If we saw a shutdown/reboot record we can remove
+	 *	the entire current utmplist.
+	 */
+	if (down) {
+		lastboot = ut.ut_time;
+		whydown = (ut.ut_type == SHUTDOWN_TIME) ? R_DOWN : R_CRASH;
+		for (p = utmplist; p; p = next) {
+			next = p->next;
+			free(p);
+		}
+		utmplist = NULL;
+		down = 0;
+	}
+  }
+  printf("\n%s begins %s", mybasename(ufile), ctime(&begintime));
+
+  fclose(fp);
+
+  /*
+   *	Should we free memory here? Nah. This is not NT :)
+   */
+  return 0;
+}

Deleted: sysvinit-upstream/tags/2.87dsf/src/shutdown.c
===================================================================
--- sysvinit-upstream/trunk/src/shutdown.c	2009-07-10 21:51:19 UTC (rev 1428)
+++ sysvinit-upstream/tags/2.87dsf/src/shutdown.c	2009-07-12 18:00:14 UTC (rev 1458)
@@ -1,712 +0,0 @@
-/*
- * 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 at cistron.nl
- *
- * Version:	@(#)shutdown  2.86-1  31-Jul-2004  miquels at cistron.nl
- *
- *		This file is part of the sysvinit suite,
- *		Copyright 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.
- */
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <time.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <stdio.h> 
-#include <signal.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <utmp.h>
-#include <syslog.h>
-#include "paths.h"
-#include "reboot.h"
-#include "initreq.h"
-
-char *Version = "@(#) shutdown 2.86-1 31-Jul-2004 miquels at cistron.nl";
-
-#define MESSAGELEN	256
-
-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[64];	/* What are we gonna do		*/
-int doself = 0;		/* Don't use init		*/
-int got_alrm = 0;
-
-char *clean_env[] = {
-	"HOME=/",
-	"PATH=/bin:/usr/bin:/sbin:/usr/sbin",
-	"TERM=dumb",
-	NULL,
-};
-
-/* From "wall.c" */
-extern void wall(char *, int, int);
-
-/* 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.
- */
-void stopit(int sig)
-{
-	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 [-akrhHPfnc] [-t secs] 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  -H:      halt action is to just halt.\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  -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;
-	int			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 >= 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 &&
-            write(fd, &request, sizeof(request)) == sizeof(request)) {
-                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 warn(int mins)
-{
-	char buf[MESSAGELEN + sizeof(newstate)];
-	int len;
-
-	buf[0] = 0;
-	strncat(buf, message, sizeof(buf) - 1);
-	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, 1, 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);
-
-	chdir("/");
-	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.\r\n");
-		exit(1);
-	}
-
-	/* Kill all processes. */
-	fprintf(stderr, "shutdown: sending all processes the TERM signal...\r\n");
-	kill(-1, SIGTERM);
-	sleep(sltime ? atoi(sltime) : 3);
-	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. */
-	sleep(1); /* Give init the chance to collect zombies. */
-
-	/* Record the fact that we're going down */
-	write_wtmp("shutdown", "~~", 0, RUN_LVL, "~~");
-
-	/* This is for those who have quota installed. */
-	spawn(1, "accton", NULL);
-	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 shutdown(char *halttype)
-{
-	char	*args[8];
-	int	argp = 0;
-	int	do_halt = (down_level[0] == '0');
-
-	/* Warn for the last time */
-	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 ret;
-
-	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;
-	uid_t			realuid;
-	char			*halttype;
-	char			*downusers[32];
-	char			buf[128];
-	char			term[UT_LINESIZE + 6];
-	char			*sp;
-	char			*when = NULL;
-	int			c, i, wt;
-	int			hours, mins;
-	int			didnolog = 0;
-	int			cancel = 0;
-	int			useacl = 0;
-	int			pid = 0;
-	int			user_ok = 0;
-
-	/* We can be installed setuid root (executable for a special group) */
-	realuid = getuid();
-	setuid(geteuid());
-
-	if (getuid() != 0) {
-  		fprintf(stderr, "shutdown: you must be root to do that!\n");
-  		exit(1);
-	}
-	strcpy(down_level, "1");
-	halttype = NULL;
-
-	/* Process the options. */
-	while((c = getopt(argc, argv, "HPacqkrhnfFyt:g:i:")) != EOF) {
-  		switch(c) {
-			case 'H':
-				halttype = "HALT";
-				break;
-			case 'P':
-				halttype = "POWERDOWN";
-				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 'y': /* Ignored for sysV compatibility */
-				break;
-			case 'g': /* sysv style to specify time. */
-				when = optarg;
-				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;	
-  		}
-	}
-
-	/* 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) {
-		fscanf(fp, "%d", &pid);
-		fclose(fp);
-	}
-
-	/* Read remaining words, skip time if needed. */
-	message[0] = 0;
-	for(c = optind + (!cancel && !when); 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, 1, 0);
-		exit(0);
-	}
-  
-	/* Check syntax. */
-	if (when == NULL) {
-		if (optind == argc) usage();
-		when = argv[optind++];
-	}
-
-	/* 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':
-			strcpy(newstate, "for system halt");
-			break;
-		case '6':
-			strcpy(newstate, "for reboot");
-			break;
-		case '1':
-			strcpy(newstate, "to maintenance mode");
-			break;
-		default:
-			sprintf(newstate, "to runlevel %s", down_level);
-			break;
-	}
-
-	/* 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);
-
-	/* Go to the root directory */
-	chdir("/");
-	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");
-	if (when[0] == '+') when++;
-
-	/* Decode shutdown time. */
-	for (sp = when; *sp; sp++) {
-		if (*sp != ':' && (*sp < '0' || *sp > '9'))
-			usage();
-	}
-	if (strchr(when, ':') == NULL) {
-		/* Time in minutes. */
-		wt = atoi(when);
-		if (wt == 0 && when[0] != '0') usage();
-	} else {
-		/* Time in hh:mm format. */
-		if (sscanf(when, "%d:%2d", &hours, &mins) != 2) usage();
-		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) shutdown(halttype);
-
-	/* Give warnings on regular intervals and finally shutdown. */
-	if (wt < 15 && !needwarning(wt)) warn(wt);
-	while(wt) {
-		if (wt <= 5 && !didnolog) {
-			donologin(wt);
-			didnolog++;
-		}
-		if (needwarning(wt)) warn(wt);
-		hardsleep(60);
-		wt--;
-	}
-	shutdown(halttype);
-
-	return 0; /* Never happens */
-}

Copied: sysvinit-upstream/tags/2.87dsf/src/shutdown.c (from rev 1451, sysvinit-upstream/trunk/src/shutdown.c)
===================================================================
--- sysvinit-upstream/tags/2.87dsf/src/shutdown.c	                        (rev 0)
+++ sysvinit-upstream/tags/2.87dsf/src/shutdown.c	2009-07-12 18:00:14 UTC (rev 1458)
@@ -0,0 +1,718 @@
+/*
+ * 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 at cistron.nl
+ *
+ * Version:	@(#)shutdown  2.86-1  31-Jul-2004  miquels at cistron.nl
+ *
+ *		This file is part of the sysvinit suite,
+ *		Copyright 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.
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h> 
+#include <signal.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <utmp.h>
+#include <syslog.h>
+#include "paths.h"
+#include "reboot.h"
+#include "initreq.h"
+
+char *Version = "@(#) shutdown 2.86-1 31-Jul-2004 miquels at cistron.nl";
+
+#define MESSAGELEN	256
+
+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[64];	/* What are we gonna do		*/
+int doself = 0;		/* Don't use init		*/
+int got_alrm = 0;
+
+char *clean_env[] = {
+	"HOME=/",
+	"PATH=/bin:/usr/bin:/sbin:/usr/sbin",
+	"TERM=dumb",
+	NULL,
+};
+
+/* From "wall.c" */
+extern void wall(char *, int, int);
+
+/* 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.
+ */
+void stopit(int sig)
+{
+	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 [-akrhHPfnc] [-t secs] 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  -H:      halt action is to just halt.\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  -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;
+	int			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 >= 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 &&
+            write(fd, &request, sizeof(request)) == sizeof(request)) {
+                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 warn(int mins)
+{
+	char buf[MESSAGELEN + sizeof(newstate)];
+	int len;
+
+	buf[0] = 0;
+	strncat(buf, message, sizeof(buf) - 1);
+	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, 1, 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);
+
+	chdir("/");
+	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.\r\n");
+		exit(1);
+	}
+
+	/* Kill all processes. */
+	fprintf(stderr, "shutdown: sending all processes the TERM signal...\r\n");
+	kill(-1, SIGTERM);
+	sleep(sltime ? atoi(sltime) : 3);
+	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. */
+	sleep(1); /* Give init the chance to collect zombies. */
+
+	/* Record the fact that we're going down */
+	write_wtmp("shutdown", "~~", 0, RUN_LVL, "~~");
+
+	/* This is for those who have quota installed. */
+	spawn(1, "accton", NULL);
+	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 shutdown(char *halttype)
+{
+	char	*args[8];
+	int	argp = 0;
+	int	do_halt = (down_level[0] == '0');
+
+	/* Warn for the last time */
+	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 ret;
+
+	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;
+	uid_t			realuid;
+	char			*halttype;
+	char			*downusers[32];
+	char			buf[128];
+	char			term[UT_LINESIZE + 6];
+	char			*sp;
+	char			*when = NULL;
+	int			c, i, wt;
+	int			hours, mins;
+	int			didnolog = 0;
+	int			cancel = 0;
+	int			useacl = 0;
+	int			pid = 0;
+	int			user_ok = 0;
+
+	/* We can be installed setuid root (executable for a special group) */
+	realuid = getuid();
+	setuid(geteuid());
+
+	if (getuid() != 0) {
+  		fprintf(stderr, "shutdown: you must be root to do that!\n");
+  		exit(1);
+	}
+	strcpy(down_level, "1");
+	halttype = NULL;
+
+	/* Process the options. */
+	while((c = getopt(argc, argv, "HPacqkrhnfFyt:g:i:")) != EOF) {
+  		switch(c) {
+			case 'H':
+				halttype = "HALT";
+				break;
+			case 'P':
+				halttype = "POWERDOWN";
+				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 'y': /* Ignored for sysV compatibility */
+				break;
+			case 'g': /* sysv style to specify time. */
+				when = optarg;
+				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) {
+		fscanf(fp, "%d", &pid);
+		fclose(fp);
+	}
+
+	/* Read remaining words, skip time if needed. */
+	message[0] = 0;
+	for(c = optind + (!cancel && !when); 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, 1, 0);
+		exit(0);
+	}
+  
+	/* Check syntax. */
+	if (when == NULL) {
+		if (optind == argc) usage();
+		when = argv[optind++];
+	}
+
+	/* 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':
+			strcpy(newstate, "for system halt");
+			break;
+		case '6':
+			strcpy(newstate, "for reboot");
+			break;
+		case '1':
+			strcpy(newstate, "to maintenance mode");
+			break;
+		default:
+			sprintf(newstate, "to runlevel %s", down_level);
+			break;
+	}
+
+	/* 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);
+
+	/* Go to the root directory */
+	chdir("/");
+	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");
+	if (when[0] == '+') when++;
+
+	/* Decode shutdown time. */
+	for (sp = when; *sp; sp++) {
+		if (*sp != ':' && (*sp < '0' || *sp > '9'))
+			usage();
+	}
+	if (strchr(when, ':') == NULL) {
+		/* Time in minutes. */
+		wt = atoi(when);
+		if (wt == 0 && when[0] != '0') usage();
+	} else {
+		/* Time in hh:mm format. */
+		if (sscanf(when, "%d:%2d", &hours, &mins) != 2) usage();
+		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) shutdown(halttype);
+
+	/* Give warnings on regular intervals and finally shutdown. */
+	if (wt < 15 && !needwarning(wt)) warn(wt);
+	while(wt) {
+		if (wt <= 5 && !didnolog) {
+			donologin(wt);
+			didnolog++;
+		}
+		if (needwarning(wt)) warn(wt);
+		hardsleep(60);
+		wt--;
+	}
+	shutdown(halttype);
+
+	return 0; /* Never happens */
+}

Deleted: sysvinit-upstream/tags/2.87dsf/src/sulogin.c
===================================================================
--- sysvinit-upstream/trunk/src/sulogin.c	2009-07-10 21:51:19 UTC (rev 1428)
+++ sysvinit-upstream/tags/2.87dsf/src/sulogin.c	2009-07-12 18:00:14 UTC (rev 1458)
@@ -1,476 +0,0 @@
-/*
- * sulogin	This program gives Linux machines a reasonable
- *		secure way to boot single user. It forces the
- *		user to supply the root password before a
- *		shell is started.
- *
- *		If there is a shadow password file and the
- *		encrypted root password is "x" the shadow
- *		password will be used.
- *
- * Version:	@(#)sulogin 2.85-3 23-Apr-2003 miquels at cistron.nl
- *
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <pwd.h>
-#include <shadow.h>
-#include <termios.h>
-#include <sys/ioctl.h>
-#if defined(__GLIBC__)
-#  include <crypt.h>
-#endif
-
-#ifdef WITH_SELINUX
-#  include <selinux/selinux.h>
-#  include <selinux/get_context_list.h>
-#endif
-
-#define CHECK_DES	1
-#define CHECK_MD5	1
-
-#define F_PASSWD	"/etc/passwd"
-#define F_SHADOW	"/etc/shadow"
-#define BINSH		"/bin/sh"
-
-char *Version = "@(#)sulogin 2.85-3 23-Apr-2003 miquels at cistron.nl";
-
-int timeout = 0;
-int profile = 0;
-
-#ifndef IUCLC
-#  define IUCLC	0
-#endif
-
-#if 0
-/*
- *	Fix the tty modes and set reasonable defaults.
- *	(I'm not sure if this is needed under Linux, but..)
- */
-void fixtty(void)
-{
-	struct termios tty;
-
-	tcgetattr(0, &tty);
-
-	/*
-	 *	Set or adjust tty modes.
-	 */
-	tty.c_iflag &= ~(INLCR|IGNCR|IUCLC);
-	tty.c_iflag |= ICRNL;
-	tty.c_oflag &= ~(OCRNL|OLCUC|ONOCR|ONLRET|OFILL);
-	tty.c_oflag |= OPOST|ONLCR;
-	tty.c_cflag |= CLOCAL;
-	tty.c_lflag  = ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE;
-
-	/*
-	 *	Set the most important characters */
-	 */
-	tty.c_cc[VINTR]  = 3;
-	tty.c_cc[VQUIT]  = 28;
-	tty.c_cc[VERASE] = 127;
-	tty.c_cc[VKILL]  = 24;
-	tty.c_cc[VEOF]   = 4;
-	tty.c_cc[VTIME]  = 0;
-	tty.c_cc[VMIN]   = 1;
-	tty.c_cc[VSTART] = 17;
-	tty.c_cc[VSTOP]  = 19;
-	tty.c_cc[VSUSP]  = 26;
- 
-	tcsetattr(0, TCSANOW, &tty);
-}
-#endif
-
-
-/*
- *	Called at timeout.
- */
-void alrm_handler()
-{
-}
-
-/*
- *	See if an encrypted password is valid. The encrypted
- *	password is checked for traditional-style DES and
- *	FreeBSD-style MD5 encryption.
- */
-int valid(char *pass)
-{
-	char *s;
-	int len;
-
-	if (pass[0] == 0) return 1;
-#if CHECK_MD5
-	/*
-	 *	3 bytes for the signature $1$
-	 *	up to 8 bytes for the salt
-	 *	$
-	 *	the MD5 hash (128 bits or 16 bytes) encoded in base64 = 22 bytes
-	 */
-	if (strncmp(pass, "$1$", 3) == 0) {
-		for(s = pass + 3; *s && *s != '$'; s++)
-			;
-		if (*s++ != '$') return 0;
-		len = strlen(s);
-		if (len < 22 || len > 24) return 0;
-
-		return 1;
-	}
-#endif
-#if CHECK_DES
-	if (strlen(pass) != 13) return 0;
-	for (s = pass; *s; s++) {
-		if ((*s < '0' || *s > '9') &&
-		    (*s < 'a' || *s > 'z') &&
-		    (*s < 'A' || *s > 'Z') &&
-		    *s != '.' && *s != '/') return 0;
-	}
-#endif
-	return 1;
-}
-
-/*
- *	Set a variable if the value is not NULL.
- */
-void set(char **var, char *val)
-{
-	if (val) *var = val;
-}
-
-/*
- *	Get the root password entry.
- */
-struct passwd *getrootpwent(int try_manually)
-{
-	static struct passwd pwd;
-	struct passwd *pw;
-	struct spwd *spw;
-	FILE *fp;
-	static char line[256];
-	static char sline[256];
-	char *p;
-
-	/*
-	 *	First, we try to get the password the standard
-	 *	way using normal library calls.
-	 */
-	if ((pw = getpwnam("root")) &&
-	    !strcmp(pw->pw_passwd, "x") &&
-	    (spw = getspnam("root")))
-		pw->pw_passwd = spw->sp_pwdp;
-	if (pw || !try_manually) return pw;
-
-	/*
-	 *	If we come here, we could not retrieve the root
-	 *	password through library calls and we try to
-	 *	read the password and shadow files manually.
-	 */
-	pwd.pw_name = "root";
-	pwd.pw_passwd = "";
-	pwd.pw_gecos = "Super User";
-	pwd.pw_dir = "/";
-	pwd.pw_shell = "";
-	pwd.pw_uid = 0;
-	pwd.pw_gid = 0;
-
-	if ((fp = fopen(F_PASSWD, "r")) == NULL) {
-		perror(F_PASSWD);
-		return &pwd;
-	}
-
-	/*
-	 *	Find root in the password file.
-	 */
-	while((p = fgets(line, 256, fp)) != NULL) {
-		if (strncmp(line, "root:", 5) != 0)
-			continue;
-		p += 5;
-		set(&pwd.pw_passwd, strsep(&p, ":"));
-		(void)strsep(&p, ":");
-		(void)strsep(&p, ":");
-		set(&pwd.pw_gecos, strsep(&p, ":"));
-		set(&pwd.pw_dir, strsep(&p, ":"));
-		set(&pwd.pw_shell, strsep(&p, "\n"));
-		p = line;
-		break;
-	}
-	fclose(fp);
-
-	/*
-	 *	If the encrypted password is valid
-	 *	or not found, return.
-	 */
-	if (p == NULL) {
-		fprintf(stderr, "%s: no entry for root\n", F_PASSWD);
-		return &pwd;
-	}
-	if (valid(pwd.pw_passwd)) return &pwd;
-
-	/*
-	 *	The password is invalid. If there is a
-	 *	shadow password, try it.
-	 */
-	strcpy(pwd.pw_passwd, "");
-	if ((fp = fopen(F_SHADOW, "r")) == NULL) {
-		fprintf(stderr, "%s: root password garbled\n", F_PASSWD);
-		return &pwd;
-	}
-	while((p = fgets(sline, 256, fp)) != NULL) {
-		if (strncmp(sline, "root:", 5) != 0)
-			continue;
-		p += 5;
-		set(&pwd.pw_passwd, strsep(&p, ":"));
-		break;
-	}
-	fclose(fp);
-
-	/*
-	 *	If the password is still invalid,
-	 *	NULL it, and return.
-	 */
-	if (p == NULL) {
-		fprintf(stderr, "%s: no entry for root\n", F_SHADOW);
-		strcpy(pwd.pw_passwd, "");
-	}
-	if (!valid(pwd.pw_passwd)) {
-		fprintf(stderr, "%s: root password garbled\n", F_SHADOW);
-		strcpy(pwd.pw_passwd, ""); }
-	return &pwd;
-}
-
-/*
- *	Ask for the password. Note that there is no
- *	default timeout as we normally skip this during boot.
- */
-char *getpasswd(char *crypted)
-{
-	struct sigaction sa;
-	struct termios old, tty;
-	static char pass[128];
-	char *ret = pass;
-	int i;
-
-	if (crypted[0])
-		printf("Give root password for maintenance\n");
-	else
-		printf("Press enter for maintenance\n");
-	printf("(or type Control-D to continue): ");
-	fflush(stdout);
-
-	tcgetattr(0, &old);
-	tcgetattr(0, &tty);
-	tty.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY);
-	tty.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP);
-	tcsetattr(0, TCSANOW, &tty);
-
-	pass[sizeof(pass) - 1] = 0;
-
-	sa.sa_handler = alrm_handler;
-	sa.sa_flags = 0;
-	sigaction(SIGALRM, &sa, NULL);
-	if (timeout) alarm(timeout);
-
-	if (read(0, pass, sizeof(pass) - 1) <= 0)
-		ret = NULL;
-	else {
-		for(i = 0; i < sizeof(pass) && pass[i]; i++)
-			if (pass[i] == '\r' || pass[i] == '\n') {
-				pass[i] = 0;
-				break;
-			}
-	}
-	alarm(0);
-	tcsetattr(0, TCSANOW, &old);
-	printf("\n");
-
-	return ret;
-}
-
-/*
- *	Password was OK, execute a shell.
- */
-void sushell(struct passwd *pwd)
-{
-	char shell[128];
-	char home[128];
-	char *p;
-	char *sushell;
-
-	/*
-	 *	Set directory and shell.
-	 */
-	(void)chdir(pwd->pw_dir);
-	if ((p = getenv("SUSHELL")) != NULL)
-		sushell = p;
-	else if ((p = getenv("sushell")) != NULL)
-		sushell = p;
-	else {
-		if (pwd->pw_shell[0])
-			sushell = pwd->pw_shell;
-		else
-			sushell = BINSH;
-	}
-	if ((p = strrchr(sushell, '/')) == NULL)
-		p = sushell;
-	else
-		p++;
-	snprintf(shell, sizeof(shell), profile ? "-%s" : "%s", p);
-
-	/*
-	 *	Set some important environment variables.
-	 */
-	getcwd(home, sizeof(home));
-	setenv("HOME", home, 1);
-	setenv("LOGNAME", "root", 1);
-	setenv("USER", "root", 1);
-	if (!profile)
-		setenv("SHLVL","0",1);
-
-	/*
-	 *	Try to execute a shell.
-	 */
-	setenv("SHELL", sushell, 1);
-	signal(SIGINT, SIG_DFL);
-	signal(SIGTSTP, SIG_DFL);
-	signal(SIGQUIT, SIG_DFL);
-#ifdef WITH_SELINUX
-	if (is_selinux_enabled > 0) {
-	  security_context_t scon=NULL;
-	  char *seuser=NULL;
-	  char *level=NULL;
-	  if (getseuserbyname("root", &seuser, &level) == 0)
-		  if (get_default_context_with_level(seuser, level, 0, &scon) > 0) {
-			  if (setexeccon(scon) != 0) 
-				  fprintf(stderr, "setexeccon faile\n");
-			  freecon(scon);
-		  }
-		free(seuser);
-		free(level);
-	}
-#endif
-	execl(sushell, shell, NULL);
-	perror(sushell);
-
-	setenv("SHELL", BINSH, 1);
-	execl(BINSH, profile ? "-sh" : "sh", NULL);
-	perror(BINSH);
-}
-
-void usage(void)
-{
-	fprintf(stderr, "Usage: sulogin [-e] [-p] [-t timeout] [tty device]\n");
-}
-
-int main(int argc, char **argv)
-{
-	char *tty = NULL;
-	char *p;
-	struct passwd *pwd;
-	int c, fd = -1;
-	int opt_e = 0;
-	pid_t pid, pgrp, ppgrp, ttypgrp;
-
-	/*
-	 *	See if we have a timeout flag.
-	 */
-	opterr = 0;
-	while((c = getopt(argc, argv, "ept:")) != EOF) switch(c) {
-		case 't':
-			timeout = atoi(optarg);
-			break;
-		case 'p':
-			profile = 1;
-			break;
-		case 'e':
-			opt_e = 1;
-			break;
-		default:
-			usage();
-			/* Do not exit! */
-			break;
-	}
-
-	if (geteuid() != 0) {
-		fprintf(stderr, "sulogin: only root can run sulogin.\n");
-		exit(1);
-	}
-
-	/*
-	 *	See if we need to open an other tty device.
-	 */
-	signal(SIGINT, SIG_IGN);
-	signal(SIGQUIT, SIG_IGN);
-	signal(SIGTSTP, SIG_IGN);
-	if (optind < argc) tty = argv[optind];
-	if (tty) {
-		if ((fd = open(tty, O_RDWR)) < 0) {
-			perror(tty);
-		} else if (!isatty(fd)) {
-			fprintf(stderr, "%s: not a tty\n", tty);
-			close(fd);
-		} else {
-
-			/*
-			 *	Only go through this trouble if the new
-			 *	tty doesn't fall in this process group.
-			 */
-			pid = getpid();
-			pgrp = getpgid(0);
-			ppgrp = getpgid(getppid());
-			ioctl(fd, TIOCGPGRP, &ttypgrp);
-
-			if (pgrp != ttypgrp && ppgrp != ttypgrp) {
-				if (pid != getsid(0)) {
-					if (pid == getpgid(0))
-						setpgid(0, getpgid(getppid()));
-					setsid();
-				}
-
-				signal(SIGHUP, SIG_IGN);
-				ioctl(0, TIOCNOTTY, (char *)1);
-				signal(SIGHUP, SIG_DFL);
-				close(0);
-				close(1);
-				close(2);
-				close(fd);
-				fd = open(tty, O_RDWR);
-				ioctl(0, TIOCSCTTY, (char *)1);
-				dup(fd);
-				dup(fd);
-			} else
-				close(fd);
-		}
-	}
-
-	/*
-	 *	Get the root password.
-	 */
-	if ((pwd = getrootpwent(opt_e)) == NULL) {
-		fprintf(stderr, "sulogin: cannot open password database!\n");
-		sleep(2);
-	}
-
-	/*
-	 *	Ask for the password.
-	 */
-	while(pwd) {
-		if ((p = getpasswd(pwd->pw_passwd)) == NULL) break;
-		if (pwd->pw_passwd[0] == 0 ||
-		    strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd) == 0)
-			sushell(pwd);
-		printf("Login incorrect.\n");
-	}
-
-	/*
-	 *	User pressed Control-D.
-	 */
-	return 0;
-}
-

Copied: sysvinit-upstream/tags/2.87dsf/src/sulogin.c (from rev 1453, sysvinit-upstream/trunk/src/sulogin.c)
===================================================================
--- sysvinit-upstream/tags/2.87dsf/src/sulogin.c	                        (rev 0)
+++ sysvinit-upstream/tags/2.87dsf/src/sulogin.c	2009-07-12 18:00:14 UTC (rev 1458)
@@ -0,0 +1,489 @@
+/*
+ * sulogin	This program gives Linux machines a reasonable
+ *		secure way to boot single user. It forces the
+ *		user to supply the root password before a
+ *		shell is started.
+ *
+ *		If there is a shadow password file and the
+ *		encrypted root password is "x" the shadow
+ *		password will be used.
+ *
+ * Version:	@(#)sulogin 2.85-3 23-Apr-2003 miquels at cistron.nl
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <pwd.h>
+#include <shadow.h>
+#include <termios.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#if defined(__GLIBC__)
+#  include <crypt.h>
+#endif
+
+#ifdef WITH_SELINUX
+#  include <selinux/selinux.h>
+#  include <selinux/get_context_list.h>
+#endif
+
+#define CHECK_DES	1
+#define CHECK_MD5	1
+
+#define F_PASSWD	"/etc/passwd"
+#define F_SHADOW	"/etc/shadow"
+#define BINSH		"/bin/sh"
+#define STATICSH	"/bin/sash"
+
+char *Version = "@(#)sulogin 2.85-3 23-Apr-2003 miquels at cistron.nl";
+
+int timeout = 0;
+int profile = 0;
+
+#ifndef IUCLC
+#  define IUCLC	0
+#endif
+
+#if 0
+/*
+ *	Fix the tty modes and set reasonable defaults.
+ *	(I'm not sure if this is needed under Linux, but..)
+ */
+void fixtty(void)
+{
+	struct termios tty;
+
+	tcgetattr(0, &tty);
+
+	/*
+	 *	Set or adjust tty modes.
+	 */
+	tty.c_iflag &= ~(INLCR|IGNCR|IUCLC);
+	tty.c_iflag |= ICRNL;
+	tty.c_oflag &= ~(OCRNL|OLCUC|ONOCR|ONLRET|OFILL);
+	tty.c_oflag |= OPOST|ONLCR;
+	tty.c_cflag |= CLOCAL;
+	tty.c_lflag  = ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE;
+
+	/*
+	 *	Set the most important characters */
+	 */
+	tty.c_cc[VINTR]  = 3;
+	tty.c_cc[VQUIT]  = 28;
+	tty.c_cc[VERASE] = 127;
+	tty.c_cc[VKILL]  = 24;
+	tty.c_cc[VEOF]   = 4;
+	tty.c_cc[VTIME]  = 0;
+	tty.c_cc[VMIN]   = 1;
+	tty.c_cc[VSTART] = 17;
+	tty.c_cc[VSTOP]  = 19;
+	tty.c_cc[VSUSP]  = 26;
+ 
+	tcsetattr(0, TCSANOW, &tty);
+}
+#endif
+
+
+/*
+ *	Called at timeout.
+ */
+void alrm_handler()
+{
+}
+
+/*
+ *	See if an encrypted password is valid. The encrypted
+ *	password is checked for traditional-style DES and
+ *	FreeBSD-style MD5 encryption.
+ */
+int valid(char *pass)
+{
+	char *s;
+	int len;
+
+	if (pass[0] == 0) return 1;
+#if CHECK_MD5
+	/*
+	 *	3 bytes for the signature $1$
+	 *	up to 8 bytes for the salt
+	 *	$
+	 *	the MD5 hash (128 bits or 16 bytes) encoded in base64 = 22 bytes
+	 */
+	if (strncmp(pass, "$1$", 3) == 0) {
+		for(s = pass + 3; *s && *s != '$'; s++)
+			;
+		if (*s++ != '$') return 0;
+		len = strlen(s);
+		if (len < 22 || len > 24) return 0;
+
+		return 1;
+	}
+#endif
+#if CHECK_DES
+	if (strlen(pass) != 13) return 0;
+	for (s = pass; *s; s++) {
+		if ((*s < '0' || *s > '9') &&
+		    (*s < 'a' || *s > 'z') &&
+		    (*s < 'A' || *s > 'Z') &&
+		    *s != '.' && *s != '/') return 0;
+	}
+#endif
+	return 1;
+}
+
+/*
+ *	Set a variable if the value is not NULL.
+ */
+void set(char **var, char *val)
+{
+	if (val) *var = val;
+}
+
+/*
+ *	Get the root password entry.
+ */
+struct passwd *getrootpwent(int try_manually)
+{
+	static struct passwd pwd;
+	struct passwd *pw;
+	struct spwd *spw;
+	FILE *fp;
+	static char line[256];
+	static char sline[256];
+	char *p;
+
+	/*
+	 *	First, we try to get the password the standard
+	 *	way using normal library calls.
+	 */
+	if ((pw = getpwnam("root")) &&
+	    !strcmp(pw->pw_passwd, "x") &&
+	    (spw = getspnam("root")))
+		pw->pw_passwd = spw->sp_pwdp;
+	if (pw || !try_manually) return pw;
+
+	/*
+	 *	If we come here, we could not retrieve the root
+	 *	password through library calls and we try to
+	 *	read the password and shadow files manually.
+	 */
+	pwd.pw_name = "root";
+	pwd.pw_passwd = "";
+	pwd.pw_gecos = "Super User";
+	pwd.pw_dir = "/";
+	pwd.pw_shell = "";
+	pwd.pw_uid = 0;
+	pwd.pw_gid = 0;
+
+	if ((fp = fopen(F_PASSWD, "r")) == NULL) {
+		perror(F_PASSWD);
+		return &pwd;
+	}
+
+	/*
+	 *	Find root in the password file.
+	 */
+	while((p = fgets(line, 256, fp)) != NULL) {
+		if (strncmp(line, "root:", 5) != 0)
+			continue;
+		p += 5;
+		set(&pwd.pw_passwd, strsep(&p, ":"));
+		(void)strsep(&p, ":");
+		(void)strsep(&p, ":");
+		set(&pwd.pw_gecos, strsep(&p, ":"));
+		set(&pwd.pw_dir, strsep(&p, ":"));
+		set(&pwd.pw_shell, strsep(&p, "\n"));
+		p = line;
+		break;
+	}
+	fclose(fp);
+
+	/*
+	 *	If the encrypted password is valid
+	 *	or not found, return.
+	 */
+	if (p == NULL) {
+		fprintf(stderr, "%s: no entry for root\n", F_PASSWD);
+		return &pwd;
+	}
+	if (valid(pwd.pw_passwd)) return &pwd;
+
+	/*
+	 *	The password is invalid. If there is a
+	 *	shadow password, try it.
+	 */
+	strcpy(pwd.pw_passwd, "");
+	if ((fp = fopen(F_SHADOW, "r")) == NULL) {
+		fprintf(stderr, "%s: root password garbled\n", F_PASSWD);
+		return &pwd;
+	}
+	while((p = fgets(sline, 256, fp)) != NULL) {
+		if (strncmp(sline, "root:", 5) != 0)
+			continue;
+		p += 5;
+		set(&pwd.pw_passwd, strsep(&p, ":"));
+		break;
+	}
+	fclose(fp);
+
+	/*
+	 *	If the password is still invalid,
+	 *	NULL it, and return.
+	 */
+	if (p == NULL) {
+		fprintf(stderr, "%s: no entry for root\n", F_SHADOW);
+		strcpy(pwd.pw_passwd, "");
+	}
+	if (!valid(pwd.pw_passwd)) {
+		fprintf(stderr, "%s: root password garbled\n", F_SHADOW);
+		strcpy(pwd.pw_passwd, ""); }
+	return &pwd;
+}
+
+/*
+ *	Ask for the password. Note that there is no
+ *	default timeout as we normally skip this during boot.
+ */
+char *getpasswd(char *crypted)
+{
+	struct sigaction sa;
+	struct termios old, tty;
+	static char pass[128];
+	char *ret = pass;
+	int i;
+
+	if (crypted[0])
+		printf("Give root password for maintenance\n");
+	else
+		printf("Press enter for maintenance\n");
+	printf("(or type Control-D to continue): ");
+	fflush(stdout);
+
+	tcgetattr(0, &old);
+	tcgetattr(0, &tty);
+	tty.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY);
+	tty.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP);
+	tcsetattr(0, TCSANOW, &tty);
+
+	pass[sizeof(pass) - 1] = 0;
+
+	sa.sa_handler = alrm_handler;
+	sa.sa_flags = 0;
+	sigaction(SIGALRM, &sa, NULL);
+	if (timeout) alarm(timeout);
+
+	if (read(0, pass, sizeof(pass) - 1) <= 0)
+		ret = NULL;
+	else {
+		for(i = 0; i < sizeof(pass) && pass[i]; i++)
+			if (pass[i] == '\r' || pass[i] == '\n') {
+				pass[i] = 0;
+				break;
+			}
+	}
+	alarm(0);
+	tcsetattr(0, TCSANOW, &old);
+	printf("\n");
+
+	return ret;
+}
+
+/*
+ *	Password was OK, execute a shell.
+ */
+void sushell(struct passwd *pwd)
+{
+	char shell[128];
+	char home[128];
+	char *p;
+	char *sushell;
+
+	/*
+	 *	Set directory and shell.
+	 */
+	(void)chdir(pwd->pw_dir);
+	if ((p = getenv("SUSHELL")) != NULL)
+		sushell = p;
+	else if ((p = getenv("sushell")) != NULL)
+		sushell = p;
+	else {
+		if (pwd->pw_shell[0])
+			sushell = pwd->pw_shell;
+		else
+			sushell = BINSH;
+	}
+	if ((p = strrchr(sushell, '/')) == NULL)
+		p = sushell;
+	else
+		p++;
+	snprintf(shell, sizeof(shell), profile ? "-%s" : "%s", p);
+
+	/*
+	 *	Set some important environment variables.
+	 */
+	getcwd(home, sizeof(home));
+	setenv("HOME", home, 1);
+	setenv("LOGNAME", "root", 1);
+	setenv("USER", "root", 1);
+	if (!profile)
+		setenv("SHLVL","0",1);
+
+	/*
+	 *	Try to execute a shell.
+	 */
+	setenv("SHELL", sushell, 1);
+	signal(SIGINT, SIG_DFL);
+	signal(SIGTSTP, SIG_DFL);
+	signal(SIGQUIT, SIG_DFL);
+#ifdef WITH_SELINUX
+	if (is_selinux_enabled > 0) {
+	  security_context_t scon=NULL;
+	  char *seuser=NULL;
+	  char *level=NULL;
+	  if (getseuserbyname("root", &seuser, &level) == 0)
+		  if (get_default_context_with_level(seuser, level, 0, &scon) > 0) {
+			  if (setexeccon(scon) != 0) 
+				  fprintf(stderr, "setexeccon faile\n");
+			  freecon(scon);
+		  }
+		free(seuser);
+		free(level);
+	}
+#endif
+	execl(sushell, shell, NULL);
+	perror(sushell);
+
+	setenv("SHELL", BINSH, 1);
+	execl(BINSH, profile ? "-sh" : "sh", NULL);
+	perror(BINSH);
+
+	/* Fall back to staticly linked shell if both the users shell
+	   and /bin/sh failed to execute. */
+	setenv("SHELL", STATICSH, 1);
+	execl(STATICSH, STATICSH, NULL);
+	perror(STATICSH);
+}
+
+void usage(void)
+{
+	fprintf(stderr, "Usage: sulogin [-e] [-p] [-t timeout] [tty device]\n");
+}
+
+int main(int argc, char **argv)
+{
+	char *tty = NULL;
+	char *p;
+	struct passwd *pwd;
+	int c, fd = -1;
+	int opt_e = 0;
+	pid_t pid, pgrp, ppgrp, ttypgrp;
+
+	/*
+	 *	See if we have a timeout flag.
+	 */
+	opterr = 0;
+	while((c = getopt(argc, argv, "ept:")) != EOF) switch(c) {
+		case 't':
+			timeout = atoi(optarg);
+			break;
+		case 'p':
+			profile = 1;
+			break;
+		case 'e':
+			opt_e = 1;
+			break;
+		default:
+			usage();
+			/* Do not exit! */
+			break;
+	}
+
+	if (geteuid() != 0) {
+		fprintf(stderr, "sulogin: only root can run sulogin.\n");
+		exit(1);
+	}
+
+	/*
+	 *	See if we need to open an other tty device.
+	 */
+	signal(SIGINT, SIG_IGN);
+	signal(SIGQUIT, SIG_IGN);
+	signal(SIGTSTP, SIG_IGN);
+	if (optind < argc) tty = argv[optind];
+	if (tty) {
+		if ((fd = open(tty, O_RDWR)) < 0) {
+			perror(tty);
+		} else if (!isatty(fd)) {
+			fprintf(stderr, "%s: not a tty\n", tty);
+			close(fd);
+		} else {
+
+			/*
+			 *	Only go through this trouble if the new
+			 *	tty doesn't fall in this process group.
+			 */
+			pid = getpid();
+			pgrp = getpgid(0);
+			ppgrp = getpgid(getppid());
+			ioctl(fd, TIOCGPGRP, &ttypgrp);
+
+			if (pgrp != ttypgrp && ppgrp != ttypgrp) {
+				if (pid != getsid(0)) {
+					if (pid == getpgid(0))
+						setpgid(0, getpgid(getppid()));
+					setsid();
+				}
+
+				signal(SIGHUP, SIG_IGN);
+				ioctl(0, TIOCNOTTY, (char *)1);
+				signal(SIGHUP, SIG_DFL);
+				close(0);
+				close(1);
+				close(2);
+				close(fd);
+				fd = open(tty, O_RDWR);
+				ioctl(0, TIOCSCTTY, (char *)1);
+				dup(fd);
+				dup(fd);
+			} else
+				close(fd);
+		}
+	} else if (getpid() == 1) {
+		/* We are init. We hence need to set a session anyway */
+		setsid();
+		if (ioctl(0, TIOCSCTTY, (char *)1))
+			perror("ioctl(TIOCSCTTY)");
+	}
+
+	/*
+	 *	Get the root password.
+	 */
+	if ((pwd = getrootpwent(opt_e)) == NULL) {
+		fprintf(stderr, "sulogin: cannot open password database!\n");
+		sleep(2);
+	}
+
+	/*
+	 *	Ask for the password.
+	 */
+	while(pwd) {
+		if ((p = getpasswd(pwd->pw_passwd)) == NULL) break;
+		if (pwd->pw_passwd[0] == 0 ||
+		    strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd) == 0)
+			sushell(pwd);
+		printf("Login incorrect.\n");
+	}
+
+	/*
+	 *	User pressed Control-D.
+	 */
+	return 0;
+}
+




More information about the Pkg-sysvinit-commits mailing list