[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(®.prov, PROVIDES, REG_EXTENDED|REG_ICASE);
+ regcompiler(®.req_start, REQUIRED_START, REG_EXTENDED|REG_ICASE|REG_NEWLINE);
+ regcompiler(®.req_stop, REQUIRED_STOP, REG_EXTENDED|REG_ICASE|REG_NEWLINE);
+ regcompiler(®.shl_start, SHOULD_START, REG_EXTENDED|REG_ICASE|REG_NEWLINE);
+ regcompiler(®.shl_stop, SHOULD_STOP, REG_EXTENDED|REG_ICASE|REG_NEWLINE);
+ regcompiler(®.start_bf, START_BEFORE, REG_EXTENDED|REG_ICASE|REG_NEWLINE);
+ regcompiler(®.stop_af, STOP_AFTER, REG_EXTENDED|REG_ICASE|REG_NEWLINE);
+ regcompiler(®.def_start, DEFAULT_START, REG_EXTENDED|REG_ICASE|REG_NEWLINE);
+ regcompiler(®.def_stop, DEFAULT_STOP, REG_EXTENDED|REG_ICASE|REG_NEWLINE);
+ regcompiler(®.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(®.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(®.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(®.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(®.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(®.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(®.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(®.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(®.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(®.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(®.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(®.prov);
+ regfree(®.req_start);
+ regfree(®.req_stop);
+ regfree(®.shl_start);
+ regfree(®.shl_stop);
+ regfree(®.start_bf);
+ regfree(®.stop_af);
+ regfree(®.def_start);
+ regfree(®.def_stop);
+ regfree(®.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