[Initscripts-ng-commits] r873 - in /trunk/src/insserv: CHANGES COPYING Makefile README debian/ init-functions insserv-1.12.0.lsm insserv.8.in insserv.c insserv.conf install_initd listing.c listing.h remove_initd tests/ tests/suite

kelmo-guest at users.alioth.debian.org kelmo-guest at users.alioth.debian.org
Sat Mar 14 15:47:02 UTC 2009


Author: kelmo-guest
Date: Sat Mar 14 15:47:02 2009
New Revision: 873

URL: http://svn.debian.org/wsvn/initscripts-ng/?sc=1&rev=873
Log:
Commit upstream source to repo and remove mergeWithUpstream property from ./debian

Added:
    trunk/src/insserv/CHANGES
    trunk/src/insserv/COPYING
    trunk/src/insserv/Makefile
    trunk/src/insserv/README
    trunk/src/insserv/init-functions
    trunk/src/insserv/insserv-1.12.0.lsm
    trunk/src/insserv/insserv.8.in
    trunk/src/insserv/insserv.c
    trunk/src/insserv/insserv.conf
    trunk/src/insserv/install_initd   (with props)
    trunk/src/insserv/listing.c
    trunk/src/insserv/listing.h
    trunk/src/insserv/remove_initd   (with props)
    trunk/src/insserv/tests/
    trunk/src/insserv/tests/suite
Modified:
    trunk/src/insserv/debian/   (props changed)

Added: trunk/src/insserv/CHANGES
URL: http://svn.debian.org/wsvn/initscripts-ng/trunk/src/insserv/CHANGES?rev=873&op=file
==============================================================================
--- trunk/src/insserv/CHANGES (added)
+++ trunk/src/insserv/CHANGES Sat Mar 14 15:47:02 2009
@@ -1,0 +1,416 @@
+-------------------------------------------------------------------
+Tue Jul 29 15:23:43 CEST 2008 - werner at suse.de
+
+- Resolve server minor problems on openSUSE and Debian
+  * Handle the runlevel bit for system boot in lvl2str()
+  * Handle dependencies on several script on command line
+  * Let link scheme overwrite empty default start/stop tags
+
+-------------------------------------------------------------------
+Wed Jul  2 19:38:15 CEST 2008 - werner at suse.de
+
+- Use prefetch from kernels code for lists
+- Make start/stop requirements link to the services its self
+- Make -pedantic work
+- Be sure that the code is optimized
+
+-------------------------------------------------------------------
+Wed Jun 25 19:37:35 CEST 2008 - werner at suse.de
+
+- Handle provides and service lists in parallel, this should
+  reduce the double efforts.
+- Calculate start oder and stop order separately
+- Sort targets in the makefile accordingly to their order
+
+-------------------------------------------------------------------
+Wed Jun 18 15:27:16 CEST 2008 - werner at suse.de
+
+- Clean out several provides of one specific script, add therefore
+  an alias list to the first provide. This makes less work load on
+  following the full dependcy trees.
+- Use aligned memory allocation to avoid memory fragmentation
+- Use reference counts to be able to free not needed memory
+- Be able to follow not only the start but also the stop dependcies
+
+-------------------------------------------------------------------
+Wed Jun 11 14:35:13 CEST 2008 - werner at suse.de
+
+- Make kbd interactive to avoid race during tty resize (bnc#259577)
+
+-------------------------------------------------------------------
+Wed Jun  4 12:17:44 CEST 2008 - werner at suse.de
+
+- Scan service links even for non LSB scripts (bnc#391014)
+
+-------------------------------------------------------------------
+Thu May 29 00:42:42 CEST 2008 - dmueller at suse.de
+
+- really remove last reference to boot.setclock (bnc#384254)
+
+-------------------------------------------------------------------
+Tue May 20 09:25:41 CEST 2008 - werner at suse.de
+
+- Remove last occurence of boot.setclock (bnc#384254)
+
+-------------------------------------------------------------------
+Thu May 15 13:42:57 CEST 2008 - werner at suse.de
+
+- Also ignore temporary (mostly?) errors if executed within an rpm
+  scriptlet (bnc#385498, bnc#384254)
+- Move stat() check for /etc/insserv.conf.d/ configure files
+  to scan_conf() otherwise we never scan those files.
+
+-------------------------------------------------------------------
+Mon May  5 18:47:26 CEST 2008 - werner at suse.de
+
+- Ignore temporary errors during update with YaST/zypper (bnc#385498)
+
+-------------------------------------------------------------------
+Mon Apr 28 15:25:54 CEST 2008 - werner at suse.de
+
+- boot.clock was into two scripts for boot and shutdown
+  Todo: make insserv knowing about Required-Stop to merge them
+  again to one boot.clock.
+
+-------------------------------------------------------------------
+Wed Apr  9 16:02:26 CEST 2008 - mkoenig at suse.de
+
+- add boot.crypto-early to insserv.conf
+
+-------------------------------------------------------------------
+Mon Feb  4 18:32:33 CET 2008 - werner at suse.de
+
+- Expand system facilities to make deep of the dependcy graph
+  less deeper.
+
+-------------------------------------------------------------------
+Fri Feb  1 14:34:52 CET 2008 - werner at suse.de
+
+- Avoid SIGSEGV in functions which can handle NULL pointers
+  thanks goes to Petter Reinholdtsen for his report
+
+-------------------------------------------------------------------
+Wed Jan 30 17:49:55 CET 2008 - werner at suse.de
+
+- New version 1.11.0 of insserv
+- Code cleanup, update copyrights, and manual pages
+- Use __attribute__ of gcc for better function management
+- Use __attribute__ of gcc for alignment of list_t pointers
+- Some preparation listing.c for kill link sorting (TODO)
+
+-------------------------------------------------------------------
+Thu Jan 24 18:59:14 CET 2008 - werner at suse.de
+
+- Add and integrate many patches from Debian svn tree done by
+  Petter Reinholdtsen
+  * Make it possible to set the path at runtime, to make it easier
+    to write test suites
+  * Support for reading LSB headers info from override directroy
+  * Accept script names like 'rc.local' for Debian build
+  * Use other defaults on Debian systems (start, stop levels)
+  * Put redundant level informations in one API
+  * Fix the handling of stop scripts and the shutdown sequence
+    on Debian systems
+  * Better loop report
+  * Make loops fatal if not forced
+- Clean the API for listing the services
+
+-------------------------------------------------------------------
+Wed Oct 10 12:39:25 CEST 2007 - werner at suse.de
+
+- Even disabled scripts should be occur in dependcies (#331615)
+- Handle return values of strsep in case of several provides
+- Do not scan services links if removed later on
+- New version 1.10.0 of insserv
+
+-------------------------------------------------------------------
+Fri Aug 31 16:08:47 CEST 2007 - werner at suse.de
+
+- Scan all scripts for Start-Before even if already known (#297214)
+- Do not add disabled scripts to the depend files
+
+-------------------------------------------------------------------
+Fri Jul 13 12:05:19 CEST 2007 - werner at suse.de
+
+- Remove hotplug and pcmcia from insserv.conf because they are
+  dropped (bug #291417)
+
+-------------------------------------------------------------------
+Tue Jun 19 18:59:30 CEST 2007 - werner at suse.de
+
+- Scan all files in `should start before' even facilities
+- Read insserv.conf in other root environments
+
+-------------------------------------------------------------------
+Tue May 29 17:45:06 CEST 2007 - werner at suse.de
+
+- Ignore rcs-files (bug #278520)
+
+-------------------------------------------------------------------
+Mon Jan 29 15:08:17 CET 2007 - werner at suse.de
+
+- Split insserv.conf off from source tar ball to avoid patching
+- Add boot.crypto to $local_fs
+- Add smbfs/cifs to $remote_fs
+
+-------------------------------------------------------------------
+Mon Jan 22 15:17:23 CET 2007 - werner at suse.de
+
+- Add missed `start this script before' feature patch (fate#301269)
+
+-------------------------------------------------------------------
+Tue Jan 16 14:04:06 CET 2007 - werner at suse.de
+
+- Remove obsolate `$netdaemons' facility (#209380)
+- Add `start this script before' feature (fate #301269)
+- New version 1.09.0 of insserv
+
+-------------------------------------------------------------------
+Mon Nov 20 11:42:40 CET 2006 - werner at suse.de
+
+- Expand aliases even for services which requires $all (#216202)
+
+-------------------------------------------------------------------
+Mon May 15 12:56:27 CEST 2006 - werner at suse.de
+
+- Make kdump boot script a interactive script to enforce that this
+  script runs not in parallel with other script (#175340, #171332)
+
+-------------------------------------------------------------------
+Wed Mar  8 17:06:47 CET 2006 - werner at suse.de
+
+- Ignore .orig and .org file (bug #155944)
+
+-------------------------------------------------------------------
+Wed Mar  1 12:51:17 CET 2006 - werner at suse.de
+
+- Add a few lines about $all into the man page (bug #151561)
+
+-------------------------------------------------------------------
+Mon Feb  6 16:40:46 CET 2006 - werner at suse.de
+
+- Handle duplets even for interactive scripts
+
+-------------------------------------------------------------------
+Tue Jan 31 15:06:53 CET 2006 - werner at suse.de
+
+- Be sure to find all interactive scripts and set their unique
+  start number.  This solves the problem of two interactive
+  scripts in the same start order.
+
+-------------------------------------------------------------------
+Tue Apr  4 18:23:24 CEST 2006 - werner at suse.de
+
+- Add patches from Petter Reinholdtsen
+- Make debian part work
+
+-------------------------------------------------------------------
+Wed Jan 25 14:52:26 CET 2006 - werner at suse.de
+
+- Fix the broken fix (bug #145403)
+
+-------------------------------------------------------------------
+Mon Jan 23 13:35:40 CET 2006 - werner at suse.de
+
+- Make missing Provides and Requires non-fatal.
+
+-------------------------------------------------------------------
+Fri Jan 20 18:13:39 CET 2006 - werner at suse.de
+
+- Fix bug in handling of non-LSB scripts
+- Add error condition for broken LSB scripts
+- Make calculation of order number somewhat smarter, e.g. do not
+  count system facilities.
+
+-------------------------------------------------------------------
+Thu Jan 19 15:33:06 CET 2006 - werner at suse.de
+
+- Make the restore option work even on broken link scheme
+- Don't count empty provides
+
+-------------------------------------------------------------------
+Thu Nov 10 18:05:53 CET 2005 - werner at suse.de
+
+- Add patches from Petter Reinholdtsen
+  * Avoid zero pointer
+  * Allow not existing rc ditrectories at dryrun
+  * Some more debugging code
+  * Map the runlevel scheme into a common struct
+
+-------------------------------------------------------------------
+Fri Oct 28 17:48:38 CEST 2005 - werner at suse.de
+
+- Fix duplet handling in make like service handling (bug #130451)
+
+-------------------------------------------------------------------
+Thu Sep 15 16:54:40 CEST 2005 - werner at suse.de
+
+- Add dryrun changes from Petter Reinholdtsen
+- First step for support of traditional SystemV link scheme
+
+-------------------------------------------------------------------
+Wed May 25 17:33:30 CEST 2005 - werner at suse.de
+
+- Include confdir patch from Ludwig Nussel
+- Bounce version to 1.01.0
+
+-------------------------------------------------------------------
+Mon Nov 29 16:32:04 CET 2004 - werner at suse.de
+
+- Add some comments about boot script file names.
+
+-------------------------------------------------------------------
+Thu Nov 25 18:24:35 CET 2004 - werner at suse.de
+
+- Update to 1.00.8 : use correct listing head (bug #48415)
+
+-------------------------------------------------------------------
+Thu Nov 25 13:48:45 CET 2004 - werner at suse.de
+
+- Update to 1.00.7 : be more verbose on invalid file names
+
+-------------------------------------------------------------------
+Tue Nov 23 13:13:35 CET 2004 - werner at suse.de
+
+- Update to 1.00.6
+
+-------------------------------------------------------------------
+Tue Nov 23 13:00:22 CET 2004 - werner at suse.de
+
+- Fix segmentation fault caused by broken cast on reversed scanned
+  linkage structure (bug #48415)
+
+-------------------------------------------------------------------
+Wed Sep 22 11:52:43 CEST 2004 - werner at suse.de
+
+- Do not call error recursively if chdir fails (bugzilla #45767)
+
+-------------------------------------------------------------------
+Mon Sep 20 16:40:13 CEST 2004 - werner at suse.de
+
+- Add a few lines about the make like dependency files to the
+  manual page of insserv.
+
+-------------------------------------------------------------------
+Fri Sep 17 12:16:04 CEST 2004 - werner at suse.de
+
+- Boot scripts which may call sulogin are INTERACTIVE
+
+-------------------------------------------------------------------
+Thu Sep 16 14:19:56 CEST 2004 - werner at suse.de
+
+- Add dnsmasq and lwresd as optional to system facility named
+
+-------------------------------------------------------------------
+Thu Sep  2 11:34:09 BST 2004 - werner at suse.de
+
+- Fix dependency of boot.clock also used in single mode (bug#44610)
+
+-------------------------------------------------------------------
+Fri Aug 27 17:50:39 CEST 2004 - werner at suse.de
+
+- Fix dependencies of single script
+- Fix $ALL handling for dependency files
+- Fix handling of interactive scripts for for dependency files
+
+-------------------------------------------------------------------
+Thu Aug 19 17:37:06 CEST 2004 - werner at suse.de
+
+- Update to 1.00.3 to support dependency files for make calls
+
+-------------------------------------------------------------------
+Wed Mar 31 11:52:31 CEST 2004 - werner at suse.de
+
+- Verbose option and explain exit status in manual page (#37599)
+
+-------------------------------------------------------------------
+Thu Mar 18 17:53:04 CET 2004 - werner at suse.de
+
+- Remove debug message
+
+-------------------------------------------------------------------
+Wed Mar 17 15:12:55 CET 2004 - werner at suse.de
+
+- Implement the `$all' feature (bug #36140)
+
+-------------------------------------------------------------------
+Wed Mar 10 17:27:53 CET 2004 - werner at suse.de
+
+- YAL (Yet Another Loop) fixed (bug #35522)
+
+-------------------------------------------------------------------
+Thu Feb 19 18:40:36 CET 2004 - werner at suse.de
+
+- Do not create a K* link if no S* link exist.
+
+-------------------------------------------------------------------
+Thu Feb 19 13:55:14 CET 2004 - werner at suse.de
+
+- More about K* links in /etc/init.d/boot.d
+
+-------------------------------------------------------------------
+Tue Feb 17 14:18:30 CET 2004 - ro at suse.de
+
+- enable K* (kill) links in /etc/init.d/boot.d
+
+-------------------------------------------------------------------
+Wed Oct  1 17:58:08 CEST 2003 - werner at suse.de
+
+- Allow numbers in initial segment of namespace of scripts (#31793)
+
+-------------------------------------------------------------------
+Mon Sep 22 18:41:26 CEST 2003 - werner at suse.de
+
+- Stop recursive walk on dependency tree hard if a loop is detected
+
+-------------------------------------------------------------------
+Tue Sep 16 13:57:59 CEST 2003 - werner at suse.de
+
+- Add extra flag for ENABLED status of services due the level
+  can not used for checking this anymore (bug #31000)
+
+-------------------------------------------------------------------
+Mon Sep  1 13:49:23 CEST 2003 - werner at suse.de
+
+- Move (re)calculation of order of active scripts after the
+  calculation of all start orders to hold dependencies unique
+
+-------------------------------------------------------------------
+Fri Aug 29 14:42:22 CEST 2003 - werner at suse.de
+
+- Update to 1.00.0 which fixes the handling of interactive
+  services for passphrase input (bug #29375) and enhance
+  the calculation of already enabled NONE-LSB scripts.
+
+-------------------------------------------------------------------
+Thu Jul  3 14:53:39 CEST 2003 - werner at suse.de
+
+- Follow LSB specs and specify script functions for proc
+  handling (no /sbin in PATH anymore).
+
+-------------------------------------------------------------------
+Wed Jun 18 14:39:47 CEST 2003 - werner at suse.de
+
+- Update to 0.99.9: better handling with not LSB conform scripts
+
+-------------------------------------------------------------------
+Thu Jun 12 10:47:07 CEST 2003 - kukuk at suse.de
+
+- fix filelist 
+
+-------------------------------------------------------------------
+Wed Apr 16 18:31:07 CEST 2003 - werner at suse.de
+
+- Update to 0.99.8: be able to remove doubles with -rf
+
+-------------------------------------------------------------------
+Sat Mar  8 16:00:23 CET 2003 - kukuk at suse.de
+
+- Add /lib/lsb back [Bug #24904]
+
+-------------------------------------------------------------------
+Wed Jan 15 17:07:54 CET 2003 - ro at suse.de
+
+- split from aaa_base
+ 
+

Added: trunk/src/insserv/COPYING
URL: http://svn.debian.org/wsvn/initscripts-ng/trunk/src/insserv/COPYING?rev=873&op=file
==============================================================================
--- trunk/src/insserv/COPYING (added)
+++ trunk/src/insserv/COPYING Sat Mar 14 15:47:02 2009
@@ -1,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  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 Library 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) 19yy  <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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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) 19yy 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 Library General
+Public License instead of this License.

Added: trunk/src/insserv/Makefile
URL: http://svn.debian.org/wsvn/initscripts-ng/trunk/src/insserv/Makefile?rev=873&op=file
==============================================================================
--- trunk/src/insserv/Makefile (added)
+++ trunk/src/insserv/Makefile Sat Mar 14 15:47:02 2009
@@ -1,0 +1,192 @@
+#
+# Makefile for compiling insserv tool
+#
+# Author: Werner Fink,  <werner at suse.de>
+#
+
+INITDIR  =	/etc/init.d
+INSCONF  =	/etc/insserv.conf
+#DESTDIR =	/tmp/root
+#DEBUG	 =	-DDEBUG=1 -Wpacked
+DEBUG	 =
+ISSUSE	 =	-DSUSE
+DESTDIR	 =
+VERSION	 =	1.12.0
+DATE	 =	$(shell date +'%d%b%y' | tr '[:lower:]' '[:upper:]')
+
+#
+# Architecture
+#
+ifdef RPM_OPT_FLAGS
+	  COPTS = -g $(RPM_OPT_FLAGS)
+else
+	   ARCH = $(shell uname -i)
+ifeq ($(ARCH),i386)
+	  COPTS = -g -O3 -mcpu=i586 -mtune=i686
+else
+	  COPTS = -g -O2
+endif
+endif
+	 CFLAGS = -W -Wall $(COPTS) $(DEBUG) $(LOOPS) -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 \
+		  $(ISSUSE) -DINITDIR=\"$(INITDIR)\" -DINSCONF=\"$(INSCONF)\" -pipe
+	  CLOOP = -falign-loops=0
+	LDFLAGS = -Wl,-O,3,--relax
+	   LIBS =
+ifdef USE_RPMLIB
+	 CFLAGS += -DUSE_RPMLIB=1
+	LDFLAGS += -Wl,--as-needed
+	   LIBS += -lrpm
+endif
+	     CC = gcc
+	     RM = rm -f
+	  MKDIR = mkdir -p
+	  RMDIR = rm -rf
+   INSTBINFLAGS = -m 0700
+	INSTBIN = install $(INSTBINFLAGS)
+   INSTSRPFLAGS = -m 0700
+	INSTSRP = install $(INSTSRPFLAGS)
+   INSTDOCFLAGS = -c -m 0444
+	INSTDOC = install $(INSTDOCFLAGS)
+   INSTCONFLAGS = -c -m 0644
+	INSTCON = install $(INSTDOCFLAGS)
+	   LINK = ln -sf
+#
+	SDOCDIR = $(DESTDIR)/usr/share/man/man8
+	SBINDIR = $(DESTDIR)/sbin
+	CONFDIR = $(DESTDIR)/etc
+	 LSBDIR = $(DESTDIR)/lib/lsb
+      USRLSBDIR = $(DESTDIR)/usr/lib/lsb
+
+#
+# Determine if a library provides a specific function
+# Fist argument is the function to test, the second
+# one is the library its self.
+#
+	  CTEST = $(CC) -nostdinc -fno-builtin -o /dev/null -xc
+    cc-function = $(shell printf 'void *$(1)();\nint main(){return($(1)(0)?0:1);}'|$(CTEST) - -l$(2:lib%=%) > /dev/null 2>&1 && echo $(1))
+
+#
+# The rules
+#
+
+TODO	=	insserv insserv.8
+
+all:		$(TODO)
+
+insserv:	insserv.o listing.o
+	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+listing.o:	listing.c listing.h config.h .system
+	$(CC) $(CFLAGS) $(CLOOP) -c $<
+
+insserv.o:	insserv.c listing.h config.h .system
+	$(CC) $(CFLAGS) $(CLOOP) -c $<
+
+listing.h:	.system
+
+config.h:	ADRESSES  = ^\#\s*if\s+defined\(HAS_[[:alnum:]_]+\)\s+&&\s+defined\(_ATFILE_SOURCE\)
+config.h:	FUNCTIONS = $(shell sed -rn '/$(ADRESSES)/{ s/.*defined\(HAS_([[:alnum:]_]+)\).*/\1/p; }' listing.h)
+config.h:	listing.h
+	@echo '/* Generated automatically by running make -- do not edit */'  > config.h
+	@echo '#ifndef CONFIG_H' >> config.h
+	@echo '#define CONFIG_H' >> config.h
+	@for def in $(foreach func,$(FUNCTIONS),$(call cc-function,$(func),libc)); do \
+	    echo "#define HAS_$$def"; \
+	 done >> config.h
+	@echo '#endif' >> config.h
+
+ifeq ($(ISSUSE),-DSUSE)
+insserv.8:	insserv.8.in .system
+	sed -r '\!@@(ELSE|NOT)_SUSE@@!,\!@@END_SUSE@@!d;\!@@(BEGIN|END)_SUSE@@!d' < $< > $@
+else
+insserv.8:	insserv.8.in .system
+	sed -r '\!@@BEGIN_SUSE@@!,\!@@(ELSE|END)_SUSE@@!d;\!@@(NOT|END)_SUSE@@!d' < $< > $@
+endif
+
+.system:	SYSTEM=$(shell cat .system 2> /dev/null)
+.system:	.force
+	@test "$(SYSTEM)" = "$(ISSUSE)$(DEBUG)" || echo "$(ISSUSE)$(DEBUG)" > .system
+
+.force:
+
+.PHONY:		clean
+clean:
+	$(RM) *.o *~ $(TODO) config.h .depend.* .system
+
+ifneq ($(MAKECMDGOALS),clean)
+
+-include	.depend.listing .depend.insserv
+
+.depend.listing::	listing.c listing.h
+	@$(CC) $(CFLAGS) -M listing.c >$@ 2>/dev/null
+
+.depend.insserv::	insserv.c listing.h
+	@$(CC) $(CFLAGS) -M insserv.c >$@ 2>/dev/null
+
+endif
+
+install:	$(TODO)
+	$(MKDIR)   $(SBINDIR)
+	$(MKDIR)   $(SDOCDIR)
+	$(MKDIR)   $(CONFDIR)
+ifeq ($(ISSUSE),-DSUSE)
+	$(MKDIR)   $(LSBDIR)
+	$(MKDIR)   $(DESTDIR)/usr/lib
+	$(MKDIR)   $(USRLSBDIR)
+endif
+	$(INSTBIN) insserv        $(SBINDIR)/
+	$(INSTDOC) insserv.8      $(SDOCDIR)/
+	$(INSTCON) insserv.conf   $(CONFDIR)/
+ifeq ($(ISSUSE),-DSUSE)
+	$(INSTCON) init-functions $(LSBDIR)/
+	$(INSTSRP) install_initd  $(USRLSBDIR)/
+	$(INSTSRP) remove_initd   $(USRLSBDIR)/
+endif
+
+#
+# Make distribution
+#
+FILES	= README         \
+	  COPYING        \
+	  CHANGES        \
+	  Makefile       \
+	  listing.c      \
+	  listing.h      \
+	  insserv.8.in   \
+	  insserv.c      \
+	  insserv.conf   \
+	  init-functions \
+	  remove_initd   \
+	  install_initd  \
+	  tests/suite    \
+	  insserv-$(VERSION).lsm
+
+dest:	clean
+	$(MKDIR) insserv-$(VERSION)/tests
+	@echo -e "Begin3\n\
+Title:		insserv tool for boot scripts\n\
+Version:	$(VERSION)\n\
+Entered-date:	$(DATE)\n\
+Description:	Used for enabling of installed boot scripts\n\
+x 		by scanning comment headers which are LSB conform.\n\
+Keywords:	boot service control, LSB\n\
+Author:		Werner Fink <werner at suse.de>\n\
+Maintained-by:	Werner Fink <werner at suse.de>\n\
+Primary-site:	sunsite.unc.edu /pub/Linux/system/daemons/init\n\
+x		@UNKNOWN insserv-$(VERSION).tar.gz\n\
+Alternate-site:	ftp.suse.com /pub/projects/init\n\
+Platforms:	Linux with System VR2 or higher boot scheme\n\
+Copying-policy:	GPL\n\
+End" | sed 's@^ @@g;s@^x@@g' > insserv-$(VERSION).lsm
+	for file in $(FILES) ; do \
+	    case "$$file" in \
+	    tests/*) cp -p $$file insserv-$(VERSION)/tests/ ;; \
+	    *)	     cp -p $$file insserv-$(VERSION)/ ;; \
+	    esac; \
+	done
+	tar -cps -zf  insserv-$(VERSION).tar.gz insserv-$(VERSION)/
+	$(RMDIR)    insserv-$(VERSION)
+	set -- `gzip -l insserv-$(VERSION).tar.gz | tail -1` ; \
+	sed "s:@UNKNOWN:$$1:" < insserv-$(VERSION).lsm > \
+	insserv-$(VERSION).lsm.tmp ; \
+	mv insserv-$(VERSION).lsm.tmp insserv-$(VERSION).lsm

Added: trunk/src/insserv/README
URL: http://svn.debian.org/wsvn/initscripts-ng/trunk/src/insserv/README?rev=873&op=file
==============================================================================
--- trunk/src/insserv/README (added)
+++ trunk/src/insserv/README Sat Mar 14 15:47:02 2009
@@ -1,0 +1,34 @@
+   Install
+   =======
+
+Edit the Makefile (set INITDIR to the path of the
+boot scripts used by the system during boot time),
+type `make' and `make install'.
+
+   Downloading latest version
+   ==========================
+
+The latest version of the insserv source is available from
+<URL: ftp://ftp.suse.com/pub/projects/init/ >.
+
+   Processes controlling
+   =====================
+
+This small package provides a tool for process controlling
+in System V boot scripts.
+
+The syntax is simple:
+
+   insserv
+
+   insserv etc/init.d
+
+   insserv etc/init.d/myscript
+
+See manual page for more information.
+
+
+Happy booting,
+
+       Werner Fink
+

Propchange: trunk/src/insserv/debian/
            ('mergeWithUpstream' removed)

Added: trunk/src/insserv/init-functions
URL: http://svn.debian.org/wsvn/initscripts-ng/trunk/src/insserv/init-functions?rev=873&op=file
==============================================================================
--- trunk/src/insserv/init-functions (added)
+++ trunk/src/insserv/init-functions Sat Mar 14 15:47:02 2009
@@ -1,0 +1,55 @@
+#
+# Define init LSB shell functions
+#
+
+#
+# Source SuSE's rc functions
+#
+. /etc/rc.status
+
+#
+# Be sure that  start_daemon, killproc, and
+# pidofproc will be script functions.
+#
+function start_daemon ()
+{
+    /sbin/start_daemon ${1+"$@"}
+}
+
+function killproc ()
+{
+    /sbin/killproc ${1+"$@"}
+}
+
+function pidofproc ()
+{
+    /sbin/pidofproc ${1+"$@"}
+}
+
+#
+# Logging of succes messages
+#
+function log_success_msg ()
+{
+    echo -en "$@"
+    echo -e  "$rc_done"
+}
+
+#
+# Logging of failure messages
+#
+function log_failure_msg ()
+{
+    echo -en "$@"
+    echo -e  "$rc_failed"
+}
+
+#
+# Logging of warn messages
+#
+function log_warning_msg ()
+{
+    echo -en "$@"
+    echo -e  "${stat}${attn} warning${norm}"
+}
+

Added: trunk/src/insserv/insserv-1.12.0.lsm
URL: http://svn.debian.org/wsvn/initscripts-ng/trunk/src/insserv/insserv-1.12.0.lsm?rev=873&op=file
==============================================================================
--- trunk/src/insserv/insserv-1.12.0.lsm (added)
+++ trunk/src/insserv/insserv-1.12.0.lsm Sat Mar 14 15:47:02 2009
@@ -1,0 +1,15 @@
+Begin3
+Title:		insserv tool for boot scripts
+Version:	1.12.0
+Entered-date:	30JUL08
+Description:	Used for enabling of installed boot scripts
+ 		by scanning comment headers which are LSB conform.
+Keywords:	boot service control, LSB
+Author:		Werner Fink <werner at suse.de>
+Maintained-by:	Werner Fink <werner at suse.de>
+Primary-site:	sunsite.unc.edu /pub/Linux/system/daemons/init
+		@UNKNOWN insserv-1.12.0.tar.gz
+Alternate-site:	ftp.suse.com /pub/projects/init
+Platforms:	Linux with System VR2 or higher boot scheme
+Copying-policy:	GPL
+End

Added: trunk/src/insserv/insserv.8.in
URL: http://svn.debian.org/wsvn/initscripts-ng/trunk/src/insserv/insserv.8.in?rev=873&op=file
==============================================================================
--- trunk/src/insserv/insserv.8.in (added)
+++ trunk/src/insserv/insserv.8.in Sat Mar 14 15:47:02 2009
@@ -1,0 +1,443 @@
+.\"
+.\" Copyright 2000-2008 Werner Fink
+.\" Copyright 2000-2003 SuSE GmbH Nuernberg, Germany
+.\" Copyright 2007 SuSE Linux Products GmbH Nuernberg, Germany
+.\" Copyright 2008 SuSE Linux Products GmbH Nuernberg, Germany
+.\"
+.\" 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.
+.\"
+@@BEGIN_SUSE@@
+.TH INSSERV 8 "Jul 29, 2008" "Version 1.11" "The SuSE boot concept"
+.UC 8
+.OS SuSE Linux
+@@ELSE_SUSE@@
+.TH INSSERV 8 "Jul 29, 2008" "Version 1.11"
+.UC 8
+.OS Debian
+@@END_SUSE@@
+.SH NAME
+insserv \- Enable an installed system init script
+.SH SYNOPSIS
+.\"
+.B insserv
+.RB [ \-v ]
+.RB [ \-c\ <config> ]
+.RB [ \-p\ <path> ]
+.RB [ \-d ]
+.RB [ \-f ]
+.RI [[ / ] path/to/init.d/ ] script \ ...
+.PP
+.B insserv
+.RB [ \-v ]
+.RB [ \-c\ <config> ]
+.RB [ \-p\ <path> ]
+@@BEGIN_SUSE@@
+.RI [[ / ] path/to/init.d/ ] script [ ,start=<lvl1> [ ,<lvl2>\ ... ]
+@@ELSE_SUSE@@
+.RI [[ / ] path/to/init.d/ ] script [ ,start=<lvl1> [ ,<lvl2>\ ... ] ,stop=<lvl1> [ ,<lvl2>\ ... ]]
+@@END_SUSE@@
+.PP
+.B insserv
+.RB [ \-v ]
+.RB [ \-c\ <config> ]
+.RB [ \-p\ <path> ]
+.B \-r
+.RB [ \-d ]
+.RB [ \-f ]
+.RI [[ / ] path/to/init.d/ ] script \ ...
+.PP
+.B insserv
+.B \-h
+.PP
+@@BEGIN_SUSE@@
+.RB /usr/lib/lsb/install_initd
+.RI [[ / ] path/to/init.d/script ]
+.PP
+.RB /usr/lib/lsb/remove_initd
+.RI [[ / ] path/to/init.d/script ]
+@@END_SUSE@@
+.SH DESCRIPTION
+.B insserv
+enables an installed system init script (`boot script')
+by reading the comment header of the script, e.g.:
+.sp 1
+.in +1l
+.nf
+ ### BEGIN INIT INFO
+ # Provides:          boot_facility_1 [ boot_facility_2 ...]
+ # Required-Start:    boot_facility_1 [ boot_facility_2 ...]
+ # Required-Stop:     boot_facility_1 [ boot_facility_2 ...]
+ # Should-Start:      boot_facility_1 [ boot_facility_2 ...]
+ # Should-Stop:       boot_facility_1 [ boot_facility_2 ...]
+ # X-Start-Before:    boot_facility_1 [ boot_facility_2 ...]
+ # X-Stop-After:      boot_facility_1 [ boot_facility_2 ...]
+ # Default-Start:     run_level_1 [ run_level_2 ...]
+ # Default-Stop:      run_level_1 [ run_level_2 ...]
+ # Short-Description: single_line_description
+ # Description:       multiline_description
+ ### END INIT INFO
+.fi
+.in -1l
+.sp 1
+and calculating the dependencies between all scripts.
+@@BEGIN_SUSE@@
+Please note, that the
+.B Default\-Stop
+are ignored in SuSE Linux, because the SuSE boot script concept
+uses a differential link scheme (see
+.IR init.d (7)).
+@@ELSE_SUSE@@
+Please be aware that the line
+.sp 1
+.in +1l
+.nf
+ # Required-Stop:  boot_facility_1 [ boot_facility_2 ...]
+.fi
+.in -1l
+.sp 1
+declares facilities which must be available during shutdown of the service
+declared in the
+.B Provides
+tag.  Same holds true for
+.sp 1
+.in +1l
+.nf
+ # Should-Stop:    boot_facility_1 [ boot_facility_2 ...]
+.fi
+.in -1l
+.sp 1
+which declares facilities which should be available during shutdown of
+the service declared in the 
+.B Provides
+tag. In both cases the script system should avoid stopping services
+which are declared by these two Stop tags until the script including
+these tags is stopped.
+@@END_SUSE@@
+.PP
+The optional
+.B X\-Start\-Before
+keyword implies that the script using this keyword
+should be started
+.B before
+the specified service names.
+Wereas the optional
+.B X\-Stop\-After
+keyword implies that the script using this keyword
+should be stopped
+.B after
+the specified service names. Both implies that those
+services now depend on the specifying script. 
+With known dependencies and runlevel(s)
+.B insserv
+sets and reorders the corresponding symbolic links
+of the concerned runlevels
+@@BEGIN_SUSE@@
+directories (see \fI init.d\fR (7)).
+@@ELSE_SUSE@@
+directories.
+@@END_SUSE@@
+Known runlevels are:
+.sp 1
+.in +1l
+.nf
+ \fB0\fR\   used for System halt
+ \fB1\fR\   used for single user mode
+ \fB2\fR\   used for local multiuser without remote network
+ \fB3\fR\   used for full multiuser with network
+ \fB4\fR\   reserved for local use
+ \fB5\fR\   used for full multiuser with network and xdm
+ \fB6\fR\   used for System reboot
+@@BEGIN_SUSE@@
+ \fBS\fR\   used during boot into single user mode
+ \fBB\fR\   used during boot before any other runlevel
+@@ELSE_SUSE@@
+ \fBS\fR\   used during boot before any other runlevel
+@@END_SUSE@@
+.fi
+.in -1l
+.sp 1
+.PP
+.B insserv
+scans for
+.B System Facilities
+in the configuration file
+.I /etc/insserv.conf
+and each file in the directory
+.IR /etc/insserv.conf.d/ .
+Each line which begins with
+.B $
+and a following name defines a system facility
+accordingly to the Linux Standard Base Specification (LSB),
+All names followed by such a system facility
+will declare the required dependencies of the facility.
+Here is an example for
+.IR /etc/insserv.conf :
+.sp 1
+.in +1l
+.nf
+ # All local filesystems are mounted
+ # (done during boot phase)
+ $local_fs       boot
+
+ # Low level networking
+ $network        network route
+
+ # Named is operational
+ $named          named
+
+ # All remote filesystems are mounted
+ # (in some cases /usr may be remote).
+ $remote_fs      $local_fs nfs
+
+ # System logger is operational
+ $syslog         syslog
+
+ # All network daemons are running
+ $netdaemons     portmap inetd
+
+ # Services which need to be interactive
+ <interactive>   boot.crypto
+.fi
+.in -1l
+.sp 1
+Names starting with a `+' sign are marked as optional.
+If the service with the name after the plus sign is
+available it will be used, if not available it is
+ignored silently.  Words beginning with
+.B <
+and ending with
+.B >
+are keywords.  Currently
+.B <interactive>
+is the only know keyword for marking a service
+as an interactive one, e.g. a service which requires
+a passphrase or password input during boot
+or runlevel change.
+.P
+Beside the defined
+.B System Facilities
+in the configuration file
+.IR /etc/insserv.conf ,
+.B insserv
+also knows the special facility
+.BR $all .
+This facility indicates that a service should be inserted
+at the end of all services.  Clearly all services using
+this facility will be grouped into one starting order.
+.\"
+.SH OPTIONS
+Currently there exists nine options for
+.BR insserv .
+.TP
+.BR \-v ,\  \-\-verbose
+Write out what is currently going on.
+.TP
+.BR \-c\ <config> ,\  \-\-config\ <config>
+Specify path to the insserv.conf file and the insserv.conf.d
+directory.  Useful for testing.
+.TP
+.BR \-o\ <path> ,\  \-\-override\ <path>
+Path to replace existing LSB comment headers with the comment
+headers found in this path (default path is
+.IR /etc/insserv/overrides/ ).
+.TP
+.BR \-p\ <path> ,\  \-\-path\ <path>
+Specify path to init.d directory.  Useful for testing.
+.TP
+.BR \-n ,\  \-\-dryrun
+Do not update symlinks.
+.TP
+.BR \-r ,\  \-\-remove
+Remove the listed scripts from all runlevels.
+.TP
+.BR \-d ,\  \-\-default
+Use default runlevels a defined in the scripts.
+This may restore an edited runlevel link scheme.
+.TP
+.BR \-f ,\  \-\-force
+Ignore if a required service is missed.
+.TP
+.BR \-h ,\  \-\-help
+Print out short usage message.
+.PP
+But you may use the argument syntax described in the
+following section.
+.SH ARGUMENTS
+.TP
+.RI [[ / ] path/to/init.d/ ]
+Relative or absolute path to the init scripts base directory.
+@@BEGIN_SUSE@@
+For the SuSE Linux boot concept, this defaults to
+@@ELSE_SUSE@@
+This defaults to
+@@END_SUSE@@
+.I /etc/init.d/
+in compliance with the LSB specification.
+In this case
+.B insserv
+does not add or remove a script to the runlevels
+declared in the script headers, but may re\-order the
+runlevels if the order of the currently enabled scripts
+has changed (see option
+.BR \-d ).
+Note that if a relative path is used
+.B insserv
+has to be called from the root directory.
+.TP
+.RI [[ / ] path/to/init.d/ ] script\ ...
+List of scripts which have to be added to
+the runlevels. If a path is used it
+should point to the absolute or relative
+location of the boot scripts.
+.B insserv
+checks for the existence of these scripts.
+For the runlevels the information found in
+the script is used.
+.TP
+.RI [[ / ] path/to/init.d/ ] script [ ,start=<lvl1> [ ,<lvl2> ]]\ ...
+List of scripts which have to be added to
+the specified runlevels to be started with.
+You may use this extension to override the default values
+for start and stop runlevels of the script.
+Note that
+.BR <lvl1> ,\  <lvl2> ,\ ...
+are the known runlevels explained above.
+The extension
+.IR ,stop=<lvl1> [ ,<lvl2> ]]
+is possible
+@@BEGIN_SUSE@@
+is possible but ignored on SuSE Linux.
+@@ELSE_SUSE@@
+is also possible.
+@@END_SUSE@@
+.TP
+.RI \fB\-r\fR\ [[ / ] path/to/init.d/ ] script\ ...
+List of scripts which should be removed from
+the runlevels. If a path is used it
+should point to the absolute or relative
+location of the boot scripts.
+.B insserv
+checks for the existence of these scripts.
+.\"
+.SH OVERRIDES
+Beside using the extensions
+.IR ,start=<lvl1> [ ,<lvl2> ]]
+and
+.IR ,stop=<lvl1> [ ,<lvl2> ]]
+it is possible to use override files replace a LSB comment header
+or simple provide a missing LSB comment header.  This can be done
+by placing a file with the new LSB comment header using the same
+name as the boot or init script in the directory
+.IR /etc/insserv/overrides/ .
+.\"
+.SH EXIT CODES
+The exit codes have the following conditions:
+.RS 7
+.IP 0 5
+Service was successfully installed or removed
+.IP 1 5
+Service was not installed or removed
+.RE
+.RS 5
+.SH NOTE
+Please be aware that the following patterns of
+boot script file names will be not accepted by
+.BR insserv:
+.sp 1
+.in +1l
+.nf
+@@BEGIN_SUSE@@
+        *.local
+@@END_SUSE@@
+        *.dpkg*
+        *.rpm*
+        *.ba*
+        *.old
+        *.new
+        *.org
+        *.orig
+        *.save
+        *.swp
+        *.core
+        *~
+.fi
+.in -1l
+.sp 1
+with the wildcard character
+.BR * .
+Beside this all boot script file names beginning with one
+of the following characters
+.sp 1
+.in +1l
+.nf
+        $.#%_+-\\*[]^:()~
+.fi
+.in -1l
+.sp 1
+will be ignored.
+.SH BUGS
+Boot script sometimes misses comments.
+.SH FILES
+.TP
+.I /etc/insserv.conf
+configuration file for
+.B insserv
+which defines the LSB System Facilities.
+.TP
+.I /etc/insserv.conf.d/
+directory for further configuration files for declaring
+LSB System Facilities.
+.TP
+.I /etc/insserv/overrides/
+path to replace existing LSB comment headers with the comment
+headers found in this path.
+.TP
+.I /etc/init.d/
+path to the
+@@BEGIN_SUSE@@
+SuSE
+@@END_SUSE@@
+init script base directory as
+required by the Linux Standard Base Specification (LSB).
+.PP
+.IR /etc/init.d/.depend.boot ,
+.br
+.IR /etc/init.d/.depend.start ,
+.br
+.I  /etc/init.d/.depend.stop
+.in +7
+The
+.BR make (1)
+like dependency files produced by
+.B insserv
+for
+.IR booting ", " starting ", and " stopping
+with the help of
+.BR startpar (8).
+.in -7
+
+.\"
+.SH SEE ALSO
+@@BEGIN_SUSE@@
+.BR init.d (7),
+@@END_SUSE@@
+.BR init (7),
+@@BEGIN_SUSE@@
+.BR startproc (8),
+.BR checkproc (8),
+.BR killproc (8),
+@@END_SUSE@@
+.BR startpar (8).
+.SH COPYRIGHT
+2000\-2008 Werner Fink,
+.br
+2000\-2003 SuSE GmbH Nuernberg, Germany,
+.br
+2007 SuSE Linux Products GmbH Nuernberg, Germany.
+.br
+2008 SuSE Linux Products GmbH Nuernberg, Germany.
+.SH AUTHOR
+Werner Fink <feedback at suse.de>

Added: trunk/src/insserv/insserv.c
URL: http://svn.debian.org/wsvn/initscripts-ng/trunk/src/insserv/insserv.c?rev=873&op=file
==============================================================================
--- trunk/src/insserv/insserv.c (added)
+++ trunk/src/insserv/insserv.c Sat Mar 14 15:47:02 2009
@@ -1,0 +1,3461 @@
+/*
+ * insserv(.c)
+ *
+ * Copyright 2000-2008 Werner Fink, 2000 SuSE GmbH Nuernberg, Germany,
+ *				    2003 SuSE Linux AG, Germany.
+ *				    2004 SuSE LINUX AG, Germany.
+ *			       2005-2008 SUSE LINUX Products GmbH, Germany.
+ * Copyright 2005,2008 Petter Reinholdtsen
+ *
+ * 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.
+ */
+
+#define MINIMAL_MAKE	1	/* Remove disabled scripts from .depend.boot,
+				 * .depend.start, .depend.halt, and .depend.stop */
+#define MINIMAL_RULES	1	/* ditto */
+
+#include <pwd.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/syscall.h>
+#include <dirent.h>
+#include <regex.h>
+#include <errno.h>
+#include <limits.h>
+#include <getopt.h>
+#if defined(USE_RPMLIB) && (USE_RPMLIB > 0)
+# include <rpm/rpmlib.h>
+# include <rpm/rpmmacro.h>
+#endif /* USE_RPMLIB */
+#include "listing.h"
+
+#ifdef SUSE
+# define DEFAULT_START_LVL	"3 5"
+# define DEFAULT_STOP_LVL	"3 5"
+# define USE_KILL_IN_BOOT	1
+# define USE_COMPAT_EMPTY	1
+static inline void oneway(char *restrict stop) attribute((always_inline,nonnull(1)));
+static inline void oneway(char *restrict stop)
+{
+    char * ptr = stop;
+    while ((ptr = strpbrk(ptr, "016sS")))
+	*ptr++ = ' ';
+}
+#else /* not SUSE, but Debian */
+# define DEFAULT_START_LVL	"2 3 4 5"
+# define DEFAULT_STOP_LVL	"0 1 6"
+# define DEFAULT_DEPENDENCY	"$remote_fs $syslog"
+# undef  USE_KILL_IN_BOOT
+# undef  USE_COMPAT_EMPTY
+#endif /* not SUSE, but Debian */
+
+#ifndef  INITDIR
+# define INITDIR	"/etc/init.d"
+#endif
+#ifndef  OVERRIDEDIR
+# define OVERRIDEDIR	"/etc/insserv/overrides"
+#endif
+#ifndef  INSCONF
+# define INSCONF	"/etc/insserv.conf"
+#endif
+
+/*
+ * For a description of regular expressions see regex(7).
+ */
+#define COMM		"^#[[:blank:]]*"
+#define VALUE		":[[:blank:]]*([[:print:]]*)"
+/* The second substring contains our value (the first is all) */
+#define SUBNUM		2
+#define SUBNUM_SHD	3
+#define START		"[-_]+start"
+#define STOP		"[-_]+stop"
+
+/* The main regular search expressions */
+#define PROVIDES	COMM "provides" VALUE
+#define REQUIRED	COMM "required"
+#define SHOULD		COMM "(x[-_]+[a-z0-9_-]*)?should"
+#define BEFORE		COMM "(x[-_]+[a-z0-9_-]*)?start[-_]+before"
+#define AFTER		COMM "(x[-_]+[a-z0-9_-]*)?stop[-_]+after"
+#define DEFAULT		COMM "default"
+#define REQUIRED_START  REQUIRED START VALUE
+#define REQUIRED_STOP	REQUIRED STOP  VALUE
+#define SHOULD_START	SHOULD   START VALUE
+#define SHOULD_STOP	SHOULD   STOP  VALUE
+#define START_BEFORE	BEFORE   VALUE
+#define STOP_AFTER	AFTER    VALUE
+#define DEFAULT_START	DEFAULT  START VALUE
+#define DEFAULT_STOP	DEFAULT  STOP  VALUE
+#define DESCRIPTION	COMM "description" VALUE
+
+/* System facility search within /etc/insserv.conf */
+#define EQSIGN		"([[:blank:]]*[=:][[:blank:]]*|[[:blank:]]+)"
+#define CONFLINE	"^(\\$[a-z0-9_-]+)" EQSIGN "([[:print:]]*)"
+#define CONFLINE2	"^(<[a-z0-9_-]+>)"  EQSIGN "([[:print:]]*)"
+#define SUBCONF		2
+#define SUBCONFNUM	4
+
+/* The root file system */
+static char *root;
+
+/* The main line buffer if unique */
+static char buf[LINE_MAX];
+
+/* When to be verbose */
+static boolean verbose = false;
+
+/* When to be verbose */
+static boolean dryrun = false;
+
+/* When paths set do not add root if any */
+static boolean set_override = false;
+static boolean set_insconf = false;
+
+/* Search results points here */
+typedef struct lsb_struct {
+    char *provides;
+    char *required_start;
+    char *required_stop;
+    char *should_start;
+    char *should_stop;
+    char *start_before;
+    char *stop_after;
+    char *default_start;
+    char *default_stop;
+    char *description;
+} attribute((aligned(sizeof(char*)))) lsb_t;
+
+/* Search results points here */
+typedef struct reg_struct {
+    regex_t prov;
+    regex_t req_start;
+    regex_t req_stop;
+    regex_t shl_start;
+    regex_t shl_stop;
+    regex_t start_bf;
+    regex_t stop_af;
+    regex_t def_start;
+    regex_t def_stop;
+    regex_t desc;
+} attribute((aligned(sizeof(regex_t)))) reg_t;
+
+typedef struct creg_struct {
+    regex_t isysfaci;
+    regex_t isactive;
+} attribute((aligned(sizeof(regex_t)))) creg_t;
+
+static lsb_t script_inf;
+static reg_t reg;
+static creg_t creg;
+static char empty[1] = "";
+
+/* Delimeters used for spliting results with strsep(3) */
+const char *const delimeter = " ,;\t";
+
+/*
+ * push and pop directory changes: pushd() and popd()
+ */
+typedef struct pwd_struct {
+    list_t	deep;
+    char	*pwd;
+} __align pwd_t;
+#define getpwd(list)	list_entry((list), struct pwd_struct, deep)
+
+static list_t pwd = { &pwd, &pwd }, * topd = &pwd;
+
+static void pushd(const char *restrict const path) attribute((nonnull(1)));
+static void pushd(const char *restrict const path)
+{
+    pwd_t *restrict dir;
+
+    if (posix_memalign((void*)&dir, sizeof(void*), alignof(pwd_t)) == 0) {
+	if (!(dir->pwd = getcwd((char*)0, 0)))
+	    goto err;
+	insert(&dir->deep, topd->prev);
+	if (chdir(path) < 0)
+	    goto err;
+	return;
+    }
+err:
+    error ("pushd() can not change to directory %s: %s\n", path, strerror(errno));
+}
+
+static void popd(void)
+{
+    pwd_t * dir;
+
+    if (list_empty(topd))
+	goto out;
+    dir = getpwd(topd->prev);
+    if (chdir(dir->pwd) < 0)
+	error ("popd() can not change directory %s: %s\n", dir->pwd, strerror(errno));
+    delete(topd->prev);
+    free(dir->pwd);
+    free(dir);
+out:
+    return;
+}
+
+/*
+ * Linked list of system facilities services and their replacment
+ */
+typedef struct string {
+    int *restrict ref;
+    char	*name;
+} __align string_t;
+
+typedef struct repl {
+    list_t     r_list;
+    string_t	 r[1];
+} __align repl_t;
+#define getrepl(arg)	list_entry((arg), struct repl, r_list)
+
+typedef struct faci {
+    list_t	 list;
+    list_t    replace;
+    char	*name;
+} __align faci_t;
+#define getfaci(arg)	list_entry((arg), struct faci, list)
+
+static list_t sysfaci = { &sysfaci, &sysfaci }, *sysfaci_start = &sysfaci;
+
+/*
+ * Remember requests for required or should services and expand `$' token
+ */
+static void rememberreq(service_t *restrict serv, uint bit,
+		        const char *restrict required) attribute((noinline,nonnull(1,3)));
+static void rememberreq(service_t * restrict serv, uint bit, const char * restrict required)
+{
+    const char type = (bit & REQ_KILL) ? 'K' : 'S';
+    const char * token;
+    char * tmp = strdupa(required);
+    list_t * ptr, * list;
+    ushort old = bit;
+
+    if (!tmp)
+	error("%s", strerror(errno));
+
+    while ((token = strsep(&tmp, delimeter)) && *token) {
+	service_t * req, * here, * need;
+	boolean found = false;
+
+	bit = old;
+
+	switch(*token) {
+	case '+':
+	    /* This is an optional token */
+	    token++;
+	    bit &= ~REQ_MUST;
+	    bit |=  REQ_SHLD;
+	default:
+	    req = addservice(token);
+	    if (bit & REQ_KILL) {
+		req  = getorig(req);
+		list = &req->sort.rev;
+		here = req;
+		need = serv;
+	    } else {
+		serv = getorig(serv);
+		list = &serv->sort.req;
+		here = serv;
+		need = req;
+	    }
+	    np_list_for_each(ptr, list) {
+		if (!strcmp(getreq(ptr)->serv->name, need->name)) {
+		    getreq(ptr)->flags |= bit;
+		    found = true;
+		    break;
+		}
+	    }
+	    if (!found) {
+		req_t *restrict this;
+		if (posix_memalign((void*)&this, sizeof(void*), alignof(req_t)) != 0)
+		    error("%s", strerror(errno));
+		memset(this, 0, alignof(req_t));
+		insert(&this->list, list->prev);
+		this->flags = bit;
+		this->serv = need;
+	    }
+	    /* Expand requested services for sorting */
+	    requires(here, need, type);
+	    break;
+	case '$':
+	    if (strcasecmp(token, "$all") == 0) {
+		serv->attr.flags |= SERV_ALL;
+		break;
+	    }
+	    /* Expand the `$' token recursively down */
+	    list_for_each(ptr, sysfaci_start) {
+		if (!strcmp(token, getfaci(ptr)->name)) {
+		    list_t * lst;
+		    np_list_for_each(lst, &getfaci(ptr)->replace)
+			rememberreq(serv, bit, getrepl(lst)->r[0].name);
+		    break;
+		}
+	    }
+	    break;
+	}
+    }
+}
+
+static void reversereq(service_t *restrict serv, uint bit,
+		       const char *restrict list) attribute((noinline,nonnull(1,3)));
+static void reversereq(service_t *restrict serv, uint bit, const char *restrict list)
+{
+    const char * token;
+    char * tmp = strdupa(list);
+    ushort old = bit;
+
+    if (!tmp)
+	error("%s", strerror(errno));
+
+    while ((token = strsep(&tmp, delimeter)) && *token) {
+	service_t * rev;
+	list_t * ptr;
+
+	bit = old;
+
+	switch (*token) {
+	case '+':
+	    token++;
+	    bit &= ~REQ_MUST;
+	    bit |=  REQ_SHLD;
+	default:
+	    rev = addservice(token);
+	    rememberreq(rev, bit, serv->name);
+	    break;
+	case '$':
+	    list_for_each(ptr, sysfaci_start) {
+		if (!strcmp(token, getfaci(ptr)->name)) {
+		    list_t * lst;
+		    np_list_for_each(lst, &getfaci(ptr)->replace)
+			reversereq(serv, bit, getrepl(lst)->r[0].name);
+		    break;
+		}
+	    }
+	    break;
+	}
+    }
+}
+
+/*
+ * Check required services for name
+ */
+static boolean chkrequired(service_t *restrict serv) attribute((nonnull(1)));
+static boolean chkrequired(service_t *restrict serv)
+{
+    boolean ret = true;
+    list_t * pos;
+
+    if (!serv)
+	goto out;
+    serv = getorig(serv);
+
+    np_list_for_each(pos, &serv->sort.req) {
+	req_t *req = getreq(pos);
+	service_t * must;
+
+	if ((req->flags & REQ_MUST) == 0)
+	    continue;
+	must = req->serv;
+	must = getorig(must);
+
+	if ((must->attr.flags & (SERV_CMDLINE|SERV_ENABLED)) == 0) {
+	    warn("Service %s has to be enabled to start service %s\n",
+		 req->serv->name, serv->name);
+	    ret = false;
+	}
+    }
+#if 0
+    if (serv->attr.flags & (SERV_CMDLINE|SERV_ENABLED))
+	goto out;
+    np_list_for_each(pos, &serv->sort.rev) {
+	req_t *rev = getreq(pos);
+	service_t * must;
+
+	if ((rev->flags & REQ_MUST) == 0)
+	    continue;
+	must = rev->serv;
+	must = getorig(must);
+
+	if (must->attr.flags & (SERV_CMDLINE|SERV_ENABLED)) {
+	    warn("Service %s has to be enabled to stop service %s\n",
+		 serv->name, rev->serv->name);
+	    ret = false;
+	}
+    }
+#endif
+out:
+    return ret;
+}
+
+/*
+ * Check dependencies for name as a service
+ */
+static boolean chkdependencies(service_t *restrict serv) attribute((nonnull(1)));
+static boolean chkdependencies(service_t *restrict serv)
+{
+    const char * const name = serv->name;
+    boolean ret = true;
+    list_t * ptr;
+
+    list_for_each(ptr, s_start) {
+	service_t * cur = getservice(ptr);
+	list_t * pos;
+
+	if (!cur)
+	    continue;
+
+	if ((cur->attr.flags & SERV_ENABLED) == 0)
+	    continue;
+
+	if (cur->attr.flags & SERV_DUPLET)
+	    continue;
+
+	if (list_empty(&cur->sort.req))
+	    continue;
+
+	np_list_for_each(pos, &cur->sort.req) {
+	    req_t *req = getreq(pos);
+	    const ushort flags = req->serv->attr.flags;
+
+	    if (!(req->flags & REQ_MUST))
+		continue;
+
+	    if (strcmp(req->serv->name, name) != 0)
+		continue;
+
+	    if ((cur->attr.flags & SERV_CMDLINE) && (flags & SERV_CMDLINE))
+		continue;
+
+	    warn("Service %s has to be enabled to start service %s\n",
+		 name, cur->name);
+	    ret = false;
+	}
+    }
+    return ret;
+}
+
+/*
+ * This helps us to work out the current symbolic link structure
+ */
+static inline service_t * current_structure(const char *const restrict this, const char order,
+				     const int runlvl, const char type) attribute((always_inline,nonnull(1)));
+static inline service_t * current_structure(const char *const this, const char order,
+				     const int runlvl, const char type)
+{
+    service_t * serv = addservice(this);
+    level_t * run;
+    ushort here = map_runlevel_to_lvl(runlvl);
+
+    if (type == 'K') {
+	run = serv->stopp;
+	if (!serv->attr.korder)
+	    serv->attr.korder = 99;
+	if (serv->attr.korder > order)
+	    serv->attr.korder = order;
+#ifdef SUSE
+	/* This because SuSE boot script concept uses a differential link scheme. */
+	here &= ~LVL_ONEWAY;
+#endif /* SUSE */
+    } else {
+	run = serv->start;
+	if (serv->attr.sorder < order)
+	    serv->attr.sorder = order;
+    }
+    run->lvl |= here;
+
+    return serv;
+}
+
+static void setlsb(const char *restrict const name) attribute((unused));
+static void setlsb(const char *restrict const name)
+{
+    service_t * serv = findservice(name);
+    if (serv)
+	serv->attr.flags &= ~SERV_NOTLSB;
+}
+
+/*
+ * This helps us to set none LSB conform scripts to required
+ * max order, therefore we set a dependency to the first
+ * lsb conform service found in current link scheme.
+ */
+static inline void nonlsb_script(void) attribute((always_inline));
+static inline void nonlsb_script(void)
+{
+    list_t * pos;
+
+    list_for_each(pos, s_start) {
+	if (getservice(pos)->attr.flags & SERV_NOTLSB) {
+	    service_t * req, * srv = getservice(pos);
+	    list_t * tmp;
+	    uchar max;
+
+	    max = 0;
+	    req = (service_t*)0;
+	    list_for_each(tmp, s_start) {
+		service_t * cur = getservice(tmp);
+		if (cur->attr.flags & SERV_NOTLSB)
+		    continue;
+		if ((cur->attr.flags & SERV_ENABLED) == 0)
+		    continue;
+		if (!cur->attr.sorder)
+		    continue;
+		if ((srv->start->lvl & cur->start->lvl) == 0)
+		    continue;
+		if (cur->attr.sorder >= srv->attr.sorder)
+		    continue;
+		if (max < cur->attr.sorder) {
+		    max = cur->attr.sorder;
+		    req = cur;
+		}
+	    }
+
+	    if (req)
+		requires(srv, req, 'S');
+
+	    max = 99;
+	    req = (service_t*)0;
+	    list_for_each(tmp, s_start) {
+		service_t * cur = getservice(tmp);
+		if (cur->attr.flags & SERV_NOTLSB)
+		    continue;
+		if ((cur->attr.flags & SERV_ENABLED) == 0)
+		    continue;
+		if (!cur->attr.korder)
+		    continue;
+		if ((srv->stopp->lvl & cur->stopp->lvl) == 0)
+		    continue;
+		if (cur->attr.korder <= srv->attr.korder)
+		    continue;
+		if (max > cur->attr.korder) {
+		    max = cur->attr.korder;
+		    req = cur;
+		}
+	    }
+
+	    if (req)
+		requires(req, srv, 'K');
+	}
+    }
+}
+
+/*
+ * This helps us to get interactive scripts to be the only service
+ * within on start or stop service group. Remaining problem is that
+ * if required scripts are missed the order can be wrong.
+ */
+static inline void active_script(void) attribute((always_inline));
+static inline void active_script(void)
+{
+    list_t * pos;
+    int deep = 1;
+
+    for (deep = 0; deep < 100; deep++) {
+	list_for_each(pos, s_start) {
+	    service_t * serv = getservice(pos);
+	    list_t * tmp;
+
+	    if (serv->attr.script == (char*)0)
+		continue;
+
+	    if ((serv->attr.flags & SERV_INTRACT) == 0)
+		continue;
+
+	    serv->attr.sorder = getorder(serv->attr.script, 'S');
+
+	    if (serv->attr.sorder != deep)
+		continue;
+
+	    if (serv->attr.flags & SERV_DUPLET)
+		continue;		/* Duplet */
+
+	    list_for_each(tmp, s_start) {
+		service_t * cur = getservice(tmp);
+		const char * script;
+
+		if (getorig(cur) == serv)
+		    continue;
+
+		if ((serv->start->lvl & cur->start->lvl) == 0)
+		    continue;
+
+		/*
+		 * Use real script name for getorder()/setorder()
+		 */
+		if (cur->attr.script == (char*)0)
+		    continue;
+		script = cur->attr.script;
+
+		cur->attr.sorder = getorder(script, 'S');
+
+		if (cur->attr.sorder != deep)
+		    continue;
+		/*
+		 * Increase order of members of the same start
+		 * group and recalculate dependency order (`true')
+		 */
+		setorder(script, 'S', ++cur->attr.sorder, true);
+	    }
+	}
+    }
+}
+
+/*
+ * Last but not least the `$all' scripts will be set to the
+ * end of the current start order.
+ */
+static inline void all_script(void) attribute((always_inline));
+static inline void all_script(void)
+{
+    list_t * pos;
+
+    list_for_each(pos, s_start) {
+	service_t * serv = getservice(pos);
+	list_t * tmp;
+	int neworder;
+
+	if (serv->attr.flags & SERV_DUPLET)
+	    continue;			/* Duplet */
+
+	if (!(serv->attr.flags & SERV_ALL))
+	    continue;
+
+	if (serv->attr.script == (char*)0)
+	    continue;
+
+	neworder = 0;
+	list_for_each(tmp, s_start) {
+	    service_t * cur = getservice(tmp);
+
+	    if (cur->attr.flags & SERV_DUPLET)
+		continue;		/* Duplet */
+
+	    if ((serv->start->lvl & cur->start->lvl) == 0)
+		continue;
+
+	    if (cur->attr.script == (char*)0)
+		continue;
+
+	    if (cur == serv)
+		continue;
+
+	    if (cur->attr.flags & SERV_ALL)
+		continue;
+
+	    cur->attr.sorder = getorder(cur->attr.script, 'S');
+
+	    if (cur->attr.sorder > neworder)
+		neworder = cur->attr.sorder;
+	}
+	neworder++;
+
+	if      (neworder > MAX_DEEP)
+	    neworder = maxstart;
+	else if (neworder > maxstart)
+	    maxstart = neworder;
+
+	setorder(serv->attr.script, 'S', neworder, false);
+    }
+}
+
+/*
+ * Make the dependency files
+ */
+static inline void makedep(void) attribute((always_inline));
+static inline void makedep(void)
+{
+    FILE *boot, *start, *stop, *out;
+#ifdef USE_KILL_IN_BOOT
+    FILE *halt;
+#endif /* USE_KILL_IN_BOOT */
+    const char *target;
+    service_t *serv;
+
+    if (dryrun) {
+#ifdef USE_KILL_IN_BOOT
+	info("dryrun, not creating .depend.boot, .depend.start, .depend.halt, and .depend.stop\n");
+#else  /* not USE_KILL_IN_BOOT */
+	info("dryrun, not creating .depend.boot, .depend.start, and .depend.stop\n");
+#endif /* not USE_KILL_IN_BOOT */
+	return;
+    }
+    if (!(boot  = fopen(".depend.boot",  "w"))) {
+	warn("fopen(.depend.stop): %s\n", strerror(errno));
+	return;
+    }
+
+    if (!(start = fopen(".depend.start", "w"))) {
+	warn("fopen(.depend.start): %s\n", strerror(errno));
+	fclose(boot);
+	return;
+    }
+
+    info("creating .depend.boot\n");
+    info("creating .depend.start\n");
+
+    lsort('S');					/* Sort into start order, set new sorder */
+
+    target = (char*)0;
+    fprintf(boot, "TARGETS =");
+    while ((serv = listscripts(&target, 'S', LVL_BOOT))) {
+	if (!serv)
+	    continue;
+#if defined(MINIMAL_MAKE) && (MINIMAL_MAKE != 0)
+	if (serv->attr.ref <= 0)
+	    continue;
+#endif /* MINIMAL_MAKE */
+	fprintf(boot, " %s", target);
+    }
+    fputc('\n', boot);
+
+    target = (char*)0;
+    fprintf(start, "TARGETS =");
+    while ((serv = listscripts(&target, 'S', LVL_ALL))) {	/* LVL_ALL: nearly all but not BOOT */
+	if (!serv)
+	    continue;
+#if defined(MINIMAL_MAKE) && (MINIMAL_MAKE != 0)
+	if (serv->attr.ref <= 0)
+	    continue;
+#endif /* MINIMAL_MAKE */
+	fprintf(start, " %s", target);
+    }
+    fputc('\n', start);
+
+    fprintf(boot,  "INTERACTIVE =");
+    fprintf(start, "INTERACTIVE =");
+
+    target = (char*)0;
+    while ((serv = listscripts(&target, 'S', LVL_BOOT|LVL_ALL))) {
+	if (!serv)
+	    continue;
+#if defined(MINIMAL_MAKE) && (MINIMAL_MAKE != 0)
+	if (serv->attr.ref <= 0)
+	    continue;
+#endif /* not MINIMAL_MAKE */
+
+	if (list_empty(&serv->sort.req))
+	    continue;
+
+	if (serv->start->lvl & LVL_BOOT)
+	    out = boot;
+	else
+	    out = start;
+
+	if (serv->attr.flags & SERV_INTRACT)
+	    fprintf(out, " %s", target);
+    }
+    fputc('\n', boot);
+    fputc('\n', start);
+
+    target = (char*)0;
+    while ((serv = listscripts(&target, 'S', LVL_BOOT|LVL_ALL))) {
+	boolean mark;
+	list_t * pos;
+
+	if (!serv)
+	    continue;
+#if defined(MINIMAL_RULES) && (MINIMAL_RULES != 0)
+	if (serv->attr.ref <= 0)
+	    continue;
+#endif /* not MINIMAL_RULES */
+
+	if (list_empty(&serv->sort.req))
+	    continue;
+
+	if (serv->start->lvl & LVL_BOOT)
+	    out = boot;
+	else
+	    out = start;
+
+	mark = false;
+	if (serv->attr.flags & SERV_ALL) {
+	    list_for_each(pos, s_start) {
+		service_t * dep = getservice(pos);
+		const char * name;
+
+		if (!dep)
+		    continue;
+
+		if (dep->attr.flags & SERV_DUPLET)
+		    continue;			/* Duplet */
+
+#if defined(MINIMAL_RULES) && (MINIMAL_RULES != 0)
+		if (dep->attr.ref <= 0)
+		    continue;
+#endif /* not MINIMAL_RULES */
+
+		/*
+		 * No self dependcies or from the last
+		 */
+		if (dep == serv || (dep->attr.flags & SERV_ALL))
+		    continue;
+
+		if ((serv->start->lvl & dep->start->lvl) == 0)
+		    continue;
+
+		if ((name = dep->attr.script) == (char*)0)
+		    continue;
+
+		if (!mark) {
+		    fprintf(out, "%s:", target);
+		    mark = true;
+		}
+		fprintf(out, " %s", name);
+	    }
+	} else {
+	    np_list_for_each(pos, &serv->sort.req) {
+		req_t * req = getreq(pos);
+		service_t * dep = req->serv;
+		const char * name;
+
+		if (!dep)
+		    continue;
+
+		if (dep->attr.flags & SERV_DUPLET)
+		    continue;
+
+#if defined(MINIMAL_RULES) && (MINIMAL_RULES != 0)
+		if (dep->attr.ref <= 0)
+		    continue;
+#endif /* not MINIMAL_RULES */
+
+		/*
+		 * No self dependcies or from the last
+		 */
+		if (dep == serv || (dep->attr.flags & SERV_ALL))
+		    continue;
+
+		if ((serv->start->lvl & dep->start->lvl) == 0)
+		    continue;
+
+		if ((name = dep->attr.script) == (char*)0)
+		    continue;
+
+		if (!mark) {
+		    fprintf(out, "%s:", target);
+		    mark = true;
+		}
+		fprintf(out, " %s", name);
+	    }
+	}
+	if (mark) fputc('\n', out);
+    }
+
+    fclose(boot);
+    fclose(start);
+
+    if (!(stop  = fopen(".depend.stop",  "w"))) {
+	warn("fopen(.depend.stop): %s\n", strerror(errno));
+	return;
+    }
+
+#ifdef USE_KILL_IN_BOOT
+    if (!(halt = fopen(".depend.halt", "w"))) {
+	warn("fopen(.depend.start): %s\n", strerror(errno));
+	fclose(stop);
+	return;
+    }
+
+    info("creating .depend.halt\n");
+#endif /* USE_KILL_IN_BOOT */
+    info("creating .depend.stop\n");
+
+    lsort('K');					/* Sort into stop order, set new korder */
+
+    target = (char*)0;
+    fprintf(stop, "TARGETS =");
+    while ((serv = listscripts(&target, 'K', LVL_NORM))) {	/* LVL_NORM: nearly all but not BOOT and not SINGLE */
+	if (!serv)
+	    continue;
+#if defined(MINIMAL_MAKE) && (MINIMAL_MAKE != 0)
+	if (serv->attr.ref <= 0)
+	    continue;
+#endif /* MINIMAL_MAKE */
+	fprintf(stop, " %s", target);
+    }
+    fputc('\n', stop);
+
+#ifdef USE_KILL_IN_BOOT
+    target = (char*)0;
+    fprintf(halt, "TARGETS =");
+    while ((serv = listscripts(&target, 'K', LVL_BOOT))) {
+	if (!serv)
+	    continue;
+# if defined(MINIMAL_MAKE) && (MINIMAL_MAKE != 0)
+	if (serv->attr.ref <= 0)
+	    continue;
+# endif /* MINIMAL_MAKE */
+	fprintf(halt, " %s", target);
+    }
+    fputc('\n', halt);
+#endif /* USE_KILL_IN_BOOT */
+
+    target = (char*)0;
+    while ((serv = listscripts(&target, 'K', (LVL_NORM|LVL_BOOT)))) {
+	boolean mark;
+	list_t * pos;
+
+	if (!serv)
+	    continue;
+#if defined(MINIMAL_RULES) && (MINIMAL_RULES != 0)
+	if (serv->attr.ref <= 0)
+	    continue;
+#endif /* not MINIMAL_RULES */
+
+	if (list_empty(&serv->sort.rev))
+	    continue;
+
+	if (serv->stopp->lvl & LVL_BOOT)
+#ifdef USE_KILL_IN_BOOT
+	    out = halt;
+	else
+#else  /* not USE_KILL_IN_BOOT */
+	    continue;
+#endif /* not USE_KILL_IN_BOOT */
+	out = stop;
+
+	mark = false;
+	np_list_for_each(pos, &serv->sort.rev) {
+	    req_t * rev = getreq(pos);
+	    service_t * dep = rev->serv;
+	    const char * name;
+
+	    if (!dep)
+		continue;
+
+	    if (dep->attr.flags & (SERV_DUPLET|SERV_NOSTOP))
+		continue;			/* Duplet or no stop link */
+
+#if defined(MINIMAL_RULES) && (MINIMAL_RULES != 0)
+	    if (dep->attr.ref <= 0)
+		continue;
+#endif /* not MINIMAL_RULES */
+
+	    if ((serv->stopp->lvl & dep->stopp->lvl) == 0)
+		continue;
+
+	    if ((name = dep->attr.script) == (char*)0)
+		continue;
+
+	    if (!mark) {
+		fprintf(out, "%s:", target);
+		mark = true;
+	    }
+	    fprintf(out, " %s", name);
+	}
+	if (mark) fputc('\n', out);
+    }
+
+#ifdef USE_KILL_IN_BOOT
+    fclose(halt);
+#endif /* USE_KILL_IN_BOOT */
+    fclose(stop);
+}
+
+/*
+ * Internal logger
+ */
+char *myname = (char*)0;
+static void _logger (const char *restrict const fmt, va_list ap);
+static void _logger (const char *restrict const fmt, va_list ap)
+{
+    extension char buf[strlen(myname)+2+strlen(fmt)+1];
+    strcat(strcat(strcpy(buf, myname), ": "), fmt);
+    vfprintf(stderr, buf, ap);
+    return;
+}
+
+/*
+ * Cry and exit.
+ */
+void error (const char *restrict const fmt, ...)
+{
+    static char called;
+    va_list ap;
+    if (called++)
+	exit (1);
+    va_start(ap, fmt);
+    _logger(fmt, ap);
+    va_end(ap);
+    popd();
+    exit (1);
+}
+
+/*
+ * Warn the user.
+ */
+void warn (const char *restrict const fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    _logger(fmt, ap);
+    va_end(ap);
+    return;
+}
+
+/*
+ * Print message when verbose is enabled
+ */
+void info(const char *fmt, ...) {
+    va_list ap;
+    if (!verbose)
+	goto out;
+    va_start(ap, fmt);
+    _logger(fmt, ap);
+    va_end(ap);
+out:
+    return;
+}
+
+/*
+ *  Check for script in list.
+ */
+static int curr_argc = -1;
+static inline boolean chkfor(const char *restrict const script,
+			     char **restrict const list, const int cnt) attribute((nonnull(1,2)));
+static inline boolean chkfor(const char *restrict const script, char **restrict const list, const int cnt)
+{
+    boolean isinc = false;
+    register int c = cnt;
+
+    curr_argc = -1;
+    while (c--) {
+	if (*script != *list[c])
+	    continue;
+	if (!strcmp(script, list[c])) {
+	    isinc = true;
+	    curr_argc = c;
+	    break;
+	}
+    }
+    return isinc;
+}
+
+/*
+ * Open a runlevel directory, if it not
+ * exists than create one.
+ */
+static DIR * openrcdir(const char *restrict const rcpath) attribute((nonnull(1)));
+static DIR * openrcdir(const char *restrict const rcpath)
+{
+   DIR * rcdir;
+   struct stat st;
+   int dfd;
+
+    if (stat(rcpath, &st) < 0) {
+	if (errno == ENOENT) {
+	    info("creating directory '%s'\n", rcpath);
+	    if (!dryrun)
+		mkdir(rcpath, (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH));
+	} else
+	    error("can not stat(%s): %s\n", rcpath, strerror(errno));
+    }
+
+    if ((rcdir = opendir(rcpath)) == (DIR*)0) {
+	if (dryrun)
+	    warn ("can not opendir(%s): %s\n", rcpath, strerror(errno));
+	else
+	    error("can not opendir(%s): %s\n", rcpath, strerror(errno));
+    }
+#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
+    else if ((dfd = dirfd(rcdir)) != 0) {
+	(void)posix_fadvise(dfd, 0, 0, POSIX_FADV_WILLNEED);
+	(void)posix_fadvise(dfd, 0, 0, POSIX_FADV_SEQUENTIAL);
+    }
+#endif
+    return rcdir;
+}
+
+/*
+ * Wrapper for regcomp(3)
+ */
+static inline void regcompiler(regex_t *restrict preg,
+			       const char *restrict regex,
+			       int cflags) attribute((always_inline,nonnull(1,2)));
+static inline void regcompiler(regex_t *restrict preg, const char *restrict regex, int cflags)
+{
+    register int ret = regcomp(preg, regex, cflags);
+    if (ret) {
+	regerror(ret, preg, buf, sizeof (buf));
+	regfree (preg);
+	error("%s\n", buf);
+    }
+    return;
+}
+
+/*
+ * Wrapper for regexec(3)
+ */
+static inline boolean regexecutor(regex_t *restrict preg,
+				  const char *restrict string,
+				  size_t nmatch, regmatch_t pmatch[], int eflags) attribute((nonnull(1,2)));
+static inline boolean regexecutor(regex_t *preg, const char *string,
+	size_t nmatch, regmatch_t pmatch[], int eflags)
+{
+    register int ret = regexec(preg, string, nmatch, pmatch, eflags);
+    if (ret > REG_NOMATCH) {
+	regerror(ret, preg, buf, sizeof (buf));
+	regfree (preg);
+	warn("%s\n", buf);
+    }
+    return (ret ? false : true);
+}
+
+/*
+ * The script scanning engine.
+ * We have to alloc the regular expressions first before
+ * calling scan_script_defaults().  After the last call
+ * of scan_script_defaults() we may free the expressions.
+ */
+static inline void scan_script_regalloc(void) attribute((always_inline));
+static inline void scan_script_regalloc(void)
+{
+    regcompiler(&reg.prov,      PROVIDES,       REG_EXTENDED|REG_ICASE);
+    regcompiler(&reg.req_start, REQUIRED_START, REG_EXTENDED|REG_ICASE|REG_NEWLINE);
+    regcompiler(&reg.req_stop,  REQUIRED_STOP,  REG_EXTENDED|REG_ICASE|REG_NEWLINE);
+    regcompiler(&reg.shl_start, SHOULD_START,   REG_EXTENDED|REG_ICASE|REG_NEWLINE);
+    regcompiler(&reg.shl_stop,  SHOULD_STOP,    REG_EXTENDED|REG_ICASE|REG_NEWLINE);
+    regcompiler(&reg.start_bf,  START_BEFORE,   REG_EXTENDED|REG_ICASE|REG_NEWLINE);
+    regcompiler(&reg.stop_af,   STOP_AFTER,     REG_EXTENDED|REG_ICASE|REG_NEWLINE);
+    regcompiler(&reg.def_start, DEFAULT_START,  REG_EXTENDED|REG_ICASE|REG_NEWLINE);
+    regcompiler(&reg.def_stop,  DEFAULT_STOP,   REG_EXTENDED|REG_ICASE|REG_NEWLINE);
+    regcompiler(&reg.desc,      DESCRIPTION,    REG_EXTENDED|REG_ICASE|REG_NEWLINE);
+}
+
+static inline void scan_script_reset(void) attribute((always_inline));
+static inline void scan_script_reset(void)
+{
+    xreset(script_inf.provides);
+    xreset(script_inf.required_start);
+    xreset(script_inf.required_stop);
+    xreset(script_inf.should_start);
+    xreset(script_inf.should_stop);
+    xreset(script_inf.start_before);
+    xreset(script_inf.stop_after);
+    xreset(script_inf.default_start);
+    xreset(script_inf.default_stop);
+    xreset(script_inf.description);
+}
+
+#define FOUND_LSB_HEADER   0x01
+#define FOUND_LSB_DEFAULT  0x02
+#define FOUND_LSB_OVERRIDE 0x04
+
+static int o_flags = O_RDONLY;
+
+static uchar scan_lsb_headers(const int dfd, const char *restrict const path,
+			      const boolean cache, const boolean ignore) attribute((nonnull(2)));
+static uchar scan_lsb_headers(const int dfd, const char *restrict const path,
+			      const boolean cache, const boolean ignore)
+{
+    regmatch_t subloc[SUBNUM_SHD+1], *val = &subloc[SUBNUM-1], *shl = &subloc[SUBNUM_SHD-1];
+    char *begin = (char*)0, *end = (char*)0;
+    char *pbuf = buf;
+    FILE *script;
+    uchar ret = 0;
+    int fd;
+
+#define provides	script_inf.provides
+#define required_start	script_inf.required_start
+#define required_stop	script_inf.required_stop
+#define should_start	script_inf.should_start
+#define should_stop	script_inf.should_stop
+#define start_before	script_inf.start_before
+#define stop_after	script_inf.stop_after
+#define default_start	script_inf.default_start
+#define default_stop	script_inf.default_stop
+#define description	script_inf.description
+
+    info("Loading %s\n", path);
+
+    if ((fd = xopen(dfd, path, o_flags)) < 0 || (script = fdopen(fd, "r")) == (FILE*)0)
+	error("fopen(%s): %s\n", path, strerror(errno));
+
+#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
+    (void)posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
+#endif
+
+#define COMMON_ARGS	buf, SUBNUM, subloc, 0
+#define COMMON_SHD_ARGS	buf, SUBNUM_SHD, subloc, 0
+    while (fgets(buf, sizeof(buf), script)) {
+
+	/* Skip scanning above from LSB magic start */
+	if (!begin) {
+	    if ( (begin = strstr(buf, "### BEGIN INIT INFO")) ) {
+	        /* Let the latest LSB header override the one found earlier */
+	        scan_script_reset();
+	    }
+	    continue;
+	}
+
+	if (!provides       && regexecutor(&reg.prov,      COMMON_ARGS) == true) {
+	    if (val->rm_so < val->rm_eo) {
+		*(pbuf+val->rm_eo) = '\0';
+	        provides = xstrdup(pbuf+val->rm_so);
+	    } else
+		provides = empty;
+	}
+	if (!required_start && regexecutor(&reg.req_start, COMMON_ARGS) == true) {
+	    if (val->rm_so < val->rm_eo) {
+		*(pbuf+val->rm_eo) = '\0';
+		required_start = xstrdup(pbuf+val->rm_so);
+	    } else
+		required_start = empty;
+	}
+	if (!required_stop  && regexecutor(&reg.req_stop,  COMMON_ARGS) == true) {
+	    if (val->rm_so < val->rm_eo) {
+		*(pbuf+val->rm_eo) = '\0';
+		required_stop = xstrdup(pbuf+val->rm_so);
+	    } else
+		required_stop = empty;
+	}
+	if (!should_start && regexecutor(&reg.shl_start,   COMMON_SHD_ARGS) == true) {
+	    if (shl->rm_so < shl->rm_eo) {
+		*(pbuf+shl->rm_eo) = '\0';
+		should_start = xstrdup(pbuf+shl->rm_so);
+	    } else
+		should_start = empty;
+	}
+	if (!should_stop  && regexecutor(&reg.shl_stop,    COMMON_SHD_ARGS) == true) {
+	    if (shl->rm_so < shl->rm_eo) {
+		*(pbuf+shl->rm_eo) = '\0';
+		should_stop = xstrdup(pbuf+shl->rm_so);
+	    } else
+		should_stop = empty;
+	}
+	if (!start_before && regexecutor(&reg.start_bf,    COMMON_SHD_ARGS) == true) {
+	    if (shl->rm_so < shl->rm_eo) {
+		*(pbuf+shl->rm_eo) = '\0';
+		start_before = xstrdup(pbuf+shl->rm_so);
+	    } else
+		start_before = empty;
+	}
+	if (!stop_after  && regexecutor(&reg.stop_af,      COMMON_SHD_ARGS) == true) {
+	    if (shl->rm_so < shl->rm_eo) {
+		*(pbuf+shl->rm_eo) = '\0';
+		stop_after = xstrdup(pbuf+shl->rm_so);
+	    } else
+		stop_after = empty;
+	}
+	if (!default_start  && regexecutor(&reg.def_start, COMMON_ARGS) == true) {
+	    if (val->rm_so < val->rm_eo) {
+		*(pbuf+val->rm_eo) = '\0';
+		default_start = xstrdup(pbuf+val->rm_so);
+	    } else
+		default_start = empty;
+	}
+#ifndef SUSE
+	if (!default_stop   && regexecutor(&reg.def_stop,  COMMON_ARGS) == true) {
+	    if (val->rm_so < val->rm_eo) {
+		*(pbuf+val->rm_eo) = '\0';
+		default_stop = xstrdup(pbuf+val->rm_so);
+	    } else
+		default_stop = empty;
+	}
+#endif
+	if (!description    && regexecutor(&reg.desc,      COMMON_ARGS) == true) {
+	    if (val->rm_so < val->rm_eo) {
+		*(pbuf+val->rm_eo) = '\0';
+		description = xstrdup(pbuf+val->rm_so);
+	    } else
+		description = empty;
+	}
+
+	/* Skip scanning below from LSB magic end */
+	if ((end = strstr(buf, "### END INIT INFO")))
+	    break;
+    }
+#undef COMMON_ARGS
+#undef COMMON_SHD_ARGS
+
+#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
+    if (cache) {
+	off_t deep = ftello(script);
+	(void)posix_fadvise(fd, 0, deep, POSIX_FADV_WILLNEED);
+	(void)posix_fadvise(fd, deep, 0, POSIX_FADV_DONTNEED);
+    } else
+	(void)posix_fadvise(fd, 0, 0, POSIX_FADV_NOREUSE);
+#endif
+
+    fclose(script);
+
+    if (begin && end)
+	ret |= FOUND_LSB_HEADER;
+
+    if (begin && !end) {
+	char *name = basename(path);
+	if (*name == 'S' || *name == 'K')
+	    name += 3;
+	warn("Script %s is broken: missing end of LSB comment.\n", name);
+	if (!ignore)
+	    error("exiting now!\n");
+    }
+
+    if (begin && end && (!provides || (provides == empty) ||
+#ifdef SUSE
+			 !required_start || !required_stop || !default_start
+#else  /* not SUSE */
+			 !required_start || !required_stop || !default_start || !default_stop
+#endif /* not SUSE */
+	))
+    {
+	char *name = basename(path);
+	if (*name == 'S' || *name == 'K')
+	    name += 3;
+	warn("Script %s is broken: incomplete LSB comment.\n", name);
+	if (!provides)
+	    warn("missing `Provides:' entry: please add.\n");
+	if (provides == empty)
+	    warn("missing valid name for `Provides:' please add.\n");
+	if (!required_start)
+	    warn("missing `Required-Start:' entry: please add even if empty.\n");
+	if (!required_stop)
+	    warn("missing `Required-Stop:'  entry: please add even if empty.\n");
+	if (!default_start)
+	    warn("missing `Default-Start:'  entry: please add even if empty.\n");
+#ifndef SUSE
+	if (!default_stop)
+	    warn("missing `Default-Stop:'   entry: please add even if empty.\n");
+#endif
+    }
+
+#undef provides
+#undef required_start
+#undef required_stop
+#undef should_start
+#undef should_stop
+#undef start_before
+#undef stop_after
+#undef default_start
+#undef default_stop
+#undef description
+    return ret;
+}
+
+/*
+ * Follow symlinks, return the basename of the file pointed to by
+ * symlinks or the basename of the current path if no symlink.
+ */
+static char * scriptname(int dfd, const char *restrict const path, char **restrict first) attribute((malloc,nonnull(2)));
+static char * scriptname(int dfd, const char *restrict const path, char **restrict first)
+{
+    uint deep = 0;
+    char linkbuf[PATH_MAX+1];
+    char *script = xstrdup(path);
+
+    strncpy(linkbuf, script, sizeof(linkbuf)-1);
+    linkbuf[PATH_MAX] = '\0';
+
+    do {
+        struct stat st;
+	int linklen;
+
+	if (deep++ > MAXSYMLINKS) {
+	    errno = ELOOP;
+	    warn("Can not determine script name for %s: %s\n", path, strerror(errno));
+	    break;
+	}
+
+	if (xlstat(dfd, script, &st) < 0) {
+	    warn("Can not stat %s: %s\n", script, strerror(errno));
+	    break;
+	}
+
+	if (!S_ISLNK(st.st_mode))
+	    break;
+
+	if ((linklen = xreadlink(dfd, script, linkbuf, sizeof(linkbuf)-1)) < 0)
+	    break;
+	linkbuf[linklen] = '\0';
+
+	if (linkbuf[0] != '/') {	/* restore relative links */
+	    const char *lastslash;
+
+	    if ((lastslash = strrchr(script, '/'))) {
+		size_t dirname_len = lastslash - script + 1;
+
+		if (dirname_len + linklen > PATH_MAX)
+		    linklen = PATH_MAX - dirname_len;
+
+		memmove(&linkbuf[dirname_len], &linkbuf[0], linklen + 1);
+		memcpy(&linkbuf[0], script, dirname_len);
+	    }
+	}
+
+	free(script);
+	script = xstrdup(linkbuf);
+
+	if (deep == 1 && first)
+	    *first = xstrdup(basename(linkbuf));
+
+    } while (1);
+
+    free(script);
+    script = xstrdup(basename(linkbuf));
+
+    return script;
+}
+
+static uchar load_overrides(const char *restrict const dir,
+			    const char *restrict const name,
+			    const boolean cache, const boolean ignore) attribute((nonnull(1,2)));
+static uchar load_overrides(const char *restrict const dir,
+			    const char *restrict const name,
+			    const boolean cache, const boolean ignore)
+{
+    uchar ret = 0;
+    char fullpath[PATH_MAX+1];
+    struct stat statbuf;
+    int n;
+
+    n = snprintf(&fullpath[0], sizeof(fullpath), "%s%s/%s", (root && !set_override) ? root : "", dir, name);
+    if (n >= (int)sizeof(fullpath) || n < 0)
+	error("snprintf(): %s\n", strerror(errno));
+
+    if (stat(fullpath, &statbuf) == 0 && S_ISREG(statbuf.st_mode))
+        ret = scan_lsb_headers(-1, fullpath, cache, ignore);
+    if (ret & FOUND_LSB_HEADER)
+	ret |= FOUND_LSB_OVERRIDE;
+    return ret;
+}
+
+static uchar scan_script_defaults(int dfd, const char *const restrict path,
+				  const char *const restrict override_path,
+				  char **restrict first,
+				  const boolean cache, const boolean ignore) attribute((nonnull(2,3)));
+static uchar scan_script_defaults(int dfd, const char *restrict const path,
+				  const char *restrict const override_path,
+				  char **restrict first,
+				  const boolean cache, const boolean ignore)
+{
+    char * name = scriptname(dfd, path, first);
+    uchar ret = 0;
+
+    if (!name)
+	return ret;
+
+    /* Reset old results */
+    scan_script_reset();
+
+#ifdef SUSE
+    /* Common script ... */
+    if (!strcmp(name, "halt")) {
+	ret |= (FOUND_LSB_HEADER|FOUND_LSB_DEFAULT);
+	goto out;
+    }
+
+    /* ... and its link */
+    if (!strcmp(name, "reboot")) {
+	ret |= (FOUND_LSB_HEADER|FOUND_LSB_DEFAULT);
+	goto out;
+    }
+
+    /* Common script for single mode */
+    if (!strcmp(name, "single")) {
+	ret |= (FOUND_LSB_HEADER|FOUND_LSB_DEFAULT);
+	goto out;
+    }
+#endif /* SUSE */
+
+    /* Replace with headers from the script itself */
+    ret |= scan_lsb_headers(dfd, path, cache, ignore);
+
+    /* Load values if the override file exist */
+    if ((ret & FOUND_LSB_HEADER) == 0)
+	ret |= load_overrides("/usr/share/insserv/overrides", name, cache, ignore);
+    else
+	ret |= FOUND_LSB_DEFAULT;
+
+    /*
+     * Allow host-specific overrides to replace the content in the
+     * init.d scripts
+     */
+    ret |= load_overrides(override_path, name, cache, ignore);
+#ifdef SUSE
+out:
+#endif /* SUSE */
+    free(name);
+    return ret;
+}
+
+static inline void scan_script_regfree() attribute((always_inline));
+static inline void scan_script_regfree()
+{
+    regfree(&reg.prov);
+    regfree(&reg.req_start);
+    regfree(&reg.req_stop);
+    regfree(&reg.shl_start);
+    regfree(&reg.shl_stop);
+    regfree(&reg.start_bf);
+    regfree(&reg.stop_af);
+    regfree(&reg.def_start);
+    regfree(&reg.def_stop);
+    regfree(&reg.desc);
+}
+
+static struct {
+    char *location;
+    const ushort lvl;
+    const ushort seek;
+    const char key;
+} attribute((aligned(sizeof(char*)))) runlevel_locations[] = {
+#ifdef SUSE	/* SuSE's SystemV link scheme */
+    {"rc0.d/",    LVL_HALT,   LVL_NORM, '0'},
+    {"rc1.d/",    LVL_ONE,    LVL_NORM, '1'}, /* runlevel 1 switch over to single user mode */
+    {"rc2.d/",    LVL_TWO,    LVL_NORM, '2'},
+    {"rc3.d/",    LVL_THREE,  LVL_NORM, '3'},
+    {"rc4.d/",    LVL_FOUR,   LVL_NORM, '4'},
+    {"rc5.d/",    LVL_FIVE,   LVL_NORM, '5'},
+    {"rc6.d/",    LVL_REBOOT, LVL_NORM, '6'},
+    {"rcS.d/",    LVL_SINGLE, LVL_NORM, 'S'}, /* runlevel S is for single user mode */
+    {"boot.d/",   LVL_BOOT,   LVL_BOOT, 'B'}, /* runlevel B is for system initialization */
+#else		/* not SUSE (actually, Debian) */
+    {"../rc0.d/", LVL_HALT,   LVL_NORM, '0'},
+    {"../rc1.d/", LVL_ONE,    LVL_NORM, '1'}, /* runlevel 1 switch over to single user mode */
+    {"../rc2.d/", LVL_TWO,    LVL_NORM, '2'},
+    {"../rc3.d/", LVL_THREE,  LVL_NORM, '3'},
+    {"../rc4.d/", LVL_FOUR,   LVL_NORM, '4'},
+    {"../rc5.d/", LVL_FIVE,   LVL_NORM, '5'},
+    {"../rc6.d/", LVL_REBOOT, LVL_NORM, '6'},
+    {"../rcS.d/", LVL_BOOT,   LVL_BOOT, 'S'}, /* runlevel S is for system initialization */
+		/* On e.g. Debian there exist no boot.d */
+#endif		/* not SUSE */
+};
+
+#define RUNLEVLES (int)(sizeof(runlevel_locations)/sizeof(runlevel_locations[0]))
+
+int map_has_runlevels(void)
+{
+    return RUNLEVLES;
+}
+
+char map_runlevel_to_key(const int runlevel)
+{
+    if (runlevel >= RUNLEVLES) {
+	warn("Wrong runlevel %d\n", runlevel);
+    }
+    return runlevel_locations[runlevel].key;
+}
+
+ushort map_key_to_lvl(const char key)
+{
+    int runlevel;
+    const char uckey = toupper(key);
+    for (runlevel = 0; runlevel < RUNLEVLES; runlevel++) {
+	if (uckey == runlevel_locations[runlevel].key)
+	    return runlevel_locations[runlevel].lvl;
+    }
+    warn("Wrong runlevel key '%c'\n", uckey);
+    return 0;
+}
+
+const char *map_runlevel_to_location(const int runlevel)
+{
+    if (runlevel >= RUNLEVLES) {
+	warn("Wrong runlevel %d\n", runlevel);
+    }
+    return runlevel_locations[runlevel].location;
+}
+
+ushort map_runlevel_to_lvl(const int runlevel)
+{
+    if (runlevel >= RUNLEVLES) {
+	warn("Wrong runlevel %d\n", runlevel);
+    }
+    return runlevel_locations[runlevel].lvl;
+}
+
+ushort map_runlevel_to_seek(const int runlevel)
+{
+    return runlevel_locations[runlevel].seek;
+}
+
+/*
+ * Two helpers for runlevel bits and strings.
+ */
+ushort str2lvl(const char *restrict lvl)
+{
+    char * token, *tmp = strdupa(lvl);
+    ushort ret = 0;
+
+    if (!tmp)
+	error("%s", strerror(errno));
+
+    while ((token = strsep(&tmp, delimeter))) {
+	if (!*token || strlen(token) != 1)
+	    continue;
+	if (!strpbrk(token, "0123456sSbB"))
+	    continue;
+
+        ret |= map_key_to_lvl(*token);
+    }
+
+    return ret;
+}
+
+char * lvl2str(const ushort lvl)
+{
+    char * ptr, * last;
+    char str[20];
+    int num;
+    uint bit = 0x001;
+
+    last = ptr = &str[0];
+    memset(ptr, '\0', sizeof(str));
+    for (num = 0; num < RUNLEVLES; num++) {
+	if (bit & lvl) {
+	    if (ptr > last)
+		*ptr++ = ' ';
+	    last = ptr;
+	    if (LVL_NORM & bit)
+		*ptr++ = num + 48;
+#ifdef SUSE
+	    else if (LVL_SINGLE & bit)
+		*ptr++ = 'S';
+	    else if (LVL_BOOT & bit)
+		*ptr++ = 'B';
+#else  /* not SUSE */
+	    else if (LVL_BOOT & bit)
+		*ptr++ = 'S';
+#endif /* not SUSE */
+	    else
+		error("Wrong runlevel %d\n", num);
+	}
+	bit <<= 1;
+    }
+    if (strlen(str) == 0)
+	return (char*)0;
+    return xstrdup(str);
+}
+
+/*
+ * Scan current service structure
+ */
+static void scan_script_locations(const char *const restrict path,
+				  const char *const restrict override_path,
+				  const boolean ignore) attribute((nonnull(1,2)));
+static void scan_script_locations(const char *const path, const char *const override_path,
+				  const boolean ignore)
+{
+    int runlevel;
+
+    pushd(path);
+    for (runlevel = 0; runlevel < RUNLEVLES; runlevel++) {
+	const char * rcd = (char*)0;
+	struct stat st_script;
+	struct dirent *d;
+	DIR  * rcdir;
+	char * token;
+	int dfd;
+
+	rcd = map_runlevel_to_location(runlevel);
+
+	rcdir = openrcdir(rcd);		/* Creates runlevel directory if necessary */
+	if (rcdir == (DIR*)0)
+	    break;
+	if ((dfd = dirfd(rcdir)) < 0) {
+	    closedir(rcdir);
+	    break;
+	}
+	pushd(rcd);
+
+	while ((d = readdir(rcdir)) != (struct dirent*)0) {
+	    char * name = (char *)0;
+	    char * ptr = d->d_name;
+	    service_t * first;
+	    char * begin;		/* Remember address of ptr handled by strsep() */
+	    char order;
+	    uchar lsb;
+	    char type;
+
+	    if (*ptr != 'S' && *ptr != 'K')
+		continue;
+	    type = *ptr;
+	    ptr++;
+
+	    if (strspn(ptr, "0123456789") < 2)
+		continue;
+	    order = atoi(ptr);
+	    ptr += 2;
+
+	    if (xstat(dfd, d->d_name, &st_script) < 0) {
+		xremove(dfd, d->d_name);	/* dangling sym link */
+		continue;
+	    }
+
+	    lsb = scan_script_defaults(dfd, d->d_name, override_path, &name, true, ignore);
+	    if (!script_inf.provides || script_inf.provides == empty)
+		script_inf.provides = xstrdup(ptr);
+
+#ifndef SUSE
+	    if (!lsb) {
+	        script_inf.required_start = xstrdup(DEFAULT_DEPENDENCY);
+		script_inf.required_stop  = xstrdup(DEFAULT_DEPENDENCY);
+	    }
+#endif /* not SUSE */
+
+	    first = (service_t*)0;
+	    begin = script_inf.provides;
+	    while ((token = strsep(&begin, delimeter)) && *token) {
+		service_t * service;
+
+		if (*token == '$') {
+		    warn("script %s provides system facility %s, skipped!\n", d->d_name, token);
+		    continue;
+		}
+		if (*token == '#') {
+		    warn("script %s provides facility %s with comment sign, skipped!\n", d->d_name, token);
+		    continue;
+		}
+
+		service = current_structure(token, order, runlevel, type);
+
+		if (first)
+		    nickservice(first, service);
+		else
+		    first = service;
+
+		if (!makeprov(service, name))
+		    continue;
+
+		++service->attr.ref;			/* May enabled in several levels */
+
+		if (service->attr.flags & SERV_KNOWN)
+		    continue;
+		service->attr.flags |= (SERV_KNOWN|SERV_ENABLED);
+
+		if (!lsb)
+		    service->attr.flags |= SERV_NOTLSB;
+
+		if ((lsb & FOUND_LSB_HEADER) == 0) {
+		    if ((lsb & (FOUND_LSB_DEFAULT|FOUND_LSB_OVERRIDE)) == 0)
+		      warn("warning: script '%s' missing LSB tags and overrides\n", d->d_name);
+		    else
+  		        warn("warning: script '%s' missing LSB tags\n", d->d_name);
+		}
+
+		if (script_inf.required_start && script_inf.required_start != empty) {
+		    rememberreq(service, REQ_MUST, script_inf.required_start);
+#ifdef USE_COMPAT_EMPTY
+		    if (!script_inf.required_stop || script_inf.required_stop == empty)
+			script_inf.required_stop = xstrdup(script_inf.required_start);
+#endif /* USE_COMPAT_EMPTY */
+		}
+		if (script_inf.should_start && script_inf.should_start != empty) {
+		    rememberreq(service, REQ_SHLD, script_inf.should_start);
+#ifdef USE_COMPAT_EMPTY
+		    if (!script_inf.should_stop || script_inf.should_stop == empty)
+			script_inf.should_stop = xstrdup(script_inf.should_start);
+#endif /* USE_COMPAT_EMPTY */
+		}
+		if (script_inf.start_before && script_inf.start_before != empty) {
+		    reversereq(service, REQ_SHLD, script_inf.start_before);
+#ifdef USE_COMPAT_EMPTY
+		    if (!script_inf.stop_after || script_inf.stop_after == empty)
+			script_inf.stop_after = xstrdup(script_inf.start_before);
+#endif /* USE_COMPAT_EMPTY */
+		}
+		if (script_inf.required_stop && script_inf.required_stop != empty) {
+		    rememberreq(service, REQ_MUST|REQ_KILL, script_inf.required_stop);
+		}
+		if (script_inf.should_stop && script_inf.should_stop != empty) {
+		    rememberreq(service, REQ_SHLD|REQ_KILL, script_inf.should_stop);
+		}
+		if (script_inf.stop_after && script_inf.stop_after != empty) {
+		    reversereq(service, REQ_SHLD|REQ_KILL, script_inf.stop_after);
+		}
+	    }
+
+	    if (name) 
+		xreset(name);
+
+	    scan_script_reset();
+
+	}	/* while ((token = strsep(&begin, delimeter)) && *token) */
+
+	popd();
+	closedir(rcdir);
+    }
+    popd();
+    return;
+}
+
+/*
+ * The /etc/insserv.conf scanning engine.
+ */
+static void scan_conf_file(const char *restrict file) attribute((nonnull(1)));
+static void scan_conf_file(const char *restrict file)
+{
+    regmatch_t subloc[SUBCONFNUM], *val = (regmatch_t*)0;
+    FILE *conf;
+
+    info("Loading %s\n", file);
+
+    do {
+	const char * fptr = file;
+	if (*fptr == '/')
+	    fptr++;
+	/* Try relativ location first */
+	if ((conf = fopen(fptr, "r")))
+	    break;
+	/* Try absolute location */
+	if ((conf = fopen(file, "r")))
+	    break;
+	goto err;
+    } while (1);
+
+    while (fgets(buf, sizeof(buf), conf)) {
+	char *pbuf = &buf[0];
+	if (*pbuf == '#')
+	    continue;
+	if (*pbuf == '\n')
+	    continue;
+	if (regexecutor(&creg.isysfaci, buf, SUBCONFNUM, subloc, 0) == true) {
+	    char * virt = (char*)0, * real = (char*)0;
+	    val = &subloc[SUBCONF - 1];
+	    if (val->rm_so < val->rm_eo) {
+		*(pbuf+val->rm_eo) = '\0';
+		virt = pbuf+val->rm_so;
+	    }
+	    val = &subloc[SUBCONFNUM - 1];
+	    if (val->rm_so < val->rm_eo) {
+		*(pbuf+val->rm_eo) = '\0';
+		real = pbuf+val->rm_so;
+	    }
+	    if (virt) {
+		list_t * ptr;
+		boolean found = false;
+		list_for_each(ptr, sysfaci_start) {
+		    if (!strcmp(getfaci(ptr)->name, virt)) {
+			found = true;
+			if(real) {
+			    list_t * r_list = &getfaci(ptr)->replace;
+			    char * token;
+			    while ((token = strsep(&real, delimeter))) {
+				repl_t *restrict subst;
+				string_t * r;
+				if (posix_memalign((void*)&subst, sizeof(void*), alignof(repl_t)) != 0)
+				    error("%s", strerror(errno));
+				insert(&subst->r_list, r_list->prev);
+				r = &subst->r[0];
+				if (posix_memalign((void*)&r->ref, sizeof(void*), alignof(typeof(r->ref))+strsize(token)) != 0)
+				    error("%s", strerror(errno));
+				*r->ref = 1;
+				r->name = ((char*)(r->ref))+alignof(typeof(r->ref));
+				strcpy(r->name, token);
+			    }
+			}
+			break;
+		    }
+		}
+		if (!found) {
+		    faci_t *restrict this;
+		    if (posix_memalign((void*)&this, sizeof(void*), alignof(faci_t)) != 0)
+			error("%s", strerror(errno));
+		    else {
+			list_t * r_list = &this->replace;
+			char * token;
+			r_list->next = r_list;
+			r_list->prev = r_list;
+			insert(&this->list, sysfaci_start->prev);
+			this->name = xstrdup(virt);
+			while ((token = strsep(&real, delimeter))) {
+			    repl_t *restrict subst;
+			    string_t * r;
+			    if (posix_memalign((void*)&subst, sizeof(void*), alignof(repl_t)) != 0)
+				error("%s", strerror(errno));
+			    insert(&subst->r_list, r_list->prev);
+			    r = &subst->r[0];
+			    if (posix_memalign((void*)&r->ref, sizeof(void*), alignof(typeof(r->ref))+strsize(token)) != 0)
+				error("%s", strerror(errno));
+			    *r->ref = 1;
+			    r->name = ((char*)(r->ref))+alignof(typeof(r->ref));
+			    strcpy(r->name, token);
+			}
+		    }
+		}
+	    }
+	}
+	if (regexecutor(&creg.isactive, buf, SUBCONFNUM, subloc, 0) == true) {
+	    char * key = (char*)0, * servs = (char*)0;
+	    val = &subloc[SUBCONF - 1];
+	    if (val->rm_so < val->rm_eo) {
+		*(pbuf+val->rm_eo) = '\0';
+		key = pbuf+val->rm_so;
+	    }
+	    val = &subloc[SUBCONFNUM - 1];
+	    if (val->rm_so < val->rm_eo) {
+		*(pbuf+val->rm_eo) = '\0';
+		servs = pbuf+val->rm_so;
+	    }
+	    if (key && *key == '<' && servs && *servs) {
+		if (!strncmp("<interactive>", key, strlen(key))) {
+		    char * token;
+		    while ((token = strsep(&servs, delimeter))) {
+			service_t *service = addservice(token);
+			service = getorig(service);
+			service->attr.flags |= SERV_INTRACT;
+		    }
+		}
+	    }
+	}
+    }
+
+    fclose(conf);
+    return;
+err:
+    warn("fopen(%s): %s\n", file, strerror(errno));
+}
+
+static int cfgfile_filter(const struct dirent *restrict d) attribute((nonnull(1)));
+static int cfgfile_filter(const struct dirent *restrict d)
+{
+    boolean ret = false;
+    const char * name = d->d_name;
+    const char * end;
+
+    if (*name == '.')
+	goto out;
+    if (!name || (*name == '\0'))
+	goto out;
+    if ((end = strrchr(name, '.'))) {
+	end++;
+	if (!strncmp(end, "rpm", 3)	|| /* .rpmorig, .rpmnew, .rmpsave, ... */
+	    !strncmp(end, "ba", 2)	|| /* .bak, .backup, ... */
+#ifdef SUSE
+	    !strcmp(end,  "local")	|| /* .local are sourced by the basename */
+#endif /* not SUSE */
+	    !strcmp(end,  "old")	||
+	    !strcmp(end,  "new")	||
+	    !strcmp(end,  "org")	||
+	    !strcmp(end,  "orig")	||
+	    !strncmp(end, "dpkg", 3)	|| /* .dpkg-old, .dpkg-new ... */
+	    !strcmp(end,  "save")	||
+	    !strcmp(end,  "swp")	|| /* Used by vi like editors */
+	    !strcmp(end,  "core"))	   /* modern core dump */
+	{
+	    goto out;
+	}
+    }
+    if ((end = strrchr(name, ','))) {
+	end++;
+	if (!strcmp(end,  "v"))		  /* rcs-files */
+	    goto out;
+    }
+    ret = true;
+out:
+    return (int)ret;
+}
+
+static void scan_conf(const char *restrict file) attribute((nonnull(1)));
+static void scan_conf(const char *restrict file)
+{
+    struct dirent** namelist = (struct dirent**)0;
+    char path[PATH_MAX+1];
+    int n;
+
+    regcompiler(&creg.isysfaci,  CONFLINE, REG_EXTENDED|REG_ICASE);
+    regcompiler(&creg.isactive, CONFLINE2, REG_EXTENDED|REG_ICASE);
+
+    n = snprintf(&path[0], sizeof(path), "%s%s",   (root && !set_insconf) ? root : "", file);
+    if (n >= (int)sizeof(path) || n < 0)
+	error("snprintf(): %s\n", strerror(errno));
+
+    scan_conf_file(path);
+
+    n = snprintf(&path[0], sizeof(path), "%s%s.d", (root && !set_insconf) ? root : "", file);
+    if (n >= (int)sizeof(path) || n < 0)
+	error("snprintf(): %s\n", strerror(errno));
+
+    n = scandir(path, &namelist, cfgfile_filter, alphasort);
+    if(n > 0) {
+	while(n--) {
+	    struct stat st;
+	    char buf[PATH_MAX+1];
+	    int r;
+
+	    r = snprintf(&buf[0], sizeof(buf), "%s/%s", path, namelist[n]->d_name);
+	    if (r >= (int)sizeof(buf) || r < 0)
+		error("snprintf(): %s\n", strerror(errno));
+
+	    if ((stat(buf, &st) < 0) || !S_ISREG(st.st_mode))
+	        continue;
+
+	    scan_conf_file(buf);
+
+	    free(namelist[n]);
+	}
+    }
+
+    if (namelist)
+	free(namelist);
+
+    regfree(&creg.isysfaci);
+    regfree(&creg.isactive);
+}
+
+static void expand_faci(list_t *restrict rlist, list_t *restrict head,
+			int *restrict deep) attribute((noinline,nonnull(1,2,3)));
+static void expand_faci(list_t *restrict rlist, list_t *restrict head, int *restrict deep)
+{
+	repl_t * rent = getrepl(rlist);
+	list_t * tmp, * safe, * ptr = (list_t*)0;
+
+	list_for_each(tmp, sysfaci_start) {
+	    if (!strcmp(getfaci(tmp)->name, rent->r[0].name)) {
+		ptr = &getfaci(tmp)->replace;
+		break;
+	    }
+	}
+
+	if (!ptr || list_empty(ptr)) {
+	    delete(rlist);
+	    if (--(*rent->r[0].ref) <= 0)
+		free(rent->r[0].ref);
+	    free(rent);
+	    goto out;
+	}
+
+	if ((*deep)++ > 10) {
+	    warn("The nested level of the system facilities in the insserv.conf file(s) is to large\n");
+	    goto out;
+	}
+
+	list_for_each_safe(tmp, safe, ptr) {
+	    repl_t * rnxt = getrepl(tmp);
+	    if (*rnxt->r[0].name == '$') {
+		expand_faci(tmp, head, deep);
+	    } else {
+		if (*deep == 1) {
+		    if (--(*rent->r[0].ref) <= 0)
+			free(rent->r[0].ref);
+		    rent->r[0] = rnxt->r[0];
+		    ++(*rent->r[0].ref);
+		} else {
+		    repl_t *restrict subst;
+		    if (posix_memalign((void*)&subst, sizeof(void*), alignof(repl_t)) != 0)
+			error("%s", strerror(errno));
+		    insert(&subst->r_list, head);
+		    subst->r[0] = rnxt->r[0];
+		    ++(*subst->r[0].ref);
+		}
+	    }
+	}
+out:
+	(*deep)--;
+	return;
+}
+
+static inline void expand_conf(void)
+{
+    list_t *ptr;
+    list_for_each(ptr, sysfaci_start) {
+	list_t * rlist, * safe, * head = &getfaci(ptr)->replace;
+	list_for_each_safe(rlist, safe, head) {
+	    if (*getrepl(rlist)->r[0].name == '$') {
+		int deep = 0;
+		expand_faci(rlist, rlist, &deep);
+	    }
+	}
+    }
+}
+
+/*
+ * Scan for a Start or Kill script within a runlevel directory.
+ * We start were we leave the directory, the upper level
+ * has to call rewinddir(3) if necessary.
+ */
+static inline char * scan_for(DIR *const restrict rcdir,
+			      const char *const restrict script,
+			      const char type) attribute((always_inline,nonnull(1,2)));
+static inline char * scan_for(DIR *const rcdir,
+			      const char *const script, const char type)
+{
+    struct dirent *d;
+    char * ret = (char*)0;
+
+    while ((d = readdir(rcdir)) != (struct dirent*)0) {
+	char * ptr = d->d_name;
+
+	if (*ptr != type)
+	    continue;
+	ptr++;
+
+	if (strspn(ptr, "0123456789") < 2)
+	    continue;
+	ptr += 2;
+
+	if (!strcmp(ptr, script)) {
+	    ret = d->d_name;
+	    break;
+	}
+    }
+    return ret;
+}
+
+#ifdef SUSE
+/*
+ * A simple command line checker of the parent process to determine if this is
+ * a sub process "/bin/sh" forked off for executing a temporary file for %preun,
+ * %postun, %pre, or %post scriptlet.
+ */
+static inline boolean underrpm(void)
+{
+    boolean ret = false;
+    const pid_t pp = getppid();
+    char buf[PATH_MAX], *argv[3], *ptr;
+# if defined(USE_RPMLIB) && (USE_RPMLIB > 0)
+    char *tmppath, *shell;
+# endif /* USE_RPMLIB */
+    int argc, fd;
+    ssize_t len;
+
+    snprintf(buf, sizeof(buf)-1, "/proc/%lu/cmdline", (unsigned long)pp);
+    if ((fd = open(buf, O_NOCTTY|O_RDONLY)) < 0)
+	goto out;
+
+    memset(buf, '\0', sizeof(buf));
+    if ((len = read(fd , buf, sizeof(buf)-1)) < 0)
+	goto out;
+
+    ptr = &buf[0];
+    argc = 0;
+    do {
+	argv[argc++] = ptr;
+	if (argc > 2)
+	    break;
+	if ((len = len - (ssize_t)(ptr - &buf[0])) < 0)
+	    break;
+    } while ((ptr = memchr(ptr, '\0', len)) && *(++ptr));
+
+    if (argc != 3)
+	goto out;
+
+# if defined(USE_RPMLIB) && (USE_RPMLIB > 0)
+    rpmReadConfigFiles(NULL, NULL);
+    rpmFreeRpmrc();
+
+    if ((shell = rpmExpand("%_buildshell", NULL)) == NULL)
+	shell = xstrdup("/bin/sh");
+
+    if (strncmp(argv[0], shell, strlen(shell)) != 0) {
+	free(shell);
+	goto out;
+    }
+    free(shell);
+
+    if ((tmppath = rpmExpand("%_tmppath", NULL)) == NULL)
+	tmppath = xstrdup("/var/tmp");
+
+    if (strncmp(argv[1], tmppath, strlen(tmppath)) != 0) {
+	free(tmppath);
+	goto out;
+    }
+
+    len = strlen(tmppath);
+    free(tmppath);
+
+    ptr = argv[1];
+    if (strncmp(ptr + len, "/rpm-tmp.", 9) != 0)
+	goto out;
+# else  /* not USE_RPMLIB */
+    if ((strcmp(argv[0], "/bin/sh") != 0) &&
+	(strcmp(argv[0], "/bin/bash") != 0))
+	goto out;
+
+    if ((strncmp(argv[1], "/var/tmp/rpm-tmp.", 17) != 0) &&
+	(strncmp(argv[1], "/usr/tmp/rpm-tmp.", 17) != 0) &&
+	(strncmp(argv[1], "/tmp/rpm-tmp.", 13) != 0))
+	goto out;
+# endif /* not USE_RPMLIB */
+    if ((argc = atoi(argv[2])) >= 0 && argc <= 2)
+	ret = true;
+out:
+    if (fd >= 0)
+	close(fd);
+
+    return ret;
+}
+#endif /* SUSE */
+
+static struct option long_options[] =
+{
+    {"verbose",	0, (int*)0, 'v'},
+    {"config",	1, (int*)0, 'c'},
+    {"dryrun",	0, (int*)0, 'n'},
+    {"default",	0, (int*)0, 'd'},
+    {"remove",	0, (int*)0, 'r'},
+    {"force",	0, (int*)0, 'f'},
+    {"path",	1, (int*)0, 'p'},
+    {"override",1, (int*)0, 'o'},
+    {"help",	0, (int*)0, 'h'},
+    { 0,	0, (int*)0,  0 },
+};
+
+static void help(const char *restrict const name) attribute((nonnull(1)));
+static void help(const char *restrict const  name)
+{
+    printf("Usage: %s [<options>] [init_script|init_directory]\n", name);
+    printf("Available options:\n");
+    printf("  -h, --help       This help.\n");
+    printf("  -r, --remove     Remove the listed scripts from all runlevels.\n");
+    printf("  -f, --force      Ignore if a required service is missed.\n");
+    printf("  -v, --verbose    Provide information on what is being done.\n");
+    printf("  -p <path>, --path <path>  Path to replace " INITDIR ".\n");
+    printf("  -o <path>, --override <path> Path to replace " OVERRIDEDIR ".\n");
+    printf("  -c <config>, --config <config>  Path to config file.\n");
+    printf("  -n, --dryrun     Do not change the system, only talk about it.\n");
+    printf("  -d, --default    Use default runlevels a defined in the scripts\n");
+}
+
+
+/*
+ * Do the job.
+ */
+int main (int argc, char *argv[])
+{
+    DIR * initdir;
+    struct dirent *d;
+    struct stat st_script;
+    extension char * argr[argc];
+    char * path = INITDIR;
+    char * override_path = OVERRIDEDIR;
+    char * insconf = INSCONF;
+    const char *const ipath = path;
+    int runlevel, c, dfd;
+    boolean del = false;
+    boolean defaults = false;
+    boolean ignore = false;
+
+    myname = basename(*argv);
+
+#ifdef SUSE
+    if (underrpm())
+	ignore = true;
+#endif /* SUSE */
+
+    if (getuid() == (uid_t)0)
+	o_flags |= O_NOATIME;
+
+    for (c = 0; c < argc; c++)
+	argr[c] = (char*)0;
+
+    while ((c = getopt_long(argc, argv, "c:dfrhvno:p:", long_options, (int *)0)) != -1) {
+	size_t l;
+	switch (c) {
+	    case 'c':
+		if (optarg == (char*)0 || *optarg == '\0')
+		    goto err;
+		insconf = optarg;
+		set_insconf = true;
+		break;
+	    case 'd':
+		defaults = true;
+		break;
+	    case 'r':
+		del = true;
+		break;
+	    case 'f':
+		ignore = true;
+		break;
+	    case 'v':
+		verbose = true;
+		break;
+	    case 'n':
+		verbose = true;
+		dryrun = true;
+		break;
+	    case 'p':
+		if (optarg == (char*)0 || *optarg == '\0')
+		    goto err;
+		if (path != ipath) free(path);
+		l = strlen(optarg) - 1;
+		path = xstrdup(optarg);
+		if (*(path+l) == '/')
+		    *(path+l) = '\0';
+		break;
+	    case 'o':
+		if (optarg == (char*)0 || *optarg == '\0')
+		    goto err;
+		override_path = optarg;
+		set_override = true;
+		break;
+	    case '?':
+	    err:
+		error("For help use: %s -h\n", myname);
+	    case 'h':
+		help(myname);
+		exit(0);
+	    default:
+		break;
+	}
+    }
+    argv += optind;
+    argc -= optind;
+
+    if (!argc && del)
+	error("usage: %s [[-r] init_script|init_directory]\n", myname);
+
+    if (*argv) {
+	char * token = strpbrk(*argv, delimeter);
+
+	/*
+	 * Let us separate the script/service name from the additional arguments.
+	 */
+	if (token && *token) {
+	    *token = '\0';
+	    *argr = ++token;
+	}
+
+	/* Catch `/path/script', `./script', and `path/script' */
+	if (strchr(*argv, '/')) {
+	    if (stat(*argv, &st_script) < 0)
+		error("%s: %s\n", *argv, strerror(errno));
+	} else {
+	    pushd(path);
+	    if (stat(*argv, &st_script) < 0)
+		error("%s: %s\n", *argv, strerror(errno));
+	    popd();
+	}
+
+	if (S_ISDIR(st_script.st_mode)) {
+	    const size_t l = strlen(*argv) - 1;
+
+	    if (path != ipath) free(path);
+	    path = xstrdup(*argv);
+	    if (*(path+l) == '/')
+		*(path+l) = '\0';
+
+	    argv++;
+	    argc--;
+	    if (argc || del)
+		error("usage: %s [[-r] init_script|init_directory]\n", myname);
+
+	} else {
+	    char * base, * ptr = xstrdup(*argv);
+
+	    if ((base = strrchr(ptr, '/'))) {
+		if (path != ipath) free(path);
+		*base = '\0';
+		path  = ptr;
+	    } else
+		free(ptr);
+	}
+    }
+
+    if (strcmp(path, INITDIR) != 0) {
+	char * tmp;
+	root = xstrdup(path);
+	if ((tmp = strstr(root, INITDIR))) {
+	    *tmp = '\0';
+	} else {
+	    free(root);
+	    root = (char*)0;
+	}
+    }
+
+    c = argc;
+    while (c--) {
+	char * base;
+	char * token = strpbrk(argv[c], delimeter);
+
+	/*
+	 * Let us separate the script/service name from the additional arguments.
+	 */
+	if (token && *token) {
+	    *token = '\0';
+	    argr[c] = ++token;
+	}
+
+	if (stat(argv[c], &st_script) < 0) {
+	    if (errno != ENOENT)
+		error("%s: %s\n", argv[c], strerror(errno));
+	    pushd(path);
+	    if (stat(argv[c], &st_script) < 0)
+		error("%s: %s\n", argv[c], strerror(errno));
+	    popd();
+	}
+	if ((base = strrchr(argv[c], '/'))) {
+	    base++;
+	    argv[c] = base;
+	}
+    }
+
+#if defined(DEBUG) && (DEBUG > 0)
+    for (c = 0; c < argc; c++)
+	if (argr[c])
+	    printf("Overwrite argument for %s is %s\n", argv[c], argr[c]);
+#endif /* DEBUG */
+
+    /*
+     * Scan and set our configuration for virtual services.
+     */
+    scan_conf(insconf);
+
+    /*
+     * Expand system facilities to real serivces
+     */
+    expand_conf();
+
+    /*
+     * Initialize the regular scanner for the scripts.
+     */
+    scan_script_regalloc();
+
+    /*
+     * Scan always for the runlevel links to see the current
+     * link scheme of the services.
+     */
+    scan_script_locations(path, override_path, ignore);
+
+    /*
+     * Clear out aliases found for scripts found up to this point.
+     */
+    clear_all();
+
+    /*
+     * Open the script directory
+     */
+    if ((initdir = opendir(path)) == (DIR*)0 || (dfd = dirfd(initdir)) < 0)
+	error("can not opendir(%s): %s\n", path, strerror(errno));
+
+#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
+    (void)posix_fadvise(dfd, 0, 0, POSIX_FADV_WILLNEED);
+    (void)posix_fadvise(dfd, 0, 0, POSIX_FADV_SEQUENTIAL);
+#endif
+
+    /*
+     * Now scan for the service scripts and their LSB comments.
+     */
+    pushd(path);
+
+    /*
+     * Scan scripts found in the command line to be able to resolve
+     * all dependcies given within those scripts.
+     */
+    if (argc > 1) for (c = 0; c < argc; c++) {
+	const char *const name = argv[c];
+	service_t * first = (service_t*)0;
+	char * provides, * begin, * token;
+	const uchar lsb = scan_script_defaults(dfd, name, override_path, (char**)0, true, ignore);
+
+	if ((lsb & FOUND_LSB_HEADER) == 0) {
+	    if ((lsb & (FOUND_LSB_DEFAULT|FOUND_LSB_OVERRIDE)) == 0)
+	        warn("warning: script '%s' missing LSB tags and overrides\n", name);
+	    else
+	        warn("warning: script '%s' missing LSB tags\n", name);
+	}
+
+	if (!script_inf.provides || script_inf.provides == empty)
+	    script_inf.provides = xstrdup(name);
+
+	provides = xstrdup(script_inf.provides);
+	begin = provides;
+	while ((token = strsep(&begin, delimeter)) && *token) {
+	    service_t * service;
+
+	    if (*token == '$') {
+		warn("script %s provides system facility %s, skipped!\n", name, token);
+		continue;
+	    }
+	    if (*token == '#') {
+		warn("script %s provides facility %s with comment sign, skipped!\n", name, token);
+		continue;
+	    }
+
+	    service = addservice(token);
+
+	    if (first)
+		nickservice(first, service);
+	    else
+		first = service;
+
+	    service->attr.flags |= SERV_CMDLINE;
+	}
+	free(provides);
+    }
+
+    /*
+     * Scan now all scripts found in the init.d/ directory
+     */
+    while ((d = readdir(initdir)) != (struct dirent*)0) {
+	const boolean isarg = chkfor(d->d_name, argv, argc);
+	service_t * service = (service_t*)0;
+	char * token;
+	char * begin = (char*)0;	/* hold start pointer of strings handled by strsep() */
+	boolean hard = false;
+	uchar lsb = 0;
+#if defined(DEBUG) && (DEBUG > 0)
+	int nobug = 0;
+#endif
+
+	if (*d->d_name == '.')
+	    continue;
+	errno = 0;
+
+	/* d_type seems not to work, therefore use (l)stat(2) */
+	if (xstat(dfd, d->d_name, &st_script) < 0) {
+	    warn("can not stat(%s)\n", d->d_name);
+	    continue;
+	}
+	if (!S_ISREG(st_script.st_mode) || !(S_IXUSR & st_script.st_mode))
+	{
+	    if (S_ISDIR(st_script.st_mode))
+		continue;
+	    if (isarg)
+		warn("script %s is not an executable regular file, skipped!\n", d->d_name);
+	    continue;
+	}
+
+	if (!strncmp(d->d_name, "README", strlen("README"))) {
+	    if (isarg)
+		warn("script name %s is not valid, skipped!\n", d->d_name);
+	    continue;
+	}
+
+	if (!strncmp(d->d_name, "Makefile", strlen("Makefile"))) {
+	    if (isarg)
+		warn("script name %s is not valid, skipped!\n", d->d_name);
+	    continue;
+	}
+
+	if (!strncmp(d->d_name, "core", strlen("core"))) {
+	    if (isarg)
+		warn("script name %s is not valid, skipped!\n", d->d_name);
+	    continue;
+	}
+
+	/* Common scripts not used within runlevels */
+	if (!strcmp(d->d_name, "rx")	   ||
+	    !strncmp(d->d_name, "skeleton", 8) ||
+	    !strncmp(d->d_name, "powerfail", 9))
+	{
+	    if (isarg)
+		warn("script name %s is not valid, skipped!\n", d->d_name);
+	    continue;
+	}
+
+#ifdef SUSE
+	if (!strcmp(d->d_name, "boot") || !strcmp(d->d_name, "rc"))
+#else  /* not SUSE */
+	if (!strcmp(d->d_name, "rcS") || !strcmp(d->d_name, "rc"))
+#endif /* not SUSE */
+	{
+	    if (isarg)
+		warn("script name %s is not valid, skipped!\n", d->d_name);
+	    continue;
+	}
+
+	if (cfgfile_filter(d) == 0) {
+	    if (isarg)
+		warn("script name %s is not valid, skipped!\n", d->d_name);
+	    continue;
+	}
+
+	/* left by emacs like editors */
+	if (d->d_name[strlen(d->d_name)-1] == '~') {
+	    if (isarg)
+		warn("script name %s is not valid, skipped!\n", d->d_name);
+	    continue;
+	}
+
+	if (strspn(d->d_name, "$.#%_+-\\*[]^:()~")) {
+	    if (isarg)
+		warn("script name %s is not valid, skipped!\n", d->d_name);
+	    continue;
+	}
+
+	/* main scanner for LSB comment in current script */
+	lsb = scan_script_defaults(dfd, d->d_name, override_path, (char**)0, false, ignore);
+
+	if ((lsb & FOUND_LSB_HEADER) == 0) {
+	    if ((lsb & (FOUND_LSB_DEFAULT|FOUND_LSB_OVERRIDE)) == 0)
+	        warn("warning: script '%s' missing LSB tags and overrides\n", d->d_name);
+	    else
+	        warn("warning: script '%s' missing LSB tags\n", d->d_name);
+	}
+
+#ifdef SUSE
+	/* Common script ... */
+	if (!strcmp(d->d_name, "halt")) {
+	    service_t *serv = addservice("halt");
+	    serv = getorig(serv);
+	    makeprov(serv,   d->d_name);
+	    runlevels(serv, 'S', "0");
+	    serv->attr.flags |= (SERV_ALL|SERV_NOSTOP|SERV_INTRACT);
+	    continue;
+	}
+
+	/* ... and its link */
+	if (!strcmp(d->d_name, "reboot")) {
+	    service_t *serv = addservice("reboot");
+	    serv = getorig(serv);
+	    makeprov(serv,   d->d_name);
+	    runlevels(serv, 'S', "6");
+	    serv->attr.flags |= (SERV_ALL|SERV_NOSTOP|SERV_INTRACT);
+	    continue;
+	}
+
+	/* Common script for single mode */
+	if (!strcmp(d->d_name, "single")) {
+	    service_t *serv = addservice("single");
+	    serv = getorig(serv);
+	    makeprov(serv,   d->d_name);
+	    runlevels(serv, 'S', "1 S");
+	    serv->attr.flags |= (SERV_ALL|SERV_NOSTOP|SERV_INTRACT);
+	    rememberreq(serv, REQ_SHLD, "kbd");
+	    continue;
+	}
+#endif /* SUSE */
+
+#ifndef SUSE
+	if (!lsb) {
+	    script_inf.required_start = xstrdup(DEFAULT_DEPENDENCY);
+	    script_inf.required_stop = xstrdup(DEFAULT_DEPENDENCY);
+	    script_inf.default_start = xstrdup(DEFAULT_START_LVL);
+	    script_inf.default_stop = xstrdup(DEFAULT_STOP_LVL);
+	}
+#endif /* not SUSE */
+
+	/*
+	 * Oops, no comment found, guess one
+	 */
+	if (!script_inf.provides || script_inf.provides == empty) {
+	    service_t * guess;
+	    script_inf.provides = xstrdup(d->d_name);
+
+	    /*
+	     * Use guessed service to find it within the the runlevels
+	     * (by using the list from the first scan for script locations).
+	     */
+	    if ((guess = findservice(script_inf.provides))) {
+		/*
+		 * Try to guess required services out from current scheme.
+		 * Note, this means that all services are required.
+		 */
+		if (!script_inf.required_start || script_inf.required_start == empty) {
+		    list_t * ptr;
+		    list_for_each_prev(ptr, s_start) {
+			service_t * tmp = getservice(ptr);
+			tmp = getorig(tmp);
+			if (!tmp->attr.sorder)
+			    continue;
+			if (tmp->attr.sorder >= guess->attr.sorder)
+			    continue;
+			if (tmp->start->lvl & guess->start->lvl) {
+			    script_inf.required_start = xstrdup(tmp->name);
+			    break;
+			}
+		    }
+		}
+		if (!script_inf.required_stop || script_inf.required_stop == empty) {
+		    list_t * ptr;
+		    list_for_each_prev(ptr, s_start) {
+			service_t * tmp = getservice(ptr);
+			tmp = getorig(tmp);
+			if (!tmp->attr.korder)
+			    continue;
+			if (tmp->attr.korder <= guess->attr.korder)
+			    continue;
+			if (tmp->stopp->lvl & guess->stopp->lvl) {
+			    script_inf.required_stop = xstrdup(tmp->name);
+			    break;
+			}
+		    }
+		}
+		if (!script_inf.default_start || script_inf.default_start == empty) {
+		    if (guess->start->lvl)
+			script_inf.default_start = lvl2str(guess->start->lvl);
+		}
+		if (!script_inf.default_stop || script_inf.default_stop == empty) {
+		    if (guess->stopp->lvl)
+			script_inf.default_stop = lvl2str(guess->stopp->lvl);
+		}
+
+	    } else {	/* !findservice(&guess, script_inf.provides) */
+
+		list_t * ptr;
+		/*
+		 * Find out which levels this service may have out from current scheme.
+		 * Note, this means that the first requiring service wins.
+		 */
+		list_for_each(ptr, s_start) {
+		    service_t * cur;
+		    list_t * req;
+
+		    if (script_inf.default_start && script_inf.default_start != empty)
+			   break;
+		    cur = getservice(ptr);
+		    cur = getorig(cur);
+
+		    if (list_empty(&cur->sort.req) || !(cur->attr.flags & SERV_ENABLED))
+			continue;
+
+		    np_list_for_each(req, &cur->sort.req) {
+			if (!strcmp(getreq(req)->serv->name, script_inf.provides)) {
+			    script_inf.default_start = lvl2str(getservice(ptr)->start->lvl);
+			    break;
+			}
+		    }
+		}
+		list_for_each(ptr, s_start) {
+		    service_t * cur;
+		    list_t * rev;
+
+		    if (script_inf.default_stop && script_inf.default_stop != empty)
+			   break;
+		    cur = getservice(ptr);
+		    cur = getorig(cur);
+
+		    if (list_empty(&cur->sort.rev) || !(cur->attr.flags & SERV_ENABLED))
+			continue;
+
+		    np_list_for_each(rev, &cur->sort.rev) {
+			if (!strcmp(getreq(rev)->serv->name, script_inf.provides)) {
+			    script_inf.default_stop = lvl2str(getservice(ptr)->stopp->lvl);
+			    break;
+			}
+		    }
+		}
+	    }		/* !findservice(&guess, script_inf.provides) */
+	}
+
+	/*
+	 * Use guessed service to find it within the the runlevels
+	 * (by using the list from the first scan for script locations).
+	 */
+	if (!service) {
+	    char * provides = xstrdup(script_inf.provides);
+	    service_t * first = (service_t*)0;
+
+	    begin = provides;
+	    while ((token = strsep(&begin, delimeter)) && *token) {
+
+		if (*token == '$') {
+		    warn("script %s provides system facility %s, skipped!\n", d->d_name, token);
+		    continue;
+		}
+		if (*token == '#') {
+		    warn("script %s provides facility %s with comment sign, skipped!\n", d->d_name, token);
+		    continue;
+		}
+
+		service = addservice(token);
+ 
+		if (first)
+		    nickservice(first, service);
+		else
+		    first = service;
+
+#if defined(DEBUG) && (DEBUG > 0)
+		nobug++;
+#endif
+		if (!makeprov(service, d->d_name)) {
+
+		    if (!del || (del && !isarg))
+			warn("script %s: service %s already provided!\n", d->d_name, token);
+
+		    if (!del && !ignore && isarg)
+			error("exiting now!\n");
+
+		    if (!del || (del && !ignore && !isarg))
+			continue;
+
+		    /* Provide this service with an other name to be able to delete it */
+		    service = addservice(d->d_name);
+		    service = getorig(service);
+		    service->attr.flags |= SERV_ALREADY;
+		    (void)makeprov(service, d->d_name);
+
+		    continue;
+	    	}
+
+		if (service) {
+		    boolean known = (service->attr.flags & SERV_KNOWN);
+		    service->attr.flags |= SERV_KNOWN;
+
+		    if (!known) {
+			if (script_inf.required_start && script_inf.required_start != empty) {
+			    rememberreq(service, REQ_MUST, script_inf.required_start);
+#ifdef USE_COMPAT_EMPTY
+			    if (!script_inf.required_stop || script_inf.required_stop == empty)
+				script_inf.required_stop = xstrdup(script_inf.required_start);
+#endif /* USE_COMPAT_EMPTY */
+			}
+			if (script_inf.should_start && script_inf.should_start != empty) {
+			    rememberreq(service, REQ_SHLD, script_inf.should_start);
+#ifdef USE_COMPAT_EMPTY
+			    if (!script_inf.should_stop || script_inf.should_stop == empty)
+				script_inf.should_stop = xstrdup(script_inf.should_start);
+#endif /* USE_COMPAT_EMPTY */
+			}
+			if (script_inf.required_stop && script_inf.required_stop != empty) {
+			    rememberreq(service, REQ_MUST|REQ_KILL, script_inf.required_stop);
+			}
+			if (script_inf.should_stop && script_inf.should_stop != empty) {
+			    rememberreq(service, REQ_SHLD|REQ_KILL, script_inf.should_stop);
+			}
+		    }
+
+		    if (script_inf.start_before && script_inf.start_before != empty) {
+			reversereq(service, REQ_SHLD, script_inf.start_before);
+#ifdef USE_COMPAT_EMPTY
+			if (!script_inf.stop_after || script_inf.stop_after == empty)
+			    script_inf.stop_after = xstrdup(script_inf.start_before);
+#endif /* USE_COMPAT_EMPTY */
+		    }
+		    if (script_inf.stop_after && script_inf.stop_after != empty) {
+			reversereq(service, REQ_SHLD|REQ_KILL, script_inf.stop_after);
+		    }
+		    /*
+		     * Use information from symbolic link structure to
+		     * check if all services are around for this script.
+		     */
+		    if (isarg && !ignore) {
+			boolean ok = true;
+			if (del)
+			    ok = chkdependencies(service);
+			else
+			    ok = chkrequired(service);
+			if (!ok && !ignore)
+			    error("exiting now!\n");
+		    }
+
+		    if (script_inf.default_start && script_inf.default_start != empty) {
+		 	ushort deflvls = str2lvl(script_inf.default_start);
+
+			if (service->attr.flags & SERV_ENABLED) {
+			    /*
+			     * Currently linked into service runlevel scheme, check
+			     * if the defaults are overwriten. Compare all bits,
+			     * which means `==' and not `&' and overwrite the defaults
+			     * of the current script.
+			     */
+			    if (!defaults && (deflvls != service->start->lvl)) {
+				if (!del && isarg && !(argr[curr_argc]))
+				    warn("warning: current start runlevel(s) (%s) of script `%s' overwrites defaults (%s).\n",
+					 service->start->lvl ? lvl2str(service->start->lvl) : "empty", d->d_name, lvl2str(deflvls));
+			    }
+			} else
+			    /*
+			     * Currently not linked into service runlevel scheme, info
+			     * needed for enabling interactive services at first time.
+			     */
+			    service->start->lvl = deflvls;
+
+		    } else if (script_inf.default_start == empty) {
+			if (service->attr.flags & SERV_ENABLED) {
+			    /*
+			     * Currently linked into service runlevel scheme, check
+			     * if the defaults are overwriten. Compare all bits,
+			     * which means `==' and not `&' and overwrite the defaults
+			     * of the current script.
+			     */
+			    if (!defaults && service->start->lvl != 0) {
+				warn("warning: current start runlevel(s) (%s) of script `%s' overwrites defaults (empty).\n",
+				     lvl2str(service->start->lvl), d->d_name);
+				script_inf.default_start = lvl2str(service->start->lvl);
+			    }
+			}
+		    } else if (!script_inf.default_start && (service->attr.flags & SERV_NOTLSB)) {
+#ifdef SUSE
+			/*
+			 * Could be a none LSB script, use info from current link scheme.
+			 * If not found use default.
+			 */
+			if (service->attr.flags & SERV_ENABLED)
+			    script_inf.default_start = lvl2str(service->start->lvl);
+			else
+			    script_inf.default_start = xstrdup(DEFAULT_START_LVL);
+#endif /* SUSE */
+		    }
+#ifdef SUSE
+		    /*
+		     * This because SuSE boot script concept uses a differential link scheme.
+		     * Therefore default_stop is ignored and overwriten by default_start.
+		     */
+		    xreset(script_inf.default_stop);
+		    if (script_inf.default_start && script_inf.default_start != empty)
+			script_inf.default_stop = xstrdup(script_inf.default_start);
+		    else
+			script_inf.default_stop = empty;
+		    oneway(script_inf.default_stop);
+#endif /* SUSE */
+		    if (script_inf.default_stop && script_inf.default_stop != empty) {
+		 	ushort deflvlk = str2lvl(script_inf.default_stop);
+
+			/*
+			 * Compare all bits, which means `==' and not `&' and overwrite
+			 * the defaults of the current script.
+			 */
+			if (service->attr.flags & SERV_ENABLED) {
+			    /*
+			     * Currently linked into service runlevel scheme, check
+			     * if the defaults are overwriten.
+			     */
+			    if (!defaults && (deflvlk != service->stopp->lvl)) {
+				if (!del && isarg && !(argr[curr_argc]))
+				    warn("warning: current stop runlevel(s) (%s) of script `%s' overwrites defaults (%s).\n",
+					 service->stopp->lvl ? lvl2str(service->stopp->lvl) : "empty", d->d_name, lvl2str(deflvlk));
+			    }
+			} else
+			    /*
+			     * Currently not linked into service runlevel scheme, info
+			     * needed for enabling interactive services at first time.
+			     */
+			    service->stopp->lvl = deflvlk;
+
+		    } else if (script_inf.default_stop == empty) {
+			if (service->attr.flags & SERV_ENABLED) {
+			    /*
+			     * Currently linked into service runlevel scheme, check
+			     * if the defaults are overwriten. Compare all bits,
+			     * which means `==' and not `&' and overwrite the defaults
+			     * of the current script.
+			     */
+			    if (!defaults && service->stopp->lvl != 0) {
+				warn("warning: current stop runlevel(s) (%s) of script `%s' overwrites defaults (empty).\n",
+				     lvl2str(service->stopp->lvl), d->d_name);
+				script_inf.default_stop = lvl2str(service->stopp->lvl);
+			    }
+			}
+		    } else if (!script_inf.default_stop && (service->attr.flags & SERV_NOTLSB)) {
+#ifdef SUSE
+			/*
+			 * Could be a none LSB script, use info from current link scheme.
+			 * If not found use default.
+			 */
+			if (service->attr.flags & SERV_ENABLED)
+			    script_inf.default_stop = lvl2str(service->stopp->lvl);
+			else
+			    script_inf.default_stop = xstrdup(DEFAULT_STOP_LVL);
+#endif /* SUSE */
+		    }
+		}
+	    }
+	    free(provides);
+	}
+
+#ifdef SUSE
+	/* Ahh ... set default multiuser with network */
+	if (!script_inf.default_start || script_inf.default_start == empty) {
+	    if (!script_inf.default_start)
+		warn("Default-Start undefined, assuming default start runlevel(s) for script `%s'\n", d->d_name);
+	    script_inf.default_start = xstrdup(DEFAULT_START_LVL);
+	    xreset(script_inf.default_stop);
+	    script_inf.default_stop = xstrdup(script_inf.default_start);
+	    oneway(script_inf.default_stop);
+	}
+#else  /* not SUSE */
+	if (!script_inf.default_start) {
+	    warn("Default-Start undefined, assuming empty start runlevel(s) for script `%s'\n", d->d_name);
+	    script_inf.default_start = empty;
+	}
+#endif /* not SUSE */
+
+#ifdef SUSE
+	if (!script_inf.default_stop || script_inf.default_stop == empty) {
+	    if (script_inf.default_start && script_inf.default_start != empty)
+		script_inf.default_stop = xstrdup(script_inf.default_start);
+	    else
+		script_inf.default_stop = xstrdup(DEFAULT_STOP_LVL);
+	    oneway(script_inf.default_stop);
+	}
+#else  /* not SUSE */
+	if (!script_inf.default_stop) {
+	    warn("Default-Stop  undefined, assuming empty stop  runlevel(s) for script `%s'\n", d->d_name);
+	    script_inf.default_stop = empty;
+	}
+#endif /* not SUSE */
+
+	if (isarg && !defaults && !del) {
+	    if (argr[curr_argc]) {
+		char * ptr = argr[curr_argc];
+		struct _mark {
+		    const char * wrd;
+		    char * order;
+		    char ** str;
+		} mark[] = {
+		    {"start=",	  (char*)0, &script_inf.default_start},
+		    {"stop=",	  (char*)0, &script_inf.default_stop },
+#if 0
+		    {"reqstart=", (char*)0, &script_inf.required_start},
+		    {"reqstop=",  (char*)0, &script_inf.required_stop },
+#endif
+		    {(char*)0,	  (char*)0, (char**)0}
+		};
+
+		for (c = 0; mark[c].wrd; c++) {
+		    char * order = strstr(ptr, mark[c].wrd);
+		    if (order)
+			mark[c].order = order;
+		}
+
+		for (c = 0; mark[c].wrd; c++)
+		    if (mark[c].order) {
+			*(mark[c].order) = '\0';
+			mark[c].order += strlen(mark[c].wrd);
+		    }
+
+		for (c = 0; mark[c].wrd; c++)
+		    if (mark[c].order) {
+			size_t len = strlen(mark[c].order);
+			if (len > 0) {
+			    char * ptr = mark[c].order + len - 1;
+			    if (*ptr == ',') *ptr = '\0';
+			}
+			xreset(*(mark[c].str));
+			*(mark[c].str) = xstrdup(mark[c].order);
+		    }
+		hard = true;
+#ifdef SUSE
+		/*
+		 * This because SuSE boot script concept uses a differential link scheme.
+		 * Therefore default_stop is ignored and overwriten by default_start.
+		 */
+		if (strcmp(script_inf.default_stop, script_inf.default_start) != 0) {
+		    xreset(script_inf.default_stop);
+		    script_inf.default_stop = xstrdup(script_inf.default_start);
+		    oneway(script_inf.default_stop);
+		}
+#endif /* SUSE */
+	    }
+	}
+
+#if defined(DEBUG) && (DEBUG > 0)
+	if (!nobug) {
+	    fprintf(stderr, "internal BUG at line %d with script %s\n", __LINE__, d->d_name);
+	    exit(1);
+	}
+#endif
+
+	begin = script_inf.provides;
+	while ((token = strsep(&script_inf.provides, delimeter)) && *token) {
+	    if (*token == '$')
+		continue;
+	    if (*token == '#')
+		continue;
+	    if (!service)
+		service = addservice(token);
+	    service = getorig(service);
+
+	    if ((service->attr.flags & SERV_ENABLED) && !hard) {
+		if (del)
+		    continue;
+		if (!defaults)
+		    continue;
+	    }
+
+	    if (script_inf.default_start && script_inf.default_start != empty)
+		runlevels(service, 'S', script_inf.default_start);
+	    if (script_inf.default_stop && script_inf.default_stop != empty)
+		runlevels(service, 'K', script_inf.default_stop);
+	}
+	script_inf.provides = begin;
+
+	/* Remember if not LSB conform script */
+	if (!lsb && service) {
+	    service = getorig(service);
+	    service->attr.flags |= SERV_NOTLSB;
+	}
+    }
+    /* Reset remaining pointers */
+    scan_script_reset();
+
+    /*
+     * Free the regular scanner for the scripts.
+     */
+    scan_script_regfree();
+
+    /* back */
+    popd();
+    closedir(initdir);
+
+    /*
+     * Clear out aliases found for all scripts.
+     */
+    clear_all();
+
+    /*
+     * Set virtual dependencies for already enabled none LSB scripts.
+     */
+    nonlsb_script();
+
+    /*
+     * Now generate for all scripts the dependencies
+     */
+    follow_all();
+    if (is_loop_detected() && !ignore)
+	error("exiting without changing boot order!\n");
+
+    /*
+     * Be sure that interactive scripts are the only member of
+     * a start group (for parallel start only).
+     */
+    active_script();
+
+    /*
+     * Move the `$all' scripts to the end of all
+     */
+    all_script();
+
+    /*
+     * Sorry but we support only [KS][0-9][0-9]<name>
+     */
+    if (maxstart > MAX_DEEP || maxstop > MAX_DEEP)
+	error("Maximum of %u in ordering reached\n", MAX_DEEP);
+
+#if defined(DEBUG) && (DEBUG > 0)
+    printf("Maxorder %d/%d\n", maxstart, maxstop);
+    show_all();
+#else
+# ifdef SUSE	/* SuSE's SystemV link scheme */
+    pushd(path);
+    for (runlevel = 0; runlevel < RUNLEVLES; runlevel++) {
+	const ushort lvl = map_runlevel_to_lvl(runlevel);
+	char nlink[PATH_MAX+1], olink[PATH_MAX+1];
+	const char * rcd = (char*)0;
+	const char * script;
+	service_t *serv;
+	DIR  * rcdir;
+
+	if ((rcd = map_runlevel_to_location(runlevel)) == (char*)0)
+	    continue;
+
+	rcdir = openrcdir(rcd);		/* Creates runlevel directory if necessary */
+	if (rcdir == (DIR*)0)
+	    break;
+	if ((dfd = dirfd(rcdir)) < 0) {
+	    closedir(rcdir);
+	    break;
+	}
+	pushd(rcd);
+
+	/*
+	 * See if we found scripts which should not be
+	 * included within this runlevel directory.
+	 */
+	while ((d = readdir(rcdir)) != (struct dirent*)0) {
+	    const char * ptr = d->d_name;
+	    char type;
+
+	    if (*ptr != 'S' && *ptr != 'K')
+		continue;
+	    type = *ptr;
+	    ptr++;
+
+	    if (strspn(ptr, "0123456789") != 2)
+		continue;
+	    ptr += 2;
+
+	    if (xstat(dfd, d->d_name, &st_script) < 0)
+		xremove(dfd, d->d_name);	/* dangling sym link */
+
+	    if (notincluded(ptr, type, runlevel)) {
+		serv = findservice(getprovides(ptr));
+		if (defaults) {
+		    xremove(dfd, d->d_name);
+		    if (serv && --serv->attr.ref <= 0)
+			serv->attr.flags &= ~SERV_ENABLED;
+		} else if (lvl & LVL_ONEWAY) {
+		    xremove(dfd, d->d_name);
+		    if (serv && --serv->attr.ref <= 0)
+			serv->attr.flags &= ~SERV_ENABLED;
+		} else if (del && ignore) {
+		    if (serv && (serv->attr.flags & SERV_ALREADY)) {
+			xremove(dfd, d->d_name);
+			if (--serv->attr.ref <= 0)
+			    serv->attr.flags &= ~SERV_ENABLED;
+		    }
+		}
+	    }
+	}
+
+	/*
+	 * Seek for scripts which are included, link or
+	 * correct order number if necessary.
+	 */
+
+	script = (char*)0;
+	while ((serv = listscripts(&script, 'X', lvl))) {
+	    const boolean this = chkfor(script, argv, argc);
+	    boolean found, slink;
+	    char * clink;
+
+	    if (*script == '$')		/* Do not link in virtual dependencies */
+		continue;
+
+	    slink = false;
+	    if ((serv->start->lvl & lvl) == 0)
+		goto stop;
+
+	    sprintf(olink, "../%s",   script);
+	    sprintf(nlink, "S%.2d%s", serv->attr.sorder, script);
+
+	    found = false;
+	    rewinddir(rcdir);
+	    while ((clink = scan_for(rcdir, script, 'S'))) {
+		found = true;
+		if (strcmp(clink, nlink)) {
+		    xremove(dfd, clink);		/* Wrong order, remove link */
+		    if (--serv->attr.ref <= 0)
+			serv->attr.flags &= ~SERV_ENABLED;
+		    if (!this) {
+			xsymlink(dfd, olink, nlink);	/* Not ours, but correct order */
+			if (++serv->attr.ref)
+			    serv->attr.flags |= SERV_ENABLED;
+		    }
+		    if (this && !del) {
+			xsymlink(dfd, olink, nlink);	/* Restore, with correct order */
+			if (++serv->attr.ref)
+			    serv->attr.flags |= SERV_ENABLED;
+		    }
+		} else {
+		    if (del && this) {
+			xremove(dfd, clink);		/* Found it, remove link */
+			if (--serv->attr.ref <= 0)
+			    serv->attr.flags &= ~SERV_ENABLED;
+		    }
+		}
+	    }
+
+	    if (this) {
+		/*
+		 * If we haven't found it and we shouldn't delete it
+		 * we try to add it.
+		 */
+		if (!del && !found) {
+		    xsymlink(dfd, olink, nlink);
+		    if (++serv->attr.ref)
+			serv->attr.flags |= SERV_ENABLED;
+		    found = true;
+		}
+	    }
+
+	    /* Start links done, now do Kill links */
+
+	    slink = found;
+	stop:
+	    if ((serv->stopp->lvl & lvl) == 0)
+		continue;
+
+	    sprintf(olink, "../%s",   script);
+	    sprintf(nlink, "K%.2d%s", serv->attr.korder, script);
+
+	    found = false;
+	    rewinddir(rcdir);
+	    while ((clink = scan_for(rcdir, script, 'K'))) {
+		found = true;
+		if (strcmp(clink, nlink)) {
+		    xremove(dfd, clink);		/* Wrong order, remove link */
+		    if (--serv->attr.ref <= 0)
+			serv->attr.flags &= ~SERV_ENABLED;
+		    if (!this) {
+			xsymlink(dfd, olink, nlink);	/* Not ours, but correct order */
+			if (++serv->attr.ref)
+			    serv->attr.flags |= SERV_ENABLED;
+		    }
+		    if (this && !del) {
+			xsymlink(dfd, olink, nlink);	/* Restore, with correct order */
+			if (++serv->attr.ref)
+			    serv->attr.flags |= SERV_ENABLED;
+		    }
+		} else {
+		    if (del && this) {
+			xremove(dfd, clink);		/* Found it, remove link */
+			if (--serv->attr.ref <= 0)
+			    serv->attr.flags &= ~SERV_ENABLED;
+		    }
+		}
+	    }
+
+	    if (this && slink) {
+		/*
+		 * If we haven't found it and we shouldn't delete it
+		 * we try to add it.
+		 */
+		if (!del && !found) {
+		    xsymlink(dfd, olink, nlink);
+		    if (++serv->attr.ref)
+			serv->attr.flags |= SERV_ENABLED;
+		}
+	    }
+	}
+	popd();
+	closedir(rcdir);
+    }
+# else  /* not SUSE but Debian SystemV link scheme */
+   /*
+    * Remark: At SuSE we use boot scripts for system initialization which
+    * will be executed by /etc/init.d/boot (which is equal to rc.sysinit).
+    * At system reboot or system halt the stop links of those boot scripts
+    * will be executed by /etc/init.d/halt.  Don't know how todo this for
+    * a traditional standard SystemV link scheme.  Maybe for such an
+    * approach a new directory halt.d/ whould be an idea.
+    */
+    pushd(path);
+    for (runlevel = 0; runlevel < RUNLEVLES; runlevel++) {
+	char nlink[PATH_MAX+1], olink[PATH_MAX+1];
+	const char * rcd = (char*)0;
+	const char * script;
+	service_t * serv;
+	ushort lvl, seek;
+	DIR  * rcdir;
+
+	if ((rcd = map_runlevel_to_location(runlevel)) == (char*)0)
+	    continue;
+	lvl  = map_runlevel_to_lvl(runlevel);
+	seek = map_runlevel_to_seek(runlevel);
+
+	rcdir = openrcdir(rcd);		/* Creates runlevel directory if necessary */
+	if (rcdir == (DIR*)0)
+	    break;
+	if ((dfd = dirfd(rcdir)) < 0) {
+	    closedir(rcdir);
+	    break;
+	}
+	pushd(rcd);
+
+	/*
+	 * See if we found scripts which should not be
+	 * included within this runlevel directory.
+	 */
+	while ((d = readdir(rcdir)) != (struct dirent*)0) {
+	    const char * ptr = d->d_name;
+	    char type;
+
+	    if (*ptr != 'S' && *ptr != 'K')
+		continue;
+	    type = *ptr;
+	    ptr++;
+
+	    if (strspn(ptr, "0123456789") != 2)
+		continue;
+	    ptr += 2;
+
+	    if (xstat(dfd, d->d_name, &st_script) < 0)
+		xremove(dfd, d->d_name);	/* dangling sym link */
+
+	    if (notincluded(ptr, type, runlevel)) {
+		serv = findservice(getprovides(ptr));
+		if (defaults) {
+		    xremove(dfd, d->d_name);
+		    if (serv && --serv->attr.ref <= 0)
+			serv->attr.flags &= ~SERV_ENABLED;
+#  ifndef USE_KILL_IN_BOOT
+		} else if (lvl & LVL_BOOT) {
+		    xremove(dfd, d->d_name);
+		    if (serv && --serv->attr.ref <= 0)
+			serv->attr.flags &= ~SERV_ENABLED;
+#  endif /* USE_KILL_IN_BOOT */
+		} else if (del && ignore) {
+		    if (serv && (serv->attr.flags & SERV_ALREADY))
+			xremove(dfd, d->d_name);
+			if (--serv->attr.ref <= 0)
+			    serv->attr.flags &= ~SERV_ENABLED;
+		}
+	    }
+	}
+
+	script = (char*)0;
+	while ((serv = listscripts(&script, 'X', seek))) {
+	    const boolean this = chkfor(script, argv, argc);
+	    boolean found;
+	    char * clink;
+	    char mode;
+
+	    if (*script == '$')		/* Do not link in virtual dependencies */
+		continue;
+
+	    sprintf(olink, "../init.d/%s", script);
+	    if (serv->stopp->lvl & lvl) {
+#  ifndef USE_KILL_IN_BOOT
+		if (lvl & LVL_BOOT)			/* No kill links in rcS.d */
+			continue;
+#  endif /* USE_KILL_IN_BOOT */
+		sprintf(nlink, "K%.2d%s", serv->attr.korder, script);
+		mode = 'K';
+	    } else if (serv->start->lvl & lvl) {
+		sprintf(nlink, "S%.2d%s", serv->attr.sorder, script);
+		mode = 'S';
+	    } else
+		continue;		/* We aren't suppose to be on this runlevel */
+
+	    found = false;
+
+	    rewinddir(rcdir);
+	    while ((clink = scan_for(rcdir, script, mode))) {
+		found = true;
+		if (strcmp(clink, nlink)) {
+		    xremove(dfd, clink);		/* Wrong order, remove link */
+		    if (--serv->attr.ref <= 0)
+			serv->attr.flags &= ~SERV_ENABLED;
+		    if (!this) {
+			xsymlink(dfd, olink, nlink);	/* Not ours, but correct order */
+			if (++serv->attr.ref)
+			    serv->attr.flags |= SERV_ENABLED;
+		    }
+		    if (this && !del) {
+			xsymlink(dfd, olink, nlink);	/* Restore, with correct order */
+			if (++serv->attr.ref)
+			    serv->attr.flags |= SERV_ENABLED;
+		    }
+		} else {
+		    if (del && this) {
+			xremove(dfd, clink);		/* Found it, remove link */
+			if (--serv->attr.ref <= 0)
+			    serv->attr.flags &= ~SERV_ENABLED;
+		    }
+		}
+	    }
+
+	    if (this) {
+		/*
+		 * If we haven't found it and we shouldn't delete it
+		 * we try to add it.
+		 */
+		if (!del && !found) {
+		    xsymlink(dfd, olink, nlink);
+		    if (++serv->attr.ref)
+			serv->attr.flags |= SERV_ENABLED;
+		    found = true;
+		}
+	    }
+	}
+
+	popd();
+	closedir(rcdir);
+    }
+# endif /* !SUSE, standard SystemV link scheme */
+#endif  /* !DEBUG */
+
+    /*
+     * Do the makedep
+     */
+    makedep();
+
+    /*
+     * Back to the root(s)
+     */
+    popd();
+
+    /*
+     * Make valgrind happy
+     */
+    if (path != ipath) free(path);
+    if (root) free(root);
+
+    return 0;
+}

Added: trunk/src/insserv/insserv.conf
URL: http://svn.debian.org/wsvn/initscripts-ng/trunk/src/insserv/insserv.conf?rev=873&op=file
==============================================================================
--- trunk/src/insserv/insserv.conf (added)
+++ trunk/src/insserv/insserv.conf Sat Mar 14 15:47:02 2009
@@ -1,0 +1,41 @@
+#
+# All local filesystems are mounted (done during boot phase)
+#
+$local_fs	boot.localfs
+
+#
+# Low level networking (ethernet card)
+#
+$network	network +pcmcia +hotplug
+
+#
+# Named is operational
+#
+$named		+named +dnsmasq +lwresd $network
+
+#
+# All remote filesystems are mounted (note in some cases /usr may
+# be remote. Most applications that care will probably require
+# both $local_fs and $remote_fs)
+#
+$remote_fs	$local_fs +nfs
+
+#
+# System logger is operational
+#
+$syslog		syslog
+
+#
+# SunRPC portmapper available
+#
+$portmap	portmap
+
+#
+# The system time has been set correctly
+#
+$time		boot.clock +xntpd
+
+#
+# Services which need to be interactive
+#
+<interactive>   boot.crypto boot.localfs boot.rootfsck apache apache2 kdump

Added: trunk/src/insserv/install_initd
URL: http://svn.debian.org/wsvn/initscripts-ng/trunk/src/insserv/install_initd?rev=873&op=file
==============================================================================
--- trunk/src/insserv/install_initd (added)
+++ trunk/src/insserv/install_initd Sat Mar 14 15:47:02 2009
@@ -1,0 +1,2 @@
+#!/bin/sh
+exec /sbin/insserv ${1+"$@"}

Propchange: trunk/src/insserv/install_initd
------------------------------------------------------------------------------
    svn:executable = *

Added: trunk/src/insserv/listing.c
URL: http://svn.debian.org/wsvn/initscripts-ng/trunk/src/insserv/listing.c?rev=873&op=file
==============================================================================
--- trunk/src/insserv/listing.c (added)
+++ trunk/src/insserv/listing.c Sat Mar 14 15:47:02 2009
@@ -1,0 +1,1163 @@
+/*
+ * listing.c
+ *
+ * Copyright 2000-2008 Werner Fink, 2000 SuSE GmbH Nuernberg, Germany,
+ *				    2003 SuSE Linux AG, Germany.
+ *			       2007-2008 SuSE Linux Products GmbH Nuernberg, Germany
+ *
+ * This source is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <ctype.h>
+#include "listing.h"
+
+int maxstart = 0;  		/* Maximum start order of runlevels 0 upto 6 and S */
+int maxstop  = 0;  		/* Maximum stop  order of runlevels 0 upto 6 and S */
+static int *maxorder;		/* Pointer to one of above */
+
+/* See listing.c for list_t and list_entry() macro */
+#define getdir(list)		list_entry((list), dir_t,   d_list)
+#define getlink(list)		list_entry((list), link_t,  l_list)
+#define getnextlink(list)	(list_empty(list) ? (dir_t*)0 : getlink((list)->next)->target)
+
+/*
+ * We handle services (aka scripts) as directories because
+ * dependencies can be handels as symbolic links therein.
+ * A provided service will be linked into a required service.
+ * For the general type of linked lists see listing.h.
+ */
+
+typedef struct dir_struct dir_t;
+
+typedef struct link_struct {
+    list_t		  l_list;	/* The linked list of symbolic links */
+    dir_t	*restrict target;
+} __align link_t;			/* This is a "symbolic link" */
+
+typedef struct handle_struct {
+    list_t		    link;	/* The linked list of symbolic start/stop links in the directory */
+    level_t		     run;
+    ushort		   flags;
+    uchar		 mindeep;	/* Default start/stop deep if any */
+    uchar		    deep;	/* Current start/stop deep */
+    char		  * name;
+} __align handle_t;
+
+struct dir_struct {
+    list_t		  d_list;	/* The peg into linked list to other directories */
+    handle_t		   start;
+    handle_t		   stopp;
+    service_t	  *restrict serv;
+    int			     ref;
+    char		* script;
+    char		  * name;
+} __align;				/* This is a "directory" */
+
+#define attof(dir)	(&(dir)->serv->attr)
+
+/*
+ * The linked list off all directories, note that the s_list
+ * entry within the dir_struct is used as the peg pointer.
+ */
+static list_t dirs = { &dirs, &dirs };
+static list_t * d_start = &dirs;
+
+#define DIR_SCAN	0x0001
+#define DIR_LOOP	0x0002
+#define DIR_LOOPREPORT	0x0004
+#define DIR_MAXDEEP	0x0008
+
+/*
+ * The linked list off all services, note that the d_list
+ * entry within the service_struct is used as the peg pointer.
+ */
+static list_t servs = { &servs, &servs };
+list_t * s_start = &servs;
+
+/*
+ * Provide or find a service dir, set initial states and
+ * link it into the maintaining if a new one.
+ */
+
+static inline dir_t * providedir(const char *restrict const name) attribute((malloc,always_inline,nonnull(1)));
+static inline dir_t * providedir(const char *restrict const name)
+{
+    dir_t *restrict dir = (dir_t*)0;
+    service_t *restrict serv;
+    list_t * ptr;
+
+    list_for_each_prev(ptr, d_start) {
+	dir = getdir(ptr);
+	if (!strcmp(dir->name, name))
+	    goto out;
+    }
+
+    if (posix_memalign((void*)&serv, sizeof(void*), alignof(service_t)+strsize(name)) != 0)
+	error("%s", strerror(errno));
+
+    memset(serv, 0, alignof(service_t)+strsize(name));
+    insert(&serv->s_list, s_start->prev);
+    serv->name = ((char*)serv)+alignof(service_t);
+
+    if (posix_memalign((void*)&dir, sizeof(void*), alignof(dir_t)) != 0)
+	error("%s", strerror(errno));
+
+    memset(dir, 0, alignof(dir_t));
+    insert(&dir->d_list, d_start->prev);
+    dir->ref = 1;
+
+    serv->dir = (void*)dir;
+    dir->serv = serv;
+
+    initial(&dir->start.link);
+    initial(&dir->stopp.link);
+
+    initial(&serv->sort.req);
+    initial(&serv->sort.rev);
+
+    strcpy(serv->name, name);
+    dir->name	    = serv->name;
+    dir->start.name = serv->name;
+    dir->stopp.name = serv->name;
+
+    dir->start.mindeep = 1;
+    dir->stopp.mindeep = 1;
+
+    serv->start = &dir->start.run;
+    serv->stopp = &dir->stopp.run;
+out:
+    return dir;
+}
+
+/*
+ * Find or add and initialize a service
+ */
+service_t * addservice(const char *restrict const serv) attribute((malloc,nonnull(1)));
+service_t * addservice(const char *restrict const serv)
+{
+    service_t * this;
+    list_t * ptr;
+    dir_t * dir;
+
+    list_for_each_prev(ptr, s_start) {
+	this = getservice(ptr);
+	if (!strcmp(this->name, serv))
+	    goto out;
+    }
+    dir = providedir(serv);
+    this = dir->serv;
+out:
+    return this;
+}
+
+/*
+ * Always return the address of the original service
+ */
+service_t * getorig(service_t *restrict const serv)
+{
+    dir_t *const dir = (dir_t *)serv->dir;
+    return dir->serv;
+}
+
+/*
+ * Find a service dir by its script name.
+ */
+static inline dir_t * findscript(const char *restrict const script) attribute((always_inline,nonnull(1)));
+static inline dir_t * findscript(const char *restrict const script)
+{
+    dir_t  * ret = (dir_t*)0;
+    list_t * ptr;
+
+    list_for_each_prev(ptr, d_start) {
+	dir_t * dir = getdir(ptr);
+
+	if (!dir->script)
+	    continue;
+
+	if (!strcmp(dir->script, script)) {
+	    ret = dir;
+	    break;
+	}
+    }
+
+    return ret;
+}
+
+/*
+ * Link the current service into the required service.
+ * If the services do not exist, they will be created.
+ */
+static void ln_sf(dir_t *restrict cur, dir_t *restrict req, const char mode) attribute((nonnull(1,2)));
+static void ln_sf(dir_t *restrict cur, dir_t *restrict req, const char mode)
+{
+    list_t * dent, * l_list = (mode == 'K') ? &req->stopp.link : &req->start.link;
+    link_t *restrict this;
+
+    if (cur == req)
+	goto out;
+
+    list_for_each_prev(dent, l_list) {
+	dir_t * target = getlink(dent)->target;
+	if (!strcmp(target->name, cur->name))
+	    goto out;
+    }
+
+    if (posix_memalign((void*)&this, sizeof(void*), alignof(link_t)) == 0) {
+	insert(&this->l_list, l_list->prev);
+	this->target = cur;
+	++cur->ref;
+	goto out;
+    }
+    error("%s", strerror(errno));
+out:
+    return;
+}
+
+/*
+ * Remember loops to warn only once
+ */
+static inline boolean remembernode (handle_t *restrict const peg) attribute((always_inline,nonnull(1)));
+static inline boolean remembernode (handle_t *restrict const peg)
+{
+    register boolean ret = true;
+
+    if (peg->flags & DIR_LOOP)
+	goto out;
+
+    ret = false;
+    peg->flags |= DIR_LOOP;
+out:
+    return ret;
+}
+
+/*
+ * Recursively called function to follow all
+ * links within a service dir.
+ * Just like a `find * -follow' within a directory tree
+ * of depth one with cross linked dependencies.
+ *
+ * Be warned: the direction is naturally reversed.  That
+ * means that the most requested services have the lowest
+ * order.  In other word, an empty link list of a service
+ * indicates that this service has a higher order number.
+ */
+#if defined(DEBUG) && (DEBUG > 0)
+# define loop_warn_two(a,b,o)	\
+	warn("There is a loop between service %s and %s if %s (list:%d)\n", \
+	(a)->name, (b)->name, o, __LINE__)
+# define loop_warn_one(a,o)	\
+	warn("There is a loop at service %s if %s (list:%d)\n", \
+	(a)->name, o, __LINE__)
+#else
+# define loop_warn_two(a,b,o)	\
+	warn("There is a loop between service %s and %s if %s\n", (a)->name, (b)->name, o)
+# define loop_warn_one(a,o)	\
+	warn("There is a loop at service %s if %s\n", (a)->name, o)
+#endif
+#define loop_check(a)	\
+	((a) && (a)->flags & DIR_LOOP)
+
+static void __follow (dir_t *restrict dir, dir_t *restrict skip, const int, const char, const char)
+#if  __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+	attribute((noinline,flatten,nonnull(1)));
+#else
+	attribute((noinline,nonnull(1)));
+#endif
+static void __follow (dir_t *restrict dir, dir_t *restrict skip, const int level, const char mode, const char reportloop)
+{
+    list_t * l_list;
+    dir_t * tmp;
+    register int deep = level;	/* Link depth, maybe we're called recursively */
+    register int loop = 0;	/* Count number of links in symbolic list */
+    handle_t * peg, * pskp = (handle_t*)0;
+    const char * act;
+
+    if (mode == 'K') {
+	peg = &dir->stopp;
+	if (skip) pskp = &skip->stopp;
+	act  = "stopped";
+    } else {
+	peg = &dir->start;
+	if (skip) pskp = &skip->start;
+	act  = "started";
+    }
+    l_list = &peg->link;
+    prefetch(l_list->next);
+
+    if (peg->flags & DIR_SCAN) {
+	if (pskp) {
+	    if (!remembernode(pskp) || !remembernode(peg))
+		loop_warn_two(peg, pskp, act);
+	} else {
+	    /* Does this happen? */
+	    if (!remembernode(pskp))
+		loop_warn_one(peg, act);
+	}
+	goto out;
+    }
+
+    if (deep < (peg->mindeep))	/* Default deep of this tree is higher */
+	deep = (peg->mindeep);
+
+    if (deep > MAX_DEEP) {
+	if ((peg->flags & DIR_MAXDEEP) == 0)
+	    warn("Max recursions depth %d for %s reached\n",  MAX_DEEP, peg->name);
+	peg->flags |= DIR_MAXDEEP;
+	goto out;
+    }
+
+    for (tmp = dir; tmp; tmp = getnextlink(l_list)) {
+	register boolean recursion = true;
+	handle_t * ptmp = (mode == 'K') ? &tmp->stopp : &tmp->start;
+	uchar  * order = &ptmp->deep;
+	list_t * dent;
+
+	if (loop++ > MAX_DEEP) {
+	    if (pskp) {
+		if (!remembernode(pskp) || !remembernode(ptmp))
+		    loop_warn_two(ptmp, pskp, act);
+	    } else {
+		if (!remembernode(ptmp))
+		    loop_warn_one(ptmp, act);
+	    }
+	    break;			/* Loop detected, stop recursion */
+	}
+	l_list = &ptmp->link;		/* List of symbolic links for getnextlink() */
+	prefetch(l_list->next);
+
+	if (!((peg->run.lvl) & (ptmp->run.lvl)))
+	     continue;			/* Not same boot level */
+
+	if (pskp && pskp == ptmp) {
+	    if (!remembernode(pskp) || !remembernode(ptmp))
+		loop_warn_one(pskp, act);
+	    break;			/* Loop detected, stop recursion */
+	}
+
+	/*
+	 * As higher the link depth, as higher the start order.
+	 */
+	if (*order > deep)
+	    deep = *order;
+	if (*order < deep)
+	    *order = deep;
+
+	if ((ptmp->run.lvl) & LVL_ALL) {
+	    if (maxorder && (*maxorder < *order))
+		*maxorder = *order;
+	}
+
+	if (list_empty(l_list))
+	    break;			/* No further service requires this one */
+
+	/*
+	 * Do not count the dependcy deep of the system facilities
+	 * but follow them to count the replacing provides.
+	 */
+	if (*ptmp->name == '$')
+	    warn("System facilities not fully expanded, see %s!\n", dir->name);
+	else if (++deep > MAX_DEEP) {
+	    if ((ptmp->flags & DIR_MAXDEEP) == 0)
+		warn("Max recursions depth %d reached\n",  MAX_DEEP);
+	    ptmp->flags |= DIR_MAXDEEP;
+	    break;
+	}
+
+	ptmp->flags |= DIR_SCAN; 	/* Mark this service for loop detection */
+
+	/*
+	 * If there are links in the links included, follow them
+	 */
+	np_list_for_each(dent, l_list) {
+	    dir_t * target = getlink(dent)->target;
+	    handle_t * ptrg = (mode == 'K') ? &target->stopp : &target->start;
+
+	    if ((peg->run.lvl & ptrg->run.lvl) == 0)
+		continue;			/* Not same boot level */
+
+	    if (target == tmp)
+		break;				/* Loop avoided */
+	
+	    if (target == dir)
+		break;				/* Loop avoided */
+	
+	    if (skip && skip == target) {
+		if (!remembernode(pskp) || !remembernode(ptmp))
+		    loop_warn_two(pskp, ptmp, act);
+		recursion = false;
+		break;				/* Loop detected, stop recursion */
+	    }
+
+	    if (ptrg->deep >= deep)		/* Nothing new */
+		continue;
+						/* The inner recursion */
+	    __follow(target, tmp, deep, mode, reportloop);
+	    prefetch(dent->next);
+
+	    /* Just for the case an inner recursion was stopped */
+	    if (loop_check(ptrg) || loop_check(ptmp) || loop_check(pskp)) {
+		recursion = false;
+		break;				/* Loop detected, stop recursion */
+	    }
+	}
+
+	ptmp->flags &= ~DIR_SCAN; 	/* Remove loop detection mark */
+	prefetch(l_list->next);
+
+	if (!recursion) {
+	    if (reportloop && !(ptmp->flags & DIR_LOOPREPORT)) {
+		warn(" loop involving service %s at depth %d\n", tmp->name, level);
+		ptmp->flags |= DIR_LOOPREPORT;
+	    }
+	    break;			/* Loop detected, stop recursion */
+	}
+    }
+out:
+    return;			/* Make compiler happy */
+}
+
+#undef loop_warn_two
+#undef loop_warn_one
+#undef loop_check
+
+/*
+ * Helper for follow_all: start with depth one.
+ */
+static inline void follow(dir_t *restrict dir, const char mode, const char reportloop) attribute((always_inline,nonnull(1)));
+static inline void follow(dir_t *restrict dir, const char mode, const char reportloop)
+{
+    const int deep = (mode == 'K') ? (dir->stopp.mindeep) : (dir->start.mindeep);
+    /* Link depth starts here with one */
+    __follow(dir, (dir_t*)0, deep, mode, reportloop);
+}
+
+/*
+ * Put not existing services into a guessed order.
+ * The maximal order of not existing services can be
+ * set if they are required by existing services.
+ */
+static void guess_order(dir_t *restrict dir, const char mode) attribute((nonnull(1)));
+static void guess_order(dir_t *restrict dir, const char mode)
+{
+    handle_t * peg  = (mode == 'K') ? &dir->stopp : &dir->start;
+    list_t * l_list = &peg->link;
+    register int min = 99;
+    register int deep = 0;
+    ushort lvl = 0;
+
+    if (dir->script)	/* Skip it because we have read it */
+	goto out;
+
+    if (*dir->name == '$') {	/* Don't touch our system facilities */
+	warn("System facilities not fully expanded, see %s!\n", dir->name);
+	goto out;
+    }
+
+    /* No full loop required because we seek for the lowest order */
+    if (!list_empty(l_list)) {
+	dir_t * target = getnextlink(l_list);
+	handle_t * ptrg = (mode == 'K') ? &target->stopp : &target->start;
+	uchar * order = &ptrg->deep;
+	list_t * dent;
+
+	if (min > *order)
+	    min = *order;
+
+	lvl |= ptrg->run.lvl;
+
+	list_for_each_prev(dent, l_list) {
+	    dir_t * tmp = getlink(dent)->target;
+	    handle_t * ptmp = (mode == 'K') ? &tmp->stopp : &tmp->start;
+	    uchar * order = &ptmp->deep;
+
+	    if (++deep > MAX_DEEP)
+		break;
+
+	    if (target == dir)
+		break;		/* Loop detected */
+
+	    if (min > *order)
+		min = *order;
+
+	    lvl |= ptmp->run.lvl;
+	}
+	if (min > 1) {		/* Set guessed order of this unknown script */
+	    uchar * order = &peg->deep;
+	    *order = min - 1;
+	    peg->run.lvl |= lvl;	/* Set guessed runlevels of this unknown script */
+	} else {
+	    peg->run.lvl  = LVL_BOOT;
+	}
+    }
+out:
+    return;
+}
+
+/*
+ * Sort linked list of provides into start or stop order
+ * during this set new start or stop order of the serives.
+ */
+#undef SORT_REQUESTS
+void lsort(const char type)
+{
+    list_t sort = { &sort, &sort };
+#ifdef SORT_REQUESTS
+    list_t * this;
+#endif /* SORT_REQUESTS */
+    int order;
+
+    switch (type) {
+    case 'K':
+	for (order = 0; order <= maxstop; order++) {
+	    list_t * ptr, * safe;
+	    list_for_each_safe(ptr, safe, d_start) {
+		dir_t * dir = getdir(ptr);
+		if (dir->stopp.deep == order)
+		    move_tail(ptr, &sort);
+	    }
+	}
+	join(&sort, d_start);
+#ifdef SORT_REQUESTS
+	list_for_each(this, s_start) {
+	    service_t * serv = getservice(this);
+	    if (serv->attr.flags & SERV_DUPLET)
+		continue;
+	    initial(&sort);
+	    for (order = 0; order <= maxstop; order++) {
+		list_t * ptr, * safe;
+		list_for_each_safe(ptr, safe, &serv->sort.rev) {
+		    req_t * rev = getreq(ptr);
+		    dir_t * dir = (dir_t*)rev->serv->dir;
+		    if (dir->stopp.deep == order)
+			move_tail(ptr, &sort);
+		}
+	    }
+	    join(&sort, &serv->sort.rev);
+	}
+#endif /* SORT_REQUESTS */
+	break;
+    default:
+	for (order = 0; order <= maxstart; order++) {
+	    list_t * ptr, * safe;
+	    list_for_each_safe(ptr, safe, d_start) {
+		dir_t * dir = getdir(ptr);
+		if (dir->start.deep == order)
+		    move_tail(ptr, &sort);
+	    }
+	}
+	join(&sort, d_start);
+#ifdef SORT_REQUESTS
+	list_for_each(this, s_start) {
+	    service_t * serv = getservice(this);
+	    if (serv->attr.flags & SERV_DUPLET)
+		continue;
+	    initial(&sort);
+	    for (order = 0; order <= maxstart; order++) {
+		list_t * ptr, * safe;
+		list_for_each_safe(ptr, safe, &serv->sort.req) {
+		    req_t * req = getreq(ptr);
+		    dir_t * dir = (dir_t*)req->serv->dir;
+		    if (dir->start.deep == order)
+			move_tail(ptr, &sort);
+		}
+	    }
+	    join(&sort, &serv->sort.req);
+	}
+#endif /* SORT_REQUESTS */
+	break;
+    }
+
+
+}
+
+/*
+ * Clear out aliases of existing services, that is that for *one* script there
+ * exist several provides which could have have been required different by
+ * other services.  This avoids doing the same work several times.
+ */ 
+void nickservice(service_t *restrict orig, service_t *restrict nick)
+{
+    dir_t * dir = (dir_t*)orig->dir;
+    dir_t * cmp = (dir_t*)nick->dir;
+    list_t * dent, * safe;
+
+    if (dir == cmp)
+	return;
+
+    if (cmp->script && cmp->script != dir->script)
+	return;
+
+    list_for_each_safe(dent, safe, &cmp->start.link) {
+	link_t * link  = getlink(dent);
+	dir_t * target = link->target;
+
+	if (target == cmp)
+	    continue;
+
+	ln_sf(target, dir, 'S');
+
+	/* remove the link from local link list but never free the target */
+
+	delete(dent);
+	free(link);
+    }
+
+    list_for_each_safe(dent, safe, &cmp->stopp.link) {
+	link_t * link  = getlink(dent);
+	dir_t * target = link->target;
+
+	if (target == cmp)
+	    continue;
+
+	ln_sf(target, dir, 'K');
+
+	/* remove the link from local link list but never free the target */
+
+	delete(dent);
+	free(link);
+    }
+
+    delete(&cmp->d_list);	/* remove alias entry from global service list */
+
+	    			/* remember levels of old start handle */
+    dir->start.run.lvl |= cmp->start.run.lvl;
+    dir->start.flags   |= cmp->start.flags;
+
+				/* remember levels of old stop handle */
+    dir->stopp.run.lvl |= cmp->stopp.run.lvl;
+    dir->stopp.flags   |= cmp->stopp.flags;
+
+				/* remember global flags of old provide */
+    orig->attr.flags |= nick->attr.flags;
+    nick->attr.flags |= SERV_DUPLET;
+
+    if (cmp->script && cmp->script != dir->script) {
+	free(nick->attr.script);
+	nick->attr.script = orig->attr.script;
+    }
+
+    nick->dir   = (void*)dir;	/* remember main provide */
+    nick->start = &dir->start.run;
+    nick->stopp = &dir->stopp.run;
+
+    if (--cmp->ref <= 0) free(cmp);
+
+    list_for_each_safe(dent, safe, &nick->sort.req) {
+	req_t * this = getreq(dent);
+	boolean ok = true;
+	list_t * req;
+	list_for_each(req, &orig->sort.req) {
+	    if (!strcmp(this->serv->name,getreq(req)->serv->name)) {
+		ok = false;
+		break;
+	    }
+	}
+	if (!ok) {
+	    delete(dent);
+	    free(this);
+	} else
+	    move_tail(dent, &orig->sort.req);
+    }
+
+    list_for_each_safe(dent, safe, &nick->sort.rev) {
+	req_t * this = getreq(dent);
+	boolean ok = true;
+	list_t * rev;
+	list_for_each(rev, &orig->sort.rev) {
+	    if (!strcmp(this->serv->name,getreq(rev)->serv->name)) {
+		ok = false;
+		break;
+	    }
+	}
+	if (!ok) {
+	    delete(dent);
+	    free(this);
+	} else
+	    move_tail(dent, &orig->sort.rev);
+    }
+}
+
+void clear_all(void)
+{
+    list_t * this;
+
+    /*
+     * Find dangling links in global service list and remove them
+     * if we by detect the remove bit from set above in the flags.
+     */
+
+    list_for_each(this, d_start) {
+	dir_t *dir = getdir(this);
+	list_t *dent, *hold;
+
+	list_for_each_safe(dent, hold, &dir->start.link) {
+	    link_t * link  = getlink(dent);
+	    dir_t * target = link->target;
+
+	    if (target == dir)
+		continue;
+
+	    if ((attof(target)->flags & SERV_DUPLET) == 0)
+		continue;
+
+	    /* remove the link from local link list */
+
+	    delete(dent);
+	    free(link);
+
+ 	    /* 
+	     * Do not free allocated strings and structure if in use
+	     * never free cmp->attr.script as this remains always in use.
+	     */
+
+	    if (--target->ref <= 0) free(target);
+	}
+
+	list_for_each_safe(dent, hold, &dir->stopp.link) {
+	    link_t * link  = getlink(dent);
+	    dir_t * target = link->target;
+
+	    if (target == dir)
+		continue;
+
+	    if ((attof(target)->flags & SERV_DUPLET) == 0)
+		continue;
+
+	    /* remove the link from local link list */
+
+	    delete(dent);
+	    free(link);
+
+ 	    /* 
+	     * Do not free allocated strings and structure if in use
+	     * never free cmp->attr.script as this remains always in use.
+	     */
+
+	    if (--target->ref <= 0) free(target);
+	}
+    }
+#if defined(DEBUG) && (DEBUG > 0)
+    list_for_each(this, s_start) {
+	service_t * srv = getservice(this);
+	list_t * nxt, * hold;
+
+	if (srv->attr.flags & SERV_DUPLET)
+	    continue;
+
+	list_for_each_safe(nxt, hold, s_start) {
+	    list_t * dent, * safe;
+	    service_t * orv;
+
+	    orv = getservice(nxt);
+
+	    if ((orv->attr.flags & SERV_DUPLET) == 0)
+		continue;
+
+	    if (srv->dir != orv->dir)
+		continue;
+
+	    srv->attr.flags |= orv->attr.flags;
+	    srv->attr.flags &= ~SERV_DUPLET;
+
+	    list_for_each_safe(dent, safe, &orv->sort.req) {
+		req_t * this = getreq(dent);
+		boolean ok = true;
+		list_t * req;
+		list_for_each(req, &srv->sort.req) {
+		    if (!strcmp(this->serv->name,getreq(req)->serv->name)) {
+			ok = false;
+			break;
+		    }
+		}
+		if (!ok) {
+		   fprintf(stderr, "BUG: removed %s from start list of %s, missed getorig()?\n",
+			   this->serv->name, orv->name);
+		   delete(dent);
+		   free(this);
+		} else {
+		   fprintf(stderr, "BUG: moved %s from start list of %s to %s, missed getorig()?\n",
+			   this->serv->name, orv->name, srv->name);
+		   move_tail(dent, &srv->sort.req);
+		}
+	    }
+
+	    list_for_each_safe(dent, safe, &orv->sort.rev) {
+		req_t * this = getreq(dent);
+		boolean ok = true;
+		list_t * rev;
+		list_for_each(rev, &srv->sort.rev) {
+		   if (!strcmp(this->serv->name,getreq(rev)->serv->name)) {
+			ok = false;
+			break;
+		   }
+		}
+		if (!ok) {
+		   fprintf(stderr, "BUG: removed %s from start list of %s, missed getorig()?\n",
+			   this->serv->name, orv->name);
+		   delete(dent);
+		   free(this);
+		} else {
+		   fprintf(stderr, "BUG: moved %s from start list of %s to %s, missed getorig()?\n",
+			   this->serv->name, orv->name, srv->name);
+		   move_tail(dent, &srv->sort.rev);
+		}
+	    }
+	}
+    }
+#endif
+}
+
+/*
+ * Follow all services and their dependencies recursivly.
+ */
+void follow_all(void)
+{
+    list_t *tmp;
+
+    /*
+     * Follow all scripts and calculate the main ordering.
+     */
+    list_for_each(tmp, d_start) {
+	maxorder = &maxstart;
+	follow(getdir(tmp), 'S', 1);
+	maxorder = &maxstop;
+	follow(getdir(tmp), 'K', 1);
+    }
+
+    /*
+     * Guess order of not installed scripts in comparision
+     * to the well known scripts.
+     */
+    list_for_each(tmp, d_start) {
+	maxorder = &maxstart;
+	guess_order(getdir(tmp), 'S');
+	maxorder = &maxstart;
+	guess_order(getdir(tmp), 'K');
+    }
+}
+
+boolean is_loop_detected(void)
+{
+    list_t *tmp;
+    list_for_each(tmp, d_start) {
+	dir_t * dir = getdir(tmp);
+	if (dir->start.flags & DIR_LOOPREPORT)
+	    return true;
+	if (dir->stopp.flags  & DIR_LOOPREPORT)
+	    return true;
+    }
+    return false;
+}
+
+/*
+ * For debuging: show all services
+ */
+#if defined(DEBUG) && (DEBUG > 0)
+void show_all()
+{
+    list_t *tmp;
+    if (maxstop > 0) list_for_each(tmp, d_start) {
+	char * script, *name, *lvlstr;
+	dir_t * dir = getdir(tmp);
+	handle_t * peg;
+	uchar deep;
+	ushort lvl;
+	if (!dir)
+	    continue;
+	name = dir->name;
+	peg  = &dir->stopp;
+	lvl  = peg->run.lvl;
+	deep = peg->deep;
+	if (attof(dir)->script)
+	    script = attof(dir)->script;
+	else if (*name == '$')
+	    script = "%system";
+	else
+	    script = "%guessed";
+	lvlstr = lvl2str(lvl);
+	info("K%.2d %s 0x%.2x '%s' (%s)\n", deep, name, lvl, lvlstr, script);
+	xreset(lvlstr);
+    }
+    if (maxstart > 0) list_for_each(tmp, d_start) {
+	char * script, *name, *lvlstr;
+	dir_t * dir = getdir(tmp);
+	handle_t * peg;
+	uchar deep;
+	ushort lvl;
+	if (!dir)
+	    continue;
+	name = dir->name;
+	peg  = &dir->start;
+	lvl  = peg->run.lvl;
+	deep = peg->deep;
+	if (attof(dir)->script)
+	    script = attof(dir)->script;
+	else if (*name == '$')
+	    script = "%system";
+	else
+	    script = "%guessed";
+	lvlstr = lvl2str(lvl);
+	info("S%.2d %s 0x%.2x '%s' (%s)\n", deep, name, lvl, lvlstr, script);
+	xreset(lvlstr);
+    }
+}
+#endif
+
+/*
+ * Used within loops to get scripts not included in this runlevel
+ */
+boolean notincluded(const char *restrict const script, const char mode, const int runlevel)
+{
+    list_t *tmp;
+    boolean ret = false;
+    const ushort lvl = map_runlevel_to_lvl (runlevel);
+
+    list_for_each_prev(tmp, d_start) {
+	dir_t * dir = getdir(tmp);
+	level_t * run = (mode == 'K') ? &dir->stopp.run : &dir->start.run;
+
+	if (run->lvl & lvl)		/* Same runlevel */
+	    continue;
+
+	if (dir->script == (char*)0)	/* No such file */
+	    continue;
+
+	if (strcmp(script, dir->script))
+	    continue;			/* Not this file */
+
+	ret = true;			/* Not included */
+	break;
+    }
+
+    return ret;
+}
+
+/*
+ * Used within loops to list services an for a given runlevel bit mask.
+ */
+service_t * listscripts(const char **restrict script, const char mode, const ushort lvl)
+{
+    static list_t * tmp;
+    service_t * serv;
+    ushort level;
+    dir_t * dir;
+
+    if (!*script)
+	tmp  = d_start->next;
+
+    do {
+	serv = (service_t*)0;
+	if (tmp == d_start)
+	    break;
+	prefetch(tmp->next);
+	dir = getdir(tmp);
+
+        attof(dir)->korder = dir->stopp.deep;
+        attof(dir)->sorder = dir->start.deep;
+
+	serv = dir->serv;
+	*script = serv->attr.script;
+
+	switch (mode) {
+	case 'X':
+	    level = (dir->stopp.run.lvl|dir->start.run.lvl);
+	    break;
+	case 'K':
+	    level = dir->stopp.run.lvl;
+	    break;
+	default:
+	    level = dir->start.run.lvl;
+	    break;
+	}
+
+	tmp = tmp->next;
+
+    } while ((*script == (char*)0) || (level & lvl) == 0);
+
+    return serv;
+}
+
+/*
+ * THIS services DEPENDS on that service befor startup or shutdown.
+ */
+void requires(service_t *restrict this, service_t *restrict dep, const char mode)
+{
+    ln_sf((dir_t*)this->dir, (dir_t*)dep->dir, mode);
+}
+
+/*
+ * Set the runlevels of a service.
+ */
+void runlevels(service_t *restrict serv, const char mode, const char *restrict lvl)
+{
+    dir_t * dir   = (dir_t *)serv->dir;
+    handle_t * peg = (mode == 'K') ? &dir->stopp : &dir->start;
+    peg->run.lvl |= str2lvl(lvl);
+}
+
+/*
+ * Reorder all services starting with a service
+ * being in same runlevels.
+ */
+void setorder(const char *restrict script, const char mode, const int order, const boolean recursive)
+{
+    dir_t * dir = findscript(script);
+    handle_t * peg;
+    list_t * tmp;
+
+    if (!dir)
+	goto out;
+
+    if (mode == 'K') {
+	peg = &dir->stopp;
+	maxorder = &maxstop;
+    } else {
+	peg = &dir->start;
+	maxorder = &maxstart;
+    }
+
+    if (peg->mindeep < order)
+	peg->mindeep = order;		/* Remember lowest default order deep */
+
+    if (peg->deep >= peg->mindeep)	/* Nothing to do */
+	goto out;
+
+    if (!recursive) {
+	peg->deep = peg->mindeep;
+	goto out;
+    }
+
+    /*
+     * Follow the script and re-calculate the ordering.
+     */
+    __follow(dir, (dir_t*)0, peg->mindeep, mode, 0);
+
+    /*
+     * Guess order of not installed scripts in comparision
+     * to the well known scripts.
+     */
+    list_for_each(tmp, d_start)
+	guess_order(getdir(tmp), mode);
+out:
+    return;
+}
+
+/*
+ * Get the order of a script.
+ */
+int getorder(const char *restrict script, const char mode)
+{
+    dir_t * dir = findscript(script);
+    int order = 0;
+
+    if (dir) {
+	handle_t * peg = (mode == 'K') ? &dir->stopp : &dir->start;
+	order = peg->deep;
+    }
+
+    return order;
+}
+
+/*
+ * Provide a service if the corresponding script
+ * was read and the scripts name was remembered.
+ * A given script name marks a service as a readed one.
+ * One script and several provided facilities leads
+ * to the same order for those facilities.
+ */
+boolean makeprov(service_t *restrict serv, const char *restrict script)
+{
+    dir_t *restrict alias = findscript(script);
+    dir_t *restrict dir   = (dir_t *restrict)serv->dir;
+    boolean ret = true;
+
+    if (!dir->script) {
+	list_t * ptr;
+	if (!alias) {
+	    serv->attr.script = xstrdup(script);
+	    serv->attr.flags |= SERV_SCRIPT;
+	    dir->script = serv->attr.script;
+	} else
+	    dir->script = alias->script;
+
+	list_for_each(ptr, s_start) {
+	    service_t * tmp = getservice(ptr);
+	    if (tmp == serv)
+		continue;
+	    if (tmp->dir != serv->dir)
+		continue;
+	    if (tmp->attr.script)
+		continue;
+	    tmp->attr.script = dir->script;
+	    tmp->attr.flags |= SERV_SCRIPT;
+	}
+
+    } else if (strcmp(dir->script, script))
+	ret = false;
+
+    return ret;
+}
+
+/*
+ * Find the script name of a provided feature
+ */
+const char * getscript(const char *restrict prov)
+{
+    char * script = (char*)0;
+    list_t * ptr;
+
+    list_for_each(ptr, s_start) {
+	service_t * this = getservice(ptr);
+	if (!strcmp(this->name, prov)) {
+	    if (this->attr.script)
+		script = this->attr.script;
+	    break;
+	}
+    }
+    return script;
+}
+
+/*
+ * Return the provided service of a given script
+ */
+const char * getprovides(const char *restrict script)
+{
+    const dir_t * dir = findscript(script);
+    const char * prov = (const char*)0;
+
+    if (dir)
+	prov = dir->name;
+    return prov;
+}
+
+/*
+ * Find a specific service by its name
+ */
+service_t * findservice(const char *restrict const name)
+{
+    list_t * ptr;
+    service_t * ret = (service_t*)0;
+
+    if (name == (const char*)0)
+	goto out;
+
+    list_for_each(ptr, s_start) {
+	service_t * this = getservice(ptr);
+	if (!strcmp(this->name, name)) {
+	    ret = this;
+	    break;
+	}
+    }
+out:
+    return ret;
+}

Added: trunk/src/insserv/listing.h
URL: http://svn.debian.org/wsvn/initscripts-ng/trunk/src/insserv/listing.h?rev=873&op=file
==============================================================================
--- trunk/src/insserv/listing.h (added)
+++ trunk/src/insserv/listing.h Sat Mar 14 15:47:02 2009
@@ -1,0 +1,407 @@
+/*
+ * listing.h
+ *
+ * Copyright 2000,2008 Werner Fink, 2000 SuSE GmbH Nuernberg, Germany.
+ *				    2008 SuSE Linux Products GmbH Nuernberg, Germany
+ *
+ * This source is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <stddef.h>
+#include <sys/types.h>
+#include "config.h"
+
+typedef enum _boolean {false, true} boolean;
+typedef unsigned char uchar;
+#ifndef __USE_MISC
+typedef unsigned short ushort;
+typedef unsigned int uint;
+#endif
+
+#ifndef __OPTIMIZE__
+# warning This will not compile without -O at least
+#endif
+#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
+# ifndef  inline
+#  define inline		__inline__
+# endif
+# ifndef  restrict
+#  define restrict		__restrict__
+# endif
+# ifndef  volatile
+#  define volatile		__volatile__
+# endif
+# ifndef  asm
+#  define asm			__asm__
+# endif
+# ifndef  extension
+#  define extension		__extension__
+# endif
+#endif
+#ifndef  attribute
+# define attribute(attr)	__attribute__(attr)
+#endif
+
+/*
+ * This is lent from the kernel by e.g. using
+ *
+ *   echo '#include <asm-i386/processor.h>\nint main () { prefetch(); return 0; }' | \
+ *	gcc -I/usr/src/linux/include -D__KERNEL__ -x c -E -P - | \
+ *	sed -rn '/void[[:blank:]]+prefetch[[:blank:]]*\(/,/^}/p'
+ *
+ * on the appropiate architecture (here on i686 for i586).
+ */
+static inline void prefetch(const void *restrict x) attribute((used,always_inline));
+static inline void prefetch(const void *restrict x)
+{
+#if   defined(__x86_64__)
+    asm volatile ("prefetcht0 %0"  :: "m" (*(unsigned long *)x))
+#elif defined(__ia64__)
+    asm volatile ("lfetch [%0]"    :: "r" (x))
+#elif defined(__powerpc64__)
+    asm volatile ("dcbt 0,%0"      :: "r" (x))
+#elif 1 && defined(__i386__)
+    asm volatile ("661:\n\t"
+		  ".byte 0x8d,0x74,0x26,0x00\n"
+		  "\n662:\n"
+		  ".section .altinstructions,\"a\"\n"
+		  "  .align 4\n"
+		  "  .long 661b\n"
+		  "  .long 663f\n"
+		  "  .byte %c0\n"
+		  "  .byte 662b-661b\n"
+		  "  .byte 664f-663f\n"
+		  ".previous\n"
+		  ".section .altinstr_replacement,\"ax\"\n"
+		  "   663:\n\t"
+		  "   prefetchnta (%1)"
+		  "   \n664:\n"
+		  ".previous"
+		  :: "i" ((0*32+25)), "r" (x))
+#endif
+    ;
+}
+
+#if defined(DEBUG) && (DEBUG > 0)
+# define __align attribute((packed))
+#else
+# define __align attribute((aligned(sizeof(struct list_struct*))))
+#endif
+#define __packed attribute((packed))
+
+#define alignof(type)		(sizeof(type)+(sizeof(type)%sizeof(void*)))
+#define strsize(string)		((strlen(string)+1)*sizeof(char))
+
+typedef struct list_struct {
+    struct list_struct * next, * prev;
+} __align list_t;
+
+/*
+ * Linked list handling
+ * ====================
+ * The structures which will be linked into such lists have to be of the
+ * same type.  The structures may have alway a list identifier of the type
+ * `list_t' as very first element.  With this the macro list_entry() can
+ * be used to cast the memory address of a list member to the corresponding
+ * allocated structure.
+ */
+
+/*
+ * Insert new entry as next member.
+ */
+static inline void insert(list_t *restrict new, list_t *restrict here) attribute((always_inline,nonnull(1,2)));
+static inline void insert(list_t *restrict new, list_t *restrict here)
+{
+    list_t * prev = here;
+    list_t * next = here->next;
+
+    next->prev = new;
+    new->next = next;
+    new->prev = prev;
+    prev->next = new;
+}
+
+/*
+ * Set head
+ */
+static inline void initial(list_t *restrict head) attribute((always_inline,nonnull(1)));
+static inline void initial(list_t *restrict head)
+{
+    head->prev = head->next = head;
+}
+
+/*
+ * Remove entries, note that the pointer its self remains.
+ */
+static inline void delete(list_t *restrict entry) attribute((always_inline,nonnull(1)));
+static inline void delete(list_t *restrict entry)
+{
+    list_t * prev = entry->prev;
+    list_t * next = entry->next;
+
+    next->prev = prev;
+    prev->next = next;
+
+    initial(entry);
+}
+
+static inline void join(list_t *restrict list, list_t *restrict head) attribute((always_inline,nonnull(1,2)));
+static inline void join(list_t *restrict list, list_t *restrict head)
+{
+    list_t * first = list->next;
+
+    if (first != list) {
+	list_t * last = list->prev;
+       	list_t * at = head->next;
+
+       	first->prev = head;
+       	head->next = first;
+
+       	last->next = at;
+       	at->prev = last;
+    }
+}
+
+static inline boolean list_empty(list_t *restrict head) attribute((always_inline,nonnull(1)));
+static inline boolean list_empty(list_t *restrict head)
+{
+     return head->next == head;
+}
+
+static inline void move_tail(list_t *restrict entry, list_t *restrict head) attribute((always_inline,nonnull(1,2)));
+static inline void move_tail(list_t *restrict entry, list_t *restrict head)
+{
+    list_t * prev = entry->prev;
+    list_t * next = entry->next;
+
+    next->prev = prev;		/* remove enty from old list */
+    prev->next = next;
+
+    prev = head->prev;
+    next = head;
+
+    next->prev = entry;		/* and add it at tail of new list */
+    entry->next = next;
+    entry->prev = prev;
+    prev->next = entry;
+}
+
+
+#define list_entry(ptr, type, member)	(__extension__ ({	\
+	const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
+	((type *)( (char *)(__mptr) - offsetof(type,member) )); }))
+#define list_for_each(pos, head)	\
+	for (pos = (head)->next; prefetch(pos->next), pos != (head); pos = pos->next)
+#define np_list_for_each(pos, head)	\
+	for (pos = (head)->next; pos != (head); pos = pos->next)
+#define list_for_each_safe(pos, safe, head)	\
+	for (pos = (head)->next, safe = pos->next; pos != (head); pos = safe, safe = pos->next)
+#define list_for_each_prev(pos, head)	\
+	for (pos = (head)->prev; prefetch(pos->prev), pos != (head); pos = pos->prev)
+#define np_list_for_each_prev(pos, head)	\
+	for (pos = (head)->prev; pos != (head); pos = pos->prev)
+
+/*
+ * The runlevel bits within own struct
+ */
+typedef struct level_struct {
+    ushort		    lvl;
+} __packed level_t;
+
+/*
+ * Common attributes
+ */
+typedef struct attr_struct {
+    ushort		  flags;
+    short		    ref;
+    uchar		 sorder;
+    uchar		 korder;
+    char		*script;
+} __packed attr_t;
+
+/*
+ * Linked list of required services (start/stop)
+ */
+typedef struct sort_struct {
+    list_t	       req, rev;
+} __align sort_t;
+
+/*
+ * Objects of linked list of required services
+ */
+typedef struct service_struct service_t;
+typedef struct req_serv {
+    list_t		   list;
+    ushort		  flags;
+    service_t	 *restrict serv;
+} __align req_t;
+#define getreq(arg)	list_entry((arg), struct req_serv, list)
+
+/*
+ * Used by findservice()
+ */
+struct service_struct {
+    list_t		 s_list;
+    sort_t		   sort;
+    void	*restrict   dir;
+    level_t	*restrict start;
+    level_t	*restrict stopp;
+    attr_t		   attr;
+    char		 * name;
+} __align;
+#define getservice(list)	list_entry((list), service_t, s_list)
+
+extern list_t * s_start;
+extern int maxstart;
+extern int maxstop;
+
+extern void clear_all(void);
+extern void nickservice(service_t *restrict orig, service_t *restrict nick) attribute((nonnull(1,2)));
+extern void follow_all(void);
+extern void show_all(void);
+extern void requires(service_t *restrict this, service_t *restrict dep, const char mode) attribute((nonnull(1,2)));
+extern void runlevels(service_t *restrict serv, const char mode, const char *restrict lvl) attribute((nonnull(1,3)));
+extern boolean makeprov(service_t *restrict serv, const char *restrict script) attribute((nonnull(1,2)));
+extern void setorder(const char *restrict script, const char mode, const int order, const boolean recursive) attribute((nonnull(1)));
+extern int getorder(const char *restrict script, const char mode) attribute((nonnull(1)));
+extern boolean notincluded(const char *restrict const script, const char mode, const int runlevel) attribute((nonnull(1)));
+extern const char * getscript(const char *restrict prov) attribute((nonnull(1)));
+extern const char * getprovides(const char *restrict script) attribute((nonnull(1)));
+extern service_t * listscripts(const char **restrict script, const char mode, const ushort lvl);
+extern boolean is_loop_detected(void);
+extern service_t * addservice(const char *restrict const serv) attribute((malloc,nonnull(1)));
+extern service_t * findservice(const char *restrict const name);
+extern service_t * getorig(service_t *restrict serv) attribute((const,nonnull(1)));
+extern void lsort(const char type);
+
+/*
+ * Common short cuts
+ */
+extern const char *const delimeter;
+extern void error(const char *restrict fmt, ...) attribute((noreturn,format(printf,1,2)));
+extern void warn (const char *restrict fmt, ...) attribute((format(printf,1,2)));
+extern void info (const char *restrict fmt, ...) attribute((format(printf,1,2)));
+extern inline int map_has_runlevels(void) attribute((always_inline));
+extern inline char map_runlevel_to_key(const int runlevel);
+extern inline ushort map_key_to_lvl(const char key);
+extern inline const char *map_runlevel_to_location(const int runlevel);
+extern inline ushort map_runlevel_to_lvl(const int runlevel);
+extern inline ushort map_runlevel_to_seek(const int runlevel);
+extern ushort str2lvl(const char *restrict lvl) attribute((nonnull(1)));
+extern char * lvl2str(const ushort lvl);
+
+static inline char * xstrdup(const char *restrict s) attribute((always_inline,malloc));
+static inline char * xstrdup(const char *restrict s)
+{
+    char * r;
+    if (!s)
+	error("%s", strerror(EINVAL));
+    if (!(r = strdup(s)))
+	error("%s", strerror(errno));
+    return r;
+} 
+
+#define xreset(ptr)	\
+	{char *restrict tmp = (char *restrict)ptr; if (ptr && *tmp) free(ptr);} ptr = NULL
+
+#if defined(HAS_unlinkat) && defined(_ATFILE_SOURCE)
+# define xremove(d,x) (__extension__ ({ if ((dryrun ? 0 : \
+	(unlinkat(d,x,0) != 0 && (errno != EISDIR || unlinkat(d,x,AT_REMOVEDIR) != 0)))) \
+	warn ("can not remove(%s%s): %s\n", rcd, x, strerror(errno)); \
+	else \
+	info("remove service %s/%s%s\n", path, rcd, x); }))
+#else
+# define xremove(d,x) (__extension__ ({ if ((dryrun ? 0 : (remove(x) != 0))) \
+	warn ("can not remove(%s%s): %s\n", rcd, x, strerror(errno)); \
+	else \
+	info("remove service %s/%s%s\n", path, rcd, x); }))
+#endif
+#if defined(HAS_symlinkat) && defined(_ATFILE_SOURCE)
+# define xsymlink(d,x,y) (__extension__ ({ if ((dryrun ? 0 : (symlinkat(x, d, y) != 0))) \
+	warn ("can not symlink(%s, %s%s): %s\n", x, rcd, y, strerror(errno)); \
+	else \
+	info("enable service %s -> %s/%s%s\n", x, path, rcd, y); }))
+#else
+# define xsymlink(d,x,y) (__extension__ ({ if ((dryrun ? 0 : (symlink(x, y) != 0))) \
+	warn ("can not symlink(%s, %s%s): %s\n", x, rcd, y, strerror(errno)); \
+	else \
+	info("enable service %s -> %s/%s%s\n", x, path, rcd, y); }))
+#endif
+#if defined(HAS_fstatat) && defined(_ATFILE_SOURCE)
+# define xstat(d,x,s)	(__extension__ ({ fstatat(d,x,s, 0); }))
+# define xlstat(d,x,s)	(__extension__ ({ fstatat(d,x,s, AT_SYMLINK_NOFOLLOW); }))
+#else
+# define xstat(d,x,s)	(__extension__ ({ stat(x,s); }))
+# define xlstat(d,x,s)	(__extension__ ({ lstat(x,s); }))
+#endif
+#if defined(HAS_readlinkat) && defined(_ATFILE_SOURCE)
+# define xreadlink(d,x,b,l)	(__extension__ ({ readlinkat(d,x,b,l); }))
+#else
+# define xreadlink(d,x,b,l)	(__extension__ ({ readlink(x,b,l); }))
+#endif
+#if defined(HAS_openat) && defined(_ATFILE_SOURCE)
+# define xopen(d,x,f)	(__extension__ ({ openat(d,x,f); }))
+#else
+# define xopen(d,x,f)	(__extension__ ({ open(x,f); }))
+#endif
+
+/*
+ * Bits of the requests
+ */
+#define REQ_MUST	0x0001
+#define REQ_SHLD	0x0002
+#define REQ_KILL	0x0004
+
+/*
+ * Bits of the services
+ */
+#define SERV_KNOWN	0x0001
+#define SERV_NOTLSB	0x0002
+#define SERV_ALREADY	0x0004
+#define SERV_INTRACT	0x0008 
+#define SERV_ENABLED	0x0010
+#define SERV_ALL	0x0020
+#define SERV_DUPLET	0x0040
+#define SERV_SCRIPT	0x0080
+#define SERV_NOSTOP	0x0100
+#define SERV_CMDLINE	0x0200
+
+/*
+ * Bits of the runlevels
+ */
+#define LVL_HALT	0x0001
+#define LVL_ONE		0x0002
+#define LVL_TWO		0x0004
+#define LVL_THREE	0x0008
+#define LVL_FOUR	0x0010
+#define LVL_FIVE	0x0020
+#define LVL_REBOOT	0x0040
+#ifdef SUSE
+# define LVL_SINGLE	0x0080
+# define LVL_BOOT	0x0100
+#else
+# define LVL_SINGLE	0x0000
+# define LVL_BOOT	0x0080
+#endif
+
+/*
+ * LVL_BOOT is already done if one of the LVL_ALL will be entered.
+ */
+#define LVL_ALL		(LVL_HALT|LVL_ONE|LVL_TWO|LVL_THREE|LVL_FOUR|LVL_FIVE|LVL_REBOOT|LVL_SINGLE)
+
+/*
+ * Normal runlevels which are _direct_ available by shutdown/reboot/halt
+ */
+#define LVL_NORM	(LVL_HALT|LVL_ONE|LVL_TWO|LVL_THREE|LVL_FOUR|LVL_FIVE|LVL_REBOOT)
+
+/*
+ * Oneway runlevels at shutdown/reboot/halt/single
+ */
+#define LVL_ONEWAY	(LVL_HALT|LVL_ONE|LVL_REBOOT|LVL_SINGLE)
+/*
+ * Maximum start/stop level
+ */
+#define MAX_DEEP 99

Added: trunk/src/insserv/remove_initd
URL: http://svn.debian.org/wsvn/initscripts-ng/trunk/src/insserv/remove_initd?rev=873&op=file
==============================================================================
--- trunk/src/insserv/remove_initd (added)
+++ trunk/src/insserv/remove_initd Sat Mar 14 15:47:02 2009
@@ -1,0 +1,2 @@
+#!/bin/sh
+exec /sbin/insserv -r ${1+"$@"}

Propchange: trunk/src/insserv/remove_initd
------------------------------------------------------------------------------
    svn:executable = *

Added: trunk/src/insserv/tests/suite
URL: http://svn.debian.org/wsvn/initscripts-ng/trunk/src/insserv/tests/suite?rev=873&op=file
==============================================================================
--- trunk/src/insserv/tests/suite (added)
+++ trunk/src/insserv/tests/suite Sat Mar 14 15:47:02 2009
@@ -1,0 +1,306 @@
+#
+# Common test suite definitions, declarations, and functions
+#
+set -eC
+set +o posix
+unset ${!LC@}
+export LANG=POSIX
+
+: ${insserv:=${PWD}/insserv}
+: ${tmpdir:=${PWD}/root}
+: ${initddir:=${tmpdir}/etc/init.d}
+: ${insconf:=${tmpdir}/etc/insserv.conf}
+: ${overridedir:=${tmpdir}/etc/insserv/override}
+: ${issuse=""}
+: ${debug:=""}
+
+declare -i retval=0
+declare -i checkfailed=0
+declare -i testcount=0
+declare -i testfailed=0
+finish_test ()
+{
+    if test 0 -ne $retval ; then
+        echo "error: $testcount test executed, $checkfailed fatal tests failed, $testfailed nonfatal test failed."
+    else
+        echo "success: $testcount test executed, $testfailed nonfatal tests failed."
+    fi
+    rm -rf ${tmpdir}
+    return $retval
+}
+trap 'finish_test' EXIT
+
+mkdir -p $initddir
+
+if test -n "${issuse}" ; then
+    runlevel_path ()
+    {
+	local -a level=($@)
+	level=(${level[@]/%s/S})
+	level=(${level[@]/#/rc})
+	level=(${level[@]/rc[bB]*/boot})
+	printf "${initddir}/%s.d\n" ${level[@]}
+    }
+    list_rclinks()
+    {
+	pushd $initddir/ &> /dev/null
+	echo ${initddir##*/}:
+	ls ${1+"$@"} *
+	popd &> /dev/null
+    }
+    cat <<-'EOF' > $insconf
+	$local_fs	boot.localfs +boot.crypto
+	$network	network
+	$named		+named +dnsmasq +lwresd $network
+	$remote_fs	$local_fs +nfs +smbfs
+	$syslog		syslog
+	$portmap	portmap
+	$time		boot.clock +ntp
+	<interactive>	boot.crypto boot.clock boot.localfs boot.rootfsck apache apache2 kdump ntp
+	EOF
+else
+    runlevel_path ()
+    {
+	printf "${initddir}/../rc%s.d\n" ${1+"$@"}
+    }
+    list_rclinks()
+    {
+	pushd $initddir/../ &> /dev/null
+	ls ${1+"$@"} *
+	popd &> /dev/null
+    }
+    cat <<-'EOF' > $insconf
+	$local_fs	+mountall +umountfs
+	$network	+networking +ifupdown
+	$named		+named +dnsmasq +lwresd +bind9 $network
+	$remote_fs	$local_fs +mountnfs +mountnfs-bootclean +umountnfs +sendsigs
+	$syslog		+syslog +sysklogd
+	$portmap	portmap
+	$time		hwclock
+	<interactive>	udev mountdevsubfs checkroot checkfs console-screen
+	EOF
+fi
+chmod u+w,a+r $insconf
+
+insserv_reg ()
+{
+    script=$(printf "${initddir}/%s\n" ${1+"$@"})
+    $insserv $debug -c $insconf -p $initddir -o $overridedir $script
+}
+
+insserv_del ()
+{
+    script=$(printf "${initddir}/%s\n" ${1+"$@"})
+    $insserv $debug -c $insconf -p $initddir -o $overridedir -r $script
+}
+
+relpath ()
+{
+    local OLDIFS IFS
+    local -a orgwords
+    local -a locwords
+    local -i relp=0
+    local -i deep=0
+    local p l
+    local path=""
+
+    OLDIFS="$IFS"; IFS=/
+    eval orgwords=(${1// /\\\\ }) ; shift
+    eval locwords=(${1// /\\\\ }) ; shift
+    IFS="$OLDIFS"
+    unset OLDIFS
+
+    deep=0
+    relp=0
+    for l in "${locwords[@]}" ; do
+        if test "$l" = ".." ; then
+	    ((deep++))
+	    continue
+	elif test $deep -gt 0 ; then
+	    while ((deep-- > 0)) ; do
+		unset locwords[$((relp+deep))]
+		(((relp-1)-deep < 0)) || unset locwords[$(((relp-1)-deep))]
+	    done
+	    continue
+        fi
+	((relp++))
+    done
+    locwords=(${locwords[@]})
+
+    deep=0
+    relp=0
+    for p in "${orgwords[@]}" ; do
+	if test "$p" = ".." ; then
+	    ((deep++))
+	    continue
+	elif test $deep -gt 0 ; then
+	    while ((deep-- > 0)) ; do
+		unset orgwords[$((relp+deep))]
+		(((relp-1)-deep < 0)) || unset orgwords[$(((relp-1)-deep))]
+	    done
+	    continue
+	fi
+	((relp++))
+    done
+    orgwords=(${orgwords[@]})
+
+    deep=0
+    relp=0
+    for p in "${orgwords[@]}" ; do
+	eval l="\${locwords[$((deep++))]}"
+	if test "$l" != "$p" -o $relp -ne 0 ; then
+	    ((relp++))
+	    path="${path}/$p"
+	    test -n "$l" || continue
+		if test $relp -eq 1 ; then
+		    path="..${path}"
+		else
+		    path="../${path}"
+		fi
+	 fi
+    done
+    unset orgwords p l
+
+    if test $deep -lt ${#locwords[@]} ; then
+	relp=0
+	while test $relp -lt $deep; do
+	    unset locwords[$((relp++))]
+	done
+	while test ${#locwords[@]} -gt 0  ; do
+	    path="../${path}"
+	    unset locwords[$((relp++))]
+	done
+    fi
+
+    echo "$path"
+}
+
+counttest ()
+{
+    testcount=$(expr $testcount + 1)
+}
+
+error ()
+{
+    echo error: $@
+    checkfailed=$(expr $checkfailed + 1)
+    retval=1
+}
+
+warning ()
+{
+    echo warning: $@
+    testfailed=$(expr $testfailed + 1)
+}
+
+addscript ()
+{
+    local scriptname=$1
+    local script=${initddir}/$scriptname
+    cat > $script
+    chmod u+w,a+rx $script
+}
+
+insertscript ()
+{
+    local scriptname=$1
+    addscript   $scriptname
+    insserv_reg $scriptname
+}
+
+present_ok ()
+{
+    local rcdpath=$(runlevel_path $1); shift
+    local script=$1;   shift
+    local ret=0
+    test -L ${rcdpath}/[KS][0-9][0-9]$script || ret=1
+    counttest
+    return $ret
+}
+
+check_script_present ()
+{
+    local runlevel=$1; shift
+    local script=$1;   shift
+    present_ok $runlevel $script && return 0
+    error "script $script not present in runlevel $runlevel"
+}
+
+test_script_present ()
+{
+    local runlevel=$1; shift
+    local script=$1;   shift
+    present_ok $runlevel $script && return 0
+    warning "script $script not present in runlevel $runlevel"
+}
+
+check_script_not_present ()
+{
+    local runlevel=$1; shift
+    local script=$1;   shift
+    if present_ok $runlevel $script ; then
+	error "script $script present in runlevel $runlevel"
+    fi
+    return 0
+}
+
+test_script_not_present ()
+{
+    local runlevel=$1; shift
+    local script=$1;   shift
+    if present_ok $runlevel $script ; then
+	warning "script $script present in runlevel $runlevel"
+    fi
+    return 0
+}
+
+order_ok ()
+{
+    local rcdpath=$(runlevel_path $1); shift
+    local script1=$1;  shift
+    local script2=$1;  shift
+    local ret=0 scr order=""
+    pushd $rcdpath &> /dev/null
+    if test -n "${issuse}" ; then
+	for scr in S[0-9][0-9]* ; do
+	    test -e "${scr}" || continue
+	    test -L "${scr}" || continue
+	    case "${scr#S[0-9][0-9]}" in
+	    ${script1}) order="${order:+$order }${script1}" ;;
+	    ${script2}) order="${order:+$order }${script2}" ;;
+	    esac
+	done
+    else
+	for scr in [SK][0-9][0-9]* ; do
+	    test -e "${scr}" || continue
+	    test -L "${scr}" || continue
+	    case "${scr#[SK][0-9][0-9]}" in
+	    ${script1}) order="${order:+$order }${script1}" ;;
+	    ${script2}) order="${order:+$order }${script2}" ;;
+	    esac
+	done
+    fi
+    popd &> /dev/null
+    test "$order" = "$script1 $script2" || ret=1
+    counttest
+    return $ret
+}
+
+# Fatal check
+check_order ()
+{
+    local runlevel=$1
+    local script1=$2
+    local script2=$3
+    order_ok ${1+"$@"} || error   "incorrect $runlevel sequence $script1 not before $script2" || true
+}
+
+# Non-fatal check
+test_order ()
+{
+    local runlevel=$1
+    local script1=$2
+    local script2=$3
+    order_ok ${1+"$@"} || warning "incorrect $runlevel sequence $script1 not before $script2" || true
+}
+




More information about the Initscripts-ng-commits mailing list