[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