Drop hurd specific dependency on libc0.3 (>= 2.3.2.ds1-12). It is
authorPetter Reinholdtsen <pere@hungry.com>
Thu, 10 Sep 2009 08:28:49 +0000 (08:28 +0000)
committerPetter Reinholdtsen <pere@hungry.com>
Thu, 10 Sep 2009 08:28:49 +0000 (08:28 +0000)
no longer needed according to Michael Bunk.  Patch from Michael
Biebl.

git-svn-id: svn://svn.sv.gnu.org/sysvinit/sysvinit/trunk@1 456724a4-4300-0410-8514-c89748c515a2

63 files changed:
COPYING [new file with mode: 0644]
COPYRIGHT [new file with mode: 0644]
README [new file with mode: 0644]
contrib/TODO [new file with mode: 0644]
contrib/alexander.viro [new file with mode: 0644]
contrib/start-stop-daemon.README [new file with mode: 0644]
contrib/start-stop-daemon.c [new file with mode: 0644]
contrib/zefram-patches [new file with mode: 0644]
doc/Changelog [new file with mode: 0644]
doc/Install [new file with mode: 0644]
doc/Propaganda [new file with mode: 0644]
doc/bootlogd.README [new file with mode: 0644]
doc/sysvinit-2.86.lsm [new file with mode: 0644]
man/bootlogd.8 [new file with mode: 0644]
man/bootlogd.8.todo [new file with mode: 0644]
man/halt.8 [new file with mode: 0644]
man/init.8 [new file with mode: 0644]
man/initscript.5 [new file with mode: 0644]
man/inittab.5 [new file with mode: 0644]
man/killall5.8 [new file with mode: 0644]
man/last.1 [new file with mode: 0644]
man/lastb.1 [new file with mode: 0644]
man/mesg.1 [new file with mode: 0644]
man/mountpoint.1 [new file with mode: 0644]
man/pidof.8 [new file with mode: 0644]
man/poweroff.8 [new file with mode: 0644]
man/reboot.8 [new file with mode: 0644]
man/runlevel.8 [new file with mode: 0644]
man/shutdown.8 [new file with mode: 0644]
man/sulogin.8 [new file with mode: 0644]
man/telinit.8 [new file with mode: 0644]
man/wall.1 [new file with mode: 0644]
obsolete/README.RIGHT.NOW [new file with mode: 0644]
obsolete/bootlogd.init [new file with mode: 0755]
obsolete/powerd.8 [new file with mode: 0644]
obsolete/powerd.README [new file with mode: 0644]
obsolete/powerd.c [new file with mode: 0644]
obsolete/powerd.cfg [new file with mode: 0644]
obsolete/utmpdump.c.OLD [new file with mode: 0644]
src/Makefile [new file with mode: 0644]
src/bootlogd.c [new file with mode: 0644]
src/dowall.c [new file with mode: 0644]
src/halt.c [new file with mode: 0644]
src/hddown.c [new file with mode: 0644]
src/ifdown.c [new file with mode: 0644]
src/init.c [new file with mode: 0644]
src/init.h [new file with mode: 0644]
src/initreq.h [new file with mode: 0644]
src/initscript.sample [new file with mode: 0755]
src/killall5.c [new file with mode: 0644]
src/last.c [new file with mode: 0644]
src/mesg.c [new file with mode: 0644]
src/mountpoint.c [new file with mode: 0644]
src/oldutmp.h [new file with mode: 0644]
src/paths.h [new file with mode: 0644]
src/reboot.h [new file with mode: 0644]
src/runlevel.c [new file with mode: 0644]
src/set.h [new file with mode: 0644]
src/shutdown.c [new file with mode: 0644]
src/sulogin.c [new file with mode: 0644]
src/utmp.c [new file with mode: 0644]
src/utmpdump.c [new file with mode: 0644]
src/wall.c [new file with mode: 0644]

diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..d511905
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/COPYRIGHT b/COPYRIGHT
new file mode 100644 (file)
index 0000000..536d712
--- /dev/null
+++ b/COPYRIGHT
@@ -0,0 +1,26 @@
+Sysvinit is Copyright (C) 1991-2004 Miquel van Smoorenburg
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+
+Send patches to sysvinit@savannah.nognu.org
+
+The of the start-stop-daemon
+
+ * A rewrite of the original Debian's start-stop-daemon Perl script
+ * in C (faster - it is executed many times during system startup).
+ *
+ * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
+ * public domain.
+
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..2bb8bff
--- /dev/null
+++ b/README
@@ -0,0 +1,7 @@
+
+contrib                Unofficial stuff
+doc            Documentation, mostly obsolete
+man            Manual pages, not obsolete
+obsolete       Really obsolete stuff ;)
+src            Source code
+
diff --git a/contrib/TODO b/contrib/TODO
new file mode 100644 (file)
index 0000000..6ec1312
--- /dev/null
@@ -0,0 +1,16 @@
+
+There are several things on the wishlist. See also the "wishlist" bugs filed
+against sysvinit in the debian bugs system (http://www.debian.org/Bugs/).
+
+1. A special target for kbrequest, so that extra CHILDs are
+  created (each one needs its own utmp/wtmp bookkeeping)
+2. Extend the initreq.h interface?
+3. Add GNU last long options to last
+
+4. Write all boot messages to a logfile
+   Problem: TIOCCONS ioctl redirects console output, it doesn't copy it.
+   I think this is not easily possible without kernel support.
+   I do not like the idea of booting with a pseudo tty as console and
+   a redirect process behind it writing to both the real console and a
+   logfile - too fragile.
+
diff --git a/contrib/alexander.viro b/contrib/alexander.viro
new file mode 100644 (file)
index 0000000..976d09b
--- /dev/null
@@ -0,0 +1,29 @@
+I proposed moving some stuff to a seperate file, such as the
+re-exec routines. Alexander wrote:
+
+
+According to Alexander Viro <viro@math.psu.edu>:
+> As for the code separation - I think it's nice. Actually, read_inittab()
+> with get_part() and newFamily are also pretty separatable. Another good
+> set is any(), spawn(), startup(), spawn_emerg() and start_if_needed().
+> BTW, fail_check();process_signals(); is equivalent to process_signal();
+> fail_check();. I think that swapping them (in main loop) would be a good
+> idea - then we can move fail_check() into start_if_needed(). And one more
+> - I'ld propose to move start_if_needed to the beginning of the main loop,
+> as in
+>       foo();
+>       while(1) { bar();foo();
+> #if 0
+>               baz();
+> #endif
+>       }
+> to
+>       while(1) { foo();bar();
+> #if 0
+>               baz();
+> #endif
+>       }
+>
+>
+> What do you think about it?
+
diff --git a/contrib/start-stop-daemon.README b/contrib/start-stop-daemon.README
new file mode 100644 (file)
index 0000000..fb69c08
--- /dev/null
@@ -0,0 +1,45 @@
+Start-stop-daemon is the program that is used by the DEBIAN style init
+scripts to start and stop services. This program is part of the "dpkg"
+package by Ian Jackson. However there is also a seperate C version (the
+original is in perl) available written by Marek Michalkiewicz. I'm including
+it for your convinience.
+
+Note that the latest debian dpkg packages (4.0.18 and later) contain
+a much improved update-rc.d. This code is almost a year old.
+
+The original announcement follows:
+
+
+From: Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>
+Message-Id: <199606060324.FAA19493@i17linuxb.ists.pwr.wroc.pl>
+Subject: Fast start-stop-daemon in C
+To: debian-devel@lists.debian.org
+Date: Thu, 6 Jun 1996 05:24:18 +0200 (MET DST)
+
+Some time ago I wrote a faster C replacement for the start-stop-daemon
+perl script.  I use it for some time now (the most recent changes were
+just a nicer help screen; the code is quite stable).
+
+This makes the system boot faster (especially on low end machines),
+and important system startup scripts no longer depend on another big
+package (perl).  Maybe in the future we can get to the point where
+a minimal system will work without perl installed at all (packages
+which need it in {pre,post}{inst,rm} scripts would depend on perl).
+
+The only problem known so far to me is that I have to reinstall this
+program after every dpkg upgrade which overwrites it with that nice
+slooow perl script :-).
+
+Just compile this program and drop the binary in /usr/sbin instead
+of the original /usr/sbin/start-stop-daemon perl script (make a copy
+of it first, just in case).  See below for source code.  I placed it
+in the public domain, but if it has to be GPL-ed to be included in
+dpkg, just tell me.  Including it in dpkg would close Bug#1670.
+
+I am posting it here so that it can be tested by more people than
+just me.  Bugs are unlikely though.
+
+Have fun,
+
+Marek
+
diff --git a/contrib/start-stop-daemon.c b/contrib/start-stop-daemon.c
new file mode 100644 (file)
index 0000000..ce286a2
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ * A rewrite of the original Debian's start-stop-daemon Perl script
+ * in C (faster - it is executed many times during system startup).
+ *
+ * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
+ * public domain.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <pwd.h>
+
+#define VERSION "version 0.3, 1996-06-05"
+
+static int testmode = 0;
+static int quietmode = 0;
+static int exitnodo = 1;
+static int start = 0;
+static int stop = 0;
+static int signal_nr = 15;
+static int user_id = -1;
+static const char *userspec = NULL;
+static const char *cmdname = NULL;
+static char *execname = NULL;
+static char *startas = NULL;
+static const char *pidfile = NULL;
+static const char *progname = "";
+
+static struct stat exec_stat;
+
+struct pid_list {
+       struct pid_list *next;
+       int pid;
+};
+
+static struct pid_list *found = NULL;
+static struct pid_list *killed = NULL;
+
+static void *xmalloc(int size);
+static void push(struct pid_list **list, int pid);
+static void do_help(void);
+static void parse_options(int argc, char * const *argv);
+static int pid_is_exec(int pid, const struct stat *esb);
+static int pid_is_user(int pid, int uid);
+static int pid_is_cmd(int pid, const char *name);
+static void check(int pid);
+static void do_pidfile(const char *name);
+static void do_procfs(void);
+static void do_stop(void);
+
+#ifdef __GNUC__
+static void fatal(const char *format, ...)
+       __attribute__((noreturn, format(printf, 1, 2)));
+static void badusage(const char *msg)
+       __attribute__((noreturn));
+#else
+static void fatal(const char *format, ...);
+static void badusage(const char *msg);
+#endif
+
+static void
+fatal(const char *format, ...)
+{
+       va_list arglist;
+
+       fprintf(stderr, "%s: ", progname);
+       va_start(arglist, format);
+       vfprintf(stderr, format, arglist);
+       va_end(arglist);
+       putc('\n', stderr);
+       exit(2);
+}
+
+
+static void *
+xmalloc(int size)
+{
+       void *ptr;
+
+       ptr = malloc(size);
+       if (ptr)
+               return ptr;
+       fatal("malloc(%d) failed", size);
+}
+
+
+static void
+push(struct pid_list **list, int pid)
+{
+       struct pid_list *p;
+
+       p = xmalloc(sizeof(*p));
+       p->next = *list;
+       p->pid = pid;
+       *list = p;
+}
+
+
+static void
+do_help(void)
+{
+       printf("\
+start-stop-daemon for Debian Linux - small and fast C version written by\n\
+Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, public domain.\n"
+VERSION "\n\
+\n\
+Usage:
+    start-stop-daemon -S|--start options ... -- arguments ...\n\
+    start-stop-daemon -K|--stop options ...\n\
+    start-stop-daemon -H|--help\n\
+    start-stop-daemon -V|--version\n\
+\n\
+Options (at least one of --exec|--pidfile|--user is required):
+    -x|--exec <executable>       program to start/check if it is running\n\
+    -p|--pidfile <pid-file>      pid file to check\n\
+    -u|--user <username>|<uid>   stop this user's processes\n\
+    -n|--name <process-name>     stop processes with this name\n\
+    -s|--signal <signal>         signal to send (default 15)\n\
+    -a|--startas <pathname>      program to start (default <executable>)\n\
+    -t|--test                    test mode, don't do anything\n\
+    -o|--oknodo                  exit status 0 (not 1) if nothing done\n\
+    -q|--quiet  |  -v, --verbose\n\
+\n\
+Exit status:  0 = done  1 = nothing done (=> 0 if --oknodo)  2 = trouble\n");
+}
+
+
+static void
+badusage(const char *msg)
+{
+       if (msg && *msg)
+               fprintf(stderr, "%s: %s\n", progname, msg);
+       fprintf(stderr, "Try `%s --help' for more information.\n", progname);
+       exit(2);
+}
+
+
+static void
+parse_options(int argc, char * const *argv)
+{
+       static struct option longopts[] = {
+               { "help",       0, NULL, 'H'},
+               { "stop",       0, NULL, 'K'},
+               { "start",      0, NULL, 'S'},
+               { "version",    0, NULL, 'V'},
+               { "startas",    1, NULL, 'a'},
+               { "name",       1, NULL, 'n'},
+               { "oknodo",     0, NULL, 'o'},
+               { "pidfile",    1, NULL, 'p'},
+               { "quiet",      0, NULL, 'q'},
+               { "signal",     1, NULL, 's'},
+               { "test",       0, NULL, 't'},
+               { "user",       1, NULL, 'u'},
+               { "verbose",    0, NULL, 'v'},
+               { "exec",       1, NULL, 'x'},
+               { NULL,         0, NULL, 0}
+       };
+       int c;
+
+       for (;;) {
+               c = getopt_long(argc, argv, "HKSVa:n:op:qs:tu:vx:",
+                               longopts, (int *) 0);
+               if (c == -1)
+                       break;
+               switch (c) {
+               case 'H':  /* --help */
+                       do_help();
+                       exit(0);
+               case 'K':  /* --stop */
+                       stop = 1;
+                       break;
+               case 'S':  /* --start */
+                       start = 1;
+                       break;
+               case 'V':  /* --version */
+                       printf("start-stop-daemon " VERSION "\n");
+                       exit(0);
+               case 'a':  /* --startas <pathname> */
+                       startas = optarg;
+                       break;
+               case 'n':  /* --name <process-name> */
+                       cmdname = optarg;
+                       break;
+               case 'o':  /* --oknodo */
+                       exitnodo = 0;
+                       break;
+               case 'p':  /* --pidfile <pid-file> */
+                       pidfile = optarg;
+                       break;
+               case 'q':  /* --quiet */
+                       quietmode = 1;
+                       break;
+               case 's':  /* --signal <signal> */
+                       if (sscanf(optarg, "%d", &signal_nr) != 1)
+                               badusage("--signal takes a numeric argument");
+                       break;
+               case 't':  /* --test */
+                       testmode = 1;
+                       break;
+               case 'u':  /* --user <username>|<uid> */
+                       userspec = optarg;
+                       break;
+               case 'v':  /* --verbose */
+                       quietmode = -1;
+                       break;
+               case 'x':  /* --exec <executable> */
+                       execname = optarg;
+                       break;
+               default:
+                       badusage("");  /* message printed by getopt */
+               }
+       }
+
+       if (start == stop)
+               badusage("need one of --start or --stop");
+
+       if (!execname && !pidfile && !userspec)
+               badusage("need at least one of --exec, --pidfile or --user");
+
+       if (!startas)
+               startas = execname;
+
+       if (start && !startas)
+               badusage("--start needs --exec or --startas");
+}
+
+
+static int
+pid_is_exec(int pid, const struct stat *esb)
+{
+       struct stat sb;
+       char buf[32];
+
+       sprintf(buf, "/proc/%d/exe", pid);
+       if (stat(buf, &sb) != 0)
+               return 0;
+       return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino);
+}
+
+
+static int
+pid_is_user(int pid, int uid)
+{
+       struct stat sb;
+       char buf[32];
+
+       sprintf(buf, "/proc/%d", pid);
+       if (stat(buf, &sb) != 0)
+               return 0;
+       return (sb.st_uid == uid);
+}
+
+
+static int
+pid_is_cmd(int pid, const char *name)
+{
+       char buf[32];
+       FILE *f;
+       int c;
+
+       sprintf(buf, "/proc/%d/stat", pid);
+       f = fopen(buf, "r");
+       if (!f)
+               return 0;
+       while ((c = getc(f)) != EOF && c != '(')
+               ;
+       if (c != '(') {
+               fclose(f);
+               return 0;
+       }
+       /* this hopefully handles command names containing ')' */
+       while ((c = getc(f)) != EOF && c == *name)
+               name++;
+       fclose(f);
+       return (c == ')' && *name == '\0');
+}
+
+
+static void
+check(int pid)
+{
+       if (execname && !pid_is_exec(pid, &exec_stat))
+               return;
+       if (userspec && !pid_is_user(pid, user_id))
+               return;
+       if (cmdname && !pid_is_cmd(pid, cmdname))
+               return;
+       push(&found, pid);
+}
+
+
+static void
+do_pidfile(const char *name)
+{
+       FILE *f;
+       int pid;
+
+       f = fopen(name, "r");
+       if (f) {
+               if (fscanf(f, "%d", &pid) == 1)
+                       check(pid);
+               fclose(f);
+       }
+}
+
+
+static void
+do_procfs(void)
+{
+       DIR *procdir;
+       struct dirent *entry;
+       int foundany, pid;
+
+       procdir = opendir("/proc");
+       if (!procdir)
+               fatal("opendir /proc: %s", strerror(errno));
+
+       foundany = 0;
+       while ((entry = readdir(procdir)) != NULL) {
+               if (sscanf(entry->d_name, "%d", &pid) != 1)
+                       continue;
+               foundany++;
+               check(pid);
+       }
+       closedir(procdir);
+       if (!foundany)
+               fatal("nothing in /proc - not mounted?");
+}
+
+
+static void
+do_stop(void)
+{
+       char what[1024];
+       struct pid_list *p;
+
+       if (cmdname)
+               strcpy(what, cmdname);
+       else if (execname)
+               strcpy(what, execname);
+       else if (pidfile)
+               sprintf(what, "process in pidfile `%s'", pidfile);
+       else if (userspec)
+               sprintf(what, "process(es) owned by `%s'", userspec);
+       else
+               fatal("internal error, please report");
+
+       if (!found) {
+               if (quietmode <= 0)
+                       printf("no %s found; none killed.\n", what);
+               exit(exitnodo);
+       }
+       for (p = found; p; p = p->next) {
+               if (testmode)
+                       printf("would send signal %d to %d.\n",
+                              signal_nr, p->pid);
+               else if (kill(p->pid, signal_nr) == 0)
+                       push(&killed, p->pid);
+               else
+                       printf("%s: warning: failed to kill %d: %s\n",
+                              progname, p->pid, strerror(errno));
+       }
+       if (quietmode < 0 && killed) {
+               printf("stopped %s (pid", what);
+               for (p = killed; p; p = p->next)
+                       printf(" %d", p->pid);
+               printf(").\n");
+       }
+}
+
+
+int
+main(int argc, char **argv)
+{
+       progname = argv[0];
+
+       parse_options(argc, argv);
+       argc -= optind;
+       argv += optind;
+
+       if (execname && stat(execname, &exec_stat))
+               fatal("stat %s: %s", execname, strerror(errno));
+
+       if (userspec && sscanf(userspec, "%d", &user_id) != 1) {
+               struct passwd *pw;
+
+               pw = getpwnam(userspec);
+               if (!pw)
+                       fatal("user `%s' not found\n", userspec);
+
+               user_id = pw->pw_uid;
+       }
+
+       if (pidfile)
+               do_pidfile(pidfile);
+       else
+               do_procfs();
+
+       if (stop) {
+               do_stop();
+               exit(0);
+       }
+
+       if (found) {
+               if (quietmode <= 0)
+                       printf("%s already running.\n", execname);
+               exit(exitnodo);
+       }
+       if (testmode) {
+               printf("would start %s ", startas);
+               while (argc-- > 0)
+                       printf("%s ", *argv++);
+               printf(".\n");
+               exit(0);
+       }
+       if (quietmode < 0)
+               printf("starting %s ...\n", startas);
+       *--argv = startas;
+       execv(startas, argv);
+       fatal("unable to start %s: %s", startas, strerror(errno));
+}
+
diff --git a/contrib/zefram-patches b/contrib/zefram-patches
new file mode 100644 (file)
index 0000000..9bdf98a
--- /dev/null
@@ -0,0 +1,120 @@
+Date: Mon, 14 Apr 1997 15:39:08 +0100 (BST)
+From: Zefram <zefram@dcs.warwick.ac.uk>
+Message-Id: <25042.199704141439@stone.dcs.warwick.ac.uk>
+Subject: SysVinit patch
+To: miquels@drinkel.cistron.nl
+
+Hi.  Enclosed is a patch for SysVinit that I am finding tiresome to
+keep updating; you might like to fold it into your official releases.
+It does the following:
+
+* shutdown: use /etc/shutdown.allow if an option -s is given instead
+  of testing for a controlling tty.  The tty check was inflexible and
+  unreliable.
+
+* sulogin(8): refer to inittab(5) instead of inittab(4).
+
+* sulogin: use libc passwd/shadow functions instead of home-grown ones
+  (there's just no point in using the special version).
+
+* shutdown/sulogin: don't rely on the username "root" -- it's the UID
+  that counts.
+
+-zefram
+
+begin 644 initdiffs.gz
+M'XL(``IG43,"`^T[:U/;R+*?E5_1>&L3&\G&#Y[FD%H")/%9)U"8G-0](44)
+M>62KD"6M1K+7)YO_?KM[1K)DFP"[V:T]=2^5`FFFIZ??W=.C##W7A;H3@YS+
+MJ1=X2;W=V#W8DN,T&8:SH+%?GC`+,\\V-S?O76:\CCWX9QI`:QO_=3N[W68;
+M6@<'N\_J]?K].(T!+CF.8FAUH-WI-G>Z.QU:MD>;%7]X\U;+:NT!OP(T7L&6
+MO/6"'!N-7;Z"3W!=3^BY=PE2./#YV48^'M^-`\?%(9J&Q)L(7M3#R9D=!UXP
+MJD^$E/9(*)CKRM>O7YD#M34^U?_0UO*I>Z\3P^Z!M;>MQ$"DX>M^*R--_!KY
+M-DHZC.>0H0L#2,8"G'`RL8,A^%X@<,!.8.;Y/MP*I#5((`G!]GU$D4H1R\:"
+M!),>OGSY`E"7]-*[@&OWU75=7KL7^'X6R#36"&U>#'::C,/8DV)(6$E(0%)B
+M*M`4$C$!3X(?CD8(X04-Q'(UQA'\%X3Q!,F8$Z(AS,8BH,TR.>..!.0@!,[>
+MSFF.[`K'J_LU"_'PBI,D]NO'?E(_%3[!1S%*0@P;``,A%!7"2;R0</>.'0=G
+MX20,DCCT%4^WP@]GX(8Q3$+DS0M<(HM6-)0X2"Z0RR53)DNF1V^$!N`C$:,E
+MP/:^WJJ;.U9K8=?(TLG59;]^W+^JGY[UB64;:=`\6,2U$PLD)AB!'8`=17$8
+MQ9Z="$`UHMJ]@+'TMD3B;)%T$OL6L324C"?"#J32EIB*>!ZB,<S&(8QME--X
+M+CT4+M@L$T2#Q"O3"63H"[@3\]O0CH>H@4#IM:!2YA"N0B)URA:%^UGH`DL*
+MI+7.6#AW+!I4B.<R(\IH_H.*92,J6@B:,.(A4D.7MYQZ<9(BH9HPV8">>[^A
+MN'$X*9@*T>0EB@99(((0NQZRF0DOUQNB"6<:)RD"N2,'Z3'_`7E6A#J2C`&)
+M1H(#&[V/*&=),]:9EXP5A"<38B028>23X2C?B46)872F)2ZAJAGI;4WM>"M.
+M@ZTTF41(5ZT!YX$_)[[<A9A"*9:E*DD,:-9Q&"::GWQ/BX1"(0'1H$TY@CSF
+M'`F.9^C*V23,8B]13J3C"UF^C*!%?P-767`FN2XZ]"H-^9;D)BJZMJU6>SL+
+M8O_O`FM=@#1+;O![7"`W/H10D1L11131K/^[OE"2+QLWBF+5]%6X^%.,?_A`
+M.>;<6SHYWRK''.,J%7"<CJBN:C6[.[O=UL'#Y9CSM'+LP&H5RA!\V\D<&#8-
+M`\L%E,`P1"$D,"(GBL-T-`;:&&ZY)""QAFDLA3\57''H=4Z7/,3!Y$U.X:.K
+M#^>`*J8BJ9!,<_B$\KG$S81OSS%Y)S.!ECCHO;DZNWP'5//@\\^]?I]3.A%`
+M:5POQG43^PY=F*J8A1/*=4ZH]N1?*%V"ZQKOO%]2I'2*2P>3$,N%X#:-1Q9,
+M>%S^-(R]X$[X#0<M/<8"(O`5DG42W6M:>[M9(3`-/2(!C:Q:P]<OM,S%,!<D
+M;E4F0Q''%%F,R@<"Z5XGD(L&/M7OXK$;.)_Q20GG,Q<I\$F7FIGY?KX.*HC7
+MJ%PGA*!^UP7^&8;!BP10\%2*96@M="=\)12-I76Q7A>+6\PL8+L)2B[7U!+P
+M6`./;7\M*%G37LO:R^OM[R`)^=\IBK5&LF_M=Q9^MX?E?^YX.>(@IW[9_ZXK
+M7`95V`=QG,5$[(%KRV290$?CR?QQU0V7%JSWQ4S6Y(MW%$BE-PILGQ>;B\52
+M[_9XARSOCM+A'%?A&KR">6243B@/4];'O6TZ%VU`E6J$ZTJ`>:Q2PT6(I'9(
+M1H7')R^IMOAE_=FKO;MOM?<*XF^CS[;1:;/(AT1A:/.&08A$PA$T#_-1+</2
+M6(26S0.F'D#I$=\YT.M>_PPVW4B].6,[ADV2.R>33YWVY\+$;>I^:K7W<6@M
+MZ?O;5J=SD(47XI!^8U1RHGF5<-[X6+7X%E1:2A[/ZCB_M<FG)DRF,X%V.D6=
+M4!*FPY)/*D6;G7BD2]C<X@4(64V<D4BB41Q5FS78.(+LK0;/G_,+\HTO1T?0
+MPA%>1C]5-T+.W3`2075P>MSOGW]$:N)*C9&\_]#OU]#[ZT28@72]#]=28A&E
+M,X%2+-;_'/85C8:GY*NP7&)Z@34U3@8\&V/%4G61:EE%"5N`(K8P_M04+89!
+M#)/HFY^)H1<_O(#??H/"P'7PHL:$>D$J#O,E'KR$3FMY!C-459(4$,$A;,KH
+M$&1DFC46ZR;-9!CY1;-A+$S",TW<EM0Z3".BJ\807YEOWO8?T&G7H+#B<X['
+M=7RLE%`-O"@7\PP=V+_+0TBIY**BT?6HKY"74JJ#4!+?!HW=A'>D_RH&'C:)
+M-$'?K*Y3KK&PND1W!G1O@<LS/*]S4?BODVP79BU-ZB_3Y":91X)0?AB<7=Y<
+M7)Z?G`T&RV*6.GVP0BM;0S'=^E%6+-`HJ$=26ZA*)G:B0)_+I(8";*Y3*((U
+M9'(3(S)X#LU?7[\^4=;?_+6YW5Q:DG%Y24F"V/-G]ES"^<\ECL@Y)U'&&`F`
+M_`&75-AYFID)&EJ\IJG(,6XQHM^IYZ_?D"F55VCJ.K3F6Y,1*A\!92ZDMJ+!
+MX#C:I-J*Z-Q`0@.BM`B42U/1_>'JYOWQN[-![]]GN>NL$EZD7!DM_Q+!4%M+
+MP3`U-VP7,UMFO.1>3H1I_$5?+4:9D_/W@_/^&4IUMA)EJ#S,ZPPW0ICK^)&U
+M?>,Z5DDEPU+R*\V8D6<;S26%9&0.5-2]T)9.&4T=U91/T;1RJJJC_`AGJYCJ
+M'(L2WA3I='[!JB=PYTEWU/6ZFK&S\]<U53N!(?$`YHRK#C-*66Q_SVH?M%46
+M6Y<\.GMMJ[/?7N2]3GL'!_(C.RN+_RP2"<<_(AVIPN=#-:_UBUG?<&P\E;V0
+M+[HJR7#BFX1#05S2O)$GPY9:D"UF'HRA<.W43[KZU=`58C:M@0WU^E6G/!,X
+MU>*&IV'6"DSQ5#<GIPA&#;6WRF)Z>PI9CTI,)EOE1_&">X99*B>.+)#A@U7-
+M)B'`DT7IY*O/NPU0D6(8"LD5':X/J27I<%VJ?C($O^!!V7/G%J%@&7LJQ#AT
+M@D9HW#X-T*ZG:$2TD^TX81HDFO<L.YH/9T?S@>QH/CT[FO=F1_/W94?SP>QH
+MDG68#V5'LYP=V8[^8'8TGYP=U:Y/RX[FT[*C^>CL:#XJ.V90&X.;WN#D[:7.
+MDN05M75P3\BB]TMC35XSGY#7S#^2U\SEO&86\YJI0F5F<\6\EIO4M_*:N9K7
+MS"?E-?.[Y#5S-:^9H!E;Y#7-I8Z[.J]Q1*%S3^BNG"95J6ZK)J'.=<NL#4XO
+M>J=KHB\&>5?B&4OS].,0#?8Y[H-TW-=F2[E!N>;2,YM8UV3+YOC*<R`B@%WJ
+ML37;W>W._3VV?-636FS[>8L-H#%X"Z=G@Y/+WL55[_R]ND?4>/&%+#^8AG>E
+MB['J?HU:M7PK5NA3CT)NR%*[%Z6/HF93(Y=\1J=C[47#D"\*551#E\IZZ]1U
+MU4WUZG9-M5QQOYZZ74%KE2$U<F-/<$=9_(IY,.%.LJ8V)TGEI<B6?%6HN]/4
+MJ0?7MT>(A,V!)JB7,@GY8A.J8F1!O]<_K_$MY86Z0V!191>T?T=1[?PM1/6`
+M*SCW&:[S#5=PC(](U#]3']K;T-KIMMK=SNZ#KN`8[T+M"MO01`=J=EO?<(7V
+M-E:HA;[+MM5I9OK^P0L</\7"\1^N$R1^8_RR-*B;34NCT6Q(0V81<&QC%%H&
+MY+Y"*%>PSN66%SJ+[5RXN7GS_L--O_?J\OCR?VYNX.41[*XOISO6=C-S[!^P
+MD*4[^9.W9R<_WZ#=&JV5T7>G.SR*YX-LXN)X,/AX:E2X."/#F`TKA>G!V^/3
+M\X]Z6C%6*:!]U7L_>(NSZC,&FGF6M9?^A2&?+L>/H/)3]8>:UA>T&GO0VJ^C
+MFNND6G@W'30JA^HP@,HXN/_P0"5A>]%Y^JHVV]JD(\^F,1#TX0`639Y]Z^>7
+M3U/;3X7Z(B#A$-]@:#K8<3M8BJ2JR-W$I98F'5?1J?1+=ORC=QJ-D1E\II.6
+M/@YOJ3:^\4:H&SPZ5+-[S<)XJ/Q7=?LI"6$5D#IZ>@B;6)P1>#3CQ,T=Z0T\
+M4R54CB_!HI$=TN2BC;>`9)*IEOK4WMG]O#(CRU.*0>X#4JIC^K'8-UY3.S7$
+MHE&&$P'Z3,37;?9P2AW'A@+<(B1D\]'LAF[D2+W<23@L3&BJ<:HT/!).*&ET
+MD$88_3Y@""S-#ST2<&6K-"C'PO=74*59P[.`?3%$H\OY7MEYEO"/%@D?80TD
+M)\:B3L'4&*L18^T<!YC[2?;ZZ$<3*+(-+3(LR%GAGHKUN=ZI[F@H*):7/F<S
+M,7S$(9U8@$K19YR-,CFZ9\,EHP)E&7>Q%-E116R-X8Q%$<M<@'D$.^J9#/MY
+M21T6V904$0XC/CK.*\@J.4)M:>[!J2)^UNM]Z(N`J.#'@+'*RX!4+M8R+H_8
+MW-6;KH<W2#\;Y;/51EE=/1411.#$\RC!3).K"\,#>K4WU("8\"A:N'B81:$I
+M,RAJD[03+5O0TD42%HZ2BV"5PMWL8XD`57B_E65<Z)CC#:LE#:*A+!EER86O
+MBB:HBA/"P3?Z=`G-<=#6P"J4Y_`6<*61%+U<M_27C*BB+6"EGN9$<8]_K95.
+M.59J:A\IH16/DD]P*?FG^]23K;*H-YGP-P1*'I:&(UY0/Q;??7U_FU3:RWSQ
+MFXK/+71CO8G^+HT_<G_@S9><8%$(<"H^EG?,6U&L#7@?)OKKPMP5@E`MT,F.
+M[W,I`^)1>286GQ#*.R]2+8%A&M,IDRKC+*EOZ(J!+J.8SOQJV=`97)=]$/KD
+M9,G\4,TM$C2M^]3:58U-A0T91,.F"1ZD"SWO4*<?+=?*&V^Z7&[PEX8V3HN`
+M,G9V'YDOJ9)4J&^COU*LG_(2Q2F:G1TG:53K@E[FNGXJQZ1!E(J^R:.OK-I[
+M5FL_OZI<DOZ?7`BAKK(XL(1D:5A&-"C7Q<DGE3IJP_75SF)NN>!9S-Q;\RQ`
+MRF7/8GRI\EE,%(N?PDYKZI^(B2+CG.&B:O,1D?G$I@\5N-EHPX?>*30S$;,2
+ME5$5XW*FDE*)!`]GVSRU%D)8'E'J+]=DO;\BZ97W5G</S47"D[E$980&D9-*
+MQE$0[GK17A0=]4=9"H`E1+R?\"4?8[(X*QE$1C?X%Q/<NBU4`JL,RFP^?CN5
+M\4H2H"YW<>/#0@#^6\9?]<Y\_961^$?YK3AL@1;T=XW&:_L;!WM6IYEW^PP5
+M<`V4CX/"&6/$LV!W6Z'$>D8$TVKE[?F[,R113;:4.61S_?,WU):N9!?&*P!T
+M`;`T6T`]>'O6[^.P3'51K^:U"ZL.S+;5WLG_Y\%W)+AHX_>1O0KS:.+7-F3V
+M]ZW.P4XN_3Q,K76*0MA1]6RK6*UR<5NH*PJA.[^_5)!K8A8&+?CM-X;(OL[!
+MPI=C<35:L*TC[,J`^BI`W;1J[FF7FN[3=':LSO9"94_D<HFQ<@C5+?B_G*__
+)!9>7)7O2-```
+`
+end
+
diff --git a/doc/Changelog b/doc/Changelog
new file mode 100644 (file)
index 0000000..0b4864a
--- /dev/null
@@ -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@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@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@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@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@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@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@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@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@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@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@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@starclass.com>)
+
+ -- Miquel van Smoorenburg <miquels@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@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@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@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@vicnet.net.au> for "last" -i option
+
+ -- Miquel van Smoorenburg <miquels@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@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@emufarm.ml.org>
+
+ -- Miquel van Smoorenburg <miquels@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@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@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@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@zeta.org.au> and
+    David Parrish <dparrish@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@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@ferret.lmh.ox.ac.uk>
+
+ -- Miquel van Smoorenburg <miquels@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@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@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@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@cistron.nl>  Wed, 22 Oct 1997 14:44:00 +0200
+
+sysvinit (2.72) unstable; urgency=low
+
+  * Applied manual page patches by Bill Hawes <whawes@star.net>.  Thanks Bill!
+  * Applied patches to the sample Slackware scripts by
+    "Jonathan I. Kamens" <jik@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@CS.Technion.AC.IL>)
+  * Compress all manpages (missed 2)
+  * Compiled for libc6
+  * Added poweroff patch by Roderich Schupp <rsch@ExperTeam.de>
+
+ -- Miquel van Smoorenburg <miquels@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@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@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@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@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@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@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@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@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.
+
diff --git a/doc/Install b/doc/Install
new file mode 100644 (file)
index 0000000..05f23a2
--- /dev/null
@@ -0,0 +1,56 @@
+
+    README for the System V style init, version 2.86
+
+init, shutdown, halt, reboot, wall, last, mesg, runlevel,
+killall5, pidof, sulogin.
+
+All programs, files and scripts in this package are covered by
+the Gnu Public License, and copyrighted by me.
+
+If you are not using Debian and the debianized package,
+you will have to install the new init by hand. You should
+be able to drop the binaries into a Slackware or Redhat
+system, I think.
+
+Here is a list of preferred directories to install the progs & manpages:
+
+wall.1, last.1, mesg.1    /usr/man/man1
+inittab.5, initscript.5           /usr/man/man5
+init.8, halt.8, reboot.8,
+shutdown.8, powerd.8,
+killall5.8, pidof.8,
+runlevel.8, sulogin.8     /usr/man/man8
+
+init                      /sbin/init
+inittab                           /etc/inittab
+initscript.sample          /etc/initscript.sample
+telinit                           a link (with ln(1) ) to init, either
+                          in /bin or in /sbin.
+halt                      /sbin/halt
+reboot                    a link to /sbin/halt in the same directory
+killall5                  /sbin/killall5
+pidof                     a link to /sbin/killall5 in the same directory.
+runlevel                  /sbin/runlevel
+shutdown                  /sbin/shutdown.
+wall                      /usr/bin/wall
+mesg                      /usr/bin/mesg
+last                      /usr/bin/last
+sulogin                           /sbin/sulogin
+bootlogd                  /sbin/bootlogd
+utmpdump                   don't install, it's just a debug thingy.
+
+If you already _have_ a "wall" in /bin (the SLS release had, for example)
+do _not_ install this wall. Chances are that the wall you are already
+using is linked to /bin/write. Either first _remove_ /bin/wall before
+installing the new one, or don't install the new one at all.
+
+You might want to create a file called "/etc/shutdown.allow". Read the
+manual page on shutdown to find out more about this.
+
+Running from a read-only file system (CDROM?):
+o All communication to init goes through the FIFO /dev/initctl.
+  There should be no problem using a read-only root file system
+  IF you use a Linux kernel > 1.3.66. Older kernels don't allow
+  writing to a FIFO on a read-only file system.
+  
+Miquel van Smoorenburg <miquels@cistron.nl>
diff --git a/doc/Propaganda b/doc/Propaganda
new file mode 100644 (file)
index 0000000..072aa13
--- /dev/null
@@ -0,0 +1,81 @@
+
+
+       Propaganda for version 2.58 of sysvinit & utilities
+       ==================================================
+
+NOTE: If you use a standard distribution like Slackware, Debian
+or Redhat there probably is no need to upgrade. Installing sysvinit
+is only for those that upgrade their system by hand or for people
+that create Linux distributions.
+
+Sysvinit is probably the most widely used init package for Linux.
+Most distributions use it. sysvinit 2.4 is really a good package,
+and it was not the need for bugfixes but the need for more features
+that made me work on sysvinit again.
+
+Sysvinit is now a debian package. Debian source packages are not
+special in any way -- in fact you can just unpack and compile
+it on any other Linux distribution.
+
+There was a 2.50 release of sysvinit but that was not very popular-
+some of the included scripts broke with certain shells and other
+minor things like that. Unfortunately I was not able to fix this
+at the time because I was abroad for some time. Therefore the
+description below is a comparison of 2.4 and 2.58 (actually the
+same blurb as from the 2.50 announce but updated).
+
+Wrt 2.4, some of the code has been made simpler. Everything, from
+halt to reboot to single user mode is now done by shell scripts
+that are executed directly by init (from /etc/inittab), so shutdown
+does not kill processes anymore and then calls reboot - it merely
+does some wall's to the logged in users and then switches to
+runlevel 0 (halt), 1 (single user) or 6 (reboot).
+
+I have removed support for the old style scripts; the included
+example scripts are the Debian GNU/Linux distribution scripts.
+This does not mean that eg the Slackware scripts stop to work;
+you can probably drop this init into Slackware 3.0 without problems.
+
+Most people have an entry in inittab to run shutdown when CTRL-ALT-DEL
+is pressed; a feature has been added to shutdown to check if a
+authorized user is logged in on one of the consoles to see if a
+shutdown is allowed. This can be configured with an access file.
+
+Some other general changes:
+- utility "runlevel" to read the current and previous runlevel from
+  /var/run/utmp (it's also shown on the command line if you do a "ps").
+- unreckognized options are silently ignored (such as the infamous
+  "ro" - mount root file system read only).
+- if the file /etc/initscript is present it will be used to launch
+  all programs that init starts (so that you can set a generic
+  umask, ulimit eg for ALL processes - see initscript.sample).
+- A "sulogin" program added that always asks for the root
+  passsword before entering single user mode.
+- A "-b" flag to init that starts a shell at boot time before
+  _any_ other processing.
+- I moved /etc/fastboot to /fastboot - wonder what that's gonna break :)
+- I even updated the manpages!
+
+Right, now some boring stuff you already know since it's the same
+as in the 2.4 release:
+
+The sysvinit package includes
+
+* a sysv compatible /sbin/init program
+* a telinit program (er, just a link to /sbin/init) to change runlevels
+* a featureful shutdown
+* halt and reboot to assist shutdown
+* a very forgiving last utility
+* the wall & mesg programs (not installed by default)
+* manpages for everything
+
+The new sysv init can be found on:
+
+tsx-11.mit.edu:/pub/linux/sources/sbin as sysvinit-2.58-1.tar.gz
+sunsite.unc.edu:/pub/Linux/system/Daemons as sysvinit-2.58-1.tar.gz
+
+It will be moved there in a few days, in the mean time it is
+probably in the Incoming directory.
+
+Mike. (02-Jan-1996)
+
diff --git a/doc/bootlogd.README b/doc/bootlogd.README
new file mode 100644 (file)
index 0000000..52f9638
--- /dev/null
@@ -0,0 +1,19 @@
+
+bootlogd: a way to capture all console output during bootup
+          in a logfile.
+
+- bootlogd opens /dev/console and finds out what the real console is
+  with an ioctl() if TIOCCONS is available
+- otherwise bootlogd tries to parse /proc/cmdline for console=
+  kernel command line arguments
+- then opens the (most probable) real console
+- allocates a pty pair
+- redirects console I/O to the pty pair
+- then goes in a loop reading from the pty, writing to the real
+  console and a logfile as soon as a r/w partition is available,
+  buffering in memory until then.
+
+As soon as bootlogd exits or gets killed, the pty is closed and the
+redirection will be automatically undone by the kernel. So that's
+pretty safe.
+
diff --git a/doc/sysvinit-2.86.lsm b/doc/sysvinit-2.86.lsm
new file mode 100644 (file)
index 0000000..3b985a5
--- /dev/null
@@ -0,0 +1,14 @@
+Begin3
+Title:         sysvinit and utilities
+Version:       2.86
+Entered-Date:  30JUL2004
+Description:   This is the Linux System V init.
+               This version can be compiled with glibc 2.0.6 and up.
+Author:                miquels@cistron.nl (Miquel van Smoorenburg)
+Primary-Site:  ftp.cistron.nl /pub/people/miquels/software
+               92K sysvinit-2.86.tar.gz
+Alternate-Site:        sunsite.unc.edu /pub/Linux/system/daemons/init
+               92K sysvinit-2.86.tar.gz
+Copying-Policy:        GPL
+Keywords:      init shutdown halt reboot
+End
diff --git a/man/bootlogd.8 b/man/bootlogd.8
new file mode 100644 (file)
index 0000000..cab345b
--- /dev/null
@@ -0,0 +1,72 @@
+'\" -*- coding: UTF-8 -*-
+.\" Copyright (C) 1998-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.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+.\"
+.TH 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@cistron.nl
+.SH "SEE ALSO"
+.BR dmesg (8),  fdatasync (3).
diff --git a/man/bootlogd.8.todo b/man/bootlogd.8.todo
new file mode 100644 (file)
index 0000000..4f24cfc
--- /dev/null
@@ -0,0 +1,52 @@
+'\" -*- coding: UTF-8 -*-
+.\" Copyright (C) 1998-1999 Miquel van Smoorenburg.
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+.\"
+.TH BOOTLOGD 8 "Aug 24, 1999" "" "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 buffered 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 logfile\fP
+Log to this logfile. The default is \fI/var/log/boot.log\fP.
+.IP \fB\-p pidfile\fP
+Put process-id in this file. The default is no pidfile.
+.SH NOTES
+There is no standard way to find out the real console device if you have
+a new-style \fI/dev/console\fP device (major 5, minor 1). \fBBootlogd\fP
+might have some difficulties to do this, especially under very old
+or very new kernels.
+.SH AUTHOR
+Miquel van Smoorenburg, miquels@cistron.nl
+.SH "SEE ALSO"
+.BR dmesg (8)
diff --git a/man/halt.8 b/man/halt.8
new file mode 100644 (file)
index 0000000..8ae3c63
--- /dev/null
@@ -0,0 +1,120 @@
+'\" -*- coding: UTF-8 -*-
+.\" Copyright (C) 1998-2001 Miquel van Smoorenburg.
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+.\"
+.\"{{{}}}
+.\"{{{  Title
+.TH HALT 8 "Nov 6, 2001" "" "Linux System Administrator's Manual"
+.\"}}}
+.\"{{{  Name
+.SH NAME
+halt, reboot, poweroff \- stop the system.
+.\"}}}
+.\"{{{  Synopsis
+.SH SYNOPSIS
+.B /sbin/halt
+.RB [ \-n ]
+.RB [ \-w ]
+.RB [ \-d ]
+.RB [ \-f ]
+.RB [ \-i ]
+.RB [ \-p ]
+.RB [ \-h ]
+.br
+.B /sbin/reboot
+.RB [ \-n ]
+.RB [ \-w ]
+.RB [ \-d ]
+.RB [ \-f ]
+.RB [ \-i ]
+.br
+.B /sbin/poweroff
+.RB [ \-n ]
+.RB [ \-w ]
+.RB [ \-d ]
+.RB [ \-f ]
+.RB [ \-i ]
+.RB [ \-h ]
+.\"}}}
+.\"{{{  Description
+.SH DESCRIPTION
+\fBHalt\fP notes that the system is being brought down in the file
+\fI/var/log/wtmp\fP, and then either tells the kernel to halt, reboot or
+power-off the system.
+.PP
+If \fBhalt\fP or \fBreboot\fP is called when the system is
+\fInot\fP in runlevel \fB0\fP or \fB6\fP, in other words when it's running
+normally, \fBshutdown\fP will be invoked instead (with the \fB-h\fP
+or \fB-r\fP flag). For more info see the \fBshutdown\fP(8)
+manpage.
+.PP
+The rest of this manpage describes the behaviour in runlevels 0
+and 6, that is when the systems shutdown scripts are being run.
+.\"}}}
+.\"{{{  Options
+.SH OPTIONS
+.IP \fB\-n\fP
+Don't sync before reboot or halt. Note that the kernel and storage
+drivers may still sync.
+.IP \fB\-w\fP
+Don't actually reboot or halt but only write the wtmp record
+(in the \fI/var/log/wtmp\fP file).
+.IP \fB\-d\fP
+Don't write the wtmp record. The \fB\-n\fP flag implies \fB\-d\fP.
+.IP \fB\-f\fP
+Force halt or reboot, don't call \fBshutdown\fP(8).
+.IP \fB\-i\fP
+Shut down all network interfaces just before halt or reboot.
+.IP \fB\-h\fP
+Put all hard drives on the system in stand-by mode just before halt or power-off.
+.IP \fB\-p\fP
+When halting the system, switch off the power. This is the default when halt is
+called as \fBpoweroff\fP.
+.\"}}}
+.\"{{{  Diagnostics
+.SH DIAGNOSTICS
+If you're not the superuser, you will get the message `must be superuser'.
+.\"}}}
+.\"{{{  Notes
+.SH NOTES
+Under older \fBsysvinit\fP releases , \fBreboot\fP and \fBhalt\fP should
+never be called directly. From release 2.74 on \fBhalt\fP and \fBreboot\fP
+invoke \fBshutdown\fP(8) if the system is not in runlevel 0 or 6. This
+means that if \fBhalt\fP or \fBreboot\fP cannot find out the current
+runlevel (for example, when \fI/var/run/utmp\fP hasn't been initialized
+correctly) \fBshutdown\fP will be called, which might not be what you want.
+Use the \fB-f\fP flag if you want to do a hard \fBhalt\fP or \fBreboot\fP.
+.PP
+The \fB-h\fP flag puts all hard disks in standby mode just before halt
+or power-off. Right now this is only implemented for IDE drives. A side
+effect of putting the drive in stand-by mode is that the write cache
+on the disk is flushed. This is important for IDE drives, since the
+kernel doesn't flush the write cache itself before power-off.
+.PP
+The \fBhalt\fP program uses /proc/ide/hd* to find all IDE disk devices,
+which means that \fI/proc\fP needs to be mounted when \fBhalt\fP or
+\fBpoweroff\fP is called or the \fB-h\fP switch will do nothing.
+.PP
+.\"}}}
+.\"{{{  Author
+.SH AUTHOR
+Miquel van Smoorenburg, miquels@cistron.nl
+.\"}}}
+.\"{{{  See also
+.SH "SEE ALSO"
+.BR shutdown (8),
+.BR init (8)
+.\"}}}
diff --git a/man/init.8 b/man/init.8
new file mode 100644 (file)
index 0000000..d106a16
--- /dev/null
@@ -0,0 +1,313 @@
+'\" -*- coding: UTF-8 -*-
+.\" Copyright (C) 1998-2004 Miquel van Smoorenburg.
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+.\"
+.\"{{{}}}
+.\"{{{  Title
+.TH INIT 8 "29 Jul 2004" "" "Linux System Administrator's Manual"
+.\"}}}
+.\"{{{  Name
+.SH NAME
+init, telinit \- process control initialization
+.\"}}}
+.\"{{{  Synopsis
+.SH SYNOPSIS
+.B /sbin/init
+.RB [ " -a " ]
+.RB [ " -s " ]
+.RB [ " -b " ]
+[ \fB\-z\fP \fIxxx\fP ]
+.RB [ " 0123456Ss " ]
+.br
+.B /sbin/telinit
+[ \fB\-t\fP \fISECONDS\fP ]
+.RB [ " 0123456sSQqabcUu " ]
+.br
+.B /sbin/telinit
+[ \fB\-e\fP \fIVAR\fP[\fB=\fP\fIVAL\fP] ]
+.\"}}}
+.\"{{{  Description
+.SH DESCRIPTION
+.\"{{{  init
+.SS Init
+.B Init
+is the parent of all processes.  Its primary role is to create processes
+from a script stored in the file \fB/etc/inittab\fP (see
+\fIinittab\fP(5)).  This file usually has entries which cause \fBinit\fP
+to spawn \fBgetty\fPs on each line that users can log in.  It also
+controls autonomous processes required by any particular system.
+.PP
+.\"{{{ Runlevels
+.SH RUNLEVELS
+A \fIrunlevel\fP is a software configuration of the system which allows
+only a selected group of processes to exist.  The processes spawned by
+\fBinit\fP for each of these runlevels are defined in the
+\fB/etc/inittab\fP file.  \fBInit\fP can be in one of eight runlevels:
+\fB0\(en6\fP and \fBS\fP or \fBs\fP.  The runlevel is
+changed by having a privileged user run \fBtelinit\fP, which sends
+appropriate signals to \fBinit\fP, telling it which runlevel to change
+to.
+.PP
+Runlevels \fB0\fP, \fB1\fP, and \fB6\fP are reserved. Runlevel 0 is used to
+halt the system, runlevel 6 is used to reboot the system, and runlevel
+1 is used to get the system down into single user mode. Runlevel \fBS\fP
+is not really meant to be used directly, but more for the scripts that are
+executed when entering runlevel 1. For more information on this,
+see the manpages for \fBshutdown\fP(8) and \fBinittab\fP(5).
+.PP
+Runlevels 7-9 are also valid, though not really documented. This is
+because "traditional" Unix variants don't use them.
+In case you're curious, runlevels \fIS\fP and \fIs\fP are in fact the same.
+Internally they are aliases for the same runlevel.
+.\"}}}
+.PP
+.SH BOOTING
+After \fBinit\fP is invoked as the last step of the kernel boot sequence,
+it looks for the file \fB/etc/inittab\fP to see if there is an entry of the
+type \fBinitdefault\fP (see \fIinittab\fP(5)). The \fBinitdefault\fP entry
+determines the initial runlevel of the system.  If there is no such
+entry (or no \fB/etc/inittab\fP at all), a runlevel must be
+entered at the system console.
+.PP
+Runlevel \fBS\fP or \fBs\fP bring the system to single user mode
+and do not require an \fB/etc/inittab\fP file.  In single user mode,
+\fB/sbin/sulogin\fP is invoked on \fB/dev/console\fP.
+.PP
+When entering single user mode, \fBinit\fP initializes the consoles
+\fBstty\fP settings to sane values. Clocal mode is set. Hardware
+speed and handshaking are not changed.
+.PP
+When entering a multi-user mode for the first time, \fBinit\fP performs the
+\fBboot\fP and \fBbootwait\fP entries to allow file systems to be
+mounted before users can log in.  Then all entries matching the runlevel
+are processed.
+.PP
+When starting a new process, \fBinit\fP first checks whether the file
+\fI/etc/initscript\fP exists. If it does, it uses this script to
+start the process.
+.PP
+Each time a child terminates, \fBinit\fP records the fact and the reason
+it died in \fB/var/run/utmp\fP and \fB/var/log/wtmp\fP,
+provided that these files exist.
+.SH CHANGING RUNLEVELS
+After it has spawned all of the processes specified, \fBinit\fP waits
+for one of its descendant processes to die, a powerfail signal, or until
+it is signaled by \fBtelinit\fP to change the system's runlevel.  
+When one of the above three conditions occurs, it re-examines
+the \fB/etc/inittab\fP file.  New entries can be added to this file at
+any time.  However, \fBinit\fP still waits for one of the above three
+conditions to occur.  To provide for an instantaneous response, the
+\fBtelinit Q\fP or \fBq\fP command can wake up \fBinit\fP to re-examine the
+\fB/etc/inittab\fP file.
+.PP
+If \fBinit\fP is not in single user mode and receives a powerfail
+signal (SIGPWR), it reads the file \fB/etc/powerstatus\fP. It then starts
+a command based on the contents of this file:
+.IP F(AIL)
+Power is failing, UPS is providing the power. Execute the \fBpowerwait\fP
+and \fBpowerfail\fP entries.
+.IP O(K)
+The power has been restored, execute the \fBpowerokwait\fP entries.
+.IP L(OW)
+The power is failing and the UPS has a low battery. Execute the
+\fBpowerfailnow\fP entries.
+.PP
+If /etc/powerstatus doesn't exist or contains anything else then the
+letters \fBF\fP, \fBO\fP or \fBL\fP, init will behave as if it has read
+the letter \fBF\fP.
+.PP
+Usage of \fBSIGPWR\fP and \fB/etc/powerstatus\fP is discouraged. Someone
+wanting to interact with \fBinit\fP should use the \fB/dev/initctl\fP
+control channel - see the source code of the \fBsysvinit\fP package
+for more documentation about this.
+.PP
+When \fBinit\fP is requested to change the runlevel, it sends the
+warning signal \s-1\fBSIGTERM\fP\s0 to all processes that are undefined
+in the new runlevel.  It then waits 5 seconds before forcibly
+terminating these processes via the \s-1\fBSIGKILL\fP\s0 signal.
+Note that \fBinit\fP assumes that all these processes (and their
+descendants) remain in the same process group which \fBinit\fP
+originally created for them.  If any process changes its process group
+affiliation it will not receive these signals.  Such processes need to
+be terminated separately.
+.\"}}}
+.\"{{{  telinit
+.SH TELINIT
+\fB/sbin/telinit\fP is linked to \fB/sbin/init\fP.  It takes a
+one-character argument and signals \fBinit\fP to perform the appropriate
+action.  The following arguments serve as directives to
+\fBtelinit\fP:
+.IP "\fB0\fP,\fB1\fP,\fB2\fP,\fB3\fP,\fB4\fP,\fB5\fP or \fB6\fP"
+tell \fBinit\fP to switch to the specified run level.
+.IP \fBa\fP,\fBb\fP,\fBc\fP
+tell \fBinit\fP to process only those \fB/etc/inittab\fP file
+entries having runlevel \fBa\fP,\fBb\fP or \fBc\fP.
+.IP "\fBQ\fP or \fBq\fP"
+tell \fBinit\fP to re-examine the \fB/etc/inittab\fP file.
+.IP "\fBS\fP or \fBs\fP"
+tell \fBinit\fP to switch to single user mode.
+.IP "\fBU\fP or \fBu\fP"
+tell \fBinit\fP to re-execute itself (preserving the state). No re-examining of 
+\fB/etc/inittab\fP file happens. Run level should be one of
+\fBSs0123456\fP
+otherwise request would be silently ignored.
+.PP
+\fBtelinit\fP can tell \fBinit\fP how long it should wait
+between sending processes the SIGTERM and SIGKILL signals.  The default
+is 5 seconds, but this can be changed with the \fB-t\fP option.
+.PP
+\fBtelinit -e\fP tells \fBinit\fP to change the environment
+for processes it spawns.
+The argument of \fB-e\fP is either of the form \fIVAR\fP=\fIVAL\fP
+which sets variable \fIVAR\fP to value \fIVAL\fP,
+or of the form \fIVAR\fP
+(without an equality sign)
+which unsets variable \fIVAR\fP.
+.PP
+\fBtelinit\fP can be invoked only by users with appropriate
+privileges.
+.PP
+The \fBinit\fP binary checks if it is \fBinit\fP or \fBtelinit\fP by looking
+at its \fIprocess id\fP; the real \fBinit\fP's process id is always \fB1\fP.
+From this it follows that instead of calling \fBtelinit\fP one can also
+just use \fBinit\fP instead as a shortcut.
+.\"}}}
+.\"}}}
+.SH ENVIRONMENT
+\fBInit\fP sets the following environment variables for all its children:
+.IP \fBPATH\fP
+\fI/bin:/usr/bin:/sbin:/usr/sbin\fP
+.IP \fBINIT_VERSION\fP
+As the name says. Useful to determine if a script runs directly from \fBinit\fP.
+.IP \fBRUNLEVEL\fP
+The current system runlevel.
+.IP \fBPREVLEVEL\fP
+The previous runlevel (useful after a runlevel switch).
+.IP \fBCONSOLE\fP
+The system console. This is really inherited from the kernel; however
+if it is not set \fBinit\fP will set it to \fB/dev/console\fP by default.
+.SH BOOTFLAGS
+It is possible to pass a number of flags to \fBinit\fP from the
+boot monitor (eg. LILO). \fBInit\fP accepts the following flags:
+.TP 0.5i
+.B -s, S, single
+Single user mode boot. In this mode \fI/etc/inittab\fP is
+examined and the bootup rc scripts are usually run before
+the single user mode shell is started.
+.PP
+.TP 0.5i
+.B 1-5
+Runlevel to boot into.
+.PP
+.TP 0.5i
+.B -b, emergency
+Boot directly into a single user shell without running any
+other startup scripts.
+.PP
+.TP 0.5i
+.B -a, auto
+The LILO boot loader adds the word "auto" to the command line if it
+booted the kernel with the default command line (without user intervention).
+If this is found \fBinit\fP sets the "AUTOBOOT" environment
+variable to "yes". Note that you cannot use this for any security
+measures - of course the user could specify "auto" or \-a on the
+command line manually.
+.PP
+.TP 0.5i
+.BI "-z " xxx
+The argument to \fB-z\fP is ignored. You can use this to expand the command
+line a bit, so that it takes some more space on the stack. \fBInit\fP
+can then manipulate the command line so that \fBps\fP(1) shows
+the current runlevel.
+.PP
+.SH INTERFACE
+Init listens on a \fIfifo\fP in /dev, \fI/dev/initctl\fP, for messages.
+\fBTelinit\fP uses this to communicate with init. The interface is not
+very well documented or finished. Those interested should study the
+\fIinitreq.h\fP file in the \fIsrc/\fP subdirectory of the \fBinit\fP
+source code tar archive.
+.SH SIGNALS
+Init reacts to several signals:
+.TP 0.5i
+.B SIGHUP
+Has the same effect as \fBtelinit q\fP.
+.PP
+.TP 0.5i
+.B SIGUSR1
+On receipt of this signals, init closes and re-opens its control fifo,
+\fB/dev/initctl\fP. Useful for bootscripts when /dev is remounted.
+.TP 0.5i
+.B SIGINT
+Normally the kernel sends this signal to init when CTRL-ALT-DEL is
+pressed. It activates the \fIctrlaltdel\fP action.
+.TP 0.5i
+.B SIGWINCH
+The kernel sends this signal when the \fIKeyboardSignal\fP key is hit.
+It activates the \fIkbrequest\fP action.
+\"{{{  Conforming to
+.SH CONFORMING TO
+\fBInit\fP is compatible with the System V init. It works closely
+together with the scripts in the directories
+\fI/etc/init.d\fP and \fI/etc/rc{runlevel}.d\fP.
+If your system uses this convention, there should be a \fIREADME\fP
+file in the directory \fI/etc/init.d\fP explaining how these scripts work.
+.\"}}}
+.\"{{{  Files
+.SH FILES
+.nf
+/etc/inittab
+/etc/initscript
+/dev/console
+/var/run/utmp
+/var/log/wtmp
+/dev/initctl
+.fi
+.\"}}}
+.\"{{{  Warnings
+.SH WARNINGS
+\fBInit\fP assumes that processes and descendants of processes
+remain in the same process group which was originally created
+for them.  If the processes change their group, \fBinit\fP can't
+kill them and you may end up with two processes reading from one
+terminal line.
+.\"}}}
+.\"{{{  Diagnostics
+.SH DIAGNOSTICS
+If \fBinit\fP finds that it is continuously respawning an entry
+more than 10 times in 2 minutes, it will assume that there is an error
+in the command string, generate an error message on the system console,
+and refuse to respawn this entry until either 5 minutes has elapsed or
+it receives a signal.  This prevents it from eating up system resources
+when someone makes a typographical error in the \fB/etc/inittab\fP file
+or the program for the entry is removed.
+.\"}}}
+.\"{{{  Author
+.SH AUTHOR
+Miquel van Smoorenburg (miquels@cistron.nl), initial manual
+page by Michael Haardt (u31b3hs@pool.informatik.rwth-aachen.de).
+.\"}}}
+.\"{{{  See also
+.SH "SEE ALSO"
+.BR getty (1),
+.BR login (1),
+.BR sh (1),
+.BR runlevel (8),
+.BR shutdown(8),
+.BR kill (1),
+.BR inittab (5),
+.BR initscript (5),
+.BR utmp (5)
+.\"}}}
diff --git a/man/initscript.5 b/man/initscript.5
new file mode 100644 (file)
index 0000000..875879c
--- /dev/null
@@ -0,0 +1,72 @@
+'\" -*- coding: UTF-8 -*-
+.\" Copyright (C) 1998-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.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+.\"
+.TH INITSCRIPT 5 "July 10, 2003" "" "Linux System Administrator's Manual"
+.SH NAME
+initscript \- script that executes inittab commands.
+.SH SYNOPSIS
+/bin/sh /etc/initscript id runlevels action process
+.SH DESCRIPTION
+When the shell script \fI/etc/initscript\fP is present, \fBinit\fP
+will use it to execute the commands from \fIinittab\fP.
+This script can be used to set things like \fBulimit\fP and
+\fBumask\fP default values for every process.
+.SH EXAMPLES
+This is a sample initscript, which might be installed on your
+system as \fI/etc/initscript.sample\fP.
+.RS
+.sp
+.nf
+.ne 7
+
+#
+# initscript   Executed by init(8) for every program it
+#              wants to spawn like this:
+#
+#              /bin/sh /etc/initscript <id> <level> <action> <process>
+#
+
+  # Set umask to safe level, and enable core dumps.
+  umask 022
+  ulimit -c 2097151
+  PATH=/bin:/sbin:/usr/bin:/usr/sbin
+  export PATH
+
+  # Increase the hard file descriptor limit for all processes
+  # to 8192.  The soft limit is still 1024, but any unprivileged
+  # process can increase its soft limit up to the hard limit
+  # with "ulimit -Sn xxx" (needs a 2.2.13 or later Linux kernel).
+  ulimit -Hn 8192
+
+  # Execute the program.
+  eval exec "$4"
+
+.sp
+.RE
+.SH NOTES
+This script is not meant as startup script for daemons or somesuch.
+It has nothing to do with a \fIrc.local\fP style script. It's just
+a handler for things executed from \fB/etc/inittab\fP. Experimenting
+with this can make your system un(re)bootable.
+.RE
+.SH FILES
+/etc/inittab,
+/etc/initscript.
+.SH AUTHOR
+Miquel van Smoorenburg ,<miquels@cistron.nl>
+.SH "SEE ALSO"
+init(8), inittab(5).
diff --git a/man/inittab.5 b/man/inittab.5
new file mode 100644 (file)
index 0000000..e1d739d
--- /dev/null
@@ -0,0 +1,265 @@
+'\" -*- coding: UTF-8 -*-
+.\" Copyright (C) 1998-2001 Miquel van Smoorenburg.
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+.\"
+.\"{{{}}}
+.\"{{{  Title
+.TH INITTAB 5 "Dec 4, 2001" "" "Linux System Administrator's Manual"
+.\"}}}
+.\"{{{  Name
+.SH NAME
+inittab \- format of the inittab file used by the sysv-compatible init
+process
+.\"}}}
+.\"{{{  Description
+.SH DESCRIPTION
+The \fBinittab\fP file describes which processes are started at bootup and
+during normal operation (e.g.\& /etc/init.d/boot, /etc/init.d/rc, gettys...).
+.BR Init (8)
+distinguishes multiple \fIrunlevels\fP, each of which can have its own set of
+processes that are started.  Valid runlevels are \fB0\fP\-\fB6\fP plus
+\fBA\fP, \fBB\fP, and \fBC\fP for \fBondemand\fP entries.  An entry in the
+\fBinittab\fP file has the following format:
+.RS
+.sp
+\fIid\fP:\fIrunlevels\fP:\fIaction\fP:\fIprocess\fP
+.sp
+.RE
+Lines beginning with `#' are ignored.
+.\"{{{  id
+.IP \fIid\fP
+is a unique sequence of 1-4 characters which identifies an entry in
+.B inittab 
+(for versions of sysvinit compiled with the \fIold\fP libc5 (< 5.2.18) or
+a.out libraries the limit is 2 characters).
+.sp
+Note: traditionally, for getty and other login processes, the value of the
+\fIid\fP field is kept the same as the suffix of the corresponding tty, e.g.\&
+\fB1\fP for \fBtty1\fP. Some ancient login accounting programs might
+expect this, though I can't think of any.
+.\"}}}
+.\"{{{  runlevels
+.IP \fIrunlevels\fP
+lists the runlevels for which the specified action should be taken.
+.\"}}}
+.\"{{{  action
+.IP \fIaction\fP
+describes which action should be taken.
+.\"}}}
+.\"{{{  process
+.IP \fIprocess\fP
+specifies the process to be executed.  If the process field starts with
+a `+' character, 
+.B init 
+will not do utmp and wtmp accounting for that process.  This is needed for 
+gettys that insist on doing their own utmp/wtmp housekeeping.  This is also 
+a historic bug.
+.\"}}}
+.PP
+The \fIrunlevels\fP field may contain multiple characters for different
+runlevels.  For example, \fB123\fP specifies that the process should be 
+started in runlevels 1, 2, and 3.
+The \fIrunlevels\fP for \fBondemand\fP entries may contain an \fBA\fP,
+\fBB\fP, or \fBC\fP.  The \fIrunlevels\fP field of \fBsysinit\fP,
+\fBboot\fP, and \fBbootwait\fP entries are ignored.
+.PP
+When the system runlevel is changed, any running processes that are not
+specified for the new runlevel are killed, first with \s-2SIGTERM\s0,
+then with \s-2SIGKILL\s0.
+.PP
+Valid actions for the \fIaction\fP field are:
+.\"{{{  respawn
+.IP \fBrespawn\fP
+The process will be restarted whenever it terminates (e.g.\& getty).
+.\"}}}
+.\"{{{  wait
+.IP \fBwait\fP
+The process will be started once when the specified runlevel is entered and 
+.B init 
+will wait for its termination.
+.\"}}}
+.\"{{{  once
+.IP \fBonce\fP
+The process will be executed once when the specified runlevel is
+entered.
+.\"}}}
+.\"{{{  boot
+.IP \fBboot\fP
+The process will be executed during system boot.  The \fIrunlevels\fP
+field is ignored.
+.\"}}}
+.\"{{{  bootwait
+.IP \fBbootwait\fP
+The process will be executed during system boot, while 
+.B init 
+waits for its termination (e.g.\& /etc/rc).  
+The \fIrunlevels\fP field is ignored.
+.\"}}}
+.\"{{{  off
+.IP \fBoff\fP
+This does nothing.
+.\"}}}
+.\"{{{  ondemand
+.IP \fBondemand\fP
+A process marked with an \fBondemand\fP runlevel will be executed
+whenever the specified \fBondemand\fP runlevel is called.  However, no
+runlevel change will occur (\fBondemand\fP runlevels are `a', `b',
+and `c').
+.\"}}}
+.\"{{{  initdefault
+.IP \fBinitdefault\fP
+An \fBinitdefault\fP entry specifies the runlevel which should be
+entered after system boot.  If none exists, 
+.B init
+will ask for a runlevel on the console. The \fIprocess\fP field is ignored.
+.\"}}}
+.\"{{{  sysinit
+.IP \fBsysinit\fP
+The process will be executed during system boot. It will be
+executed before any \fBboot\fP or \fB bootwait\fP entries.
+The \fIrunlevels\fP field is ignored.
+.\"}}}
+.\"{{{  powerwait
+.IP \fBpowerwait\fP
+The process will be executed when the power goes down. Init is usually
+informed about this by a process talking to a UPS connected to the computer.
+\fBInit\fP will wait for the process to finish before continuing.
+.\"}}}
+.\"{{{  powerfail
+.IP \fBpowerfail\fP
+As for \fBpowerwait\fP, except that \fBinit\fP does not wait for the process's
+completion.
+.\"}}}
+.\"{{{  powerokwait
+.IP \fBpowerokwait\fP
+This process will be executed as soon as \fBinit\fP is informed that the
+power has been restored.
+.\"}}}
+.\"{{{  powerfailnow
+.IP \fBpowerfailnow\fP
+This process will be executed when \fBinit\fP is told that the battery of
+the external UPS is almost empty and the power is failing (provided that the
+external UPS and the monitoring process are able to detect this condition).
+.\"}}}
+.\"{{{  ctrlaltdel
+.IP \fBctrlaltdel\fP
+The process will be executed when \fBinit\fP receives the SIGINT signal.
+This means that someone on the system console has pressed the
+\fBCTRL\-ALT\-DEL\fP key combination. Typically one wants to execute some
+sort of \fBshutdown\fP either to get into single\-user level or to
+reboot the machine.
+.\"}}}
+.\"{{{  kbrequest
+.IP \fBkbrequest\fP
+The process will be executed when \fBinit\fP receives a signal from the
+keyboard handler that a special key combination was pressed on the
+console keyboard.
+.sp
+The documentation for this function is not complete yet; more documentation
+can be found in the kbd-x.xx packages (most recent was kbd-0.94 at
+the time of this writing). Basically you want to map some keyboard
+combination to the "KeyboardSignal" action. For example, to map Alt-Uparrow
+for this purpose use the following in your keymaps file:
+.RS
+.sp
+alt keycode 103 = KeyboardSignal
+.sp
+.RE
+.\"}}}
+.\"}}}
+.\"{{{  Examples
+.SH EXAMPLES
+This is an example of a inittab which resembles the old Linux inittab:
+.RS
+.sp
+.nf
+.ne 7
+# inittab for linux
+id:1:initdefault:
+rc::bootwait:/etc/rc
+1:1:respawn:/etc/getty 9600 tty1
+2:1:respawn:/etc/getty 9600 tty2
+3:1:respawn:/etc/getty 9600 tty3
+4:1:respawn:/etc/getty 9600 tty4
+.fi
+.sp
+.RE
+This inittab file executes \fB/etc/rc\fP during boot and starts gettys
+on tty1\-tty4.
+.PP
+A more elaborate \fBinittab\fP with different runlevels (see the comments
+inside):
+.RS
+.sp
+.nf
+.ne 19
+# Level to run in
+id:2:initdefault:
+
+# Boot-time system configuration/initialization script.
+si::sysinit:/etc/init.d/rcS
+
+# What to do in single-user mode.
+~:S:wait:/sbin/sulogin
+
+# /etc/init.d executes the S and K scripts upon change
+# of runlevel.
+#
+# Runlevel 0 is halt.
+# Runlevel 1 is single-user.
+# Runlevels 2-5 are multi-user.
+# Runlevel 6 is reboot.
+
+l0:0:wait:/etc/init.d/rc 0
+l1:1:wait:/etc/init.d/rc 1
+l2:2:wait:/etc/init.d/rc 2
+l3:3:wait:/etc/init.d/rc 3
+l4:4:wait:/etc/init.d/rc 4
+l5:5:wait:/etc/init.d/rc 5
+l6:6:wait:/etc/init.d/rc 6
+
+# What to do at the "3 finger salute".
+ca::ctrlaltdel:/sbin/shutdown -t1 -h now
+
+# Runlevel 2,3: getty on virtual consoles
+# Runlevel   3: getty on terminal (ttyS0) and modem (ttyS1)
+1:23:respawn:/sbin/getty tty1 VC linux
+2:23:respawn:/sbin/getty tty2 VC linux
+3:23:respawn:/sbin/getty tty3 VC linux
+4:23:respawn:/sbin/getty tty4 VC linux
+S0:3:respawn:/sbin/getty -L 9600 ttyS0 vt320
+S1:3:respawn:/sbin/mgetty -x0 -D ttyS1
+
+.fi
+.sp
+.RE
+.\"}}}
+.\"{{{  Files
+.SH FILES
+/etc/inittab
+.\"}}}
+.\"{{{  Author
+.SH AUTHOR
+\fBInit\fP was written by Miquel van Smoorenburg 
+(miquels@cistron.nl).  This manual page was written by 
+Sebastian Lederer (lederer@francium.informatik.uni-bonn.de) and modified
+by Michael Haardt (u31b3hs@pool.informatik.rwth-aachen.de).
+.\"}}}
+.\"{{{  See also
+.SH "SEE ALSO"
+.BR init (8),
+.BR telinit (8)
+.\"}}}
diff --git a/man/killall5.8 b/man/killall5.8
new file mode 100644 (file)
index 0000000..5a3009f
--- /dev/null
@@ -0,0 +1,49 @@
+'\" -*- coding: UTF-8 -*-
+.\" Copyright (C) 1998-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.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+.\"
+.TH 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@cistron.nl
diff --git a/man/last.1 b/man/last.1
new file mode 100644 (file)
index 0000000..01b79b2
--- /dev/null
@@ -0,0 +1,122 @@
+'\" -*- coding: UTF-8 -*-
+.\" Copyright (C) 1998-2004 Miquel van Smoorenburg.
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+.\"
+.\"{{{}}}
+.\"{{{  Title
+.TH LAST,LASTB 1 "Jul 31, 2004" "" "Linux System Administrator's Manual"
+.\"}}}
+.\"{{{  Name
+.SH NAME
+last, lastb \- show listing of last logged in users
+.\"}}}
+.\"{{{  Synopsis
+.SH SYNOPSIS
+.B last
+.RB [ \-R ]
+.RB [ \-\fInum\fP ]
+.RB "[ \-\fBn\fP \fInum\fP ]"
+.RB [ \-adFiox ]
+.RB "[ \-\fBf\fP \fIfile\fP ]"
+.RB "[ \-\fBt\fP \fIYYYYMMDDHHMMSS\fP ]"
+.RI [ name... ]
+.RI [ tty... ]
+.br
+.B lastb
+.RB [ \-R ]
+.RB [ \-\fInum\fP ]
+.RB "[ \-\fBn\fP \fInum\fP ]"
+.RB "[ \-\fBf\fP \fIfile\fP ]"
+.RB [ \-adFiox ]
+.RI [ name... ]
+.RI [ tty... ]
+.\"}}}
+.\"{{{  Description
+.SH DESCRIPTION
+.B Last
+searches back through the file \fB/var/log/wtmp\fP (or the file
+designated by the \fB\-f\fP flag) and displays a list of all
+users logged in (and out) since that file was created.  Names of users
+and tty's can be given, in which case \fBlast\fP will show only those entries
+matching the arguments.  Names of ttys can be abbreviated, thus \fBlast
+0\fP is the same as \fBlast tty0\fP.  
+.PP
+When \fBlast\fP catches a \s-2SIGINT\s0 signal (generated by the interrupt key,
+usually control-C) or a \s-2SIGQUIT\s0 signal (generated by the quit key, 
+usually control-\e), \fBlast\fP will show how far it has searched through the 
+file; in the case of the \s-2SIGINT\s0 signal \fBlast\fP will then terminate.
+.PP
+The pseudo user \fBreboot\fP logs in each time the system is rebooted.
+Thus \fBlast reboot\fP will show a log of all reboots since the log file
+was created.
+.PP
+\fBLastb\fP is the same as \fBlast\fP, except that by default it shows a log
+of the file \fB/var/log/btmp\fP, which contains all the bad login attempts.
+.\"}}}
+.\"{{{  Options
+.SH OPTIONS
+.IP "\fB\-f\fP \fIfile\fP"
+Tells \fBlast\fP to use a specific file instead of \fB/var/log/wtmp\fP.
+.IP \fB\-\fP\fInum\fP
+This is a count telling \fBlast\fP how many lines to show.
+.IP "\fB\-n\fP \fInum\fP"
+The same.
+.IP "\fB\-t\fP \fIYYYYMMDDHHMMSS\fP"
+Display the state of logins as of the specified time.  This is
+useful, e.g., to determine easily who was logged in at a particular
+time -- specify that time with \fB\-t\fP and look for "still logged
+in".
+.IP \fB\-R\fP
+Suppresses the display of the hostname field.
+.IP \fB\-a\fP
+Display the hostname in the last column. Useful in combination
+with the next flag.
+.IP \fB\-d\fP
+For non-local logins, Linux stores not only the host name of the remote
+host but its IP number as well. This option translates the IP number
+back into a hostname.
+.IP \fB\-F\fP
+Print full login and logout times and dates.
+.IP \fB\-i\fP
+This option is like \fB-d\fP in that it displays the IP number of the remote
+host, but it displays the IP number in numbers-and-dots notation.
+.IP \fB\-o\fP
+Read an old-type wtmp file (written by linux-libc5 applications).
+.IP \fB\-x\fP
+Display the system shutdown entries and run level changes.
+.\"}}}
+.SH NOTES
+The files \fIwtmp\fP and \fIbtmp\fP might not be found. The system only
+logs information in these files if they are present. This is a local
+configuration issue. If you want the files to be used, they can be
+created with a simple \fBtouch\fP(1) command (for example, 
+\fItouch /var/log/wtmp\fP).
+.\"{{{  Files
+.SH FILES
+/var/log/wtmp
+.br
+/var/log/btmp
+.\"}}}
+.\"{{{  Author
+.SH AUTHOR
+Miquel van Smoorenburg, miquels@cistron.nl
+.\"}}}
+.\"{{{  See also
+.SH "SEE ALSO"
+.BR shutdown (8),
+.BR login (1),
+.BR init (8)
+.\"}}}
diff --git a/man/lastb.1 b/man/lastb.1
new file mode 100644 (file)
index 0000000..f57c02a
--- /dev/null
@@ -0,0 +1 @@
+.so man1/last.1
diff --git a/man/mesg.1 b/man/mesg.1
new file mode 100644 (file)
index 0000000..e33c348
--- /dev/null
@@ -0,0 +1,61 @@
+'\" -*- coding: UTF-8 -*-
+.\" Copyright (C) 1998-2001 Miquel van Smoorenburg.
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+.\"
+.\"{{{}}}
+.\"{{{  Title
+.TH MESG 1 "Feb 26, 2001" "" "Linux User's Manual"
+.\"}}}
+.\"{{{  Name
+.SH NAME
+mesg \- control write access to your terminal
+.\"}}}
+.\"{{{  Synopsis
+.SH SYNOPSIS
+.B mesg
+.RB [ y | n ]
+.\"}}}
+.\"{{{  Description
+.SH DESCRIPTION
+.B Mesg
+controls the access to your terminal by others.  It's typically used to
+allow or disallow other users to write to your terminal (see \fBwrite\fP(1)).
+.\"}}}
+.\"{{{  Options
+.SH OPTIONS
+.IP \fBy\fP
+Allow write access to your terminal.
+.IP \fBn\fP
+Disallow write access to your terminal.
+.PP
+If no option is given, \fBmesg\fP prints out the current access state of your
+terminal.
+.\"}}}
+.\"{{{  Notes
+.SH NOTES
+\fBMesg\fP assumes that its standard input is connected to your
+terminal. That also means that if you are logged in multiple times,
+you can get/set the mesg status of other sessions by using redirection.
+For example "mesg n < /dev/pts/46".
+.SH AUTHOR
+Miquel van Smoorenburg (miquels@cistron.nl)
+.\"}}}
+.\"{{{  See also
+.SH "SEE ALSO"
+.BR talk (1),
+.BR write (1),
+.BR wall (1)
+.\"}}}
diff --git a/man/mountpoint.1 b/man/mountpoint.1
new file mode 100644 (file)
index 0000000..e873e78
--- /dev/null
@@ -0,0 +1,54 @@
+'\" -*- coding: UTF-8 -*-
+.\" Copyright (C) 1998-2004 Miquel van Smoorenburg.
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+.\"
+.TH MOUNTPOINT 1 "Mar 15, 2004" "" "Linux System Administrator's Manual"
+.SH NAME
+mountpoint \- see if a directory is a mountpoint
+.SH SYNOPSIS
+.B /bin/mountpoint
+.RB [ \-q ]
+.RB [ \-d ]
+.I /path/to/directory
+.br
+.B /bin/mountpoint
+.RB \-x
+.I /dev/device
+.SH DESCRIPTION
+\fBMountpoint\fP checks if the directory is a mountpoint.
+
+.SH OPTIONS
+.IP \fB\-q\fP
+Be quiet - don't print anything.
+.IP \fB\-d\fP
+Print major/minor device number of the filesystem on stdout.
+.IP \fB\-x\fP
+Print major/minor device number of the blockdevice on stdout.
+.SH EXIT STATUS
+Zero if the directory is a mountpoint, non-zero if not.
+.SH NOTES
+Symbolic links are not followed, except when the \fB-x\fP option is
+used. To force following symlinks, add a trailing slash to the
+path of the directory.
+.PP
+The name of the command is misleading when the -x option is used,
+but the option is useful for comparing if a directory and a device
+match up, and there is no other command that can print the info easily.
+.PP
+.SH AUTHOR
+Miquel van Smoorenburg, miquels@cistron.nl
+.SH "SEE ALSO"
+.BR stat (1)
diff --git a/man/pidof.8 b/man/pidof.8
new file mode 100644 (file)
index 0000000..0385514
--- /dev/null
@@ -0,0 +1,78 @@
+'\" -*- coding: UTF-8 -*-
+.\" Copyright (C) 1998 Miquel van Smoorenburg.
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+.\"
+.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@cistron.nl
diff --git a/man/poweroff.8 b/man/poweroff.8
new file mode 100644 (file)
index 0000000..41c02c1
--- /dev/null
@@ -0,0 +1 @@
+.so man8/halt.8
diff --git a/man/reboot.8 b/man/reboot.8
new file mode 100644 (file)
index 0000000..41c02c1
--- /dev/null
@@ -0,0 +1 @@
+.so man8/halt.8
diff --git a/man/runlevel.8 b/man/runlevel.8
new file mode 100644 (file)
index 0000000..1e4ea77
--- /dev/null
@@ -0,0 +1,56 @@
+'\" -*- coding: UTF-8 -*-
+.\" Copyright (C) 1997 Miquel van Smoorenburg.
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+.\"
+.TH RUNLEVEL 8 "May 27, 1997" "" "Linux System Administrator's Manual"
+.SH NAME
+runlevel -- find the previous and current system runlevel.
+.SH SYNOPSIS
+.B runlevel 
+.RI [ utmp ]
+.SH DESCRIPTION
+.B Runlevel
+reads the system
+.I utmp
+file (typically 
+.IR /var/run/utmp )
+to locate the runlevel record, and then
+prints the previous and current system runlevel on its standard output, 
+separated by a single space. If there is no previous system
+runlevel, the letter \fBN\fP will be printed instead.
+.PP
+If no
+.I utmp
+file exists, or if no runlevel record can be found,
+.B runlevel
+prints the word \fBunknown\fP and exits with an error.
+.PP
+.B Runlevel
+can be used in \fIrc\fP scripts as a substitute for the System-V
+\fBwho -r\fP command. 
+However, in newer versions of \fBinit\fP(8) this information
+is also available in the environment variables \fBRUNLEVEL\fP and
+\fBPREVLEVEL\fP.
+.SH OPTIONS
+.\"{{{ utmp
+.IP \fIutmp\fP 
+The name of the \fIutmp\fP file to read.
+.\"}}}
+.SH SEE ALSO
+.BR init (8),
+.BR utmp (5)
+.SH AUTHOR
+Miquel van Smoorenburg, miquels@cistron.nl
diff --git a/man/shutdown.8 b/man/shutdown.8
new file mode 100644 (file)
index 0000000..d313df5
--- /dev/null
@@ -0,0 +1,214 @@
+'\" -*- coding: UTF-8 -*-
+.\" Copyright (C) 1998-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.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+.\"
+.\"{{{}}}
+.\"{{{  Title
+.TH 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@cistron.nl
+.\"}}}
+.\"{{{  See also
+.SH "SEE ALSO"
+.BR fsck (8),
+.BR init (8),
+.BR halt (8),
+.BR poweroff (8),
+.BR reboot (8)
+.\"}}}
diff --git a/man/sulogin.8 b/man/sulogin.8
new file mode 100644 (file)
index 0000000..4b5d153
--- /dev/null
@@ -0,0 +1,87 @@
+'\" -*- coding: UTF-8 -*-
+.\" Copyright (C) 1998-2006 Miquel van Smoorenburg.
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+.\"
+.TH SULOGIN 8 "17 Jan 2006" "" "Linux System Administrator's Manual"
+.SH NAME
+sulogin \- Single-user login
+.SH SYNOPSIS
+.B sulogin
+[ \fB\-e\fP ]
+[ \fB\-p\fP ]
+[ \fB\-t\fP \fISECONDS\fP ]
+[ \fITTY\fP ]
+.SH DESCRIPTION
+.I sulogin
+is invoked by \fBinit(8)\fP when the system goes into single user mode.
+(This is done through an entry in \fIinittab(5)\fP.)
+\fBInit\fP also
+tries to execute \fIsulogin\fP when
+the boot loader (e.g., \fBgrub\fP(8))
+passes it the \fB\-b\fP option.
+.PP
+The user is prompted
+.IP "" .5i
+Give root password for system maintenance
+.br
+(or type Control\-D for normal startup):
+.PP
+\fIsulogin\fP will be connected to the current terminal, or to the
+optional device that can be specified on the command line
+(typically \fB/dev/console\fP).
+.PP
+If the \fB\-t\fP option is used then the program only waits
+the given number of seconds for user input.
+.PP
+If the \fB\-p\fP option is used then the single-user shell is invoked
+with a \fIdash\fP as the first character in \fIargv[0]\fP.
+This causes the shell process to behave as a login shell.
+The default is \fInot\fP to do this,
+so that the shell will \fInot\fP read \fB/etc/profile\fP
+or \fB$HOME/.profile\fP at startup.
+.PP
+After the user exits the single-user shell,
+or presses control\-D at the prompt,
+the system will (continue to) boot to the default runlevel.
+.SH ENVIRONMENT VARIABLES
+\fIsulogin\fP looks for the environment variable \fBSUSHELL\fP or
+\fBsushell\fP to determine what shell to start. If the environment variable
+is not set, it will try to execute root's shell from /etc/passwd. If that
+fails it will fall back to \fB/bin/sh\fP.
+.PP
+This is very valuable together with the \fB\-b\fP option to init. To boot
+the system into single user mode, with the root file system mounted read/write,
+using a special "fail safe" shell that is statically linked (this example
+is valid for the LILO bootprompt)
+.PP
+boot: linux \-b rw sushell=/sbin/sash
+.SH FALLBACK METHODS
+\fIsulogin\fP checks the root password using the standard method (getpwnam)
+first.
+Then, if the \fB\-e\fP option was specified,
+\fIsulogin\fP examines these files directly to find the root password:
+.PP
+/etc/passwd,
+.br
+/etc/shadow (if present)
+.PP
+If they are damaged or nonexistent, sulogin will start a root shell
+without asking for a password. Only use the \fB\-e\fP option if you
+are sure the console is physically protected against unauthorized access.
+.SH AUTHOR
+Miquel van Smoorenburg <miquels@cistron.nl>
+.SH SEE ALSO
+init(8), inittab(5).
diff --git a/man/telinit.8 b/man/telinit.8
new file mode 100644 (file)
index 0000000..a12cb4f
--- /dev/null
@@ -0,0 +1 @@
+.so man8/init.8
diff --git a/man/wall.1 b/man/wall.1
new file mode 100644 (file)
index 0000000..2fe8301
--- /dev/null
@@ -0,0 +1,75 @@
+'\" -*- coding: UTF-8 -*-
+.\" Copyright (C) 1998-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.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+.\"
+.TH WALL 1 "15 April 2003" "" "Linux User's Manual"
+
+.SH NAME
+wall -- send a message to everybody's terminal.
+
+.SH SYNOPSIS
+.B wall
+.RB [ \-n ]
+.RB [ " message " ]
+
+.SH DESCRIPTION
+.B Wall
+sends a message to everybody logged in with their
+.IR mesg (1)
+permission
+set to
+.BR yes .
+The message can be given as an argument to
+.IR wall ,
+or it can be sent to
+.IR wall 's
+standard input.  When using the standard input from a terminal,
+the message should be terminated with the
+.B EOF
+key (usually Control-D).
+.PP
+The length of the message is limited to 20 lines.
+For every invocation of
+.I wall
+a notification will be written to syslog, with facility
+.B LOG_USER
+and level
+.BR LOG_INFO .
+
+.SH OPTIONS
+.IP \fB\-n\fn
+Suppresses the normal banner printed by
+.IR wall ,
+changing it to "Remote broadcast message".
+This option is only available for root if
+.I wall
+is installed set-group-id, and is used by
+.IR rpc.walld (8).
+.PP
+
+.SH ENVIRONMENT
+.I Wall
+ignores the
+.B TZ
+variable - the time printed in the banner is based on the system's
+local time.
+
+.SH SEE ALSO
+.IR mesg (1),
+.IR rpc.rwalld (8).
+
+.SH AUTHOR
+Miquel van Smoorenburg, miquels@cistron.nl
diff --git a/obsolete/README.RIGHT.NOW b/obsolete/README.RIGHT.NOW
new file mode 100644 (file)
index 0000000..7a6fb1d
--- /dev/null
@@ -0,0 +1,58 @@
+WARNING:
+
+  This version of sysvinit is really different from the 2.50 and
+  earlier version.
+
+  Shutdown now puts the system into runlevel 6 (reboot), 0 (halt)
+  or 1 (single user). This can cause unexpected results if you
+  install the binaries from this release into Slackware distributions
+  older than Slackware 3.0.
+
+SUPPORTED DISTRIBUTIONS:
+
+  The binaries from this package can be installed in:
+
+  o Debian 1.3 and later
+  o RedHat 3.x and later
+  o Slackware 3.0 (UNTESTED but it might work - no complaints yet).
+    Also read the INIT.README in the slackware/ directory.
+  o Slackware 2.x: see the slackware/ directory
+
+  Do not install any of the scripts from the debian/ directory unless
+  you know what you are doing.
+
+UNSUPPORTED DISTRIBUTIONS:
+
+  o The rest :)
+
+  If you have a non-supported system, please upgrade to the latest version
+  of your distribution that supports the Linux 2.0.x kernel (probably
+  the reason why you are installing this newer sysvinit).
+
+  You might get away by installing *just* the "init" binary, and nothing
+  else. Do _not_ replace your existing halt, reboot or shutdown programs.
+
+HOW TO NON DESTRUCTIVELY TEST THE NEW INIT:
+
+  Install *just* the init binary as /sbin/init.new. Now reboot the system,
+  and stop your bootloader so you can give arguments on the command line.
+  With LILO you can usually achieve this by keeping the SHIFT key
+  pressed during boot up. Enter the name of the kernel image (for LILO,
+  TAB shows a list) followed by the argument "init=/sbin/init.new".
+  The name "init.new" is special, do not use something like "init.test".
+
+  For example:
+
+        boot: linux init=/sbin/init.new
+
+  YOU CANNOT SHUTDOWN IN A CLEAN WAY AFTER THIS. Your best bet is to use
+  the "-n" flag to shutdown. This is because init is not running as process #1
+  if you use this method. Anyway, if this works, you can remove the old init
+  and copy the new init into place.
+
+DISCLAIMER:
+
+  If it breaks you get to keep both pieces. If you want to run the latest
+  Linux 2.0.x kernel and you can't get init to work just upgrade your entire
+  distribution to a newer version that supports the 2.0.x kernel properly.
+
diff --git a/obsolete/bootlogd.init b/obsolete/bootlogd.init
new file mode 100755 (executable)
index 0000000..cf7b9eb
--- /dev/null
@@ -0,0 +1,67 @@
+#! /bin/sh
+#
+# bootlogd     One of the first scripts to be executed. Starts or stops
+#              the bootlogd log program. If this script is called as
+#              "stop-bootlogd", it will stop the daemon instead of
+#              starting it even when called with the "start" argument.
+#
+# Version:     @(#)bootlogd  2.77  24-Aug-1999  miquels@cistron.nl
+#
+
+PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
+DAEMON=/sbin/bootlogd
+NAME=bootlogd
+DESC="Bootlog daemon"
+PIDFILE=/var/run/$NAME.pid
+
+test -f $DAEMON || exit 0
+
+## set -e # not needed
+
+. /etc/default/rcS
+
+case "$0" in
+       *stop-bootlog*)
+               stopper=yes
+               ;;
+esac
+
+case "$1" in
+       start|stop)
+               if [ "$stopper" ] || [ "$1" = "stop" ]
+               then
+                       echo -n "Stopping $DESC: "
+                       start-stop-daemon --stop --quiet --exec $DAEMON
+               else
+                       echo -n "Starting $DESC: "
+                       start-stop-daemon --start --quiet --exec $DAEMON -- -r
+               fi
+               if [ "$stopper" ] && [ -f /var/log/boot.log ] && \
+                  [ -f /var/log/boot.log~ ]
+               then
+                       cd /var/log
+                       savelog -p -c 5 boot.log > /dev/null 2>&1
+                       mv boot.log.0 boot.log
+                       mv boot.log~ boot.log.0
+               fi
+               echo "$NAME."
+               ;;
+        restart|force-reload)
+               echo -n "Restarting $DESC: "
+               start-stop-daemon --stop --quiet --pidfile \
+                       $PIDFILE --exec $DAEMON -- -p $PIDFILE
+               sleep 1
+               start-stop-daemon --start --quiet --pidfile \
+                       $PIDFILE --exec $DAEMON -- -p $PIDFILE
+               echo "$NAME."
+               ;;
+       *)
+               N=${0##*/}
+               N=${N#[SK]??}
+               echo "Usage: $N {start|stop|restart|force-reload}" >&2
+               exit 1
+               ;;
+esac
+
+exit 0
+
diff --git a/obsolete/powerd.8 b/obsolete/powerd.8
new file mode 100644 (file)
index 0000000..c1c27e3
--- /dev/null
@@ -0,0 +1,73 @@
+'\" -*- coding: UTF-8 -*-
+.\" Copyright (C) 1994 Miquel van Smoorenburg.
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+.\"
+.TH POWERD 8 "Feb 14, 1994" "" "Linux System Administrator's Manual"
+.SH NAME
+.\" powerd \(em monitor a serial line connected to an UPS.
+powerd -- monitor a serial line connected to an UPS.
+.SH SYNOPSIS
+.B /sbin/powerd
+.RB " serial-device "
+.SH DESCRIPTION
+.B Powerd
+is a daemon process that sits in the background and monitors the state
+of the DCD line of the serial device. This line is meant to be
+connected to a UPS (Uninterruptible Power Supply) so that \fBpowerd\fP knows
+about the state of the UPS. As soon as \fBpowerd\fP senses that the
+power is failing (it sees that DCD goes low) it notifies \fBinit\fP(8),
+and \fBinit\fP then executes the \fBpowerwait\fP and \fBpowerfail\fP entries.
+If \fBpowerd\fP senses that the power has been restored, it notifies \fBinit\fP
+again and \fBinit\fP will execute the \fBpowerokwait\fP entries.
+.SH ARGUMENTS
+.IP serial-device
+Some serial port that is not being used by some other device, and does not
+share an interrupt with any other serial port.
+.SH DIAGNOSTICS
+\fBPowerd\fP regularly checks the \fBDSR\fP line to see if it's high.
+\fBDSR\fP should be directly connected to \fBDTR\fP and \fBpowerd\fP
+keeps that line high, so if \fBDSR\fP is low then something is wrong
+with the connection. \fBPowerd\fP will notify you about this fact every
+two minutes. When it sees that the connection has been restored it
+will say so.
+.SH HOWTO
+It's pretty simple to connect your UPS to the Linux machine. The steps
+are easy:
+.TP 0.5i
+.B 1.
+Make sure you have an UPS with a simple relay output: it should
+close its connections (make) if the power is gone, and it should
+open its connections (break) if the power is good.
+.TP 0.5i
+.B 2.
+Buy a serial plug. Connect the DTR line to the DSR line directly.
+Connect the DTR line and the DCD line with a \fB10 kilo ohm\fP
+resistor. Now connect the relay output of the UPS to GROUND
+and the DCD line. If you don't know what pins DSR, DTR, DCD and
+GROUND are you can always ask at the store where you bought the plug.
+.TP 0.5i
+.B 3.
+You're all set.
+.SH BUGS
+Well, not a real bug but \fBpowerd\fP should be able to do a broadcast or
+something on the ethernet in case more Linux-boxes are connected to
+the same UPS and only one of them is connected to the UPS status line.
+.SH SEE ALSO
+.BR shutdown (8),
+.BR init (8),
+.BR inittab (5)
+.SH AUTHOR
+Miquel van Smoorenburg, miquels@cistron.nl
diff --git a/obsolete/powerd.README b/obsolete/powerd.README
new file mode 100644 (file)
index 0000000..dd0563c
--- /dev/null
@@ -0,0 +1,36 @@
+There are 2 *much* better powerd's than the one that is included as
+an example with sysvinit. The powerd.c in this distribution is just ment
+as a programming example, not to be used in a real life situation.
+
+1. GENPOWERD.
+
+This is a powerd written by Tom Webster <webster@kaiwan.com>. It's a
+nice package, you can find info at http://www.kaiwan.com/~webster/genpower.html
+
+2. POWERD-2.0.
+
+This is another powerd, written by rubini@ipvvis.unipv.it (Alessandro Rubini).
+The main advantage over genpowerd is that it can signal other machines over
+the network.
+
+This LSM may be out of date. Please check if a newer version exists.
+
+Begin3
+Title:          powerd
+Version:        2.0
+Entered-date:   Sep 26 1995
+Description:    A daemon to shut down and up computers connected to ups's.
+                Network-aware: server-mode and client-mode allowed.
+Keywords:       ups, powerd, init
+Author:         Alessandro Rubini (based on Miquel van Smoorenburg's work).
+Maintained-by:  rubini@ipvvis.unipv.it (Alessandro Rubini)
+Primary-site:   sunsite.unc.edu /pub/Linux/system/UPS/powerd-2.0.tar.gz
+               25kB  powerd-2.0.tar.gz
+               1kB   powerd-2.0.lsm
+Alternate-site: 
+Original-site:  iride.unipv.it /pub/linux
+               25kB  powerd-2.0.tar.gz
+               1kB   powerd-2.0.lsm
+Platform:       Linux. Porting is foreseeable.      
+Copying-policy: GPL
+End
diff --git a/obsolete/powerd.c b/obsolete/powerd.c
new file mode 100644 (file)
index 0000000..fdd31d8
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * powerd      Monitor the DCD line of a serial port connected to
+ *             an UPS. If the power goes down, notify init.
+ *             If the power comes up again, notify init again.
+ *             As long as the power is OK, the DCD line should be
+ *             "HIGH". When the power fails, DCD should go "LOW".
+ *             Powerd keeps DTR high so that you can connect
+ *             DCD and DTR with a resistor of 10 Kilo Ohm and let the
+ *             UPS or some relais pull the DCD line to ground.
+ *             You also need to connect DTR and DSR together. This
+ *             way, powerd can check now and then if DSR is high
+ *             so it knows the UPS is connected!!
+ *
+ * Usage:      powerd /dev/cua4 (or any other serial device).
+ *
+ * Author:     Miquel van Smoorenburg, <miquels@drinkel.cistron.nl>.
+ *
+ * Version:    1.31,  29-Feb-1996.
+ *
+ *             This program was originally written for my employer,
+ *                     ** Cistron Electronics **
+ *             who has given kind permission to release this program
+ *             for general puppose.
+ *
+ *             Copyright (C) 1991-1996 Cistron Electronics.
+ *
+ *             This program is free software; you can redistribute it and/or modify
+ *             it under the terms of the GNU General Public License as published by
+ *             the Free Software Foundation; either version 2 of the License, or
+ *             (at your option) any later version.
+ *
+ *             This program is distributed in the hope that it will be useful,
+ *             but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *             GNU General Public License for more details.
+ *
+ *             You should have received a copy of the GNU General Public License
+ *             along with this program; if not, write to the Free Software
+ *             Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* Use the new way of communicating with init. */
+#define NEWINIT
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <signal.h>
+#include <syslog.h>
+#include <string.h>
+#include "paths.h"
+#ifdef NEWINIT
+#include "initreq.h"
+#endif
+
+#ifndef SIGPWR
+#  define SIGPWR SIGUSR1
+#endif
+
+#ifdef NEWINIT
+void alrm_handler()
+{
+}
+#endif
+
+/* Tell init the power has either gone or is back. */
+void powerfail(ok)
+int ok;
+{
+  int fd;
+#ifdef NEWINIT
+  struct init_request req;
+
+  /* Fill out the request struct. */
+  memset(&req, 0, sizeof(req));
+  req.magic = INIT_MAGIC;
+  req.cmd   = ok ? INIT_CMD_POWEROK : INIT_CMD_POWERFAIL;
+
+  /* Open the fifo (with timeout) */
+  signal(SIGALRM, alrm_handler);
+  alarm(3);
+  if ((fd = open(INIT_FIFO, O_WRONLY)) >= 0
+               && write(fd, &req, sizeof(req)) == sizeof(req)) {
+       close(fd);
+       return;
+  }
+  /* Fall through to the old method.. */
+#endif
+
+  /* Create an info file for init. */
+  unlink(PWRSTAT);
+  if ((fd = open(PWRSTAT, O_CREAT|O_WRONLY, 0644)) >= 0) {
+       if (ok)
+               write(fd, "OK\n", 3);
+       else
+               write(fd, "FAIL\n", 5);
+       close(fd);
+  }
+  kill(1, SIGPWR);
+}
+
+/* Main program. */
+int main(int argc, char **argv)
+{
+  int fd;
+  int dtr_bit = TIOCM_DTR;
+  int flags;
+  int status, oldstat = -1;
+  int count = 0;
+  int tries = 0;
+
+  if (argc < 2) {
+       fprintf(stderr, "Usage: powerd <device>\n");
+       exit(1);
+  }
+
+  /* Start syslog. */
+  openlog("powerd", LOG_CONS|LOG_PERROR, LOG_DAEMON);
+
+  /* Open monitor device. */
+  if ((fd = open(argv[1], O_RDWR | O_NDELAY)) < 0) {
+       syslog(LOG_ERR, "%s: %s", argv[1], sys_errlist[errno]);
+       closelog();
+       exit(1);
+  }
+
+  /* Line is opened, so DTR is high. Force it anyway to be sure. */
+  ioctl(fd, TIOCMBIS, &dtr_bit);
+
+  /* Daemonize. */
+  switch(fork()) {
+       case 0: /* Child */
+               closelog();
+               setsid();
+               break;
+       case -1: /* Error */
+               syslog(LOG_ERR, "can't fork.");
+               closelog();
+               exit(1);
+       default: /* Parent */
+               closelog();
+               exit(0);
+  }
+
+  /* Restart syslog. */
+  openlog("powerd", LOG_CONS, LOG_DAEMON);
+
+  /* Now sample the DCD line. */
+  while(1) {
+       /* Get the status. */
+       ioctl(fd, TIOCMGET, &flags);
+
+       /* Check the connection: DSR should be high. */
+       tries = 0;
+       while((flags & TIOCM_DSR) == 0) {
+               /* Keep on trying, and warn every two minutes. */
+               if ((tries % 60) == 0)
+                   syslog(LOG_ALERT, "UPS connection error");
+               sleep(2);
+               tries++;
+               ioctl(fd, TIOCMGET, &flags);
+       }
+       if (tries > 0)
+               syslog(LOG_ALERT, "UPS connection OK");
+
+       /* Calculate present status. */
+       status = (flags & TIOCM_CAR);
+
+       /* Did DCD drop to zero? Then the power has failed. */
+       if (oldstat != 0 && status == 0) {
+               count++;
+               if (count > 3)
+                       powerfail(0);
+               else {
+                       sleep(1);
+                       continue;
+               }
+       }
+       /* Did DCD come up again? Then the power is back. */
+       if (oldstat == 0 && status > 0) {
+               count++;
+               if (count > 3)
+                       powerfail(1);
+               else {
+                       sleep(1);
+                       continue;
+               }
+       }
+       /* Reset count, remember status and sleep 2 seconds. */
+       count = 0;
+       oldstat = status;
+       sleep(2);
+  }
+  /* Never happens */
+  return(0);
+}
diff --git a/obsolete/powerd.cfg b/obsolete/powerd.cfg
new file mode 100644 (file)
index 0000000..65a76f0
--- /dev/null
@@ -0,0 +1,58 @@
+# Example configuration for power daemon.
+# NOTE: this is not implemented yet, just a design.
+#
+# @(#) powerd.cfg 1.01 01-Oct-1994 MvS
+#
+
+# This is the setup section. It sets up the default line
+# signals that your UPS likes to see.
+[ setup ]
+dtr = 1
+rts = 1
+baud = 2400
+send "AAAA"
+
+# Now: how to tell UPS to turn off the power.
+[ powerdown ]
+dtr = 0
+send "BYE"
+
+# How to monitor the UPS, or a remote UPS.
+# Possible line signals: dcd cts dsr ring
+#
+# Comment out the parts you don't want.
+#
+# All of this (1, 2, 3) can be combined.
+[ monitor ]
+
+# First, do we want to broadcast the UPS status
+# on ethernet when something happens?
+# Comment out to disable.
+# Syntax: address, portnumber
+#    address:    broadcast adress on ethernet
+#    portnumber: unused priviliged port (under 1024)
+broadcast = 10.0.33.255,15
+
+# monitor type 1. This tells powerd to monitor line signals.
+ok = dcd
+fail = !dcd
+lowbat = rts
+
+# Monitor type 2. Tell powerd to look for data.
+ok = "OK"
+fail = "!"
+
+# Monitor type 3. Listen to the ethernet.
+#
+# Warn_host is the hostname of the system with the UPS
+# This is for security, so that someone on a DOS box
+# can't spoof the powerd broadcast. The number after it
+# is the portnumber to listen to (see above: broadcast).
+#
+# Note: if the broadcast address set above is enabled
+# and we receive a message from a remote powerd, we check
+# the received broadcast address. If this is the same
+# as from the broadcast we just received,
+# it will not be repeated (guess why).
+remote = warn_host,15
+
diff --git a/obsolete/utmpdump.c.OLD b/obsolete/utmpdump.c.OLD
new file mode 100644 (file)
index 0000000..9161396
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * utmpdump    Simple program to dump UTMP and WTMP files in
+ *             raw format, so they can be examined.
+ *
+ * Version:    @(#)utmpdump.c  13-Aug-1996  1.00  miquels@cistron.nl
+ *
+ *             This file is part of the sysvinit suite,
+ *             Copyright (C) 1991-1996 Miquel van Smoorenburg.
+ *
+ *             This program is free software; you can redistribute it and/or modify
+ *             it under the terms of the GNU General Public License as published by
+ *             the Free Software Foundation; either version 2 of the License, or
+ *             (at your option) any later version.
+ *
+ *             This program is distributed in the hope that it will be useful,
+ *             but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *             GNU General Public License for more details.
+ *
+ *             You should have received a copy of the GNU General Public License
+ *             along with this program; if not, write to the Free Software
+ *             Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <stdio.h>
+#include <utmp.h>
+#include <time.h>
+
+void dump(fp)
+FILE *fp;
+{
+  struct utmp ut;
+  int f;
+  time_t tm;
+
+  while (fread(&ut, sizeof(struct utmp), 1, fp) == 1) {
+       for(f = 0; f < 12; f++) if (ut.ut_line[f] == ' ') ut.ut_line[f] = '_';
+       for(f = 0; f <  8; f++) if (ut.ut_name[f] == ' ') ut.ut_name[f] = '_';
+       tm = ut.ut_time;
+       printf("[%d] [%05d] [%-4.4s] [%-8.8s] [%-12.12s] [%-15.15s]\n",
+               ut.ut_type, ut.ut_pid, ut.ut_id, ut.ut_user,
+               ut.ut_line, 4 + ctime(&tm));
+  }
+}
+
+int main(argc, argv)
+int argc;
+char **argv;
+{
+  int f;
+  FILE *fp;
+
+  if (argc < 2) {
+       argc = 2;
+       argv[1] = UTMP_FILE;
+  }
+
+  for(f = 1; f < argc; f++) {
+       if (strcmp(argv[f], "-") == 0) {
+               printf("Utmp dump of stdin\n");
+               dump(stdin);
+       } else if ((fp = fopen(argv[f], "r")) != NULL) {
+               printf("Utmp dump of %s\n", argv[f]);
+               dump(fp);
+               fclose(fp);
+       } else
+               perror(argv[f]);
+  }
+  return(0);
+}
diff --git a/src/Makefile b/src/Makefile
new file mode 100644 (file)
index 0000000..c466bf8
--- /dev/null
@@ -0,0 +1,168 @@
+#
+# Makefile     Makefile for the systemV init suite.
+#              Targets:   all      compiles everything
+#                         install  installs the binaries (not the scripts)
+#                          clean    cleans up object files
+#                         clobber  really cleans up
+#
+# Version:     @(#)Makefile  2.85-13  23-Mar-2004  miquels@cistron.nl
+#
+
+CC     = gcc
+CFLAGS = -ansi -W -Wall -O2 -fomit-frame-pointer -D_GNU_SOURCE
+LDFLAGS        = -s
+STATIC =
+
+# For some known distributions we do not build all programs, otherwise we do.
+BIN    =
+SBIN   = init halt shutdown runlevel killall5
+USRBIN = last mesg
+
+MAN1   = last.1 lastb.1 mesg.1
+MAN5   = initscript.5 inittab.5
+MAN8   = halt.8 init.8 killall5.8 pidof.8 poweroff.8 reboot.8 runlevel.8
+MAN8   += shutdown.8 telinit.8
+
+ifeq ($(DISTRO),)
+BIN    += mountpoint
+SBIN   += sulogin bootlogd
+USRBIN += utmpdump wall
+MAN1   += mountpoint.1 wall.1
+MAN8   += sulogin.8 bootlogd.8
+endif
+
+ifeq ($(DISTRO),Debian)
+BIN    += mountpoint
+SBIN   += sulogin bootlogd
+MAN1   += mountpoint.1
+MAN8   += sulogin.8 bootlogd.8
+endif
+
+ifeq ($(DISTRO),Owl)
+USRBIN += wall
+MAN1   += wall.1
+endif
+
+BIN_OWNER      = root
+BIN_GROUP      = root
+BIN_COMBO      = $(BIN_OWNER):$(BIN_GROUP)
+STRIP          = strip -s -R .comment
+INSTALL_EXEC   = install -o $(BIN_OWNER) -g $(BIN_GROUP) -m 755
+INSTALL_DATA   = install -o $(BIN_OWNER) -g $(BIN_GROUP) -m 644
+MANDIR         = /usr/share/man
+
+ifeq ($(WITH_SELINUX),yes)
+  SELINUX_DEF=-DWITH_SELINUX
+  INIT_SELIBS=-lsepol -lselinux
+  SULOGIN_SELIBS=-lselinux     
+else
+  SELINUX_DEF=
+  INIT_SELIBS=
+  SULOGIN_SELIBS=
+endif
+
+
+
+# Additional libs for GNU libc.
+ifneq ($(wildcard /usr/lib/libcrypt.a),)
+LCRYPT         = -lcrypt
+endif
+
+all:           $(BIN) $(SBIN) $(USRBIN)
+
+init:          init.o init_utmp.o
+               $(CC) $(LDFLAGS) $(STATIC) -o $@ init.o init_utmp.o $(INIT_SELIBS)
+
+halt:          halt.o ifdown.o hddown.o utmp.o reboot.h
+               $(CC) $(LDFLAGS) -o $@ halt.o ifdown.o hddown.o utmp.o
+
+last:          last.o oldutmp.h
+               $(CC) $(LDFLAGS) -o $@ last.o
+
+mesg:          mesg.o
+               $(CC) $(LDFLAGS) -o $@ mesg.o
+
+mountpoint:    mountpoint.o
+               $(CC) $(LDFLAGS) -o $@ mountpoint.o
+
+utmpdump:      utmpdump.o
+               $(CC) $(LDFLAGS) -o $@ utmpdump.o
+
+runlevel:      runlevel.o
+               $(CC) $(LDFLAGS) -o $@ runlevel.o
+
+sulogin:       sulogin.o
+               $(CC) $(LDFLAGS) $(STATIC) $(SELINUX_DEF) -o $@ $^ $(LCRYPT) $(SULOGIN_SELIBS)
+
+wall:          dowall.o wall.o
+               $(CC) $(LDFLAGS) -o $@ dowall.o wall.o
+
+shutdown:      dowall.o shutdown.o utmp.o reboot.h
+               $(CC) $(LDFLAGS) -o $@ dowall.o shutdown.o utmp.o
+
+bootlogd:      bootlogd.o
+               $(CC) $(LDFLAGS) -o $@ bootlogd.o -lutil
+
+sulogin.o:     sulogin.c 
+               $(CC) -c $(CFLAGS) $(SELINUX_DEF) sulogin.c
+
+init.o:                init.c init.h set.h reboot.h initreq.h
+               $(CC) -c $(CFLAGS) $(SELINUX_DEF)  init.c
+
+utmp.o:                utmp.c init.h
+               $(CC) -c $(CFLAGS) utmp.c
+
+init_utmp.o:   utmp.c init.h
+               $(CC) -c $(CFLAGS) -DINIT_MAIN utmp.c -o init_utmp.o
+
+cleanobjs:
+               rm -f *.o *.bak
+
+clean:         cleanobjs
+               @echo Type \"make clobber\" to really clean up.
+
+clobber:       cleanobjs
+               rm -f $(BIN) $(SBIN) $(USRBIN)
+
+distclean:     clobber
+
+install:
+               for i in $(BIN); do \
+                       $(STRIP) $$i ; \
+                       $(INSTALL_EXEC) $$i $(ROOT)/bin/ ; \
+               done
+               for i in $(SBIN); do \
+                       $(STRIP) $$i ; \
+                       $(INSTALL_EXEC) $$i $(ROOT)/sbin/ ; \
+               done
+               for i in $(USRBIN); do \
+                       $(STRIP) $$i ; \
+                       $(INSTALL_EXEC) $$i $(ROOT)/usr/bin/ ; \
+               done
+               # $(INSTALL_EXEC) etc/initscript.sample $(ROOT)/etc/
+               ln -sf halt $(ROOT)/sbin/reboot
+               ln -sf halt $(ROOT)/sbin/poweroff
+               ln -sf init $(ROOT)/sbin/telinit
+               ln -sf /sbin/killall5 $(ROOT)/bin/pidof
+               if [ ! -f $(ROOT)/usr/bin/lastb ]; then \
+                       ln -sf last $(ROOT)/usr/bin/lastb; \
+               fi
+               $(INSTALL_DATA) initreq.h $(ROOT)/usr/include/
+               for i in $(MAN1); do \
+                       $(INSTALL_DATA) ../man/$$i $(ROOT)$(MANDIR)/man1/; \
+               done
+               for i in $(MAN5); do \
+                       $(INSTALL_DATA) ../man/$$i $(ROOT)$(MANDIR)/man5/; \
+               done
+               for i in $(MAN8); do \
+                       $(INSTALL_DATA) ../man/$$i $(ROOT)$(MANDIR)/man8/; \
+               done
+ifeq ($(ROOT),)
+               #
+               # This part is skipped on Debian systems, the
+               # debian.preinst script takes care of it.
+               @if [ ! -p /dev/initctl ]; then \
+                echo "Creating /dev/initctl"; \
+                rm -f /dev/initctl; \
+                mknod -m 600 /dev/initctl p; fi
+endif
diff --git a/src/bootlogd.c b/src/bootlogd.c
new file mode 100644 (file)
index 0000000..d9be60b
--- /dev/null
@@ -0,0 +1,657 @@
+/*
+ * 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@cistron.nl
+ *
+ * Bugs:       Uses openpty(), only available in glibc. Sorry.
+ *
+ *             This file is part of the sysvinit suite,
+ *             Copyright (C) 1991-2004 Miquel van Smoorenburg.
+ *
+ *             This program is free software; you can redistribute it and/or modify
+ *             it under the terms of the GNU General Public License as published by
+ *             the Free Software Foundation; either version 2 of the License, or
+ *             (at your option) any later version.
+ *
+ *             This program is distributed in the hope that it will be useful,
+ *             but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *             GNU General Public License for more details.
+ *
+ *             You should have received a copy of the GNU General Public License
+ *             along with this program; if not, write to the Free Software
+ *             Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *                             *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@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;
+}
+
diff --git a/src/dowall.c b/src/dowall.c
new file mode 100644 (file)
index 0000000..821324f
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * dowall.c    Write to all users on the system.
+ *
+ * Author:     Miquel van Smoorenburg, miquels@cistron.nl
+ * 
+ * Version:    @(#)dowall.c  2.85-5  02-Jul-2003  miquels@cistron.nl
+ *
+ *             This file is part of the sysvinit suite,
+ *             Copyright (C) 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.
+ *
+ *             This program is distributed in the hope that it will be useful,
+ *             but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *             GNU General Public License for more details.
+ *
+ *             You should have received a copy of the GNU General Public License
+ *             along with this program; if not, write to the Free Software
+ *             Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/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);
+}
+
diff --git a/src/halt.c b/src/halt.c
new file mode 100644 (file)
index 0000000..60d79a1
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ * 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@cistron.nl
+ *
+ * Version:    2.86,  30-Jul-2004
+ *
+ *             This file is part of the sysvinit suite,
+ *             Copyright (C) 1991-2004 Miquel van Smoorenburg.
+ *
+ *             This program is free software; you can redistribute it and/or modify
+ *             it under the terms of the GNU General Public License as published by
+ *             the Free Software Foundation; either version 2 of the License, or
+ *             (at your option) any later version.
+ *
+ *             This program is distributed in the hope that it will be useful,
+ *             but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *             GNU General Public License for more details.
+ *
+ *             You should have received a copy of the GNU General Public License
+ *             along with this program; if not, write to the Free Software
+ *             Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#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@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);
+}
diff --git a/src/hddown.c b/src/hddown.c
new file mode 100644 (file)
index 0000000..89e9f47
--- /dev/null
@@ -0,0 +1,512 @@
+/*
+ * hddown.c    Find all disks on the system and
+ *             shut them down.
+ *
+ * Copyright (C) 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.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+char *v_hddown = "@(#)hddown.c  1.02  22-Apr-2003  miquels@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@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
+
diff --git a/src/ifdown.c b/src/ifdown.c
new file mode 100644 (file)
index 0000000..42c0d6f
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * ifdown.c    Find all network interfaces on the system and
+ *             shut them down.
+ *
+ * Copyright (C) 1998 Miquel van Smoorenburg.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by 
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful, 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+char *v_ifdown = "@(#)ifdown.c  1.11  02-Jun-1998  miquels@cistron.nl";
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#define MAX_IFS        64
+
+/*
+ *     First, we find all shaper devices and down them. Then we
+ *     down all real interfaces. This is because the comment in the
+ *     shaper driver says "if you down the shaper device before the
+ *     attached inerface your computer will follow".
+ */
+int ifdown(void)
+{
+       struct ifreq ifr[MAX_IFS];
+       struct ifconf ifc;
+       int i, fd;
+       int numif;
+       int shaper;
+
+       if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+               fprintf(stderr, "ifdown: ");
+               perror("socket");
+               return -1;
+       }
+       ifc.ifc_len = sizeof(ifr);
+       ifc.ifc_req = ifr;
+
+       if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) {
+               fprintf(stderr, "ifdown: ");
+               perror("SIOCGIFCONF");
+               close(fd);
+               return -1;
+       }
+       numif = ifc.ifc_len / sizeof(struct ifreq);
+
+       for (shaper = 1; shaper >= 0; shaper--) {
+               for (i = 0; i < numif; i++) {
+
+                       if ((strncmp(ifr[i].ifr_name, "shaper", 6) == 0)
+                           != shaper) continue;
+
+                       if (strcmp(ifr[i].ifr_name, "lo") == 0)
+                               continue;
+                       if (strchr(ifr[i].ifr_name, ':') != NULL)
+                               continue;
+                       ifr[i].ifr_flags &= ~(IFF_UP);
+                       if (ioctl(fd, SIOCSIFFLAGS, &ifr[i]) < 0) {
+                               fprintf(stderr, "ifdown: shutdown ");
+                               perror(ifr[i].ifr_name);
+                       }
+               }
+       }
+       close(fd);
+
+       return 0;
+}
+
diff --git a/src/init.c b/src/init.c
new file mode 100644 (file)
index 0000000..1d7371c
--- /dev/null
@@ -0,0 +1,2714 @@
+/*
+ * Init                A System-V Init Clone.
+ *
+ * Usage:      /sbin/init
+ *                  init [0123456SsQqAaBbCc]
+ *               telinit [0123456SsQqAaBbCc]
+ *
+ * Version:    @(#)init.c  2.86  30-Jul-2004  miquels@cistron.nl
+ */
+#define VERSION "2.86"
+#define DATE    "31-Jul-2004"
+/*
+ *             This file is part of the sysvinit suite,
+ *             Copyright (C) 1991-2004 Miquel van Smoorenburg.
+ *
+ *             This program is free software; you can redistribute it and/or modify
+ *             it under the terms of the GNU General Public License as published by
+ *             the Free Software Foundation; either version 2 of the License, or
+ *             (at your option) any later version.
+ *
+ *             This program is distributed in the hope that it will be useful,
+ *             but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *             GNU General Public License for more details.
+ *
+ *             You should have received a copy of the GNU General Public License
+ *             along with this program; if not, write to the Free Software
+ *             Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#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@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
+         &n