From 4ec328da6d474fac41b2f6c2d066786ea2c9baf0 Mon Sep 17 00:00:00 2001 From: Kibum Kim Date: Sat, 7 Jan 2012 00:47:31 +0900 Subject: [PATCH] Git init --- CHANGES | 416 +++ COPYING | 340 ++ Makefile | 192 ++ README | 34 + debian/README.Debian | 45 + debian/README.source | 16 + debian/bash-completion | 36 + debian/bts-lefttoreport | 8 + debian/changelog | 1222 +++++++ debian/check-archive-initd-scripts | 247 ++ debian/check-initd-order | 425 +++ debian/compat | 1 + debian/control | 31 + debian/copyright | 20 + debian/dirs | 6 + debian/docs | 1 + debian/lintian-overrides | 1 + debian/make-testsuite | 33 + debian/manpages | 1 + debian/overrides/devfsd | 8 + debian/overrides/hotplug | 7 + debian/overrides/hotplug-net | 7 + debian/overrides/initrd-tools.sh | 7 + debian/overrides/modutils | 8 + debian/patches/10_nosuse.patch | 17 + debian/patches/11_debian_conf.patch | 55 + debian/patches/20_install_perms_fixup.patch | 29 + debian/patches/21_tests_suite_new_functions.patch | 36 + debian/patches/30_deterministic_order.patch | 77 + debian/patches/40_badboy_segfault.patch | 21 + debian/patches/50_symlink_in_initddir.patch | 67 + debian/patches/60_all_keyword_start_only.patch | 22 + debian/patches/61_interactive_keyword.patch | 132 + debian/patches/62_upstart_job.patch | 170 + debian/patches/70_req_start_all_depends.patch | 30 + debian/patches/71_complete_makefile.patch | 56 + debian/patches/80_manual_warnings.patch | 114 + debian/patches/81_lessverbose.patch | 157 + debian/patches/82_loop_exit_msg.patch | 20 + .../patches/90_no_runlevel_spec_for_debian.patch | 33 + debian/patches/91_kfreebsd_nofadvice.patch | 22 + debian/patches/92_m68k_alignment.patch | 20 + debian/patches/93_hurd_no_path_max.patch | 19 + debian/patches/94_v1_12_2.patch | 82 + debian/patches/95_stop_all.patch | 159 + debian/patches/96_hurd_no_at_funcs.patch | 50 + debian/patches/series | 22 + debian/po/POTFILES.in | 1 + debian/po/cs.po | 55 + debian/po/de.po | 62 + debian/po/es.po | 85 + debian/po/fi.po | 55 + debian/po/fr.po | 61 + debian/po/gl.po | 56 + debian/po/it.po | 56 + debian/po/ja.po | 53 + debian/po/nl.po | 59 + debian/po/pt.po | 57 + debian/po/ru.po | 61 + debian/po/sv.po | 57 + debian/po/templates.pot | 45 + debian/po/vi.po | 55 + debian/rules | 106 + debian/run-testsuite | 2178 ++++++++++++ debian/seq-changes | 54 + debian/update-bootsystem-insserv | 24 + debian/update-rc.d-insserv | 593 ++++ debian/update-rc.d-insserv.8 | 14 + debian/watch | 6 + init-functions | 55 + insserv-1.12.0.lsm | 15 + insserv.8.in | 443 +++ insserv.c | 3461 ++++++++++++++++++++ insserv.conf | 41 + install_initd | 2 + listing.c | 1163 +++++++ listing.h | 407 +++ packaging/10_nosuse.patch | 17 + packaging/11_debian_conf.patch | 55 + packaging/20_install_perms_fixup.patch | 29 + packaging/21_tests_suite_new_functions.patch | 36 + packaging/30_deterministic_order.patch | 77 + packaging/40_badboy_segfault.patch | 21 + packaging/50_symlink_in_initddir.patch | 67 + packaging/61_interactive_keyword.patch | 132 + packaging/62_upstart_job.patch | 170 + packaging/70_req_start_all_depends.patch | 30 + packaging/71_complete_makefile.patch | 56 + packaging/81_lessverbose.patch | 157 + packaging/82_loop_exit_msg.patch | 20 + packaging/91_kfreebsd_nofadvice.patch | 22 + packaging/92_m68k_alignment.patch | 20 + packaging/93_hurd_no_path_max.patch | 19 + packaging/94_v1_12_2.patch | 82 + packaging/95_stop_all.patch | 159 + packaging/96_hurd_no_at_funcs.patch | 50 + packaging/bash-completion | 36 + packaging/check-archive-initd-scripts | 247 ++ packaging/check-initd-order | 425 +++ packaging/devfsd | 8 + packaging/hotplug | 7 + packaging/hotplug-net | 7 + packaging/initrd-tools.sh | 7 + packaging/insserv.spec | 109 + packaging/make-testsuite | 33 + packaging/modutils | 8 + packaging/seq-changes | 54 + packaging/update-bootsystem-insserv | 24 + packaging/update-rc.d-insserv | 593 ++++ remove_initd | 2 + tests/suite | 306 ++ 111 files changed, 16987 insertions(+) create mode 100644 CHANGES create mode 100644 COPYING create mode 100644 Makefile create mode 100644 README create mode 100644 debian/README.Debian create mode 100644 debian/README.source create mode 100644 debian/bash-completion create mode 100644 debian/bts-lefttoreport create mode 100644 debian/changelog create mode 100644 debian/check-archive-initd-scripts create mode 100644 debian/check-initd-order create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/dirs create mode 100644 debian/docs create mode 100644 debian/lintian-overrides create mode 100644 debian/make-testsuite create mode 100644 debian/manpages create mode 100644 debian/overrides/devfsd create mode 100644 debian/overrides/hotplug create mode 100644 debian/overrides/hotplug-net create mode 100644 debian/overrides/initrd-tools.sh create mode 100644 debian/overrides/modutils create mode 100644 debian/patches/10_nosuse.patch create mode 100644 debian/patches/11_debian_conf.patch create mode 100644 debian/patches/20_install_perms_fixup.patch create mode 100644 debian/patches/21_tests_suite_new_functions.patch create mode 100644 debian/patches/30_deterministic_order.patch create mode 100644 debian/patches/40_badboy_segfault.patch create mode 100644 debian/patches/50_symlink_in_initddir.patch create mode 100644 debian/patches/60_all_keyword_start_only.patch create mode 100644 debian/patches/61_interactive_keyword.patch create mode 100644 debian/patches/62_upstart_job.patch create mode 100644 debian/patches/70_req_start_all_depends.patch create mode 100644 debian/patches/71_complete_makefile.patch create mode 100644 debian/patches/80_manual_warnings.patch create mode 100644 debian/patches/81_lessverbose.patch create mode 100644 debian/patches/82_loop_exit_msg.patch create mode 100644 debian/patches/90_no_runlevel_spec_for_debian.patch create mode 100644 debian/patches/91_kfreebsd_nofadvice.patch create mode 100644 debian/patches/92_m68k_alignment.patch create mode 100644 debian/patches/93_hurd_no_path_max.patch create mode 100644 debian/patches/94_v1_12_2.patch create mode 100644 debian/patches/95_stop_all.patch create mode 100644 debian/patches/96_hurd_no_at_funcs.patch create mode 100644 debian/patches/series create mode 100644 debian/po/POTFILES.in create mode 100644 debian/po/cs.po create mode 100644 debian/po/de.po create mode 100644 debian/po/es.po create mode 100644 debian/po/fi.po create mode 100644 debian/po/fr.po create mode 100644 debian/po/gl.po create mode 100644 debian/po/it.po create mode 100644 debian/po/ja.po create mode 100644 debian/po/nl.po create mode 100644 debian/po/pt.po create mode 100644 debian/po/ru.po create mode 100644 debian/po/sv.po create mode 100644 debian/po/templates.pot create mode 100644 debian/po/vi.po create mode 100755 debian/rules create mode 100644 debian/run-testsuite create mode 100644 debian/seq-changes create mode 100644 debian/update-bootsystem-insserv create mode 100644 debian/update-rc.d-insserv create mode 100644 debian/update-rc.d-insserv.8 create mode 100644 debian/watch create mode 100644 init-functions create mode 100644 insserv-1.12.0.lsm create mode 100644 insserv.8.in create mode 100644 insserv.c create mode 100644 insserv.conf create mode 100755 install_initd create mode 100644 listing.c create mode 100644 listing.h create mode 100644 packaging/10_nosuse.patch create mode 100644 packaging/11_debian_conf.patch create mode 100644 packaging/20_install_perms_fixup.patch create mode 100644 packaging/21_tests_suite_new_functions.patch create mode 100644 packaging/30_deterministic_order.patch create mode 100644 packaging/40_badboy_segfault.patch create mode 100644 packaging/50_symlink_in_initddir.patch create mode 100644 packaging/61_interactive_keyword.patch create mode 100644 packaging/62_upstart_job.patch create mode 100644 packaging/70_req_start_all_depends.patch create mode 100644 packaging/71_complete_makefile.patch create mode 100644 packaging/81_lessverbose.patch create mode 100644 packaging/82_loop_exit_msg.patch create mode 100644 packaging/91_kfreebsd_nofadvice.patch create mode 100644 packaging/92_m68k_alignment.patch create mode 100644 packaging/93_hurd_no_path_max.patch create mode 100644 packaging/94_v1_12_2.patch create mode 100644 packaging/95_stop_all.patch create mode 100644 packaging/96_hurd_no_at_funcs.patch create mode 100644 packaging/bash-completion create mode 100644 packaging/check-archive-initd-scripts create mode 100644 packaging/check-initd-order create mode 100644 packaging/devfsd create mode 100644 packaging/hotplug create mode 100644 packaging/hotplug-net create mode 100644 packaging/initrd-tools.sh create mode 100644 packaging/insserv.spec create mode 100644 packaging/make-testsuite create mode 100644 packaging/modutils create mode 100644 packaging/seq-changes create mode 100644 packaging/update-bootsystem-insserv create mode 100644 packaging/update-rc.d-insserv create mode 100755 remove_initd create mode 100644 tests/suite diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..bfc7bce --- /dev/null +++ b/CHANGES @@ -0,0 +1,416 @@ +------------------------------------------------------------------- +Tue Jul 29 15:23:43 CEST 2008 - werner@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@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@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@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@suse.de + +- Make kbd interactive to avoid race during tty resize (bnc#259577) + +------------------------------------------------------------------- +Wed Jun 4 12:17:44 CEST 2008 - werner@suse.de + +- Scan service links even for non LSB scripts (bnc#391014) + +------------------------------------------------------------------- +Thu May 29 00:42:42 CEST 2008 - dmueller@suse.de + +- really remove last reference to boot.setclock (bnc#384254) + +------------------------------------------------------------------- +Tue May 20 09:25:41 CEST 2008 - werner@suse.de + +- Remove last occurence of boot.setclock (bnc#384254) + +------------------------------------------------------------------- +Thu May 15 13:42:57 CEST 2008 - werner@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@suse.de + +- Ignore temporary errors during update with YaST/zypper (bnc#385498) + +------------------------------------------------------------------- +Mon Apr 28 15:25:54 CEST 2008 - werner@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@suse.de + +- add boot.crypto-early to insserv.conf + +------------------------------------------------------------------- +Mon Feb 4 18:32:33 CET 2008 - werner@suse.de + +- Expand system facilities to make deep of the dependcy graph + less deeper. + +------------------------------------------------------------------- +Fri Feb 1 14:34:52 CET 2008 - werner@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@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@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@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@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@suse.de + +- Remove hotplug and pcmcia from insserv.conf because they are + dropped (bug #291417) + +------------------------------------------------------------------- +Tue Jun 19 18:59:30 CEST 2007 - werner@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@suse.de + +- Ignore rcs-files (bug #278520) + +------------------------------------------------------------------- +Mon Jan 29 15:08:17 CET 2007 - werner@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@suse.de + +- Add missed `start this script before' feature patch (fate#301269) + +------------------------------------------------------------------- +Tue Jan 16 14:04:06 CET 2007 - werner@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@suse.de + +- Expand aliases even for services which requires $all (#216202) + +------------------------------------------------------------------- +Mon May 15 12:56:27 CEST 2006 - werner@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@suse.de + +- Ignore .orig and .org file (bug #155944) + +------------------------------------------------------------------- +Wed Mar 1 12:51:17 CET 2006 - werner@suse.de + +- Add a few lines about $all into the man page (bug #151561) + +------------------------------------------------------------------- +Mon Feb 6 16:40:46 CET 2006 - werner@suse.de + +- Handle duplets even for interactive scripts + +------------------------------------------------------------------- +Tue Jan 31 15:06:53 CET 2006 - werner@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@suse.de + +- Add patches from Petter Reinholdtsen +- Make debian part work + +------------------------------------------------------------------- +Wed Jan 25 14:52:26 CET 2006 - werner@suse.de + +- Fix the broken fix (bug #145403) + +------------------------------------------------------------------- +Mon Jan 23 13:35:40 CET 2006 - werner@suse.de + +- Make missing Provides and Requires non-fatal. + +------------------------------------------------------------------- +Fri Jan 20 18:13:39 CET 2006 - werner@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@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@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@suse.de + +- Fix duplet handling in make like service handling (bug #130451) + +------------------------------------------------------------------- +Thu Sep 15 16:54:40 CEST 2005 - werner@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@suse.de + +- Include confdir patch from Ludwig Nussel +- Bounce version to 1.01.0 + +------------------------------------------------------------------- +Mon Nov 29 16:32:04 CET 2004 - werner@suse.de + +- Add some comments about boot script file names. + +------------------------------------------------------------------- +Thu Nov 25 18:24:35 CET 2004 - werner@suse.de + +- Update to 1.00.8 : use correct listing head (bug #48415) + +------------------------------------------------------------------- +Thu Nov 25 13:48:45 CET 2004 - werner@suse.de + +- Update to 1.00.7 : be more verbose on invalid file names + +------------------------------------------------------------------- +Tue Nov 23 13:13:35 CET 2004 - werner@suse.de + +- Update to 1.00.6 + +------------------------------------------------------------------- +Tue Nov 23 13:00:22 CET 2004 - werner@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@suse.de + +- Do not call error recursively if chdir fails (bugzilla #45767) + +------------------------------------------------------------------- +Mon Sep 20 16:40:13 CEST 2004 - werner@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@suse.de + +- Boot scripts which may call sulogin are INTERACTIVE + +------------------------------------------------------------------- +Thu Sep 16 14:19:56 CEST 2004 - werner@suse.de + +- Add dnsmasq and lwresd as optional to system facility named + +------------------------------------------------------------------- +Thu Sep 2 11:34:09 BST 2004 - werner@suse.de + +- Fix dependency of boot.clock also used in single mode (bug#44610) + +------------------------------------------------------------------- +Fri Aug 27 17:50:39 CEST 2004 - werner@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@suse.de + +- Update to 1.00.3 to support dependency files for make calls + +------------------------------------------------------------------- +Wed Mar 31 11:52:31 CEST 2004 - werner@suse.de + +- Verbose option and explain exit status in manual page (#37599) + +------------------------------------------------------------------- +Thu Mar 18 17:53:04 CET 2004 - werner@suse.de + +- Remove debug message + +------------------------------------------------------------------- +Wed Mar 17 15:12:55 CET 2004 - werner@suse.de + +- Implement the `$all' feature (bug #36140) + +------------------------------------------------------------------- +Wed Mar 10 17:27:53 CET 2004 - werner@suse.de + +- YAL (Yet Another Loop) fixed (bug #35522) + +------------------------------------------------------------------- +Thu Feb 19 18:40:36 CET 2004 - werner@suse.de + +- Do not create a K* link if no S* link exist. + +------------------------------------------------------------------- +Thu Feb 19 13:55:14 CET 2004 - werner@suse.de + +- More about K* links in /etc/init.d/boot.d + +------------------------------------------------------------------- +Tue Feb 17 14:18:30 CET 2004 - ro@suse.de + +- enable K* (kill) links in /etc/init.d/boot.d + +------------------------------------------------------------------- +Wed Oct 1 17:58:08 CEST 2003 - werner@suse.de + +- Allow numbers in initial segment of namespace of scripts (#31793) + +------------------------------------------------------------------- +Mon Sep 22 18:41:26 CEST 2003 - werner@suse.de + +- Stop recursive walk on dependency tree hard if a loop is detected + +------------------------------------------------------------------- +Tue Sep 16 13:57:59 CEST 2003 - werner@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@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@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@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@suse.de + +- Update to 0.99.9: better handling with not LSB conform scripts + +------------------------------------------------------------------- +Thu Jun 12 10:47:07 CEST 2003 - kukuk@suse.de + +- fix filelist + +------------------------------------------------------------------- +Wed Apr 16 18:31:07 CEST 2003 - werner@suse.de + +- Update to 0.99.8: be able to remove doubles with -rf + +------------------------------------------------------------------- +Sat Mar 8 16:00:23 CET 2003 - kukuk@suse.de + +- Add /lib/lsb back [Bug #24904] + +------------------------------------------------------------------- +Wed Jan 15 17:07:54 CET 2003 - ro@suse.de + +- split from aaa_base + + diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..60549be --- /dev/null +++ b/COPYING @@ -0,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. + + + Copyright (C) 19yy + + 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. + + , 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. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..96d7673 --- /dev/null +++ b/Makefile @@ -0,0 +1,192 @@ +# +# Makefile for compiling insserv tool +# +# Author: Werner Fink, +# + +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 \n\ +Maintained-by: Werner Fink \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 diff --git a/README b/README new file mode 100644 index 0000000..af199e3 --- /dev/null +++ b/README @@ -0,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 +. + + 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 + diff --git a/debian/README.Debian b/debian/README.Debian new file mode 100644 index 0000000..e3049c0 --- /dev/null +++ b/debian/README.Debian @@ -0,0 +1,45 @@ +Dependency based boot sequencing is the default in Debian. The +insserv program is used by sysv-rc to order init.d scripts based on +their declared dependencies. + +An experimental feature to run init.d scripts in parallel is also +available. Use the CONCURRENCY setting in /etc/default/rcS to +enable it. + +In short: + + # Enable parallel booting + echo CONCURRENCY=makefile >> /etc/default/rcS + + # Ready to reboot + shutdown -r now + +The next boot should then start services in parallel, as early as +possible during the boot process based on the dependency information +provided. + +The 'makefile' style concurrency depend on complete and correct +dependencies in all init.d scripts. There is a simpler and less +strict style 'startpar', which only require all scripts with the same +sequence number to be able to run in parallel, and thus accept +incomplete dependencies as long as the boot sequence number is OK. + +To monitor the boot sequence, the bootchart project is a good choice. +Debian packages are available in etch and sid. The project itself is +available from . + +Background info on alternative boot systems in Debian is available +from +. + +Information on the LSB initscript comment convention is available from +, + and +. + +Information on an alternative approach to parallelism during boot is +available from +. + +A tool to detect cycles is available from Adam Jensen using the git +repository . diff --git a/debian/README.source b/debian/README.source new file mode 100644 index 0000000..813fafb --- /dev/null +++ b/debian/README.source @@ -0,0 +1,16 @@ +This package uses quilt to manage all modifications to the upstream +source. Changes are stored in the source package as diffs in +debian/patches and applied during the build. + +To get the fully patched source after unpacking the source package, cd +to the root level of the source package and run: + + debian/rules patch + +Removing a patch is as simple as removing its entry from the +debian/patches/series file, and please also remove the patch file +itself. + +To clean up afterwards again, "debian/rules unpatch" will do the +work for you - or you can of course choose to call +"fakeroot debian/rules clean" all together. diff --git a/debian/bash-completion b/debian/bash-completion new file mode 100644 index 0000000..68c0ef3 --- /dev/null +++ b/debian/bash-completion @@ -0,0 +1,36 @@ +# insserv(8) completion +# +# Copyright (c) 2009 Kel Modderman +# + +have insserv && +_insserv() +{ + local cur prev sysvdir services options + + cur=`_get_cword` + prev=${COMP_WORDS[COMP_CWORD-1]} + + [ -d /etc/rc.d/init.d ] && sysvdir=/etc/rc.d/init.d \ + || sysvdir=/etc/init.d + + services=( $(echo $sysvdir/!(README*|*.dpkg*|*.rpm@(orig|new|save))) ) + services=( ${services[@]#$sysvdir/} ) + options=( -c --config -d -f -n -o --override -p --path -r -v ) + + case "$prev" in + -c|--config) + _filedir + ;; + -o|--override|-p|--path) + _filedir -d + ;; + *) + COMPREPLY=( $( compgen -W '${options[@]} ${services[@]}' -- \ + $cur ) ) + ;; + esac + + return 0 +} && +complete -F _insserv insserv diff --git a/debian/bts-lefttoreport b/debian/bts-lefttoreport new file mode 100644 index 0000000..b9121f6 --- /dev/null +++ b/debian/bts-lefttoreport @@ -0,0 +1,8 @@ +#!/bin/sh + +basedir=$(dirname $0) + +ls $basedir/overrides |sort > bts-total.txt +(cd $basedir/overrides ; egrep -l 'BTS|Already present' *) |sort> bts-reported.txt +comm -23 bts-total.txt bts-reported.txt +rm bts-total.txt bts-reported.txt diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..79bd45e --- /dev/null +++ b/debian/changelog @@ -0,0 +1,1222 @@ +insserv (1.12.0-14+s2) unstable; urgency=low + + * Revert "Lower the debconf compatibility level to 5 to enable + building under Scratchbox." + * Set myself as maintainer. + + -- Rafal Krypa Wed, 14 Apr 2010 13:37:20 +0200 + +insserv (1.12.0-14+s1) unstable; urgency=low + + * Lower the debconf compatibility level to 5 to enable building under + Scratchbox. + * debian/control: replace the Uploaders field. + + -- Rafal Krypa Fri, 29 Jan 2010 18:06:34 +0900 + +insserv (1.12.0-14) unstable; urgency=low + + * Remove obsolete rules targets missing-overrides, bin-by-inst.txt, + missingpkgs, missing-by-popcon and clean-extra. + * New patch 82_loop_exit_msg.patch to make exit message when a loop + is detected loop more like the exit messages when other problems + are detected. + * Make check-initd-order report missing provides header as errors + instead of printing perl warnings. + * New patch 62_upstart_job.patch implementing support for upstart + jobs (Closes: #547235). Add testsuite test to ensure that it is + working. + * Refreshed all patches. + * New patch 96_hurd_no_at_funcs.patch to try harder to get the + source building on hurd, where for example the readlinkat() symbol + exist in libc but always fail. + + -- Petter Reinholdtsen Thu, 01 Oct 2009 19:58:44 +0200 + +insserv (1.12.0-13) unstable; urgency=low + + * New argument -b to check-initd-order, to be able to replace /etc/ + with another directory. This allow for easier testing of the script. + * Update update-rc.d-insserv to the one in sysv-rc svn. + + -- Petter Reinholdtsen Sun, 20 Sep 2009 21:58:11 +0200 + +insserv (1.12.0-12) unstable; urgency=low + + * Use dh_lintian during build. Depend on debhelper (>= 6.0.7) for this. + * Correct wiki URL in README.Debian (Closes: #545171). Thanks to + Josh Triplett for noticing the old URL. + * Make sure check-initd-order generated valid dotty files when + scripts provide strings with " in them (Closes: #545521). Thanks + to Laurent Bonnaud for discovering the problem. + * Drop the Loading... messages from the default verbosity level, and + only show them when -v is used several times. + * Add script check-archive-initd-scripts to check all init.d scripts + in the Debian archive for consistency. + + -- Petter Reinholdtsen Sun, 13 Sep 2009 11:27:49 +0200 + +insserv (1.12.0-11) unstable; urgency=low + + [ Petter Reinholdtsen ] + * Migrate the responsibility for enabling or disabling dependency + based boot sequencing from the insserv package to the sysv-rc + package. Rewrite package description to reflect this (Closes: + #475478, #511753, #538959). Keep a dummy update-bootsystem-insserv + script to avoid having to conflict with sysv-rc version 2.87dsf-2. + Keep update-rc.d-insserv to make it impossible for the update-rc.d + diversion to be a dangling link during upgrades. Make it a copy + of update-rc.d from the new sysv-rc version to make sure both + behave the same way. update-rc.d-insserv should be removed in + Squeeze+1. update-bootsystem-insserv could be removed when + sysv-rc 2.87dsf-2 has been gone from unstable for 3 months. + * Drop dependencies on sysv-rc, initscripts and sysvinit-utils, and + leave it for sysv-rc to pull in the packages needed for dependency + based boot sequencing to work properly. + * Update README to reflect that dependency based boot sequencing is + now the default in Debian. Drop reference to obsolete CONCURRENCY + setting (Closes: #540447). + * Add new test case test_override_remove trying to reproduce bug #540866. + No luck so far. + * Add new test case test_insserv_virt_loop to reproduce a bug + reported by Raphael Geissert, where an incorrect insserv.conf will + make insserv hang forever. Add new patch 94_v1_12_2.patch from + upstream to fix it (Closes: #541613). + * Correct test test_early_all to fail if $all do not work with stop + sequences. Add new patch 95_stop_all.patch from upstream to fix + it (Closes: #542043). + * Change the definition of $syslog to include rsyslog, sysklogd, + dsyslog, inetutils-syslogd and syslog-ng, to include all syslog + implmenetations in the archive. Dropped the syslog provide from + the list, as it should not be used. + * Update to Standards-Version 3.8.3, no changes required. + * Add lintian override for the transitient update-bootsystem-insserv + binary missing a manual page. + * Add new test test_local_virtual to verify that local virtual + facilities work properly. + + [ Kel Modderman ] + * Add new patch 20_install_perms_fixup.patch to install binary and + conffile with correct permissions. + * Add new patch 21_tests_suite_new_functions.patch to add a couple + of new test suite functions to upstream test suite. + * Make sure update-rc.d compares command line parameters for start/stop + runlevel configuration with the Default-Start and Default-Stop values in + LSB info comment of script and warns if there are differences. + + -- Petter Reinholdtsen Sat, 05 Sep 2009 11:50:22 +0200 + +insserv (1.12.0-10) unstable; urgency=low + + [ Petter Reinholdtsen ] + * Change check-initd-order to return a exit code when there is a problem + with the boot sequence or dependencies. + * Change the default to enable dependency based boot sequencing if + it is safe to do. This should enable it in the common case, + while avoiding conversion on problems. + * Move all code from insserv.config to insserv.postist and remove + insserv.config to make sure update-bootsystem-insserv is available + and working when it is needed to test if it is safe to migrate to + dependency based boot sequencing. + + -- Petter Reinholdtsen Sun, 26 Jul 2009 21:06:56 +0200 + +insserv (1.12.0-9) unstable; urgency=low + + * Adjust patch 71_complete_makefile to make sure the recursion depth + calculation is done correctly in expand_faci(). + + -- Petter Reinholdtsen Thu, 23 Jul 2009 20:41:24 +0200 + +insserv (1.12.0-8) unstable; urgency=low + + [ Petter Reinholdtsen ] + * Refresh 92_m68k_alignment.patch. + * Simplify test for bug #534526, while still triggering the bug. + * Change definition of $time to make hwclock optional, as it might + be dropped from the boot sequence in the future. + * New patch 71_complete_makefile from upstream fixing .depend.* + content when processing virtual facility definitions refering to + other virtual facilities (Closes: #534526). + + [ Kel Modderman ] + * Before inserting an initscript with insserv, check that + /etc/init.d/ exists in update-rc.d-insserv. + + -- Petter Reinholdtsen Wed, 22 Jul 2009 23:53:05 +0200 + +insserv (1.12.0-7) unstable; urgency=low + + * Update standards-version from 3.8.1 to 3.8.2. No changes needed. + * Fix wrong quote char in insserv(8) manual page. + * Add required trailing slash to Vcs-Browser URL. + * Improve package description to make it more obvious that insserv + is not activated when installed. + * Depend on sysvinit-utils (>= 2.86.ds1-62) to get a version of + startpar that keep working even when /dev/pts is not yet mounted. + * Depend on the initscripts version we want (>= 2.86.ds1-63) + (instead of conflicting with the version we do not want which can + give upgrade problems), to get one with the X-Interactive flags + set in the scripts. Drop hostname, mountkernfs, mountdevsubfs, + checkroot and checkfs from the list of interactive scripts. + * New patch 91_kfreebsd_nofadvice.patch trying to get the source + building on kfreebsd. + * New patch 92_m68k_alignment.patch trying to get the source + building on m68k (Closes: #493637). + * New patch 93_hurd_no_path_max.patch trying to get the source + building on hurd. Need a better one. + + -- Petter Reinholdtsen Wed, 01 Jul 2009 00:17:13 +0200 + +insserv (1.12.0-6) unstable; urgency=low + + * Add keyboard-setup, console-setup, cryptdisks, cryptdisks-early + and checkfs-loop as interactive scripts while we wait for scripts + to use X-Interactive: true as documented in bug #458224 (Closes: + #510517, #534711). + * Fix typo in testsuite function initdir_purge(), making sure the + rc?.d directories are removed during purge. + * Add new patch introducing a new keyword 'X-Interactive: true' in + the LSB header (Closes: #458224). Add test suite to verify that + it is working. + * Add DM-Upload-Allowed: yes header to allow my co-maintainer to + upload this package. + * Add testcase for incomplete .depend.boot file based on test + created by Raphael Geissert for bug #534526. Make this a + non-fatal error in production builds while we figure out what is + wrong. + + -- Petter Reinholdtsen Fri, 26 Jun 2009 20:18:36 +0200 + +insserv (1.12.0-5) unstable; urgency=low + + [ Kel Modderman ] + * Convert dpatches to quilt series and adjust debian/rules and + debian/control. + * Refresh debian/patches/10_nosuse.patch to apply without fuzz. + * Add debian/patches/70_req_start_all_depends.patch to correct + dependency information written to .depend.* files for scripts which + declare Required-Start: $all. Thanks to upstream developer Werner + Fink for giving us th heads up about this problem and patch. + * Add Japanese translation. Thanks Hideki Yamane. (Closes: #512858) + * Add Swedish translation. Thanks Martin Bagge. (Closes: #503603) + * Add debian/manpages and call dh_installman without specific + arguments in debian/rules. + * Depend on debhelper >= 6 and use compat level of 6. + * Update to Standards-Version 3.8.1 without any required changes. + * Add Homepage field to debian/control. + * Add debian/patches/80_manual_warnings.patch to correct format, + spelling and grammar errors in manual page. + * Add debian/patches/90_no_runlevel_spec_for_debian.patch to remove + reference to known runlevels on Debian systems. These should be + defined in Debian policy. (Closes: #500542) + * Add interface to disable|enable service symlinks for all Default- + Start runlevels or those specified on the command line. This is + analogous to the interface introduced to update-rc.d of 2.86.ds1-62. + * Make sure disable|enable action does not call insserv if it did not + alter any runlevel symlinks. + * Consolidate debian/insserv.dirs into debian/dirs, only one should + exist. + * Add debian/bash-completion and install it to /etc/bash_completion.d/ + to enhance usability for bash shell users. + * When arguments to start/stop/defaults action are given to update- + rc.d wrapper, emit a warning that the LSB information of script + overrides the given arguments. + * Improve the way in which update-rc.d disable/enable function + determines index of S or K bit of runlevel symlink by using rindex + instead of a hardcoded index. + * Improve update-rc.d enable/disable function for when an unhandled + runlevel is given as argument. + * Also look in /usr/share/insserv/overrides/ when performing + disable/enable function in update-rc.d. + + [ Petter Reinholdtsen ] + * Make a note in the usage text that update-rc.d disable and enable + API is not yet set in stone. + + -- Petter Reinholdtsen Tue, 23 Jun 2009 08:19:19 +0200 + +insserv (1.12.0-4) unstable; urgency=low + + [ Petter Reinholdtsen ] + * New test test_early_all to control that $all only affect start or + stop sequences. Trying to reproduce issue reported in #485307. + + [ Kel Modderman ] + * Add 60_all_keyword_start_only.dpatch to prevent Required-Stop: $all + from modifying start link sort order. (Closes: #499721) + * Make test_early_all() test suite function unconditionally fatal, + this is an importan bug fixed by 60_all_keyword_start_only.dpatch. + + -- Petter Reinholdtsen Thu, 25 Sep 2008 20:36:10 +0200 + +insserv (1.12.0-3) unstable; urgency=low + + [ Kel Modderman ] + * test_fake_loop() and test_fake_loop_reverse() are now unconditionally fatal + tests because they pass with insserv >= 1.12.0. + * Modify 10_nosuse.dpatch to define ISSUSE as -DNOTSUSE instead of unsetting + it, to avoid fooling the build system. + * Purge the rc symlinks in initddir_purge() function of testsuite-common. + * Add a remscript() function to testsuite-common for deleting initscripts + from test init.d/ directory. + * Add test_all_keyword() function to run-testsuite to observe the + semantics of using the $all keyword. It is currently a non-fatal + test. + * Add test_script_in_runlevel() function to expose segfault reported + in #493202. + * Add 40_badboy_segfault.dpatch to fix segfault when scriptname() + function of insserv does not return script name due to script in + runlevel directory not being a symlink (or corrupt). (Closes: #493202) + * Add 50_symlink_in_initddir.dpatch to defend aginst symlinks + installed to /etc/init.d/ that point to other scripts in + /etc/init.d/, causing insserv to fail due to duplicate provides. + (Closes: #485045) + * Extend test_initd_symlink() test suite case to handle cases which + 50_symlink_in_initddir.dpatch must handle. + + -- Petter Reinholdtsen Sat, 20 Sep 2008 21:31:55 +0200 + +insserv (1.12.0-2) unstable; urgency=low + + [ Kel Modderman ] + * Make test_duplicate_provides() test case more realistic by placing + initscripts in init.d dir before registering with insserv. Make sure first + script is registered. + * Add test_deterministic_order() test function to make sure that when two or + more initscripts provide the same facility, the first script actually can + be registered with insserv reliably. + * Add 30_deterministic_order.dpatch to defend against the inconsistent + directory stream sequence returned by readdir(3) under different + circumstances. (Closes: #494514) + + -- Petter Reinholdtsen Wed, 20 Aug 2008 21:08:13 +0200 + +insserv (1.12.0-1) unstable; urgency=low + + [ Kel Modderman ] + * New upstream version. + - preserve empty runlevel configurations, override adding or removoval of + existing start/top runlevel configration (Closes: #477415, #492526) + * Discard patches applied to or no longer relevant to new upstream: + - 11_more_warnings.dpatch + - 32_debug_option.dpatch + - 33_nosuse_scripts.dpatch + - 40_segfault_virtprov.dpatch + - 41_cleansystem.dpatch + - 42_loopnochangemsg.dpatch + - 50_sign_warning.dpatch + - 51_overwrite_output.dpatch + - 52_shutdown_links.dpatch + - 60_disable_cfgfilter_stat.dpatch + - 62_warn_on_missing_required_fields.dpatch + - 63_warn_on_missing_default_fields.dpatch + - 64_missing_default_fields_fallback.dpatch + * Discard patches not applied in series: + - 32_debug_option.dpatch + - 34_debian_fixedscripts.dpatch + * Refresh patches that still apply to new upstream: + - 10_nosuse.dpatch + - 31_debian_conf.dpatch + * Add an extra call to list_rclinks() in test_newbug_keepoldorder() + function of run-testsuite, after introducing the bug. + * Make test_adding_start() and test_adding_stop() run-testsuite + functions unconditionally fatal on failure. + * Make test_bogus_facility() run-testsuite function non-fatal. + * Mark tests that are currently failing with a comment in run-testsuite. + * Add test_removing_start() and test_removing_stop() to run-testsuite, + showing that insserv will preserve existing links when script header is + unproperly replaced with empty Default-Start or Default-Stop. + * Make test_adding_start() case a more realistic example. + * Make test_incorrect_stopscripts() a fatal test, insserv should not + add shutdown links when none are present. + * Make test_newbug_keepoldorder() test case non-fatal, the fact that it + passed before was not by design but by luck, as per upstream analysis + which is included with test code. + * Handle CFLAGS in debian/rules more consistently, different options were + passed to make in build and install targets, and dpkg now also tampers + with the variable. + * Remove a bunch of overrides for scripts now with valid LSB information in + testing distribution today, or have been removed from archive. + * Add common test suite function for purging init directory, runlevel links + and dependency makefiles. + * Add test_incorrect_startscripts() to replicate bug report described in + #492526, and make sure insserv do not regress in this behaviour. + * Now we have no overrides to install by default, but we may in future, + modify debian/rules to only install overrides from ./debian/overrides/* if + they are present, but not fail otherwise. + * Add test_initd_symlink() test suite function to test if illegal + symlinks in /etc/init.d/ cause problems. + * Bump Standards Version to 3.8.0, add debian/README.source to describe patch + system to conform. No other changes required. + * Add myself to Uploaders. + * Rename 31_debian_conf.dpatch to 11_debian_conf.dpatch, to keep + Debian port patches in tight sequence. + + [ Petter Reinholdtsen ] + * Mention initcycle tool from Adam Jensen in README.Debian. + * Adjust test_initd_symlink test to accept the first insertion + and reject the second, as both scripts have the same provide. + + -- Petter Reinholdtsen Wed, 30 Jul 2008 18:18:00 +0200 + +insserv (1.11.0-9) unstable; urgency=low + + [ Petter Reinholdtsen ] + * New test case to demonstrate the bug reported in #477415. + * Include empty directories /etc/insserv.conf.d and + /etc/insserv/overrides in the package, to get dpkg to warn about + content there when purging insserv (Closes: #471237). + * Debconf translations: + - Updated German from Erik Schanze (Closes: #479254). + + [ Kel Modderman ] + * Add patch 60_disable_cfgfilter_stat to remove stat check from the + callback function that filters the scanning of /etc/insserv.conf.d/ dir + for confiuration file snippets. Instead do stat check in scan_conf(). + * New test case to show that two initscripts cannot have the same Provides + field. + * New test case exposing ability to insert a script into runlevel + configuration that depends on virtual facility that is not provided or + does not exist. + * New test case to check that /etc/insserv.conf.d/ can be used to allow one + or more services to define and provide a virtual facility. + * Ensure custom insserv.conf.d/* files are cleaned after + test_insserv_conf_d() in run-testsuite. + * Add test_onlystart() test case to check we can insert scripts with empty + stop runlevel configuration. + * Add test_broken_header() test case to show it seems possible to insert a + script missing Required-{Start,Stop} lsb info fields. + * Add test_no_default_start() to show that it seems possible to insert script + missing Default-Start field. + * Add test_no_default_stop() to show that it seems possible to insert script + missing Default-Stop field, and that links are created in stop runlevels. + * Add 62_warn_on_missing_required_fields and + 63_warn_on_missing_default_fields to enable warnings by default about + missing Provides, Required-Start, Required-Stop, Default-Start or + Default-Stop LSB comment keywords. + * Add a note to new patches to relate them to a case function of the test + suite. + * Add 64_missing_default_fields_fallback to ensure sane fallback of + empty runlevel configuration is used for scripts missing Default- + Start or Default-Stop lsb keywords. + * Add test_noprovides_header() to show that it is possible to insert script + missing Provides keyword, and many warnings are exposed as a result. + * Add test_adding_start() to expose that adding start levels uncleanly + modifies on disk configuration. Give test_adding_start and + test_adding_stop test script unique names. + + [ Petter Reinholdtsen ] + * Made test_adding_start and test_adding_stop checks non-fatal for + production builds, as this problem is no regression from earlier versions. + + -- Petter Reinholdtsen Sun, 25 May 2008 21:46:04 +0200 + +insserv (1.11.0-8) unstable; urgency=low + + * Make sure the consistency check in update-bootsystem-insserv + report all problems and not only the first one. + + -- Petter Reinholdtsen Mon, 24 Mar 2008 23:32:22 +0100 + +insserv (1.11.0-7) unstable; urgency=low + + * Added override files for digitools and ddns3-client. + * Make sure the dependency based update-rc.d check the argument list + slightly, to avoid bugs like #470062. + + -- Petter Reinholdtsen Thu, 13 Mar 2008 13:54:31 +0100 + +insserv (1.11.0-6) unstable; urgency=low + + [ Petter Reinholdtsen ] + * Added override files for at, fiaif, gom, ifupdown-scripts-zg2 and tspc. + * Correct typo in override file for lvm2. + * Changed postinst and update-bootsystem-insserv to remove the + generated files /etc/init.d/.depend.* when disabled or removed. + * Implemented better support in check-initd-orderfor graphing $all + relations. + * Restructure update-bootsystem-insserv slightly to make it possible + to check if it is safe to convert to dependency based boot + sequencing without doing the conversion. + * Updated 31_debian_conf to list glibc, hostname and keymap as interactive + scripts, as none of them can use a pseudoterminal. + * Add two new tests to verify that x-start-before and x-stop-after + work as they should. + * Debconf translations: + - Added Spanish from Steve Lord Flaubert (Closes: #467391). + - Added German from Erik Schanze (Closes: #467483). + - Added Dutch from Bart Cornelis (Closes: #467418). + + [ Kel Modderman ] + * Modify debian/insserv.config debconf script to honour a preseeded debconf + value enabling dependency based boot on first installation only. + + -- Petter Reinholdtsen Sun, 2 Mar 2008 18:00:02 +0100 + +insserv (1.11.0-5) unstable; urgency=low + + * Add test to verify that introducing a loop will not change the boot + sequence, but make insserv exit with an error. + * Added patch 42_loopnochangemsg to change the message printed when + a loop is detected, to let the user know that the boot sequence is + untouched. + * Added patch 52_shutdown_links to fix incorrecly inserted stop + symlinks (Closes: #464017). + * Added patch 53_debugoutput to provide more useful debug output + used to track down the stop symlink issues. Not enabled by default. + * Debconf translations: + - Added Russian from Yuri Kozlov (Closes: #467164). + - Added Czech from Miroslav Kure (Closes: #467170). + - Added Italian from Luca Monducci (Closes: #467295). + + -- Petter Reinholdtsen Sun, 24 Feb 2008 23:49:12 +0100 + +insserv (1.11.0-4) unstable; urgency=low + + * Added override file for whitelister. + * Reinsert previously removed override file for lvm2 and others + while we wait for the packages in testing to be fixed (Closes: + #466700). These should be removed when lenny is verified to have + headers in place. + * Debconf translations: + - Added French from Christian Perrier (Closes: #466345). + + -- Petter Reinholdtsen Thu, 21 Feb 2008 09:27:34 +0100 + +insserv (1.11.0-3) unstable; urgency=low + + * Rewrote patch debian/patches/40_segfault_virtprov.dpatch with a + solution provided by upstream. + * Added script debian/seq-changes from Frans Pop installed in + /usr/share/insserv/ to extract the sequence changes done by + insserv. + * New testsuite check to detect incorrectly inserted stop symlinks + when scripts with incorrect headers are encountered. + * Removed override file for snmptrapfmt, as the package now include + the LSB header. + * Removed override file save-etc-disk. It is not present in Debian. + * Update the package description and debconf question text (Closes: #464109). + * New patch 11_more_warnings to activate more warning flags during + build. Obsoletes setting the same flags in debian/rules. + * New patch 50_sign_warning getting rid of some signed/unsigned + compare issues. + * Update test suite to the one provided by Werner Fink. + * Extended test suite to report status at the end. + * New patch 32_debug_option to add new option -D to print debug + output. + * New patch 33_nosuse_scripts to disable some SUSE specific settings. + * New patch 51_overwrite_output to improve output when symlinks on + disk do not match the default-* headers. + * Added override file for slashem-common. + * New patch 41_cleansystem to clean the .system file. Changed rules + file to make sure it take effect. + * Change test suite to use /bin/bash, as it uses bash-features. + * Debconf translations: + - Added Galician from Jacobo Tarrio (Closes: #465067). + - Added Vietnamese from Clytie Siddall (Closes: #465437). + - Added Portugese from Américo Monteiro (Closes: #465519). + - Added Finnish from Esko Arajärvi (Closes: #465800). + + -- Petter Reinholdtsen Sun, 17 Feb 2008 13:54:03 +0100 + +insserv (1.11.0-2) unstable; urgency=low + + * Changed patch 31_debian_conf to accept rsyslog and syslog-ng as + implementations for the $syslog facility. + * Added test case to detect insserv crashing when it find scripts + providing virtual system facilities. + * Changed update-bootsystem-insserv to refuse to enable dependency + based boot sequencing when a script provide a virtual system + facility. + * Changed patch 10_nosuse.dpatch to make sure we build with -g. + * Added patch debian/patches/40_segfault_virtprov.dpatch to avoid + segfault when finding an enabled script that provide a virtual + system facility. + + -- Petter Reinholdtsen Fri, 1 Feb 2008 09:24:10 +0100 + +insserv (1.11.0-1) unstable; urgency=low + + * New upstream version. + - Drop patches 20_path_at_runtime, 21_overrides, 32_debian_nolsb, + 33_debian_localok, 38_debuginfo, 40_nosusescript, + 41_debiandefault, 42_redundantlvl, 43_shutdown, + 44_reportloopmemb, 45_loopsarefatal and 46_complete_removal + merged upstream. + - Updated insserv(8) manual page for Debian (Closes: #462064). + - Correct path to insserv.conf in test suite to keep it working. + - A lot faster (Closes: #462211). + * New example script make-testsuite useful to generate a test script + demonstrating a problem. + * Added override files for guidedog and puppet. + * Removed override file for atd and lvm2, as the packages now include + the LSB header. + + -- Petter Reinholdtsen Thu, 31 Jan 2008 09:05:07 +0100 + +insserv (1.10.0-6) unstable; urgency=low + + * Implement support for preseeding insserv, to make it possible to + enable it at install time. This only work the first time the + package is installed and config is executed when + /usr/sbin/update-rc.d-insserv does not exist yet. + * Changed check-initd-order to load virtual facilities from + /etc/insserv.conf (Closes: #459522) + * Extended testsuite to more closely match real Debian for the + shutdown sequence. + * New patch 46_complete_removal.dpatch to make sure all symlinks are + removed on removal (Closes: #460034). Based on patch from Kel + Modderman. Made failing removal test fatal. + + -- Petter Reinholdtsen Sat, 19 Jan 2008 14:45:27 +0100 + +insserv (1.10.0-5) unstable; urgency=low + + * Made sure to initialize the badstate variable before it is used in + update-bootsystem-insserv. + * Removed override files for uptimed and uptimed.sh, as the uptimed + package now include the LSB headers. + * Make sure to give a proper error message when failing to enable + dependency based boot system and insserv return an error code + (Closes: #461141). + + -- Petter Reinholdtsen Wed, 16 Jan 2008 23:29:09 +0100 + +insserv (1.10.0-4) unstable; urgency=low + + * Made problematic test cases for bug #460034 and #458582 fatal + in testing and non-fatal when uploading. + * Added override files for bastille-firewall. + * Do not warn about obsolete init.d scripts that have been removed + (Closes: #461073). Patch from Kel Modderman. + * Provide more information when convertion to dependency based boot + sequencing can not be done. + + -- Petter Reinholdtsen Wed, 16 Jan 2008 22:00:50 +0100 + +insserv (1.10.0-3) unstable; urgency=low + + * Added test case for problem with symlink removal, bug #460034. + * Added override files for uptimed, uptimed.sh and guarddog. + * Removed override file nfs-user-server as the compiled in defaults + are better than the proposed overrides. + * Add mountoverflowtmp to virtual facility $local_fs, to make sure + /tmp/ is always mounted before the scripts needing /tmp/ is + started. Conflict with initscripts before 2.86.ds1-48, to avoid a + dependency loop with this change. + * Make debconf question translatable (Closes: #386703). + + -- Petter Reinholdtsen Sun, 13 Jan 2008 19:32:34 +0100 + +insserv (1.10.0-2) unstable; urgency=low + + * Implement new check-initd-order option -c to be used with -g to + generate a combined graph for boot and shutdown dependencies. + * Split test suite into two files, one generic part + (testsuite-common) and one Debian specific part (run-testsuite). + * Remove ntpdate and ntp-server as optional dependencies for $time + as both are obsolete, and changing them to the current 'ntp' would + make a loop. + * Removed override file for resolvconf and laptop-netconf, as the + unstable packages got the header now. + * Removed override file for devmapper, as the unstable packages no + longer include a init.d script + * Remove reference to lwresd in headers-reported, as the unstable + package got the header now. + * Added override files for the console-cyrillic and + gibraltar-bootsupport package. + + -- Petter Reinholdtsen Wed, 9 Jan 2008 22:42:31 +0100 + +insserv (1.10.0-1) unstable; urgency=low + + * New upstream version released 2007-10-10. + - Updated patches 10_nosuse, 20_path_at_runtime, 21_overrides and + 43_shutdown to apply on the new version. + - Removed patch 11_revdepend as it is included upstream. + * In graphs, name scripts without provides header, and scripts + without LSB header, using the name of the file in /etc/init.d/. + This make it easier to spot loops involving these scripts. + * Added override file for hpoj. + * Ask if insserv should be activated at install time, using a medium + priority debconf question. The default is no. + * Restructure test script to work with new test feature implemented + in version 1.10. + * Update patch 42_redundantlvl to get rid of two compiler warnings. + + -- Petter Reinholdtsen Mon, 7 Jan 2008 23:37:53 +0100 + +insserv (1.09.0-14) unstable; urgency=low + + * Changed patch 21_overrides to only warn once about scripts without + LSB header, to reduce the noise. + * Changed patch 21_overrides to speed up processing by only reading + override default files only when the script is lacking an LSB header. + * Moved default dependency values from patch 21_overrides to + 41_debiandefault where it belong. + * New test to check that scripts introducing a loop (or a fake loop, + see bug #458582) will refuse to install. + * New patch 45_loopsarefatal to make sure insserv considering all + kind of loops fatal, to not mess up the script sequences. + * Introduce very simple manual page for update-rc.d-insserv. + * Make failing 'make clean' fatal, as it should always work. + * Change debconf template text to make it easier to understand. + + -- Petter Reinholdtsen Sun, 6 Jan 2008 09:37:43 +0100 + +insserv (1.09.0-13) unstable; urgency=low + + * Update patch 21_overrides to fix bug in override handling. Now a + header in a script or override file complete replaces previously + loaded headers. + * Add test to check and verify that override files in + /etc/insserv/override replaces headers in the scripts in + /etc/init.d/, and made previously failing loop breaking test + fatal, as it is working with the fixed override patch. + + -- Petter Reinholdtsen Fri, 4 Jan 2008 12:25:55 +0100 + +insserv (1.09.0-12) unstable; urgency=low + + * New patch 34_debian_fixedscripts to hardcode a few script sequence + numbers, to let the generated boot sequence be more like the + original one. Modified 40_nonsusescripts to no longer disable the + setlsb() function. This patch is not enabled by default, as it is + not obvious that it is a good idea. + * Added override files for hostname.dhcp and mountfix. + * Adjust override file for lvm2, to provide both lvm2 and lvm, to + make it easier until the lvm provide is dropped. + * Adjust override file for lvm2 to use reverse depend on checkfs, + mountall and umountfs to make it possible to drop lvm relations + from initscripts. + + -- Petter Reinholdtsen Fri, 4 Jan 2008 01:38:00 +0100 + +insserv (1.09.0-11) unstable; urgency=low + + * Added test to demonstrate the fake loop warning issue (bug + #458582). + * Implemented support for non-fatal tests in the testsuite. + * Added override file for dmraid, scsitools-pre.sh and scsitools.sh. + * Added patch 44_reportloopmemb to make loop reporting code in + insserv more helpful, and make sure to report the extended loop + output in update-bootsystem-insserv when refusing to switch to + dependency based boot (Closes: #458683). + * Move code to divert update-rc.d from postinst to + update-bootsystem-insserv, to make sure both ways to activate + insserv are equivalent. + * Extended check-initd-order to graph services with multiple + provides as two nodes that depend on each other, and which ahve + the same dependencies. + * Changed update-bootsystem-insserv to call 'reset' after looping + over packages postinst scripts, in case the terminal is messed up + as it is when I test it. + * Disabled check for reverse dependencies in check-initd-order. It + does not to work properly, and gave false error reports. + * Removed flag file /etc/update-rc.d-insserv and use the update-rc.d + diversion as the flag to detect if insserv is enabled. Adjustd + package removal and update-rc.d-insserv to reflect this. + * Added Vcs-Svn and Vcs-Browser info in control file, pointing to + the Debian packaging project. + + -- Petter Reinholdtsen Wed, 2 Jan 2008 18:41:31 +0100 + +insserv (1.09.0-10) unstable; urgency=low + + * Make sure to exit with an error code if it isn't safe to remove + the package. + + -- Petter Reinholdtsen Tue, 1 Jan 2008 21:12:24 +0100 + +insserv (1.09.0-9) unstable; urgency=low + + * Removed override file pptpd as the compiled in defaults are better + than the proposed overrides. + * Correct override file for laptop-netconf after checking the script + and the package. + * Added override file for racoon, and corrected override file for + setkey, after checking the scripts in the package. + * Try to make recovery routine more robust by not trying to run + non-existing postinst scripts, and only run postinst scripts for + packages with executable scripts in /etc/init.d/. + * Extended check-initd-order to check optional start dependencies, + and implement check of the shutdown sequence. + * Extended to check reverse dependencies too. + * Changed enabling code to refuse to convert to dependency based + boot sequence when obsolete init.d scripts are found, as these + tend to mess up the boot sequence. + * Changed enabling code to refuse to convert to dependency based + boot sequence if several scripts provide the same service. + * Added prerm code to refuse to be removed while enabled, to avoid + messing up the boot system completely. + + -- Petter Reinholdtsen Tue, 1 Jan 2008 21:08:14 +0100 + +insserv (1.09.0-8) unstable; urgency=low + + [ Petter Reinholdtsen ] + * Removed override files cpqarrayd, hotkey-setup and spamassassin as + they are equivalent with the defaults compiled into insserv. + * Removed override files courier-ldap, courier-authdaemon, + courier-imap-ssl and courier-imap, irqbalance and nethack-common + as the compiled in defaults are better than the proposed + overrides. + * Extended check-initd-order to graph reverse dependencies + (X-Start-Before and X-Stop-AFter). Draw reverse dependencies in + yellow. + * Added patch 11_revdepend fetched from a review copy of version + 1.10. Modified 20_override to cope with the change. Based on + changes from Werner Fink. + * Renamed patches 20_overrides to 21_overrides and + 44_path_at_runtime to 20_path_at_runtime, to prepare for Otavios + extensions. + + [ Otavio Salvador ] + * Extended patch 21_override to allow override path changing so the + unit test can use it. + + -- Petter Reinholdtsen Mon, 31 Dec 2007 19:26:00 +0100 + +insserv (1.09.0-7) unstable; urgency=low + + * Try to make it it easier to disabling the dependency based boot + sequencing by calling the postinst of all packages with init.d + scripts to register the scripts again. + * Extend check-initd-order to handle the virtual dependecy $all. + * Reword the debconf question to try to make it clearer and + easier to understand. + * Minor cleanup in irqbalance and atd override file, only depend + on $remote_fs, no need to also depend on $local_fs. + * Update check-initd-order to use the same default dependencies + ($remote_fs $syslog) and the same virtual dependencies as insserv + when generating dotty graphs. + * Update check-initd-order to draw left-to-right dotty graphs. + Based on tip from Frans Pop and Trent Buck. + * Update lvm2 override to stop before umountroot. + + -- Petter Reinholdtsen Sun, 30 Dec 2007 18:48:47 +0100 + +insserv (1.09.0-6) unstable; urgency=low + + * Update patch 20_overrides to let scripts without an LSB header + depend on $syslog as well as $remote_fs. + * Add test case to check that scripts without LSB header is ordered + after syslog + + -- Petter Reinholdtsen Sun, 30 Dec 2007 12:39:33 +0100 + +insserv (1.09.0-5) unstable; urgency=low + + * Update patch 44_path_at_runtime to include support for -c to point + to a local config file. It is required for a proper test suite. + * Fix typo in test suite and extend it to check more scenarios. + * Use local config file when running test suite. + * Change $syslog virtual facility to depend on either syslog or + sysklogd. The sysklogd script provide syslog and not the sysklogd + string that was requested in bug #324679. + * Update patch 31_debian_conf to list udev mountdevsubfs checkroot + checkfs console-screen as interactive scripts that should run + alone. + + -- Petter Reinholdtsen Sun, 30 Dec 2007 09:23:22 +0100 + +insserv (1.09.0-4) unstable; urgency=low + + * Update patch 20_overrides to add useful default values for scripts + without LSB header (Closes: #431697). + * Update patch 43_shutdown to handle scripts with both start and + stop levels. (Closes: #452462). + * New patch 44_path_at_runtime to add new option -p to make it + possible to replace /etc/init.d with another path for testing. + * Add script debian/run-testsuite to test the generated order, and + use it during the build. + + -- Petter Reinholdtsen Sat, 29 Dec 2007 16:00:31 +0100 + +insserv (1.09.0-3) unstable; urgency=low + + * Update patch 40_nosusescript to disable unused function setlsb(). + * Add sendsigs to the $remote_fs virtual facility, to make sure the + services depending on $remote_fs for the shutdown sequence are not + killed before their init.d script get a chance to stop them. + * New patch 43_shutdown to fix the handling of stop scripts and thus + the shutdown sequence (Closes: #452462). Thanks to Otavio + Salvador for help with debugging and part of the patch. + + -- Petter Reinholdtsen Sat, 29 Dec 2007 00:20:04 +0100 + +insserv (1.09.0-2) unstable; urgency=low + + * New patch 10_nosuse to disable SUSE specific build. This make + it easier to debug insserv. + * Update patch 40_nosusescript to remove SUSE-specific handling + of the halt and reboot script. + * Remove all override files for init.d scripts with LSB style + dependency headers (Closes: #386544). + * Update snmptrapfmt override file, making it more accurate. + * Updated standards-version from 3.7.2 to 3.7.3. No changes needed. + + -- Petter Reinholdtsen Tue, 25 Dec 2007 14:24:26 +0100 + +insserv (1.09.0-1) unstable; urgency=low + + * New upstream release. (Closes: #426091) + - Support X-Start-Before and X-Stop-After (Closes: #326120) + - Building with DEB_BUILD_OPTIONS=nostrip no longer strip the + binary. (Closes: #437210) + * Let /usr/share/insserv/check-initd-order read override files in + /etc/insserv/overrides/ just like insserv does. Patch from Arjan + Oosting. (Closes: #429398) + * Correct the dependencies for nbd-client and libnss-ldap. + * Add override file for spamassassin. + * Update watch file with new upstream URL. (Closes: #450044) + + -- Petter Reinholdtsen Sat, 17 Nov 2007 21:17:20 +0100 + +insserv (1.08.0-14) unstable; urgency=low + + * Correct the dependencies for hwclock.sh. + * Update libdevmapper*, raid2 and mdadm-raid by adding + module-init-tools as an alternative to modutils, and move + both from required-start to should-start, as either or both + might be available. (Closes: #432072) + + -- Petter Reinholdtsen Mon, 9 Jul 2007 13:40:36 +0200 + +insserv (1.08.0-13) unstable; urgency=low + + * Add override files for sysfsutils and hplip. + * Add cryptdisks-early as should-start to the lvm2 override + file (Closes: 429402) + + -- Petter Reinholdtsen Mon, 18 Jun 2007 17:32:50 +0100 + +insserv (1.08.0-12) unstable; urgency=low + + * Add override files for nbd-server and libdevmapper1.02.1. + * Update override files for atd, atftpd, discover, enable-nat, + keymap.sh, klogd, mplayer, networking, open-backdoor, + openbsd-inetd, report-reboot, rsync and start-wlan + based on the headers in the packages themselves. + * Add override file for lvm2 (Closes: #426104). + + -- Petter Reinholdtsen Sat, 26 May 2007 12:42:38 +0200 + +insserv (1.08.0-11) unstable; urgency=low + + * Add override file for timidity. + * Add override file for powernowd. + * Add override file for laptop-mode. + * Update override file for libnss-ldap. + + -- Petter Reinholdtsen Thu, 2 Nov 2006 13:36:10 +0100 + +insserv (1.08.0-10) unstable; urgency=low + + * Add override file for cpqarrayd. + * Add override file for libpam-devperm. + * Add override file for screen-cleanup. + + -- Petter Reinholdtsen Sat, 14 Oct 2006 21:00:31 +0200 + +insserv (1.08.0-9) unstable; urgency=low + + * Change bind9 override file to avoid dependency loop involving + $syslog->sysklogd->$named->bind9. Remove $syslog dependency and + insert $remote_fs dependency instead. Make the $network dependency + conditional to work when netbase is not installed. + * Add override file for resolvconf. + * Add override file for installation-report. + * Minor cleanup in nviboot override file, only depend on $remote_fs, no need + to also depend on $local_fs. + + -- Petter Reinholdtsen Sat, 7 Oct 2006 10:08:04 +0200 + +insserv (1.08.0-8) unstable; urgency=low + + * Add override files for festival, hotkey-setup and lisa. + * New patch 41_debiandefault to set the default runlevels for start (2345) + and stop (016) on Debian. + + -- Petter Reinholdtsen Sat, 16 Sep 2006 17:32:24 +0200 + +insserv (1.08.0-7) unstable; urgency=low + + * Remove override file console-screen.sh. The info is now present in the + file itself. + * Modify override file for lvm to document that it should stop just + before halt and reboot. + * Modify override file for exim4 to only conditional depend on $named. + * Rewrite check-initd-order to avoid the dependency on perl-modules, + to make it easier to run in systems with small disks. + * Remove override files for aumix, cfengine2, cryptdisk, hdparm, + ifupdown, ifupdown-clean, kdm, nfs-common, nfs-kernel-server, + pcmcia, portmap, sudo, udev, udev-mtab, x11-common, + xdebconfigurator. It is good enough in the scripts themselves + now. + * Modify override file for atd to avoid redundant dependencies and + drop runlevel 'S' from the stop list. Reported as bug #376780. + + -- Petter Reinholdtsen Thu, 14 Sep 2006 15:15:49 +0200 + +insserv (1.08.0-6) unstable; urgency=low + + * Minor change to the template text, explaining that the S* symlinks + are renamed to K* symlinks in rc0.d/ and rc6.d/. + * Correct override file for sysklogd and klogd. These should not + start in runlevel S, and should stop in runlevel 1. + * Add $syslog to the dependency list for openbsd-inetd, to make sure + it can log its start to syslog. Drop $local_fs, as it is a + dependency for $remote_fs. + * New patch debian/patches/40_nosusescript to avoid inserting the + 'single' script showing up in runlevel S, and also avoid fixing + the sequence number to the values used by SuSe. + * Correct override file for hotplug-net, it should depend on $local_fs. + * Correct override file for hotplug, it should stop before $local_fs. + * Modify patch 31_debian_conf to also list ifupdown as part of the + $network facility, to make $network available in runlevel 0 and 6. + * Try to make update-bootsystem-insserv more robust on restores. + Move conversion logs and related files to /var/lib/insserv. + + -- Petter Reinholdtsen Sun, 10 Sep 2006 20:17:15 +0200 + +insserv (1.08.0-5) unstable; urgency=low + + * New flag -k for check-initd-order to look at the stop sequence instead + of the start sequence. + * Correct override files for acpid, alsa, alsa-utils, apmd, + hwclockfirst.sh, ifupdown, modutils, networking, nullmailer, + openbsd-inetd, pcmcia, procps.sh, and update-hostname. + * Remove override files for bootlogd, bootmisc.sh, checkfs.sh, + checkroot.sh, glibc.sh, halt, hostname.sh, module-init-tools, + mountall.sh, mountdevsubfs.sh, mountnfs.sh, reboot, rmnologin, + sendsigs, single, stop-bootlogd, umountfs umountnfs.sh and urandom + as the scripts themselves now have correct dependency information + in them. + * With the current patches and dependency info, insserv generate + correct shutdown order. (Closes: #350188) + + -- Petter Reinholdtsen Sat, 9 Sep 2006 20:23:28 +0200 + +insserv (1.08.0-4) unstable; urgency=low + + * Change update-bootsystem-insserv to refuse to convert the boot + system if there are dependency loops. + * New patch 37_consistent_path to make more consistent log output. + * Adjust the the rules file to make sure we build using the compiler options + specified there. + * New patch 33_debian_localok making .local a valid ending, + to accept script names like 'rc.local'. + * New patch 38_debuginfo to improve the debug output. + * New patch 39_debianlvl.dpatch to handle rcS.d/ a bit better. + * Add override for mountdevsubfs.sh, documenting its + relation to udev. + * Add override for stop-bootlogd, documenting that it should come late, + after rmnologin. + * Make it easier to enable the dependency based boot system by + adding a fairly well hidden debconf question to activate it. + * Adjust the override files for dns-clean, hotplug, hotplug-net, + hwclock.sh, keymap.sh, libdevmapper1.00, libdevmapper1.01, + libdevmapper1.02, modutils, nviboot and procps.sh to make sure + they only start in runlevel S. + * Adjust override file for acpid, nstxd and nstxcd, to make sure + they are not started in runlevel S. + * Adjust override file for makedev and rmnologin, there is + no reason to add stop links for them. + * Remove 'S' from all override files listing it in should-stop. It + never make sense to add stop scripts in rcS.d/. + * Allow check-initd-order to continue even if one file is unreadable. + * Add override files for apt-index-watcher, vbesave, acpi-support + and libnss-ldap. + * Correct the definition of $remote_fs to include mountnfs, + mountnfs-bootclean and umountnfs. + * Correct the definition of $local_fs to include mountfs, + mountfs-bootclean and umountfs. + * Adjust the override file for openbsd-inetd, to make sure it start + after /usr/ is mounted. + + -- Petter Reinholdtsen Fri, 8 Sep 2006 19:14:15 +0200 + +insserv (1.08.0-3) unstable; urgency=low + + * Extend check-initd-order to accept a new argument -o, to not load + the override files. + + -- Petter Reinholdtsen Thu, 7 Sep 2006 11:59:17 +0200 + +insserv (1.08.0-2) unstable; urgency=low + + * New patch 35_fixunused removing incorrect 'unused' flagg from a + few functions, to avoid compile warning on s390. + * New patch 36_memleak fixing a minor memory leak. + * Updated override file for libdevmapper1.00. + * Added override file for libdevmapper1.02. + * Sync override files with the unstable init.d scripts for + alsa,alsa-utils, atd, bootlogd, bootmisc.sh, cfengine2, + checkfs.sh, checkroot.sh, console-screen.sh, cryptdisk, exim4, + fam, halt, hdparm, kdm, keymap.sh, makedev, module-init-tools, + mountall.sh, mountnfs.sh, networking, nfs-common, + nfs-kernel-server, pcmcia, portmap, pppd-dns, procps.sh, reboot, + rmnologin, single, sudo, udev, udev-mtab, umountfs, umountnfs.sh, + urandom and xdebconfigurator. I assume the package maintainer + know the scripts best, and use their values. + * Added override file for usplash. + * Modify update-bootsystem-insserv to report dependency loop + problems. (Closes: #386301) + * Add recommend on perl-modules. (Closes: #386300) + * Update standards-version to 2.7.2. No changes needed. + * Do not include 'klogd' in the $syslog facility, to avoid + dependency loop. + * Change mountvirtfs to mountdevsubfs in all override files, to + use the new name instead of the obsolete name. + * The keymap override should not depend on $syslog, and neither should + keymap.sh itself (bug #386338). + * Update 20_overrides.dpatch to new version of the source. + + -- Petter Reinholdtsen Thu, 7 Sep 2006 00:45:18 +0200 + +insserv (1.08.0-1) unstable; urgency=low + + * New upstream release. + * Correct name of logfile, moving the stderr redirect to the insserv + call. (Closes: #349494) + * Add code in update-bootsystem-insserv to convert all S* symlinks + in rc1.d and rc6.d to K* symlinks before insserv is executed. to + reflect the argument passed on to these scripts in debian. + Addresses part of bug #350188. + + -- Petter Reinholdtsen Sun, 1 Apr 2006 17:30:35 +0100 + +insserv (1.04.0-2) unstable; urgency=low + + * Modify 20_override.dpatch based on input from upstream author + Werner Fink, to add more error handling. + + -- Petter Reinholdtsen Fri, 11 Nov 2005 15:35:27 +0100 + +insserv (1.04.0-1) unstable; urgency=low + + * New upstream release. + - Start building without -DSUSE, to enable processing of *-stop headers. + * Updated upstream URL in copyright file to match the latest location. + * Remove 40_dryrunmore.dpatch, applied upstream. + * Remove 41_dryrun_msg.dpatch, applied upstream. + * Remove 50_cfgfilter.dpatch, applied upstream. + * Merged 20_overrides.dpatch and 25_overrides.dpatch into one patch + 20_overrides.dpatch. + * New 34_debian.dpatch modifying the paths from rc#.d/, getting + non-SUSE case working on Debian. + * New patch 30_non_suse.dpatch fixing segfault in the non-SUSE case. + * Updated init.d override files for hwclockfirst, ifupdown, + ifupdwon-clean, initrd-tools, keymap, networking, procps and + udev-mtab. + + -- Petter Reinholdtsen Thu, 10 Nov 2005 22:50:14 +0100 + +insserv (1.02.0-3) unstable; urgency=low + + * Added init.d override files for acct, apache2, snmpd and snmptrapfmt. + * Updated and corrected override file for alsa, apache, atd, cron, + gdm, gpsd, initrd-tools, udev-mtab and xdm. + * Wrote graphviz dotty graph generation support for check-init-order (-g). + * Updated README.Debian to reflect the current status in Debian, and + included some instructions on how to use this package. + * Documented in the override files which dependency information I've + reported to BTS. + * Add 'ntpdate' as a optional dependency for the $time virtual + facility, to make sure NTP update is done on machines without + their own NFS server + * Wrote manual page for update-bootsystem-insserv(8). + + -- Petter Reinholdtsen Thu, 10 Nov 2005 00:18:49 +0100 + +insserv (1.02.0-2) unstable; urgency=low + + * Added init.d override files for hibernate, mdadm-raid, start-wlan + and x11-common. + * Corrected sysklogd override file, to only provide sysklogd. + * Document BTS bug numbers in the override file for the init.d + dependency headers I've submitted to the package maintainer. + + -- Petter Reinholdtsen Wed, 5 Oct 2005 17:04:01 +0200 + +insserv (1.02.0-1) unstable; urgency=low + + * New upstream version. + - Rewritten to handle non-SuSe systems better. + - Patches 05_verbose_doc, 10_dryrun, and 50_lsb_shold_std removed, + as they are included upstream. + - Updated patch 40_dryrunmore to match new version, and extend it to + also cover SuSe code. + * Still building with -DSUSE as the new non-SuSe features are still + buggy. + * Changed download URL in copyright file to + . + * Removed rc and rcS, as a version of sysvinit + with equivalent patches is in sid and etch now. + * Added and updated init.d dependency info override files. + The provided dependencies is tested to work on my test machines + with 2.4 and 2.6 installs. (Closes: #325798) + * New script update-bootsystem-insserv to reorder + the boot scripts with a backup. + * Avoid initscripts with .dpkg* in the name. + (51_cfgfilter_dpkg.dpatch) (Closes: #326445) + * Add dependency on sysv-rc. (Closes: #329279) + + -- Petter Reinholdtsen Sat, 3 Sep 2005 13:18:51 +0200 + +insserv (1.00.8-5) unstable; urgency=low + + * Updated dependency info for (module-init-tools, modutils, raid2, mdadm) + * Added dependency override files (noflushd, laptop-net, whereami, pcscd) + + -- Petter Reinholdtsen Fri, 2 Sep 2005 09:21:25 +0200 + +insserv (1.00.8-4) unstable; urgency=low + + * Added dependecy override files (xdm, irqbalance). + * Updated dependency info for a few override files (devfsd, + discover, hotplug, hotplug-net, hwclock.sh, keymap.sh, rmnologin, + sudo, gdm, lvm, ntpdate, xfs, aumix, freevo, laptop-netconf, + report-reboot, open-backdoor). + * New patch to avoid warning about missing override files if the + init.d file already contain LSB tags. (25_override.dpatch) + * Correct header example in the insserv(8) manual page. + (50_lsb_should_std.dpatch) + + -- Petter Reinholdtsen Thu, 1 Sep 2005 22:24:51 +0200 + +insserv (1.00.8-3) unstable; urgency=low + + * Added dependecy override files (nullmailer, binfmt-support). + * Add suggests on bootchart, a great tool to debug the boot + sequence. + * New patch to get dryrun mode working also when /etc/rc.boot is + missing. (40_dryrunmore.dpatch) + * Added more information about the dangers of reorganizing the boot + sequence in README.Debian. + * Some package cleanup. + + -- Petter Reinholdtsen Fri, 30 Aug 2005 00:20:16 +0200 + +insserv (1.00.8-2) unstable; urgency=low + + * Updated and added dependecy override files. + * Added script check-initd-order, trying to check the current boot + sequence in debian based on the LSB headers present. + + -- Petter Reinholdtsen Fri, 26 Aug 2005 00:20:16 +0200 + +insserv (1.00.8-1) unstable; urgency=low + + * Initial Release. (Closes: #324926) + * Document the -v (--verbose) flag. (05_verbose_doc.dpatch) + * Implement new option -n (--dryrun). (10_dryrun.dpatch) + * Implement support for reading LSB init.d header info from override + files. (20_overrides.dpatch) + * Adjust some paths and avoid installing LSB install scripts to + match Debian policy. (30_debian.dpatch) + * Add README.Debian explaining how to test this. + + -- Petter Reinholdtsen Fri, 26 Aug 2005 00:19:16 +0200 diff --git a/debian/check-archive-initd-scripts b/debian/check-archive-initd-scripts new file mode 100644 index 0000000..343a718 --- /dev/null +++ b/debian/check-archive-initd-scripts @@ -0,0 +1,247 @@ +#!/usr/bin/perl +# +# Check the consistency of all init.d scripts in the archive. Run +# this on bellini.debian.org. + +use warnings; +use strict; +use File::Basename; + +my $warn = 1; + +my $basedir = "/org/lintian.debian.org/laboratory/binary"; + +my @scripts = @ARGV; +@scripts = <$basedir/*/init.d/*> unless (@scripts); + +my %scriptinfo; +my %provides; + +my @virts = qw($local_fs $remote_fs $syslog $time $named + $portmap $network $all + $mail-transport-agent $x-font-server + ); +my @harddepheaders = qw(required-start required-stop); +my @softdepheaders = qw(should-start + should-stop x-start-before x-stop-after); +my $lsbheaders = "Provides|Required-Start|Required-Stop|Default-Start|Default-Stop"; +my $optheaders = "x-start-before|x-stop-after|should-start|should-stop"; + +for my $virt (@virts) { + $provides{$virt} = ['insserv/etc/insserv.conf']; +} + +# Ignore obsolete scripts, as these are unlikely to cause problems. +for my $old (qw(glibc evms raid2 ldm sdm)) { + $provides{$old} = ['obsolete']; +} + +# First pass to load the database +for my $initdscript (@scripts) { + next if $initdscript =~ m%/rc|/rcS|/README%; + my %lsbinfo = parse_lsb_header($initdscript); + $scriptinfo{$initdscript} = \%lsbinfo; + next unless ($lsbinfo{'found'}); + + my %checked; + for my $provide (split(/[ ,\t]+/, $lsbinfo{provides})) { + if (exists $provides{$provide}) { + push(@{$provides{$provide}}, $initdscript) + } else { + $provides{$provide} = [$initdscript]; + } + $checked{$provide} = 1; + } +} + +for my $provide (sort keys %provides) { + if (1 < scalar @{$provides{$provide}}) { + my %script; + map { $script{basename($_)} = 1; } @{$provides{$provide}}; + if (1 < scalar keys %script) { + error(sprintf("scripts %s provide duplicate '%s'", + join(",", short_name(@{$provides{$provide}})), + $provide)); + } + } +} + +# Second pass, to see which dependencies are missing +for my $initdscript (@scripts) { + next unless ($scriptinfo{$initdscript}->{'found'}); + my $short = short_name($initdscript); + my %checked; + my @hardmissing = (); + for my $header (@harddepheaders) { + my $list = $scriptinfo{$initdscript}->{$header}; + next unless defined $list; + for my $facility (split(/[ ,\t]+/, $list)) { + next if exists $checked{$facility}; + $checked{$facility} = 1; + push(@hardmissing, $facility) + unless exists $provides{$facility}; + } + } + error("script $short depend on non-existing provides: " + . join(" ", @hardmissing)) if (@hardmissing); + my @softmissing = (); + for my $header (@softdepheaders) { + my $list = $scriptinfo{$initdscript}->{$header}; + next unless defined $list; + for my $facility (split(/[ ,\t]+/, $list)) { + next if exists $checked{$facility}; + $checked{$facility} = 1; + push(@softmissing, $facility) + unless exists $provides{$facility}; + } + } + warning("script $short relate to non-existing provides: " + . join(" ", @softmissing)) if (@softmissing); + + if (exists $checked{'$syslog'} + && $scriptinfo{$initdscript}->{'default-start'} =~ m/s/i) { + error("script $short depend on \$syslog and start from rcS.d/"); + } + if (!exists $checked{'$remote_fs'} + && !exists $checked{'$syslog'} + && $scriptinfo{$initdscript}->{'need_remove_fs'} + && $scriptinfo{$initdscript}->{'default-start'} =~ m/s/i) { + warning("script $short possibly missing dependency on \$remote_fs"); + } elsif (!exists $checked{'$local_fs'} + && !exists $checked{'$remote_fs'} + && !exists $checked{'$syslog'} + && $scriptinfo{$initdscript}->{'need_local_fs'} + && $scriptinfo{$initdscript}->{'default-start'} =~ m/s/i) { + warning("script $short possibly missing dependency on \$local_fs"); + } + + my %provided; + for my $provide (split(/[ ,\t]+/, + $scriptinfo{$initdscript}->{provides})) { + $provided{$provide} = 1; + if ($provide =~ m/\$/) { + error("script $short provide virtual facility $provide"); + } + } + + my $basename = basename($initdscript, ".sh"); + warning("script $short does not provide its own name") + unless exists $provided{$basename}; + + # Detect common problems with runlevel settings. + my @startrl = sort split(/\s+/, lc($scriptinfo{$initdscript}->{'default-start'})); + my @stoprl = sort split(/\s+/, lc($scriptinfo{$initdscript}->{'default-stop'})); + + # Scripts starting in rcS.d/ normally do not stop or only stop + # during hald and shutdown. + if ((array_equal(['s'], \@startrl) && array_equal([], \@stoprl)) + || ( array_equal(['s'], \@startrl) + && array_equal(['0','6'], \@stoprl))) { + # OK + } else { + # Most scripts either start in rcS.d, or in runlevels 2-5 + if (!array_equal(['2', '3', '4', '5'], \@startrl) && + !array_equal(['s'], \@startrl) && + (!array_equal([], \@startrl) && @stoprl)) { + warning("script $short does not start in the usual runlevels: ", + join(" ", @startrl)); + } + + # And most scripts stop in runlevel (1) runlevels (0, 1, 6), + # only starts or only stops in (0) or (6). + if (!array_equal(['0', '1', '6'], \@stoprl) && + !array_equal(['1'], \@stoprl) && + !array_equal(['0', '6'], \@stoprl) && + !(array_equal(['0'], \@stoprl) && !@startrl) && + !(array_equal(['6'], \@stoprl) && !@startrl) && + !(array_equal([], \@stoprl) && @startrl)) { + warning("script $short does not stop in the usual runlevels: ", + join(" ", @stoprl)); + } + } +} + +exit 0; + +sub parse_lsb_header { + my $initdscript = shift; + my $short = short_name($initdscript); + my %lsbinfo; + unless (open(INIT, "<", $initdscript)) { + error("script $short is unreadable"); + return (); + } + my $inheader = 0; + while () { +# print; + chomp; + if (m/^\#\#\# BEGIN INIT INFO\s*$/) { + $lsbinfo{'found'} = 1; + $inheader = 1; + } + $inheader = 0 if (m/\#\#\# END INIT INFO$/); + if ($inheader + && m/^\# ($lsbheaders|$optheaders):\s*(\S?.*)$/i) { +# print "$1\n"; + $lsbinfo{lc($1)} = $2; + } + s/\#.*$//; # Remove comments + $lsbinfo{'need_remove_fs'} = 1 if m%/usr/s?bin/%; + $lsbinfo{'need_local_fs'} = 1 if m%/var/%; + + # Detect the use of tools resting in /usr/ + $lsbinfo{'need_remove_fs'} = 1 if m%awk%; + $lsbinfo{'need_remove_fs'} = 1 if m%which%; + } + close(INIT); + + # Check that all the required headers are present + if (!$lsbinfo{'found'}) { + error("script $short is missing LSB header"); + } else { + for my $key (split(/\|/, lc($lsbheaders))) { + if (!exists $lsbinfo{$key}) { + error("script $short missing LSB keyword '$key'"); + } + } + } + return %lsbinfo +} + +sub short_name { + my @scripts; + for my $script ( @_ ) { + my $copy = $script; + $copy =~ s%$basedir/%%g; + push @scripts, $copy; + } + if (wantarray) { + return @scripts; + } else { + return $scripts[0]; + } +} + +sub array_equal { + my ($a1, $a2) = @_; + return 0 if (scalar @{$a1} != scalar @{$a2}); + + my $i = 0; + while ($i < scalar @{$a1}) { + return 0 if $a1->[$i] ne $a2->[$i]; + $i++; + } + return 1; +} + +sub info { + print "info: @_\n"; +} + +sub warning { + print "warning: @_\n" if $warn; +} + +sub error { + print "error: @_\n"; +} diff --git a/debian/check-initd-order b/debian/check-initd-order new file mode 100644 index 0000000..e7d0ef6 --- /dev/null +++ b/debian/check-initd-order @@ -0,0 +1,425 @@ +#!/usr/bin/perl +# +# Author: Petter Reinholdtsen +# Date: 2005-08-21 +# +# Read LSM init.d headers in SysV init.d scripts, and verify correct +# start order for all runlevels. It can also provide a graph. +# +# To generate a graph, run it like this +# +# check-initd-order -g > initorder.dotty && dotty initorder.dotty + +use strict; +use warnings; + +my $rcbase = "/etc"; + +my $overridepath = "/usr/share/insserv/overrides"; +my $hostoverridepath = "/etc/insserv/overrides"; + +my $debug = 0; +my $errors = 0; + +my %rcmap = + ( + 'B' => 'rc.boot', + 'S' => 'rcS.d', + '1' => 'rc1.d', + '2' => 'rc2.d', + '3' => 'rc3.d', + '4' => 'rc4.d', + '5' => 'rc5.d', + '6' => 'rc6.d', + ); + +my %sysmap; + +my %provideslist; +my %scriptorder; +my %opts; + +# Used to draw graphs +my %gotrevdeps; +my %allprovides; + +while($#ARGV >= 0 && ($_ = $ARGV[0]) =~ /^-/) { + shift @ARGV; + if (/^-([cdgko])$/) { $opts{$1}++; next } + if (/^-b$/) { $rcbase = shift; next } + if (/^-h|--help$/) { &usage; } + &usage("unknown option"); +} + +load_sysmap("$rcbase/insserv.conf"); + +$debug = $opts{'d'}; +my $useoverrides = $opts{'o'} ? 0 : 1; + +if ($opts{'g'}) { + graph_generate(); + exit 0; +} + +check_bootorder(); +exit $errors > 0 ? 1 : 0; + +sub usage { + print STDERR "check-initd-order: error: @_\n" if ($#_ >= 0); + print STDERR <) { + chomp; + s/\#.*$//; + next if m/^\s*$/; + if (m/^(\$\S+)\s+(\S.*\S*)\S*$/) { + my $virt = $1; + for my $dep (split(/\s+/, $2)) { + $dep =~ s/^\+//g; + $sysmap{$dep} = $virt; + } + } + } + close(CONF); +} + +sub graph_addnode { + my ($isstopseq, $lsbinforef) = @_; + my %lsbinfo = %{$lsbinforef}; + + unless ($lsbinfo{'provides'}) { + error "File ". $lsbinfo{'file'} . " is missing the provides header\n"; + $lsbinfo{'provides'} = $lsbinfo{'file'}; + $lsbinfo{'provides'} =~ s/^[SK]\d{2}//; + } + + my $key = $opts{'k'} ? 'stop' : 'start'; + my $revkey = $opts{'k'} ? 'stop-after' : 'start-before'; + my @provides = split(/\s+/, $lsbinfo{'provides'}); + for my $name (@provides) { + if (exists $sysmap{$name}) { + graph_addnode($isstopseq, + {'provides' => $sysmap{$name}, + "required-$key" => $name}); + } + } + + if (1 < @provides) { + my @providescopy = @provides; + my $lastprovide = shift @providescopy; + for my $provide (@providescopy) { + graph_addnode($isstopseq, + {'provides' => $lastprovide, + "required-$key" => $provide}); + graph_addnode($isstopseq, + {'provides' => $provide, + "required-$key" => $lastprovide}); + } + } + + for my $provide (@provides) { + my $provideesc = $provide; $provideesc =~ s/"/\\"/g; + my %deps = + ( + "required-$key" => 'blue', + "should-$key" => 'springgreen', + "$revkey" => 'yellow' + ); + + for $key (keys %deps) { + if (exists $lsbinfo{$key} && $lsbinfo{$key}) { + my @depends = split(/\s+/, $lsbinfo{$key}); + + my $dependonall = 0; + for my $pkg (@depends) { + $dependonall = 1 if ($pkg eq '$all'); + } + + for my $pkg (@depends) { + my $pkgesc = $pkg; $pkgesc =~ s/"/\\"/g; + my $color = $deps{$key}; + if ($revkey eq $key) { + print "\"$provideesc\" -> \"$pkgesc\"[color=$color] ;\n"; + $gotrevdeps{$pkg} = 1 unless $dependonall; + } else { + print "\"$pkgesc\" -> \"$provideesc\"[color=$color] ;\n"; + $gotrevdeps{$provide} = 1 unless $dependonall; + } + } + } + } + + print "\"$provideesc\" [shape=box];\n" unless $allprovides{$provide}; + $allprovides{$provide} = 1; + } +} + +sub graph_generate_mode { + my ($isstopseq) = @_; + my @dirs = $isstopseq ? $rcmap{6} : ($rcmap{S}, $rcmap{2}); + for my $rcdir (@dirs) { + chdir "$rcbase/$rcdir/."; + my @scripts = $isstopseq ? : ; + for my $script (@scripts) { + my $lsbinforef = load_lsb_tags("$rcbase/$rcdir/$script", + $useoverrides); + + unless (defined $lsbinforef) { + error "LSB header missing in $rcbase/$rcdir/$script\n"; + $script =~ s/^[SK]\d{2}//; + $lsbinforef = {'provides' => $script, + 'required-start' => '$remote_fs $syslog', + 'required-stop' => '$remote_fs $syslog'}; + } + graph_addnode($isstopseq, $lsbinforef); + } + } + # Mark all packages without any reverse dependencies as depending + # on $all + for my $provide (keys %allprovides) { + next unless (exists $gotrevdeps{$provide}); + my $lsbinforef = {'provides' => '$all', + 'required-start' => "$provide", + 'required-stop' => "$provide"}; + graph_addnode($isstopseq, $lsbinforef); + } +} + +sub graph_generate { + print "# Generating graph\n"; + print < $bootorder)) { + my $deporder; + if (exists $scriptorder{$tag}{$dep}) { + $deporder = $scriptorder{$tag}{$dep} + } else { + $deporder = exists $provideslist{$dep} ? $provideslist{$dep} : "?"; + } + error(sprintf("Incorrect order %s@%s %s %s%s\n", + $dep, $deporder, 'S' eq $tag ? '>' : '<', + $name, $order)); + } + } + } + } +} + +sub check_bootorder { + my $bootorder = 0; + my @dirs = $opts{'k'} ? $rcmap{6} : ($rcmap{S}, $rcmap{2}); + my @scripts; + for my $rcdir (@dirs) { + push(@scripts, $opts{'k'} ? <$rcbase/$rcdir/K*> : <$rcbase/$rcdir/S*>); + } + + if ($opts{'k'}) { + $scriptorder{'K'}{'$all'} = 1; + } else { + # Calculate script order for the script before the scripts + # with the last boot sequence number. + my $tmpbootorder = 0; + my $allorder = 0; + my $maxorder = 0; + my $maxbootorder = 0; + for my $scriptpath (@scripts) { + my $script = $scriptpath; + $script =~ s%^.*/([^/]+)$%$1%; + $tmpbootorder++; + my ($tag, $order, $name) = $script =~ m/^(.)(\d{2})(.+)$/; + if ($order > $maxorder) { + $allorder = $maxbootorder; + $maxbootorder = $tmpbootorder; + $maxorder = $order; + } + + my $lsbinforef = load_lsb_tags($scriptpath, + $useoverrides); + + if (exists $lsbinforef->{'provides'} + && $lsbinforef->{'provides'}) { + for my $provide (split(/\s+/, $lsbinforef->{'provides'})) { + $provideslist{$provide} = $order; + } + } else { + $provideslist{$script} = $order; + } + } + $scriptorder{'S'}{'$all'} = $allorder; + } + for my $scriptpath (@scripts) { + my $script = $scriptpath; + $script =~ s%^.*/([^/]+)$%$1%; + $bootorder++; + my ($tag, $order, $name) = $script =~ m/^(.)(\d{2})(.+)$/; + + $scriptorder{$tag}{$name} = $bootorder; + $scriptorder{$tag}{$sysmap{$name}} = $bootorder + if (exists $sysmap{$name}); + +# print "$script\n"; +# print "T: $tag O: $order N: $name\n"; + my $lsbinforef = load_lsb_tags($scriptpath, + $useoverrides); + + unless (defined $lsbinforef) { + error "LSB header missing in $scriptpath\n"; + next; + } + my %lsbinfo = %{$lsbinforef}; + + if (exists $lsbinfo{'provides'} && $lsbinfo{'provides'}) { + for my $provide (split(/\s+/, $lsbinfo{'provides'})) { + $scriptorder{$tag}{$provide} = $bootorder; + $scriptorder{$tag}{$sysmap{$provide}} = $bootorder + if (exists $sysmap{$provide}); + } + } else { + error "no LSB header provides value in script $scriptpath\n"; + } + + if ('S' eq $tag) { + check_deps($lsbinforef, $tag, $order, $bootorder, 'required-start', 1); + check_deps($lsbinforef, $tag, $order, $bootorder, 'should-start', 0); +# check_deps($lsbinforef, 'K', $order, $bootorder, 'start-before', 0); + } + if ('K' eq $tag) { + check_deps($lsbinforef, $tag, $order, $bootorder, 'required-stop', 1); + check_deps($lsbinforef, $tag, $order, $bootorder, 'should-stop', 0); +# check_deps($lsbinforef, 'S', $order, $bootorder, 'stop-after', 0); + } + } +} + +sub load_lsb_tags { + my ($initfile, $useoverrides) = @_; + my $lsbinforef = load_lsb_tags_from_file($initfile); + + if ($useoverrides) { + # Try override file + $initfile = readlink($initfile) if (-l $initfile); + my $basename = basename($initfile); + + # Only read shipped override file when initscript does not + # contain LSB tags. + if (! defined($lsbinforef) && -f "$overridepath/$basename") { + print STDERR "Override $overridepath/$basename\n" if $debug; + $lsbinforef = load_lsb_tags_from_file("$overridepath/$basename"); + } + + # Always read the host override in $hostoverridepath. + if (-f "$hostoverridepath/$basename") { + print STDERR "Override $hostoverridepath/$basename\n" if $debug; + $lsbinforef = load_lsb_tags_from_file("$hostoverridepath/$basename"); + } + + } + return $lsbinforef; +} + +sub load_lsb_tags_from_file { + my ($file) = @_; + print STDERR "Loading $file\n" if $debug; + ### BEGIN INIT INFO + # Provides: xdebconfigurator + # Required-Start: $syslog + # Required-Stop: $syslog + # Default-Start: 2 3 4 5 + # Default-Stop: 1 6 + # Short-Description: Genererate xfree86 configuration at boot time + # Description: Preseed X configuration and use dexconf to + # genereate a new configuration file. + ### END INIT INFO + unless (open(FILE, "<$file")) { + warn "error: Unable to read $file"; + return; + } + my $found = 0; + my ($provides, $requiredstart, $requiredstop, $shouldstart, $shouldstop); + my ($startbefore, $stopafter); + while () { + chomp; + $found = 1 if (m/\#\#\# BEGIN INIT INFO/); + next unless $found; + last if (m/\#\#\# END INIT INFO/); + + $provides = $1 if (m/^\# provides:\s+(\S*.*\S+)\s*$/i); + $requiredstart = $1 if (m/^\# required-start:\s+(\S*.*\S+)\s*$/i); + $requiredstop = $1 if (m/^\# required-stop:\s+(\S*.*\S+)\s*$/i); + $shouldstart = $1 if (m/^\# should-start:\s+(\S*.*\S+)\s*$/i); + $shouldstop = $1 if (m/^\# should-stop:\s+(\S*.*\S+)\s*$/i); + $startbefore = $1 if (m/^\# X-Start-Before:\s+(\S*.*\S+)\s*$/i); + $stopafter = $1 if (m/^\# X-Stop-After:\s+(\S*.*\S+)\s*$/i); + } + close(FILE); + + return undef unless ($found); + +# print "Provides: $provides\n" if $provides; + return { + 'provides' => $provides, + 'required-start' => $requiredstart, + 'required-stop' => $requiredstop, + 'should-start' => $shouldstart, + 'should-stop' => $shouldstop, + 'start-before' => $startbefore, + 'stop-after' => $stopafter, + 'file' => $file, + }; +} diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..1e8b314 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +6 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..6377523 --- /dev/null +++ b/debian/control @@ -0,0 +1,31 @@ +Source: insserv +Section: misc +Priority: optional +Maintainer: Rafal Krypa +X-Original-Maintainer: Petter Reinholdtsen +X-Original-Uploaders: Kel Modderman +Build-Depends: debhelper (>= 6.0.7), po-debconf, quilt +Standards-Version: 3.8.3 +DM-Upload-Allowed: yes +Homepage: http://ftp.suse.com/pub/projects/init/ +Vcs-Svn: svn://svn.debian.org/initscripts-ng/trunk/src/insserv +Vcs-Browser: http://svn.debian.org/wsvn/initscripts-ng/trunk/src/insserv/ + +Package: insserv +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Suggests: bootchart +Breaks: sysv-rc (<< 2.87dsf-3) +Description: Tool to organize boot sequence using LSB init.d script dependencies + The insserv program is used to update the order of symlinks in + /etc/rc?.d/ with sysv-rc based on dependencies specified in the + scripts themselves using LSB init.d script headers. + . + This allow each package maintainer to specify their init.d script + relation to other scripts and make it possible to detect and reject + script dependency loops as well as making sure all scripts start in + their intended order. + . + The program insserv in this package should be used with care and + together with the sysv-rc package, as using it incorrectly can lead + to an unbootable system. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..5d841a2 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,20 @@ +This package was debianized by Petter Reinholdtsen on +Sun, 21 Aug 2005 11:20:54 +0200. + +It was downloaded from + +Copyright Holder: Werner Fink and SuSE LINUX AG. + +License: + + Copyright 2000-2004 Werner Fink, 2000 SuSE GmbH Nuernberg, Germany, + 2003 SuSE Linux AG, Germany. + 2004 SuSE LINUX AG, 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. + +On Debian systems, a copy of the GNU General Public License version 2 +may be found in the file /usr/share/common-licenses/GPL-2. diff --git a/debian/dirs b/debian/dirs new file mode 100644 index 0000000..97b3b20 --- /dev/null +++ b/debian/dirs @@ -0,0 +1,6 @@ +etc/bash_completion.d +etc/insserv.conf.d +etc/insserv/overrides +usr/sbin +usr/share/insserv/overrides +var/lib/update-rc.d diff --git a/debian/docs b/debian/docs new file mode 100644 index 0000000..e845566 --- /dev/null +++ b/debian/docs @@ -0,0 +1 @@ +README diff --git a/debian/lintian-overrides b/debian/lintian-overrides new file mode 100644 index 0000000..d31810e --- /dev/null +++ b/debian/lintian-overrides @@ -0,0 +1 @@ +insserv: binary-without-manpage usr/sbin/update-bootsystem-insserv diff --git a/debian/make-testsuite b/debian/make-testsuite new file mode 100644 index 0000000..c4aec47 --- /dev/null +++ b/debian/make-testsuite @@ -0,0 +1,33 @@ +#!/bin/sh +# +# Extract key information from the current to try to generate a test +# suite script to demonstrate detected bugs. + +echo "cat <<'EOF' > \$tmpdir\$insconf" +grep -v '#' /etc/insserv.conf |grep -v '^$' +echo "EOF" + +for f in /etc/init.d/*; do + name=$(basename $f) + case $name in + README|rc|rcS|skeleton) + ;; + *) + echo "addscript $name < boot.crypto boot.localfs boot.rootfsck apache apache2 kdump ++ glibc udev console-screen keymap keyboard-setup console-setup cryptdisks cryptdisks-early checkfs-loop diff --git a/debian/patches/20_install_perms_fixup.patch b/debian/patches/20_install_perms_fixup.patch new file mode 100644 index 0000000..c3ac3c8 --- /dev/null +++ b/debian/patches/20_install_perms_fixup.patch @@ -0,0 +1,29 @@ +Purpose: Use correct permissions for installing /sbin/insserv and + /etc/insserv.conf +Authour: Kel Modderman +Fixes: - +Status: Not yet submitted upstream. + +Index: insserv/Makefile +=================================================================== +--- insserv.orig/Makefile 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/Makefile 2009-09-26 22:35:39.000000000 +0200 +@@ -41,14 +41,14 @@ + RM = rm -f + MKDIR = mkdir -p + RMDIR = rm -rf +- INSTBINFLAGS = -m 0700 ++ INSTBINFLAGS = -m 0755 + INSTBIN = install $(INSTBINFLAGS) +- INSTSRPFLAGS = -m 0700 ++ INSTSRPFLAGS = -m 0755 + INSTSRP = install $(INSTSRPFLAGS) +- INSTDOCFLAGS = -c -m 0444 ++ INSTDOCFLAGS = -c -m 0644 + INSTDOC = install $(INSTDOCFLAGS) + INSTCONFLAGS = -c -m 0644 +- INSTCON = install $(INSTDOCFLAGS) ++ INSTCON = install $(INSTCONFLAGS) + LINK = ln -sf + # + SDOCDIR = $(DESTDIR)/usr/share/man/man8 diff --git a/debian/patches/21_tests_suite_new_functions.patch b/debian/patches/21_tests_suite_new_functions.patch new file mode 100644 index 0000000..14c0f23 --- /dev/null +++ b/debian/patches/21_tests_suite_new_functions.patch @@ -0,0 +1,36 @@ +Purpose: Add some extra functions used by Debian test suite script +Authour: Kel Modderman +Fixes: - +Status: Should be sent upstream + +Index: insserv/tests/suite +=================================================================== +--- insserv.orig/tests/suite 2009-09-26 22:35:26.000000000 +0200 ++++ insserv/tests/suite 2009-09-26 22:35:39.000000000 +0200 +@@ -94,6 +94,12 @@ + $insserv $debug -c $insconf -p $initddir -o $overridedir -r $script + } + ++initdir_purge () ++{ ++ rm -rf ${initddir}/../rc*.d ${initddir} ++ mkdir -p ${initddir} ++} ++ + relpath () + { + local OLDIFS IFS +@@ -201,6 +207,13 @@ + chmod u+w,a+rx $script + } + ++remscript () ++{ ++ local scriptname=$1 ++ local script=${initddir}/$scriptname ++ rm -f $script ++} ++ + insertscript () + { + local scriptname=$1 diff --git a/debian/patches/30_deterministic_order.patch b/debian/patches/30_deterministic_order.patch new file mode 100644 index 0000000..5e52033 --- /dev/null +++ b/debian/patches/30_deterministic_order.patch @@ -0,0 +1,77 @@ +Purpose: Defend against undeterministic directory stream sequence + returned by readdir(3). Make sure script which is being + registered is processed before all others. +Fixes: #494514 +Status: Applied upstream. +--- +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:25.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:44.000000000 +0200 +@@ -2238,6 +2238,7 @@ + boolean del = false; + boolean defaults = false; + boolean ignore = false; ++ boolean loadarg = false; + + myname = basename(*argv); + +@@ -2305,7 +2306,9 @@ + argv += optind; + argc -= optind; + +- if (!argc && del) ++ if (argc) ++ loadarg = true; ++ else if (del) + error("usage: %s [[-r] init_script|init_directory]\n", myname); + + if (*argv) { +@@ -2490,17 +2493,45 @@ + /* + * 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); ++ for (;;) { + service_t * service = (service_t*)0; + char * token; + char * begin = (char*)0; /* hold start pointer of strings handled by strsep() */ + boolean hard = false; ++ boolean isarg = false; + uchar lsb = 0; + #if defined(DEBUG) && (DEBUG > 0) + int nobug = 0; + #endif + ++ if ((d = readdir(initdir)) == (struct dirent*)0) { ++ /* ++ * If first script in argument list was loaded in advance, then ++ * rewind the init.d/ directory stream and attempt to load all ++ * other scripts. ++ */ ++ if (loadarg) { ++ loadarg = false; ++ rewinddir(initdir); ++ continue; ++ } ++ break; ++ } ++ ++ isarg = chkfor(d->d_name, argv, argc); ++ ++ /* ++ * Load first script in argument list before all other scripts. This ++ * avoids problems with loading scripts in underterministic sequence ++ * returned by readdir(3). ++ */ ++ if (loadarg && !isarg) ++ continue; ++ if (loadarg && isarg && (curr_argc != 0)) ++ continue; ++ if (!loadarg && isarg && (curr_argc == 0)) ++ continue; ++ + if (*d->d_name == '.') + continue; + errno = 0; diff --git a/debian/patches/40_badboy_segfault.patch b/debian/patches/40_badboy_segfault.patch new file mode 100644 index 0000000..cd36055 --- /dev/null +++ b/debian/patches/40_badboy_segfault.patch @@ -0,0 +1,21 @@ +Purpose: Defend against corrupt or invalid scripts living in + /etc/rc[S0-6].d/ +Fixes: #493202 +Status: Acked by upstream. +--- +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:44.000000000 +0200 +@@ -1696,6 +1696,11 @@ + } + + lsb = scan_script_defaults(dfd, d->d_name, override_path, &name, true, ignore); ++ if (!name) { ++ warn("warning: script is corrupt or invalid: %s/%s%s\n", path, rcd, d->d_name); ++ continue; ++ } ++ + if (!script_inf.provides || script_inf.provides == empty) + script_inf.provides = xstrdup(ptr); + diff --git a/debian/patches/50_symlink_in_initddir.patch b/debian/patches/50_symlink_in_initddir.patch new file mode 100644 index 0000000..11ee33e --- /dev/null +++ b/debian/patches/50_symlink_in_initddir.patch @@ -0,0 +1,67 @@ +Purpose: Defend against symlinks in init.d/ to other scripts in init.d/ +Fixes: #485045 +Status: Work in progress. +--- +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:44.000000000 +0200 +@@ -2542,11 +2542,12 @@ + errno = 0; + + /* d_type seems not to work, therefore use (l)stat(2) */ +- if (xstat(dfd, d->d_name, &st_script) < 0) { ++ if (xlstat(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_ISLNK(st_script.st_mode) && !S_ISREG(st_script.st_mode)) || ++ !(S_IXUSR & st_script.st_mode)) + { + if (S_ISDIR(st_script.st_mode)) + continue; +@@ -2555,6 +2556,43 @@ + continue; + } + ++ /* ++ * Do extra sanity checking of symlinks in init.d/ dir, except if it ++ * is named reboot, as that is a special case on SUSE ++ */ ++ if (S_ISLNK(st_script.st_mode) && ((strcmp(d->d_name, "reboot") != 0))) ++ { ++ char * base; ++ char linkbuf[PATH_MAX+1]; ++ int linklen; ++ ++ linklen = xreadlink(dfd, d->d_name, linkbuf, sizeof(linkbuf)-1); ++ if (linklen < 0) ++ continue; ++ linkbuf[linklen] = '\0'; ++ ++ /* skip symbolic links to other scripts in this relative path */ ++ if (!(base = strrchr(linkbuf, '/'))) { ++ if (isarg) ++ warn("script %s is a symlink to another script, skipped!\n", ++ d->d_name); ++ continue; ++ } ++ ++ /* stat the symlink target and make sure it is a valid script */ ++ if (xstat(dfd, d->d_name, &st_script) < 0) ++ 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); diff --git a/debian/patches/60_all_keyword_start_only.patch b/debian/patches/60_all_keyword_start_only.patch new file mode 100644 index 0000000..dafea55 --- /dev/null +++ b/debian/patches/60_all_keyword_start_only.patch @@ -0,0 +1,22 @@ +Purpose: Prevent Required-Stop: $all from modifying start links +Fixes: #485307 +Status: Work in progress. +--- +--- a/insserv.c ++++ b/insserv.c +@@ -291,8 +291,13 @@ + break; + case '$': + if (strcasecmp(token, "$all") == 0) { +- serv->attr.flags |= SERV_ALL; +- break; ++ if (bit & REQ_KILL) { ++ /* $all has no effect on stop sort order */ ++ break; ++ } else { ++ serv->attr.flags |= SERV_ALL; ++ break; ++ } + } + /* Expand the `$' token recursively down */ + list_for_each(ptr, sysfaci_start) { diff --git a/debian/patches/61_interactive_keyword.patch b/debian/patches/61_interactive_keyword.patch new file mode 100644 index 0000000..3d85384 --- /dev/null +++ b/debian/patches/61_interactive_keyword.patch @@ -0,0 +1,132 @@ +Purpose: Add support for a X-Interactive keyword to avoid specifying it in insserv.conf +Fixes: #458224 +Status: Work in progress. +--- + +Index: insserv/insserv.8.in +=================================================================== +--- insserv.orig/insserv.8.in 2009-09-26 22:35:25.000000000 +0200 ++++ insserv/insserv.8.in 2009-09-26 22:35:43.000000000 +0200 +@@ -76,6 +76,7 @@ + # 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 ...] ++ # X-Interactive: true + # Short-Description: single_line_description + # Description: multiline_description + ### END INIT INFO +@@ -117,6 +118,11 @@ + these tags is stopped. + @@END_SUSE@@ + .PP ++The optional X\-Interactive keyword implies that the script using this ++keyword should be started alone in a concurrent boot configuration ++because it interact with the user at the console. Only the value ++`true' is recogniced. All other are ignored. ++.PP + The optional + .B X\-Start\-Before + keyword implies that the script using this keyword +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:43.000000000 +0200 +@@ -97,6 +97,7 @@ + #define DEFAULT_START DEFAULT START VALUE + #define DEFAULT_STOP DEFAULT STOP VALUE + #define DESCRIPTION COMM "description" VALUE ++#define INTERACTIVE COMM "x-interactive" VALUE + + /* System facility search within /etc/insserv.conf */ + #define EQSIGN "([[:blank:]]*[=:][[:blank:]]*|[[:blank:]]+)" +@@ -133,6 +134,7 @@ + char *default_start; + char *default_stop; + char *description; ++ char *interactive; + } attribute((aligned(sizeof(char*)))) lsb_t; + + /* Search results points here */ +@@ -147,6 +149,7 @@ + regex_t def_start; + regex_t def_stop; + regex_t desc; ++ regex_t interact; + } attribute((aligned(sizeof(regex_t)))) reg_t; + + typedef struct creg_struct { +@@ -1132,6 +1135,7 @@ + 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); ++ regcompiler(®.interact, INTERACTIVE, REG_EXTENDED|REG_ICASE|REG_NEWLINE); + } + + static inline void scan_script_reset(void) attribute((always_inline)); +@@ -1147,6 +1151,7 @@ + xreset(script_inf.default_start); + xreset(script_inf.default_stop); + xreset(script_inf.description); ++ xreset(script_inf.interactive); + } + + #define FOUND_LSB_HEADER 0x01 +@@ -1177,6 +1182,7 @@ + #define default_start script_inf.default_start + #define default_stop script_inf.default_stop + #define description script_inf.description ++#define interactive script_inf.interactive + + info("Loading %s\n", path); + +@@ -1273,6 +1279,14 @@ + description = empty; + } + ++ if (!interactive && regexecutor(®.interact, COMMON_ARGS) == true) { ++ if (val->rm_so < val->rm_eo) { ++ *(pbuf+val->rm_eo) = '\0'; ++ interactive = xstrdup(pbuf+val->rm_so); ++ } else ++ interactive = empty; ++ } ++ + /* Skip scanning below from LSB magic end */ + if ((end = strstr(buf, "### END INIT INFO"))) + break; +@@ -1341,6 +1355,7 @@ + #undef default_start + #undef default_stop + #undef description ++#undef interactive + return ret; + } + +@@ -1503,6 +1518,7 @@ + regfree(®.def_start); + regfree(®.def_stop); + regfree(®.desc); ++ regfree(®.interact); + } + + static struct { +@@ -1781,6 +1797,9 @@ + if (script_inf.stop_after && script_inf.stop_after != empty) { + reversereq(service, REQ_SHLD|REQ_KILL, script_inf.stop_after); + } ++ if (script_inf.interactive && 0 == strcmp(script_inf.interactive, "true")) { ++ service->attr.flags |= SERV_INTRACT; ++ } + } + + if (name) +@@ -2881,6 +2900,9 @@ + if (script_inf.should_stop && script_inf.should_stop != empty) { + rememberreq(service, REQ_SHLD|REQ_KILL, script_inf.should_stop); + } ++ if (script_inf.interactive && 0 == strcmp(script_inf.interactive, "true")) { ++ service->attr.flags |= SERV_INTRACT; ++ } + } + + if (script_inf.start_before && script_inf.start_before != empty) { diff --git a/debian/patches/62_upstart_job.patch b/debian/patches/62_upstart_job.patch new file mode 100644 index 0000000..2c0570e --- /dev/null +++ b/debian/patches/62_upstart_job.patch @@ -0,0 +1,170 @@ +Purpose: Add support for upstart jobs. +Fixes: #547235 +Status: Work in progress, not submitted upstream yet. +--- + +Index: insserv/insserv.8.in +=================================================================== +--- insserv.orig/insserv.8.in 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.8.in 2009-09-26 22:35:42.000000000 +0200 +@@ -266,6 +266,10 @@ + .BR \-f ,\ \-\-force + Ignore if a required service is missed. + .TP ++.BR \-u\ ,\ \-\-upstart-job\ ++Path to replace existing upstart job path. (default path is ++.IR /lib/init/upstart-job ). ++.TP + .BR \-h ,\ \-\-help + Print out short usage message. + .PP +@@ -339,6 +343,12 @@ + name as the boot or init script in the directory + .IR /etc/insserv/overrides/ . + .\" ++.SH UPSTART JOB COMPATIBILITY ++To allow upstart jobs to work as init.d scripts, insserv will ++recognize a symlink from path/to/init.d/script to ++/lib/init/upstart-job as upstart jobs, and instead of reading the ++header from the file will run the script with the argument lsb-header ++to get the script header. + .SH EXIT CODES + The exit codes have the following conditions: + .RS 7 +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:43.000000000 +0200 +@@ -70,6 +70,8 @@ + # define INSCONF "/etc/insserv.conf" + #endif + ++const char *upstartjob_path = "/lib/init/upstart-job"; ++ + /* + * For a description of regular expressions see regex(7). + */ +@@ -1154,6 +1156,43 @@ + xreset(script_inf.interactive); + } + ++static char *is_upstart_job_recursive(const char *path, ++ const char *basenamestr) ++{ ++ struct stat statbuf; ++ if (-1 == lstat(path, &statbuf)) { ++ return 0; ++ } ++ if (S_ISLNK(statbuf.st_mode)) { ++ char buf[2048]; ++ int len = readlink(path, buf, sizeof(buf)-1); ++ if (0 < len) { ++ buf[len] = '\0'; ++ if (0 == strcmp(buf, upstartjob_path)) { ++ /* upstart job, return base name of original symlink */ ++ return strdup(basenamestr); ++ } else ++ return is_upstart_job_recursive(buf, basenamestr); ++ } ++ } ++ return 0; ++} ++ ++/* ++ * return name of upstart job if the script is a symlink to ++ * /lib/init/upstart-job, or NULL if path do not point to an ++ * upstart job. ++ */ ++static char* is_upstart_job(const char *path) ++{ ++ ++ char *basenamestr = basename(path); /* GNU basename */ ++ char *retval = is_upstart_job_recursive(path, basenamestr); ++ if (retval) ++ info("script '%s' is upstart job\n", basenamestr); ++ return retval; ++} ++ + #define FOUND_LSB_HEADER 0x01 + #define FOUND_LSB_DEFAULT 0x02 + #define FOUND_LSB_OVERRIDE 0x04 +@@ -1170,7 +1209,8 @@ + char *pbuf = buf; + FILE *script; + uchar ret = 0; +- int fd; ++ int fd = -1; ++ char *upstart_job = NULL; + + #define provides script_inf.provides + #define required_start script_inf.required_start +@@ -1186,12 +1226,23 @@ + + 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 (NULL != (upstart_job = is_upstart_job(path))) { ++ char cmd[2048]; ++ int len; ++ len = snprintf(cmd, sizeof(cmd), ++ "%s %s lsb-header", upstartjob_path, upstart_job); ++ if (len < 0 || sizeof(cmd) == len) ++ error("snprintf: insufficient buffer for %s\n", path); ++ if ((FILE*)0 == (script = popen(cmd, "r"))) ++ error("popen(%s): %s\n", path, strerror(errno)); ++ } else { ++ 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); ++ (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 +@@ -1303,7 +1354,12 @@ + (void)posix_fadvise(fd, 0, 0, POSIX_FADV_NOREUSE); + #endif + +- fclose(script); ++ if (upstart_job) { ++ pclose(script); ++ free(upstart_job); ++ upstart_job = 0; ++ } else ++ fclose(script); + + if (begin && end) + ret |= FOUND_LSB_HEADER; +@@ -2224,6 +2280,7 @@ + {"force", 0, (int*)0, 'f'}, + {"path", 1, (int*)0, 'p'}, + {"override",1, (int*)0, 'o'}, ++ {"upstart-job",1, (int*)0, 'u'}, + {"help", 0, (int*)0, 'h'}, + { 0, 0, (int*)0, 0 }, + }; +@@ -2277,7 +2334,7 @@ + for (c = 0; c < argc; c++) + argr[c] = (char*)0; + +- while ((c = getopt_long(argc, argv, "c:dfrhvno:p:", long_options, (int *)0)) != -1) { ++ while ((c = getopt_long(argc, argv, "c:dfrhvno:p:u:", long_options, (int *)0)) != -1) { + size_t l; + switch (c) { + case 'c': +@@ -2317,6 +2374,11 @@ + override_path = optarg; + set_override = true; + break; ++ case 'u': ++ if (optarg == (char*)0 || *optarg == '\0') ++ goto err; ++ upstartjob_path = optarg; ++ break; + case '?': + err: + error("For help use: %s -h\n", myname); diff --git a/debian/patches/70_req_start_all_depends.patch b/debian/patches/70_req_start_all_depends.patch new file mode 100644 index 0000000..2144003 --- /dev/null +++ b/debian/patches/70_req_start_all_depends.patch @@ -0,0 +1,30 @@ +Purpose: Correct dependency information written to .depend.* files + for scripts which declare Required-Start: $all +Fixes: nil +Status: Applied upstream. +--- +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:42.000000000 +0200 +@@ -776,9 +776,6 @@ + continue; + #endif /* not MINIMAL_RULES */ + +- if (list_empty(&serv->sort.req)) +- continue; +- + if (serv->start->lvl & LVL_BOOT) + out = boot; + else +@@ -820,6 +817,10 @@ + fprintf(out, " %s", name); + } + } else { ++ ++ if (list_empty(&serv->sort.req)) ++ continue; ++ + np_list_for_each(pos, &serv->sort.req) { + req_t * req = getreq(pos); + service_t * dep = req->serv; diff --git a/debian/patches/71_complete_makefile.patch b/debian/patches/71_complete_makefile.patch new file mode 100644 index 0000000..7b13a54 --- /dev/null +++ b/debian/patches/71_complete_makefile.patch @@ -0,0 +1,56 @@ +Purpose: Make sure the .depend.* files have complete dependencies when + recursive virtual facilities are used. +Fixes: #534526 +Status: From upstream. +--- +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:42.000000000 +0200 +@@ -2109,33 +2109,26 @@ + 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); ++ if (*deep > 10) { ++ warn("The nested level of the system facilities in the insserv.conf file(s) is to large\n"); ++ goto out; + } ++ (*deep)++; ++ expand_faci(tmp, head, deep); ++ (*deep)--; ++ } else if (*deep > 0) { ++ repl_t *restrict subst; ++ if (posix_memalign((void*)&subst, sizeof(void*), alignof(repl_t)) != 0) ++ error("%s", strerror(errno)); ++ insert(&subst->r_list, head->prev); ++ subst->r[0] = rnxt->r[0]; ++ (*subst->r[0].ref) = 1; + } + } + out: +- (*deep)--; + return; + } + diff --git a/debian/patches/80_manual_warnings.patch b/debian/patches/80_manual_warnings.patch new file mode 100644 index 0000000..176780d --- /dev/null +++ b/debian/patches/80_manual_warnings.patch @@ -0,0 +1,114 @@ +Purpose: Fix format warnings of manual page +Fixes: lintian - manpage-has-errors-from-man +Status: Not yet submitted upstream. +--- +Index: insserv/insserv.8.in +=================================================================== +--- insserv.orig/insserv.8.in 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.8.in 2009-09-26 22:35:41.000000000 +0200 +@@ -12,11 +12,9 @@ + @@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 +@@ -35,9 +33,9 @@ + .RB [ \-c\ ] + .RB [ \-p\ ] + @@BEGIN_SUSE@@ +-.RI [[ / ] path/to/init.d/ ] script [ ,start= [ ,\ ... ] ++.RI [[ / ] path/to/init.d/ ] script [ ,start= ] + @@ELSE_SUSE@@ +-.RI [[ / ] path/to/init.d/ ] script [ ,start= [ ,\ ... ] ,stop= [ ,\ ... ]] ++.RI [[ / ] path/to/init.d/ ] script [ ,start= ,stop= ] + @@END_SUSE@@ + .PP + .B insserv +@@ -129,7 +127,7 @@ + should be started + .B before + the specified service names. +-Wereas the optional ++Whereas the optional + .B X\-Stop\-After + keyword implies that the script using this keyword + should be stopped +@@ -223,7 +221,7 @@ + a passphrase or password input during boot + or runlevel change. + .P +-Beside the defined ++In addition to the defined + .B System Facilities + in the configuration file + .IR /etc/insserv.conf , +@@ -246,8 +244,8 @@ + directory. Useful for testing. + .TP + .BR \-o\ ,\ \-\-override\ +-Path to replace existing LSB comment headers with the comment +-headers found in this path (default path is ++LSB comment headers found in this path will override existing ++LSB comment headers of scripts in the init.d directory (default path is + .IR /etc/insserv/overrides/ ). + .TP + .BR \-p\ ,\ \-\-path\ +@@ -260,7 +258,7 @@ + Remove the listed scripts from all runlevels. + .TP + .BR \-d ,\ \-\-default +-Use default runlevels a defined in the scripts. ++Use default runlevels as defined in the scripts. + This may restore an edited runlevel link scheme. + .TP + .BR \-f ,\ \-\-force +@@ -307,17 +305,16 @@ + For the runlevels the information found in + the script is used. + .TP +-.RI [[ / ] path/to/init.d/ ] script [ ,start= [ , ]]\ ... ++.RI [[ / ] path/to/init.d/ ] script [ ,start= ] + 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 ,\ ,\ ... ++.BR lvl1 ,\ lvl2 ,\ ... + are the known runlevels explained above. + The extension +-.IR ,stop= [ , ]] +-is possible ++.IR ,stop= + @@BEGIN_SUSE@@ + is possible but ignored on SuSE Linux. + @@ELSE_SUSE@@ +@@ -334,9 +331,9 @@ + .\" + .SH OVERRIDES + Beside using the extensions +-.IR ,start= [ , ]] ++.IR ,start= + and +-.IR ,stop= [ , ]] ++.IR ,stop= + 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 +@@ -395,7 +392,9 @@ + .sp 1 + will be ignored. + .SH BUGS +-Boot script sometimes misses comments. ++Boot scripts sometimes lack a LSB comment header. Contact a package ++maintainer or developer of the software which provides the script to ++have a LSB comment header added to it. + .SH FILES + .TP + .I /etc/insserv.conf diff --git a/debian/patches/81_lessverbose.patch b/debian/patches/81_lessverbose.patch new file mode 100644 index 0000000..e8ed476 --- /dev/null +++ b/debian/patches/81_lessverbose.patch @@ -0,0 +1,157 @@ +Purpose: Reduce verbosity level (drop Loading... messages) +Fixes: - +Status: Not yet submitted upstream. +--- + +Index: insserv/listing.h +=================================================================== +--- insserv.orig/listing.h 2009-09-26 22:35:25.000000000 +0200 ++++ insserv/listing.h 2009-09-26 22:35:39.000000000 +0200 +@@ -283,7 +283,7 @@ + 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 void info (int level, const char *restrict fmt, ...) attribute((format(printf,2,3))); + 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); +@@ -312,23 +312,23 @@ + (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); })) ++ info(1, "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); })) ++ info(1, "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); })) ++ info(1, "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); })) ++ info(1, "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); })) +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:41.000000000 +0200 +@@ -114,8 +114,8 @@ + /* The main line buffer if unique */ + static char buf[LINE_MAX]; + +-/* When to be verbose */ +-static boolean verbose = false; ++/* When to be verbose, and what level of verbosity */ ++static int verbose = 0; + + /* When to be verbose */ + static boolean dryrun = false; +@@ -690,9 +690,9 @@ + + if (dryrun) { + #ifdef USE_KILL_IN_BOOT +- info("dryrun, not creating .depend.boot, .depend.start, .depend.halt, and .depend.stop\n"); ++ info(1, "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"); ++ info(1, "dryrun, not creating .depend.boot, .depend.start, and .depend.stop\n"); + #endif /* not USE_KILL_IN_BOOT */ + return; + } +@@ -707,8 +707,8 @@ + return; + } + +- info("creating .depend.boot\n"); +- info("creating .depend.start\n"); ++ info(1, "creating .depend.boot\n"); ++ info(1, "creating .depend.start\n"); + + lsort('S'); /* Sort into start order, set new sorder */ + +@@ -874,9 +874,9 @@ + return; + } + +- info("creating .depend.halt\n"); ++ info(1, "creating .depend.halt\n"); + #endif /* USE_KILL_IN_BOOT */ +- info("creating .depend.stop\n"); ++ info(1, "creating .depend.stop\n"); + + lsort('K'); /* Sort into stop order, set new korder */ + +@@ -1014,9 +1014,9 @@ + /* + * Print message when verbose is enabled + */ +-void info(const char *fmt, ...) { ++void info(int level, const char *fmt, ...) { + va_list ap; +- if (!verbose) ++ if (level > verbose) + goto out; + va_start(ap, fmt); + _logger(fmt, ap); +@@ -1062,7 +1062,7 @@ + + if (stat(rcpath, &st) < 0) { + if (errno == ENOENT) { +- info("creating directory '%s'\n", rcpath); ++ info(1, "creating directory '%s'\n", rcpath); + if (!dryrun) + mkdir(rcpath, (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)); + } else +@@ -1190,7 +1190,7 @@ + char *basenamestr = basename(path); /* GNU basename */ + char *retval = is_upstart_job_recursive(path, basenamestr); + if (retval) +- info("script '%s' is upstart job\n", basenamestr); ++ info(2, "script '%s' is upstart job\n", basenamestr); + return retval; + } + +@@ -1225,7 +1225,7 @@ + #define description script_inf.description + #define interactive script_inf.interactive + +- info("Loading %s\n", path); ++ info(2, "Loading %s\n", path); + + if (NULL != (upstart_job = is_upstart_job(path))) { + char cmd[2048]; +@@ -1882,7 +1882,7 @@ + regmatch_t subloc[SUBCONFNUM], *val = (regmatch_t*)0; + FILE *conf; + +- info("Loading %s\n", file); ++ info(2, "Loading %s\n", file); + + do { + const char * fptr = file; +@@ -2347,10 +2347,10 @@ + ignore = true; + break; + case 'v': +- verbose = true; ++ verbose ++; + break; + case 'n': +- verbose = true; ++ verbose ++; + dryrun = true; + break; + case 'p': diff --git a/debian/patches/82_loop_exit_msg.patch b/debian/patches/82_loop_exit_msg.patch new file mode 100644 index 0000000..2c8dd66 --- /dev/null +++ b/debian/patches/82_loop_exit_msg.patch @@ -0,0 +1,20 @@ +Purpose: Make message printed when loops are detected look more like + the messages printed when other errors are detected ("exiting + now!"), to make it easier for piuparts to discover these errors too. +Fixes: - +Status: Not yet submitted upstream. +--- + +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:41.000000000 +0200 +@@ -3250,7 +3250,7 @@ + */ + follow_all(); + if (is_loop_detected() && !ignore) +- error("exiting without changing boot order!\n"); ++ error("exiting now without changing boot order!\n"); + + /* + * Be sure that interactive scripts are the only member of diff --git a/debian/patches/90_no_runlevel_spec_for_debian.patch b/debian/patches/90_no_runlevel_spec_for_debian.patch new file mode 100644 index 0000000..bf145eb --- /dev/null +++ b/debian/patches/90_no_runlevel_spec_for_debian.patch @@ -0,0 +1,33 @@ +Purpose: Debian runlevels are a bit different to SUSE. +Fixes: #500542 +Status: Not yet submitted upstream. +--- +Index: insserv/insserv.8.in +=================================================================== +--- insserv.orig/insserv.8.in 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.8.in 2009-09-26 22:35:39.000000000 +0200 +@@ -143,6 +143,7 @@ + @@ELSE_SUSE@@ + directories. + @@END_SUSE@@ ++@@BEGIN_SUSE@@ + Known runlevels are: + .sp 1 + .in +1l +@@ -154,15 +155,12 @@ + \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 ++@@END_SUSE@@ + .PP + .B insserv + scans for diff --git a/debian/patches/91_kfreebsd_nofadvice.patch b/debian/patches/91_kfreebsd_nofadvice.patch new file mode 100644 index 0000000..ec8a447 --- /dev/null +++ b/debian/patches/91_kfreebsd_nofadvice.patch @@ -0,0 +1,22 @@ +Purpose: Get insserv building on kfreebsd, missing the argument values for posix_fadvise(). +Fixes: #? +Status: Not yet submitted upstream. +--- +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:40.000000000 +0200 +@@ -40,6 +40,13 @@ + #endif /* USE_RPMLIB */ + #include "listing.h" + ++#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600 ++/* kfreebsd fail to provide working posix_fadvise */ ++# ifndef POSIX_FADV_SEQUENTIAL ++# define posix_fadvise(fd, off, len, adv) (-1) ++# endif ++#endif ++ + #ifdef SUSE + # define DEFAULT_START_LVL "3 5" + # define DEFAULT_STOP_LVL "3 5" diff --git a/debian/patches/92_m68k_alignment.patch b/debian/patches/92_m68k_alignment.patch new file mode 100644 index 0000000..ef4fe3c --- /dev/null +++ b/debian/patches/92_m68k_alignment.patch @@ -0,0 +1,20 @@ +Purpose: Get insserv building on m68k, dropping some problematic + alignments (error: requested alignment is not a power of 2) +Fixes: #493637 +Status: Not yet submitted upstream. +--- +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:40.000000000 +0200 +@@ -131,6 +131,10 @@ + static boolean set_override = false; + static boolean set_insconf = false; + ++#ifdef __m68k__ /* Fix #493637 */ ++# define aligned(a) ++#endif ++ + /* Search results points here */ + typedef struct lsb_struct { + char *provides; diff --git a/debian/patches/93_hurd_no_path_max.patch b/debian/patches/93_hurd_no_path_max.patch new file mode 100644 index 0000000..bad0d1a --- /dev/null +++ b/debian/patches/93_hurd_no_path_max.patch @@ -0,0 +1,19 @@ +Purpose: Try to get insserv building on hurd, by faking a PATH_MAX value. +Status: Not yet submitted upstream. +--- +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:40.000000000 +0200 +@@ -1427,6 +1427,11 @@ + return ret; + } + ++#ifndef PATH_MAX ++/* for example hurd. Should really dynamically aligh the buffer. */ ++# define PATH_MAX 1024 ++#endif ++ + /* + * Follow symlinks, return the basename of the file pointed to by + * symlinks or the basename of the current path if no symlink. diff --git a/debian/patches/94_v1_12_2.patch b/debian/patches/94_v1_12_2.patch new file mode 100644 index 0000000..7b6c970 --- /dev/null +++ b/debian/patches/94_v1_12_2.patch @@ -0,0 +1,82 @@ +Patch from upstream to detect and reject loops in virtual +facilities (#541613) and warn about indirect dependencies to $all. + +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:39.000000000 +0200 +@@ -233,6 +233,7 @@ + typedef struct repl { + list_t r_list; + string_t r[1]; ++ ushort flags; + } __align repl_t; + #define getrepl(arg) list_entry((arg), struct repl, r_list) + +@@ -1946,6 +1947,7 @@ + if (posix_memalign((void*)&subst, sizeof(void*), alignof(repl_t)) != 0) + error("%s", strerror(errno)); + insert(&subst->r_list, r_list->prev); ++ subst->flags = 0; + r = &subst->r[0]; + if (posix_memalign((void*)&r->ref, sizeof(void*), alignof(typeof(r->ref))+strsize(token)) != 0) + error("%s", strerror(errno)); +@@ -1975,6 +1977,7 @@ + error("%s", strerror(errno)); + insert(&subst->r_list, r_list->prev); + r = &subst->r[0]; ++ subst->flags = 0; + if (posix_memalign((void*)&r->ref, sizeof(void*), alignof(typeof(r->ref))+strsize(token)) != 0) + error("%s", strerror(errno)); + *r->ref = 1; +@@ -2127,13 +2130,19 @@ + + list_for_each_safe(tmp, safe, ptr) { + repl_t * rnxt = getrepl(tmp); ++ if (rnxt->flags & 0x0001) { ++ error("Loop detected during expanding system facilities in the insserv.conf file(s): %s\n", ++ rnxt->r[0].name); ++ } + if (*rnxt->r[0].name == '$') { + if (*deep > 10) { + warn("The nested level of the system facilities in the insserv.conf file(s) is to large\n"); + goto out; + } + (*deep)++; ++ rnxt->flags |= 0x0001; + expand_faci(tmp, head, deep); ++ rnxt->flags &= ~0x0001; + (*deep)--; + } else if (*deep > 0) { + repl_t *restrict subst; +@@ -2154,9 +2163,12 @@ + 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 == '$') { ++ repl_t * tmp = getrepl(rlist); ++ if (*tmp->r[0].name == '$') { + int deep = 0; ++ tmp->flags |= 0x0001; + expand_faci(rlist, rlist, &deep); ++ tmp->flags &= ~0x0001; + } + } + } +Index: insserv/listing.c +=================================================================== +--- insserv.orig/listing.c 2009-09-26 22:35:24.000000000 +0200 ++++ insserv/listing.c 2009-09-26 22:35:39.000000000 +0200 +@@ -398,6 +398,12 @@ + break; /* Loop detected, stop recursion */ + } + ++ if ((mode == 'S') && (attof(tmp)->flags & SERV_ALL)) { ++ warn("%s depends on %s and therefore on system facility `$all' which can not be true!\n", ++ target->script ? target->script : target->name, tmp->script ? tmp->script : tmp->name); ++ continue; ++ } ++ + if (ptrg->deep >= deep) /* Nothing new */ + continue; + /* The inner recursion */ diff --git a/debian/patches/95_stop_all.patch b/debian/patches/95_stop_all.patch new file mode 100644 index 0000000..d78eb41 --- /dev/null +++ b/debian/patches/95_stop_all.patch @@ -0,0 +1,159 @@ +Patch from upstream making $all work for stop sequences, placing +scripts first in the stop sequence. This patch invalidates +60_all_keyword_start_only.patch + +Fixes #542043 + +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:39.000000000 +0200 +@@ -308,7 +308,10 @@ + break; + case '$': + if (strcasecmp(token, "$all") == 0) { +- serv->attr.flags |= SERV_ALL; ++ if (bit & REQ_KILL) ++ serv->attr.flags |= SERV_FIRST; ++ else ++ serv->attr.flags |= SERV_ALL; + break; + } + /* Expand the `$' token recursively down */ +@@ -630,8 +633,7 @@ + } + + /* +- * Last but not least the `$all' scripts will be set to the +- * end of the current start order. ++ * 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) +@@ -688,6 +690,50 @@ + } + + /* ++ * Last but not least the `$all' scripts will be set to the ++ * beginning of the current stop order. ++ */ ++static inline void first_script(void) attribute((always_inline)); ++static inline void first_script(void) ++{ ++ list_t * pos; ++ ++ list_for_each(pos, s_start) { ++ service_t * serv = getservice(pos); ++ list_t * tmp; ++ ++ if (serv->attr.flags & SERV_DUPLET) ++ continue; /* Duplet */ ++ ++ if (!(serv->attr.flags & SERV_FIRST)) ++ continue; ++ ++ if (serv->attr.script == (char*)0) ++ continue; ++ ++ 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 == serv) ++ continue; ++ ++ if (cur->attr.flags & SERV_FIRST) ++ continue; ++ ++ rememberreq(serv, REQ_SHLD|REQ_KILL, cur->name); ++ } ++ ++ setorder(serv->attr.script, 'K', 1, false); ++ } ++} ++ ++/* + * Make the dependency files + */ + static inline void makedep(void) attribute((always_inline)); +@@ -3274,6 +3320,11 @@ + nonlsb_script(); + + /* ++ * Move the `$all' stop scripts to the very beginning ++ */ ++ first_script(); ++ ++ /* + * Now generate for all scripts the dependencies + */ + follow_all(); +Index: insserv/listing.c +=================================================================== +--- insserv.orig/listing.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/listing.c 2009-09-26 22:35:39.000000000 +0200 +@@ -317,6 +317,7 @@ + } + + for (tmp = dir; tmp; tmp = getnextlink(l_list)) { ++ const typeof(attof(tmp)->flags) sflags = attof(tmp)->flags; + register boolean recursion = true; + handle_t * ptmp = (mode == 'K') ? &tmp->stopp : &tmp->start; + uchar * order = &ptmp->deep; +@@ -381,6 +382,7 @@ + np_list_for_each(dent, l_list) { + dir_t * target = getlink(dent)->target; + handle_t * ptrg = (mode == 'K') ? &target->stopp : &target->start; ++ const typeof(attof(target)->flags) kflags = attof(target)->flags; + + if ((peg->run.lvl & ptrg->run.lvl) == 0) + continue; /* Not same boot level */ +@@ -398,10 +400,18 @@ + break; /* Loop detected, stop recursion */ + } + +- if ((mode == 'S') && (attof(tmp)->flags & SERV_ALL)) { +- warn("%s depends on %s and therefore on system facility `$all' which can not be true!\n", +- target->script ? target->script : target->name, tmp->script ? tmp->script : tmp->name); +- continue; ++ if (mode == 'K') { ++ if (kflags & SERV_FIRST) { ++ warn("Stopping %s depends on %s and therefore on system facility `$all' which can not be true!\n", ++ tmp->script ? tmp->script : tmp->name, target->script ? target->script : target->name); ++ continue; ++ } ++ } else { ++ if (sflags & SERV_ALL) { ++ warn("Starting %s depends on %s and therefore on system facility `$all' which can not be true!\n", ++ target->script ? target->script : target->name, tmp->script ? tmp->script : tmp->name); ++ continue; ++ } + } + + if (ptrg->deep >= deep) /* Nothing new */ +@@ -847,7 +857,7 @@ + list_for_each(tmp, d_start) { + maxorder = &maxstart; + guess_order(getdir(tmp), 'S'); +- maxorder = &maxstart; ++ maxorder = &maxstop; + guess_order(getdir(tmp), 'K'); + } + } +Index: insserv/listing.h +=================================================================== +--- insserv.orig/listing.h 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/listing.h 2009-09-26 22:35:39.000000000 +0200 +@@ -368,6 +368,7 @@ + #define SERV_SCRIPT 0x0080 + #define SERV_NOSTOP 0x0100 + #define SERV_CMDLINE 0x0200 ++#define SERV_FIRST 0x0400 + + /* + * Bits of the runlevels diff --git a/debian/patches/96_hurd_no_at_funcs.patch b/debian/patches/96_hurd_no_at_funcs.patch new file mode 100644 index 0000000..bcf2e75 --- /dev/null +++ b/debian/patches/96_hurd_no_at_funcs.patch @@ -0,0 +1,50 @@ +Purpose: Try to get insserv building on hurd, by avoiding the dummy *at + functions which exist in libc but always return an error. +Status: Not yet submitted upstream. + +--- +Index: insserv/listing.h +=================================================================== +--- insserv.orig/listing.h 2009-09-27 15:45:38.000000000 +0200 ++++ insserv/listing.h 2009-09-27 15:45:38.000000000 +0200 +@@ -307,7 +307,7 @@ + #define xreset(ptr) \ + {char *restrict tmp = (char *restrict)ptr; if (ptr && *tmp) free(ptr);} ptr = NULL + +-#if defined(HAS_unlinkat) && defined(_ATFILE_SOURCE) ++#if defined(HAS_unlinkat) && defined(_ATFILE_SOURCE) && !defined(__stub_unlinkat) + # 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)); \ +@@ -319,7 +319,7 @@ + else \ + info(1, "remove service %s/%s%s\n", path, rcd, x); })) + #endif +-#if defined(HAS_symlinkat) && defined(_ATFILE_SOURCE) ++#if defined(HAS_symlinkat) && defined(_ATFILE_SOURCE) && !defined(__stub_symlinkat) + # 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 \ +@@ -330,19 +330,19 @@ + else \ + info(1, "enable service %s -> %s/%s%s\n", x, path, rcd, y); })) + #endif +-#if defined(HAS_fstatat) && defined(_ATFILE_SOURCE) ++#if defined(HAS_fstatat) && defined(_ATFILE_SOURCE) && !defined(__stub_fstatat) + # 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) ++#if defined(HAS_readlinkat) && defined(_ATFILE_SOURCE) && !defined(__stub_readlinkat) + # 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) ++#if defined(HAS_openat) && defined(_ATFILE_SOURCE) && !defined(__stub_openat) + # define xopen(d,x,f) (__extension__ ({ openat(d,x,f); })) + #else + # define xopen(d,x,f) (__extension__ ({ open(x,f); })) diff --git a/debian/patches/series b/debian/patches/series new file mode 100644 index 0000000..4e4c68c --- /dev/null +++ b/debian/patches/series @@ -0,0 +1,22 @@ +10_nosuse.patch +11_debian_conf.patch +20_install_perms_fixup.patch +21_tests_suite_new_functions.patch +30_deterministic_order.patch +40_badboy_segfault.patch +50_symlink_in_initddir.patch +#60_all_keyword_start_only.patch +61_interactive_keyword.patch +62_upstart_job.patch +70_req_start_all_depends.patch +71_complete_makefile.patch +80_manual_warnings.patch +81_lessverbose.patch +82_loop_exit_msg.patch +90_no_runlevel_spec_for_debian.patch +91_kfreebsd_nofadvice.patch +92_m68k_alignment.patch +93_hurd_no_path_max.patch +94_v1_12_2.patch +95_stop_all.patch +96_hurd_no_at_funcs.patch diff --git a/debian/po/POTFILES.in b/debian/po/POTFILES.in new file mode 100644 index 0000000..3b1150e --- /dev/null +++ b/debian/po/POTFILES.in @@ -0,0 +1 @@ +[type: gettext/rfc822deb] insserv.templates diff --git a/debian/po/cs.po b/debian/po/cs.po new file mode 100644 index 0000000..4f4cd8f --- /dev/null +++ b/debian/po/cs.po @@ -0,0 +1,55 @@ +# Czech translation of insserv debconf messages. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the insserv package. +# Miroslav Kure , 2008 +# +msgid "" +msgstr "" +"Project-Id-Version: insserv\n" +"Report-Msgid-Bugs-To: pere@debian.org\n" +"POT-Creation-Date: 2008-02-17 13:56+0100\n" +"PO-Revision-Date: 2008-02-23 12:52+0100\n" +"Last-Translator: Miroslav Kure \n" +"Language-Team: Czech \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "Enable (or keep enabled) the dependency-based boot sequence?" +msgstr "Povolit (nebo nechat povolené) zavádění založené na závislostech?" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"If you choose to enable the dependency-based boot sequence the scripts in /" +"etc/rc*.d/ will be reordered using dependency information provided by LSB " +"comment headers (or defaults where these are not present). All S* symlinks " +"in rc0.d/ and rc6.d/ will be turned into K* symlinks, to make sure the way " +"they are used (with the argument 'stop') matches their names. The change " +"will only be done after it is verified that it is safe to convert. Disabling " +"it when enabled will try to revert the change." +msgstr "" +"Povolíte-li zavádění založené na závislostech, budou skripty v /etc/rc*.d/ " +"přeskládány na základě informací zapsaných v LSB hlavičkách těchto skriptů. " +"(Pokud LSB informace chybí, použijí se výchozí hodnoty.) VÅ¡echny symbolické " +"odkazy S* v rc0.d/ a rc6.d/ budou přejmenovány na K*, aby byly jejich názvy " +"konzistentní se způsobem použití (volání s argumentem „stop“). Změna se " +"provede pouze poté, co se ověří, že je převod bezpečný. Pokud je zavádění " +"založené na závislostech povoleno, způsobí jeho vypnutí návrat do původního " +"stavu." + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"Please note that this feature is experimental. Attempting to revert from " +"dependency-based boot sequencing is not guaranteed to be safe, and may " +"require the reinstallation of the system." +msgstr "" +"Mějte prosím na paměti, že se jedná o experimentální vlastnost. Není " +"zaručeno, že se pokus o návrat k původnímu systému zavádění podaří. V " +"krajním případě bude možná nutné přeinstalovat celý systém." diff --git a/debian/po/de.po b/debian/po/de.po new file mode 100644 index 0000000..b20efd2 --- /dev/null +++ b/debian/po/de.po @@ -0,0 +1,62 @@ +# translation of insserv_1.11.0-8_de.po to German +# Copyright (C) 2008, Erik Schanze +# This file is distributed under the same license as the insserv package. +# +# Erik Schanze , 2008. +msgid "" +msgstr "" +"Project-Id-Version: insserv_1.11.0-8_de\n" +"Report-Msgid-Bugs-To: pere@debian.org\n" +"POT-Creation-Date: 2008-02-17 13:56+0100\n" +"PO-Revision-Date: 2008-05-04 00:19+0200\n" +"Last-Translator: Erik Schanze \n" +"Language-Team: German \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "Enable (or keep enabled) the dependency-based boot sequence?" +msgstr "" +"Abhängigkeitsgestützte Reihenfolge beim Hochfahren aktivieren (oder " +"aktiviert lassen)?" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"If you choose to enable the dependency-based boot sequence the scripts in /" +"etc/rc*.d/ will be reordered using dependency information provided by LSB " +"comment headers (or defaults where these are not present). All S* symlinks " +"in rc0.d/ and rc6.d/ will be turned into K* symlinks, to make sure the way " +"they are used (with the argument 'stop') matches their names. The change " +"will only be done after it is verified that it is safe to convert. Disabling " +"it when enabled will try to revert the change." +msgstr "" +"Wenn Sie hier zustimmen, werden alle Skripte im Verzeichnis /etc/rc*.d/ " +"anhand der in jedem Skript enthaltenen Informationen über die Abhängigkeiten " +"neu sortiert. Wenn diese Information fehlt, wird die Standardinformation " +"über Abhängigkeiten benutzt. Es werden auch alle symbolischen Links »S*« in " +"den Verzeichnissen rc0.d/ und rc6.d/ in symbolische Links »K*« umgewandelt, " +"um sicher zu stellen, dass ihre Aufrufe (mit dem Argument »stop«) zu ihren " +"Namen passen. Die Änderung wird nur vorgenommen, nachdem überprüft wurde, " +"dass die Umwandlung sicher ist. Wenn Sie hier ablehnen, nachdem Sie schon " +"einmal zugestimmt haben, wird versucht, die Änderungen zurückzunehmen." + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"Please note that this feature is experimental. Attempting to revert from " +"dependency-based boot sequencing is not guaranteed to be safe, and may " +"require the reinstallation of the system." +msgstr "" +"Bitte beachten Sie, dass es sich um eine experimentelle " +"Funktionalität handelt. Es gibt keine Garantie, dass man von einer " +"abhängigkeitsgestützten zu einer nicht abhängigkeitsgestützten " +"Reihenfolge des Hochfahrens sicher zurückzukehren kann. Eine " +"Neuinstallation des Systems könnte erforderlich werden." + diff --git a/debian/po/es.po b/debian/po/es.po new file mode 100644 index 0000000..7b3f573 --- /dev/null +++ b/debian/po/es.po @@ -0,0 +1,85 @@ +# insserv translation to spanish +# Copyright (C) 2007 Software in the Public Interest, SPI Inc. +# This file is distributed under the same license as the insserv package. +# +# Changes: +# - Initial translation +# Steve Lord Flaubert , 2008 +# +# +# Traductores, si no conoce el formato PO, merece la pena leer la +# documentación de gettext, especialmente las secciones dedicadas a este +# formato, por ejemplo ejecutando: +# info -n '(gettext)PO Files' +# info -n '(gettext)Header Entry' +# +# Equipo de traducción al español, por favor lean antes de traducir +# los siguientes documentos: +# +# - El proyecto de traducción de Debian al español +# http://www.debian.org/intl/spanish/ +# especialmente las notas y normas de traducción en +# http://www.debian.org/intl/spanish/notas +# +# - La guía de traducción de po's de debconf: +# /usr/share/doc/po-debconf/README-trans +# o http://www.debian.org/intl/l10n/po-debconf/README-trans +# +# Si tiene dudas o consultas sobre esta traducción consulte con el último +# traductor (campo Last-Translator) y ponga en copia a la lista de +# traducción de Debian al español () +# +# +msgid "" +msgstr "" +"Project-Id-Version: insserv 1.10.0-4\n" +"Report-Msgid-Bugs-To: pere@debian.org\n" +"POT-Creation-Date: 2008-02-17 13:56+0100\n" +"PO-Revision-Date: 2008-02-18 17:18-0500\n" +"Last-Translator: Steve Lord Flaubert \n" +"Language-Team: Spanish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "Enable (or keep enabled) the dependency-based boot sequence?" +msgstr "" +"¿Activar (o mantener activada) la secuencia de arranque basada en " +"dependencias?" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"If you choose to enable the dependency-based boot sequence the scripts in /" +"etc/rc*.d/ will be reordered using dependency information provided by LSB " +"comment headers (or defaults where these are not present). All S* symlinks " +"in rc0.d/ and rc6.d/ will be turned into K* symlinks, to make sure the way " +"they are used (with the argument 'stop') matches their names. The change " +"will only be done after it is verified that it is safe to convert. Disabling " +"it when enabled will try to revert the change." +msgstr "" +"Si escoge activar una secuencia de arranque basada en dependencias, los " +"scripts en «/etc/rc*.d/» serán reordenados mediante información de " +"dependencia proporcionadas por los comentarios de cabecera de LSB (o valores " +"por omisión donde estos no estén presentes). Todos los enlaces simbólicos S* " +"en «rc0.d/ y rc6.d/» serán convertidos en enlaces simbólicos K*, para " +"asegurarse que la forma con que se usan (con el argumento «stop») coincidan " +"con sus nombres. El cambio sólo se hará después de que se compruebe que la " +"conversión es segura. Si está activo al desactivarlo se intentará revertir " +"el cambio. " + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"Please note that this feature is experimental. Attempting to revert from " +"dependency-based boot sequencing is not guaranteed to be safe, and may " +"require the reinstallation of the system." +msgstr "" +"Por favor tenga en cuenta que esta característica es experimental. No está " +"garantizado que se pueda revertir desde una secuencia de arranque basada en " +"dependencias y puede necesitar la reinstalación del sistema." diff --git a/debian/po/fi.po b/debian/po/fi.po new file mode 100644 index 0000000..eb47065 --- /dev/null +++ b/debian/po/fi.po @@ -0,0 +1,55 @@ +msgid "" +msgstr "" +"Project-Id-Version: insserv\n" +"Report-Msgid-Bugs-To: pere@debian.org\n" +"POT-Creation-Date: 2008-02-17 13:56+0100\n" +"PO-Revision-Date: 2008-02-15 00:51+0200\n" +"Last-Translator: Esko Arajärvi \n" +"Language-Team: Finnish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: Finnish\n" +"X-Poedit-Country: FINLAND\n" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "Enable (or keep enabled) the dependency-based boot sequence?" +msgstr "" +"Aktivoidaanko (tai pidetäänkö aktivoituna) riippuvuuspohjainen " +"käynnistyssekvenssi?" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"If you choose to enable the dependency-based boot sequence the scripts in /" +"etc/rc*.d/ will be reordered using dependency information provided by LSB " +"comment headers (or defaults where these are not present). All S* symlinks " +"in rc0.d/ and rc6.d/ will be turned into K* symlinks, to make sure the way " +"they are used (with the argument 'stop') matches their names. The change " +"will only be done after it is verified that it is safe to convert. Disabling " +"it when enabled will try to revert the change." +msgstr "" +"Jos riippuvuuspohjainen käynnistyssekvenssi aktivoidaan, hakemistoissa /etc/" +"rc*.d/ olevien komentosarjojen käynnistysjärjestystä muutetaan LSB-" +"kommenttiotsakkeissa annettujen riippuvuustietojen mukaan (tai säilytetään " +"oletusjärjestyksessä, jos otsakkeita ei ole). Kaikki S*-tyypin symboliset " +"linkit hakemistoissa rc0.d ja rc6.d muutetaan K*-tyypin symbolisiksi " +"linkeiksi, sen varmistamiseksi, että niiden käyttötapa (argumentin ”stop” " +"kanssa) täsmää niiden nimiin. Muutos tehdään vasta, kun on varmistettu, että " +"se on turvallista tehdä. Jos riippuvuuspohjainen käynnistyssekvenssi " +"poistetaan käytöstä, muutokset yritetään perua." + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"Please note that this feature is experimental. Attempting to revert from " +"dependency-based boot sequencing is not guaranteed to be safe, and may " +"require the reinstallation of the system." +msgstr "" +"Tämä ominaisuus on kokeellinen. Riippuvuuspohjaisen käynnistyssekvenssin " +"purkaminen ei välttämättä ole turvallista ja saattaa johtaa siihen, että " +"järjestelmä on asennettava uudelleen." diff --git a/debian/po/fr.po b/debian/po/fr.po new file mode 100644 index 0000000..2924fae --- /dev/null +++ b/debian/po/fr.po @@ -0,0 +1,61 @@ +# Translation of insserv debconf templates to French +# Copyright (C) 2008 Christian Perrier +# This file is distributed under the same license as the insserv package. +# +# Christian Perrier , 2008. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: pere@debian.org\n" +"POT-Creation-Date: 2008-02-17 13:56+0100\n" +"PO-Revision-Date: 2008-02-13 07:22+0100\n" +"Last-Translator: Christian Perrier \n" +"Language-Team: French \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "Enable (or keep enabled) the dependency-based boot sequence?" +msgstr "" +"Faut-il activer (ou laisser activée) la gestion des dépendances dans la " +"séquence de démarrage ?" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"If you choose to enable the dependency-based boot sequence the scripts in /" +"etc/rc*.d/ will be reordered using dependency information provided by LSB " +"comment headers (or defaults where these are not present). All S* symlinks " +"in rc0.d/ and rc6.d/ will be turned into K* symlinks, to make sure the way " +"they are used (with the argument 'stop') matches their names. The change " +"will only be done after it is verified that it is safe to convert. Disabling " +"it when enabled will try to revert the change." +msgstr "" +"Si vous choisissez d'activer la gestion des dépendances pour la séquence de " +"démarrage, les scripts placés dans /etc/rc*.d/ seront remis dans un ordre " +"qui utilise les informations de dépendances fournies par les en-têtes LSB " +"(ou des valeurs par défaut si ceux-ci ne sont pas présents). Tous les liens " +"symboliques de démarrage (liens S*) de rc0.d/ et rc6.d/ seront transformés " +"en lien d'arrêt des services (liens K*) pour garantir que leur mode " +"d'utilisation (avec le paramètre « stop ») correspond à leurs noms. Cette " +"modification ne sera effectuée qu'après contrôle qu'elle peut se faire de " +"façon sûre. Si vous désactivez la gestion des dépendances alors qu'elle est " +"active, ces modifications seront abandonnées." + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"Please note that this feature is experimental. Attempting to revert from " +"dependency-based boot sequencing is not guaranteed to be safe, and may " +"require the reinstallation of the system." +msgstr "" +"Veuillez noter que cette fonctionnalité est expérimentale. Le retour en " +"arrière depuis une séquence de démarrage avec gestion des dépendances n'est " +"pas entièrement garanti et un échec peut imposer la réinstallation de " +"l'ensemble du système." diff --git a/debian/po/gl.po b/debian/po/gl.po new file mode 100644 index 0000000..729ef73 --- /dev/null +++ b/debian/po/gl.po @@ -0,0 +1,56 @@ +# Galician translation of insserv's debconf templates +# This file is distributed under the same license as the insserv package. +# Jacobo Tarrio , 2008. +# +msgid "" +msgstr "" +"Project-Id-Version: insserv\n" +"Report-Msgid-Bugs-To: pere@debian.org\n" +"POT-Creation-Date: 2008-02-17 13:56+0100\n" +"PO-Revision-Date: 2008-02-10 13:40+0000\n" +"Last-Translator: Jacobo Tarrio \n" +"Language-Team: Galician \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "Enable (or keep enabled) the dependency-based boot sequence?" +msgstr "" +"¿Activar (ou manter activada) a secuencia de inicio baseada en dependencias?" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"If you choose to enable the dependency-based boot sequence the scripts in /" +"etc/rc*.d/ will be reordered using dependency information provided by LSB " +"comment headers (or defaults where these are not present). All S* symlinks " +"in rc0.d/ and rc6.d/ will be turned into K* symlinks, to make sure the way " +"they are used (with the argument 'stop') matches their names. The change " +"will only be done after it is verified that it is safe to convert. Disabling " +"it when enabled will try to revert the change." +msgstr "" +"Se quere activar a secuencia de inicio baseada en dependencias hanse " +"reordear os scripts de /etc/rc*.d/ empregando a información de depencencias " +"fornecida nas cabeceiras LSB dos comentarios (ou empregando valores por " +"defecto cando estas cabeceiras non estean presentes). Hanse convertir " +"tódalas ligazóns S* de rc0.d/ e rc6.d/ en ligazóns K*, para asegurarse de " +"que a maneira en que se empregan (co argumento \"stop\") coincida cos seus " +"nomes. Só se ha facer o cambio despois de verificar que é seguro realizar a " +"conversión. Ao desactivala cando estea activada hase tentar desfacer o " +"cambio." + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"Please note that this feature is experimental. Attempting to revert from " +"dependency-based boot sequencing is not guaranteed to be safe, and may " +"require the reinstallation of the system." +msgstr "" +"Teña en conta que esta característica é experimental. Non se pode garantir " +"que reverter a secuencia de inicio baseada en dependencias sexa unha " +"operación segura, e pode facer necesario reinstalar o sistema." diff --git a/debian/po/it.po b/debian/po/it.po new file mode 100644 index 0000000..3eb4e4f --- /dev/null +++ b/debian/po/it.po @@ -0,0 +1,56 @@ +# Italian translation of the insserv debconf template +# This file is distributed under the same license as the insserv package +# Copyright (C) 2008 Free Software Foundation, Inc. +# Luca Monducci , 2008. +# +msgid "" +msgstr "" +"Project-Id-Version: insserv 1.10.0\n" +"Report-Msgid-Bugs-To: pere@debian.org\n" +"POT-Creation-Date: 2008-02-17 13:56+0100\n" +"PO-Revision-Date: 2008-02-25 14:23+0100\n" +"Last-Translator: Luca Monducci \n" +"Language-Team: Italian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "Enable (or keep enabled) the dependency-based boot sequence?" +msgstr "Attivare (o tenere attiva) la sequenza d'avvio basata su dipendenze?" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"If you choose to enable the dependency-based boot sequence the scripts in /" +"etc/rc*.d/ will be reordered using dependency information provided by LSB " +"comment headers (or defaults where these are not present). All S* symlinks " +"in rc0.d/ and rc6.d/ will be turned into K* symlinks, to make sure the way " +"they are used (with the argument 'stop') matches their names. The change " +"will only be done after it is verified that it is safe to convert. Disabling " +"it when enabled will try to revert the change." +msgstr "" +"Se si sceglie di attivare la sequenza di avvio basata sulle dipendenze, gli " +"script in /etc/rc*.d/ verranno riordinati in base alle informazioni sulle " +"dipendenze presenti nei commenti delle intestazioni LSB (o in base ai valori " +"predefiniti in caso di mancanza di queste informazioni). Tutti i link " +"simbolici S* in rc0.d/ e rc6.d/ verranno trasformati in link simbolici K* in " +"modo che il loro utilizzo (con l'argomento \"stop\") sia coerente con il " +"loro nome. La modifica verrà effettuata solo dopo aver verificato che la " +"conversione sia sicura. Una volta attivata, la disattivazione cerca di " +"ricreare la configurazione preesistente." + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"Please note that this feature is experimental. Attempting to revert from " +"dependency-based boot sequencing is not guaranteed to be safe, and may " +"require the reinstallation of the system." +msgstr "" +"Notare che questa funzionalità è sperimentale. Non si garantisce che il " +"ripristino della configurazione precedente funzioni correttamente e potrebbe " +"richiedere la reinstallazione del sistema." diff --git a/debian/po/ja.po b/debian/po/ja.po new file mode 100644 index 0000000..9f004b6 --- /dev/null +++ b/debian/po/ja.po @@ -0,0 +1,53 @@ +# Copyright (C) 2008 Petter Reinholdtsen +# This file is distributed under the same license as insserv package. +# Hideki Yamane (Debian-JP) , 2008. +# +msgid "" +msgstr "" +"Project-Id-Version: insserv 1.12.0-4\n" +"Report-Msgid-Bugs-To: pere@debian.org\n" +"POT-Creation-Date: 2008-02-17 13:56+0100\n" +"PO-Revision-Date: 2008-12-28 22:26+0900\n" +"Last-Translator: Hideki Yamane (Debian-JP) \n" +"Language-Team: Japanese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "Enable (or keep enabled) the dependency-based boot sequence?" +msgstr "依存関係ベースでの起動シーケンスを有効に (あるいは有効にしたままに) しますか?" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"If you choose to enable the dependency-based boot sequence the scripts in /" +"etc/rc*.d/ will be reordered using dependency information provided by LSB " +"comment headers (or defaults where these are not present). All S* symlinks " +"in rc0.d/ and rc6.d/ will be turned into K* symlinks, to make sure the way " +"they are used (with the argument 'stop') matches their names. The change " +"will only be done after it is verified that it is safe to convert. Disabling " +"it when enabled will try to revert the change." +msgstr "" +"依存関係ベースでの起動シーケンスを有効にした場合、LSB コメントヘッダ (あるいは" +"現在まだ無いデフォルト設定) から提供される依存関係情報を使って、/etc/rc*.d/ 内" +"のスクリプトの順番を再構成します。rc0.d/ と rc6.d/ にある全ての S* シンボリック" +"リンクは、(引数 'stop' で) 使われているのが名前と一致しているのを確かめるため、" +"K* シンボリックリンクへ変更されます。変更は変換しても安全なのが確認された後のみ" +"実行されます。有効にした場合に無効にすると変更を元に戻そうと試みます。" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"Please note that this feature is experimental. Attempting to revert from " +"dependency-based boot sequencing is not guaranteed to be safe, and may " +"require the reinstallation of the system." +msgstr "" +"この機能は実験的なものであることに注意ください。依存関係ベースでの起動シーケンス" +"から元に戻すのは、安全が確保されていない上にシステムの再インストールが必要になる" +"かもしれません。" + diff --git a/debian/po/nl.po b/debian/po/nl.po new file mode 100644 index 0000000..9f55f10 --- /dev/null +++ b/debian/po/nl.po @@ -0,0 +1,59 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: insserv\n" +"Report-Msgid-Bugs-To: pere@debian.org\n" +"POT-Creation-Date: 2008-02-17 13:56+0100\n" +"PO-Revision-Date: 2008-02-18 19:18+0100\n" +"Last-Translator: Bart Cornelis \n" +"Language-Team: debian-l10n-dutch \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: Dutch\n" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "Enable (or keep enabled) the dependency-based boot sequence?" +msgstr "" +"Wilt u de op vereisten gebaseerde opstartvolgorde activeren (of geactiveerd " +"laten)?" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"If you choose to enable the dependency-based boot sequence the scripts in /" +"etc/rc*.d/ will be reordered using dependency information provided by LSB " +"comment headers (or defaults where these are not present). All S* symlinks " +"in rc0.d/ and rc6.d/ will be turned into K* symlinks, to make sure the way " +"they are used (with the argument 'stop') matches their names. The change " +"will only be done after it is verified that it is safe to convert. Disabling " +"it when enabled will try to revert the change." +msgstr "" +"Wanneer u kiest om de op vereisten gebaseerde opstartvolgorde te activeren " +"worden de scripts in /etc/rc*.d/ geordend op basis van de vereisten die " +"voorzien zijn in de LSB-commentaar-kopteksten (of standaardwaarden wanneer " +"deze afwezig zijn). Alle S*-koppelingen in rc0.d/ en rc6.d/ worden omgezet " +"in K*-symbolische koppelingen; dit zorgt ervoor dat de manier waarop ze " +"gebruikt worden (met het argument 'stop') gereflecteerd wordt in hun naam. " +"Deze aanpassing wordt pas uitgevoerd eens nagegaan is dat deze omzetting " +"veilig is. De-activatie probeert deze aanpassing ongedaan te maken (wanneer " +"deze keuze actief was)." + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"Please note that this feature is experimental. Attempting to revert from " +"dependency-based boot sequencing is not guaranteed to be safe, and may " +"require the reinstallation of the system." +msgstr "" +"Opgelet: deze functionaliteit is experimenteel. De veiligheid van teruggaan " +"van de op vereisten gebaseerde opstartvolgorde naar de huidige situatie is " +"niet gegarandeerd en kan de herinstallatie van het systeem vereisen." diff --git a/debian/po/pt.po b/debian/po/pt.po new file mode 100644 index 0000000..c0b0b99 --- /dev/null +++ b/debian/po/pt.po @@ -0,0 +1,57 @@ +# translation of insserv debconf to Portuguese +# Copyright (C) 2008 Américo Monteiro +# This file is distributed under the same license as the insserv package. +# +# Américo Monteiro , 2008. +msgid "" +msgstr "" +"Project-Id-Version: insserv 1.10.0-4\n" +"Report-Msgid-Bugs-To: pere@debian.org\n" +"POT-Creation-Date: 2008-02-17 13:56+0100\n" +"PO-Revision-Date: 2008-02-12 00:09+0000\n" +"Last-Translator: Américo Monteiro \n" +"Language-Team: Portuguese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "Enable (or keep enabled) the dependency-based boot sequence?" +msgstr "" +"Activar (ou manter activa) a sequência de arranque baseada em dependências?" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"If you choose to enable the dependency-based boot sequence the scripts in /" +"etc/rc*.d/ will be reordered using dependency information provided by LSB " +"comment headers (or defaults where these are not present). All S* symlinks " +"in rc0.d/ and rc6.d/ will be turned into K* symlinks, to make sure the way " +"they are used (with the argument 'stop') matches their names. The change " +"will only be done after it is verified that it is safe to convert. Disabling " +"it when enabled will try to revert the change." +msgstr "" +"Se você escolher activar a sequência de arranque baseada em dependências, os " +"scripts em /etc/rc*.d/ serão reordenados usando informação disponibilizada " +"pelos comentários de cabeçalho do LSB (ou pré-definições quando estes não " +"estiverem presentes). Todos os symlinks S* em rc0.d/ e rc6.0 serão " +"convertidos em symlinks K*, para garantir que a maneira que são usados (com " +"o argumento 'stop') coincide com os seus nomes. A alteração só será feita " +"após ter sido verificado que é seguro fazê-la. Desactivando-a quando activa " +"irá tentar reverter a alteração." + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"Please note that this feature is experimental. Attempting to revert from " +"dependency-based boot sequencing is not guaranteed to be safe, and may " +"require the reinstallation of the system." +msgstr "" +"Por favor note que esta funcionalidade é experimental. A tentativa de " +"reverter de sequência de arranque baseada em dependências não é " +"garantidamente segura, e poderá necessitar da re-instalação do sistema." diff --git a/debian/po/ru.po b/debian/po/ru.po new file mode 100644 index 0000000..fdbf7a9 --- /dev/null +++ b/debian/po/ru.po @@ -0,0 +1,61 @@ +# translation of ru.po to Russian +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Yuri Kozlov , 2008. +msgid "" +msgstr "" +"Project-Id-Version: insserv 1.10.0-4\n" +"Report-Msgid-Bugs-To: pere@debian.org\n" +"POT-Creation-Date: 2008-02-17 13:56+0100\n" +"PO-Revision-Date: 2008-02-18 21:53+0300\n" +"Last-Translator: Yuri Kozlov \n" +"Language-Team: Russian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%" +"10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "Enable (or keep enabled) the dependency-based boot sequence?" +msgstr "" +"Включить (или оставить включённым) порядок загрузки, основанный на " +"зависимостях?" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"If you choose to enable the dependency-based boot sequence the scripts in /" +"etc/rc*.d/ will be reordered using dependency information provided by LSB " +"comment headers (or defaults where these are not present). All S* symlinks " +"in rc0.d/ and rc6.d/ will be turned into K* symlinks, to make sure the way " +"they are used (with the argument 'stop') matches their names. The change " +"will only be done after it is verified that it is safe to convert. Disabling " +"it when enabled will try to revert the change." +msgstr "" +"Если вы выберете включение порядка загрузки, основанного на зависимостях, то " +"сценарии в /etc/rc*.d/ будут переупорядочены согласно информации о " +"зависимостях, предоставляемых в LSB закомментированных заголовках (или " +"согласно значениям по умолчанию, если их нет). Все символические ссылки S* в " +"rc0.d/ и rc6.d/ будут обращены в символические ссылки K*, чтобы " +"удостовериться, что то, для чего они используются (с параметром 'stop'), " +"совпадает с их именами. Изменения выполнятся только после того, как будет " +"проверено, что преобразование безопасно. При выключение порядка будет " +"произведена попытка откатить сделанные изменения." + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"Please note that this feature is experimental. Attempting to revert from " +"dependency-based boot sequencing is not guaranteed to be safe, and may " +"require the reinstallation of the system." +msgstr "" +"Обратите внимание, что это пока эксперимент. Возвращение назад с порядка " +"загрузки, основанного на зависимостях не гарантируется и может потребоваться " +"переустановка системы." diff --git a/debian/po/sv.po b/debian/po/sv.po new file mode 100644 index 0000000..c6aeb80 --- /dev/null +++ b/debian/po/sv.po @@ -0,0 +1,57 @@ +# translation of insserv.po to swedish +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Martin Bagge , 2008. +msgid "" +msgstr "" +"Project-Id-Version: insserv\n" +"Report-Msgid-Bugs-To: pere@debian.org\n" +"POT-Creation-Date: 2008-02-17 13:56+0100\n" +"PO-Revision-Date: 2008-10-26 23:53+0100\n" +"Last-Translator: Martin Bagge \n" +"Language-Team: swedish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "Enable (or keep enabled) the dependency-based boot sequence?" +msgstr "Aktivera beroendebaserad uppstartssekvens?" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"If you choose to enable the dependency-based boot sequence the scripts in /" +"etc/rc*.d/ will be reordered using dependency information provided by LSB " +"comment headers (or defaults where these are not present). All S* symlinks " +"in rc0.d/ and rc6.d/ will be turned into K* symlinks, to make sure the way " +"they are used (with the argument 'stop') matches their names. The change " +"will only be done after it is verified that it is safe to convert. Disabling " +"it when enabled will try to revert the change." +msgstr "" +"Om du aktiverar beroendebaserad uppstartssekvens kommer att innebära " +"förändringar i ordningen för skripten i /etc/rc*.d/ - denna förändring " +"baseras pÃ¥ information frÃ¥n LSB-huvuden eller standardvärden om LSB-" +"information saknas. Alla S*-skript i rc0.d/ och rc6.d/ kommer att ändras " +"till K* sÃ¥ att namnen blir rätt när de används med argumentet 'stop'. " +"Förändringar kommer endast att genomföras efter att en kontroll har kommit " +"fram till att det är en säker förändring. Vid av avaktivering av " +"beroendebaserad uppstartssekvens kommer förändringarna att bli ogjorda i " +"möjligaste mÃ¥n." + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"Please note that this feature is experimental. Attempting to revert from " +"dependency-based boot sequencing is not guaranteed to be safe, and may " +"require the reinstallation of the system." +msgstr "" +"Observera att denna funktion ännu är helt experimentiell. Att Ã¥terställa " +"frÃ¥n beroendebaserad uppstartssekvens är lÃ¥ngt ifrÃ¥n garanterat riskfri och " +"kan medföra att systemet mÃ¥ste installeras om." diff --git a/debian/po/templates.pot b/debian/po/templates.pot new file mode 100644 index 0000000..a4925cd --- /dev/null +++ b/debian/po/templates.pot @@ -0,0 +1,45 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: pere@debian.org\n" +"POT-Creation-Date: 2008-02-17 13:56+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "Enable (or keep enabled) the dependency-based boot sequence?" +msgstr "" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"If you choose to enable the dependency-based boot sequence the scripts in /" +"etc/rc*.d/ will be reordered using dependency information provided by LSB " +"comment headers (or defaults where these are not present). All S* symlinks " +"in rc0.d/ and rc6.d/ will be turned into K* symlinks, to make sure the way " +"they are used (with the argument 'stop') matches their names. The change " +"will only be done after it is verified that it is safe to convert. Disabling " +"it when enabled will try to revert the change." +msgstr "" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"Please note that this feature is experimental. Attempting to revert from " +"dependency-based boot sequencing is not guaranteed to be safe, and may " +"require the reinstallation of the system." +msgstr "" diff --git a/debian/po/vi.po b/debian/po/vi.po new file mode 100644 index 0000000..4d07377 --- /dev/null +++ b/debian/po/vi.po @@ -0,0 +1,55 @@ +# Vietnamese translation for INS Serv. +# Copyright © 2008 Free Software Foundation, Inc. +# Clytie Siddall , 2008. +# +msgid "" +msgstr "" +"Project-Id-Version: insserv 1.10.0-4\n" +"Report-Msgid-Bugs-To: pere@debian.org\n" +"POT-Creation-Date: 2008-02-17 13:56+0100\n" +"PO-Revision-Date: 2008-02-12 23:06+1030\n" +"Last-Translator: Clytie Siddall \n" +"Language-Team: Vietnamese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: LocFactoryEditor 1.7b3\n" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "Enable (or keep enabled) the dependency-based boot sequence?" +msgstr "Bật (hoặc cứ bật) dãy khởi động dá»±a vào quan hệ phụ thuộc không?" + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"If you choose to enable the dependency-based boot sequence the scripts in /" +"etc/rc*.d/ will be reordered using dependency information provided by LSB " +"comment headers (or defaults where these are not present). All S* symlinks " +"in rc0.d/ and rc6.d/ will be turned into K* symlinks, to make sure the way " +"they are used (with the argument 'stop') matches their names. The change " +"will only be done after it is verified that it is safe to convert. Disabling " +"it when enabled will try to revert the change." +msgstr "" +"Bật tùy chọn này thì các văn lệnh trong thÆ° mục « /etc/rc*.d/ » sẽ được sắp " +"xếp lại tùy theo thông tin về quan hệ phụ thuộc mà được cung cấp bởi phần " +"đầu chú thích LSB (không có thì dùng các giá trị mặc định). Mọi liên kết mềm " +"« S* » đều trong hai thÆ° mục « rc0.d/ » và « rc6.d/ » sẽ được chuyển đổi " +"sang liên kết mềm « K* », để đảm bảo cách dùng chúng tÆ°Æ¡ng ứng với tên nó. " +"Thay đổi này sẽ chỉ xảy ra một khi thẩm tra tiến trình chuyển đổi sẽ chạy an " +"toàn. Sau khi bật tùy chọn này, tắt nó sẽ hoàn nguyên thay đổi." + +#. Type: boolean +#. Description +#: ../insserv.templates:2001 +msgid "" +"Please note that this feature is experimental. Attempting to revert from " +"dependency-based boot sequencing is not guaranteed to be safe, and may " +"require the reinstallation of the system." +msgstr "" +"Ghi chú rằng tính năng này vẫn còn thá»±c nghiệm. Không thể đảm bảo tính an " +"toàn khi thá»­ hoàn nguyên khỏi chức năng tạo dãy dá»±a vào quan hệ phụ thuộc: " +"nó có thể cần thiết cài đặt lại hệ thống." diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..7de562e --- /dev/null +++ b/debian/rules @@ -0,0 +1,106 @@ +#!/usr/bin/make -f +# -*- makefile -*- + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +PACKAGE = insserv + +ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) + CFLAGS = -g -O0 +else + CFLAGS = -g -O2 +endif + +#CFLAGS += -DDEBUG=1 + +INSTALL = install +INSTALL_DATA = $(INSTALL) -m644 +DESTDIR = $(CURDIR)/debian/$(PACKAGE) + +pkgdatadir = /usr/share/$(PACKAGE) +sbindir = /usr/sbin + +include /usr/share/quilt/quilt.make + +build: build-stamp + +build-stamp: $(QUILT_STAMPFN) + dh_testdir + + # Add here commands to compile the package. + $(MAKE) COPTS="$(CFLAGS)" + + chmod a+rx debian/run-testsuite + debian/run-testsuite + + touch build-stamp + +clean: + dh_testdir + rm -f build-stamp + + # Add here commands to clean up after the build process. + $(MAKE) clean + + # Remove patches after doing 'make clean', to allow patches to adjust the clean target + $(MAKE) -f debian/rules unpatch + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + # Add here commands to install the package into debian/$(PACKAGE). + $(MAKE) install COPTS="$(CFLAGS)" DESTDIR=$(DESTDIR) + + # Install overrides if present + for data in debian/overrides/* ; do \ + test -f $$data || continue ; \ + $(INSTALL_DATA) $$data $(DESTDIR)$(pkgdatadir)/overrides/. ;\ + done + + $(INSTALL) debian/check-initd-order $(DESTDIR)$(pkgdatadir)/. + $(INSTALL) debian/check-archive-initd-scripts \ + $(DESTDIR)$(pkgdatadir)/. + $(INSTALL) debian/seq-changes $(DESTDIR)$(pkgdatadir)/. + $(INSTALL) debian/make-testsuite $(DESTDIR)$(pkgdatadir)/. + $(INSTALL) debian/update-bootsystem-insserv $(DESTDIR)$(sbindir)/. + $(INSTALL) debian/update-rc.d-insserv $(DESTDIR)$(sbindir)/. + + # Install bash(1) completion + $(INSTALL_DATA) debian/bash-completion $(DESTDIR)/etc/bash_completion.d/insserv + + dh_lintian + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot + dh_installchangelogs CHANGES + dh_installdocs + dh_installexamples + dh_installdebconf +# dh_install + dh_installman + dh_link + dh_strip + dh_compress + dh_fixperms + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install + +.PHONY: phony diff --git a/debian/run-testsuite b/debian/run-testsuite new file mode 100644 index 0000000..7791bac --- /dev/null +++ b/debian/run-testsuite @@ -0,0 +1,2178 @@ +#!/bin/bash + +basedir=$(dirname $0) +. $basedir/../tests/suite + +if head -1 debian/changelog | grep -q UNRELEASED ; then + severity=check +else + severity=test +fi + +update_conf() { +set +C +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 + udev mountdevsubfs checkroot checkfs console-screen +EOF +set -C +} +########################################################################## +test_normal_sequence() { +echo +echo "info: test normal boot sequence scripts, and their order" +echo + +insertscript mountkernfs.sh <<'EOF' +### BEGIN INIT INFO +# Provides: mountkernfs +# Required-Start: +# Required-Stop: +# Should-Start: glibc +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +insertscript mountdevsubfs.sh <<'EOF' +### BEGIN INIT INFO +# Provides: mountdevsubfs mountvirtfs +# Required-Start: mountkernfs +# Required-Stop: +# Should-Start: udev +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +insertscript checkroot.sh <<'EOF' +### BEGIN INIT INFO +# Provides: checkroot +# Required-Start: mountdevsubfs +# Required-Stop: +# Should-Start: keymap hwclockfirst +# Should-stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +insertscript ifupdown-clean <<'EOF' +### BEGIN INIT INFO +# Provides: ifupdown-clean +# Required-Start: checkroot +# Required-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +insertscript ifupdown <<'EOF' +### BEGIN INIT INFO +# Provides: ifupdown +# Required-Start: ifupdown-clean +# Required-Stop: $local_fs +# Default-Start: S +# Default-Stop: 0 6 +### END INIT INFO +EOF + +insertscript checkfs.sh <<'EOF' +### BEGIN INIT INFO +# Provides: checkfs +# Required-Start: checkroot +# Required-Stop: +# Should-Start: lvm cryptdisks +# Should-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +insertscript mountall.sh <<'EOF' +### BEGIN INIT INFO +# Provides: mountall +# Required-Start: checkfs +# Required-Stop: +# Should-Start: lvm +# Should-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +insertscript mountnfs.sh <<'EOF' +### BEGIN INIT INFO +# Provides: mountnfs +# Required-Start: $local_fs +# Required-Stop: +# Should-Start: $network +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +insertscript beforenfs <<'EOF' +### BEGIN INIT INFO +# Provides: beforenfs +# Required-Start: $local_fs +# Required-Stop: +# X-Start-Before: mountnfs +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +insertscript hwclock.sh <<'EOF' +### BEGIN INIT INFO +# Provides: hwclock +# Required-Start: mountdevsubfs +# Required-Stop: $local_fs +# Default-Start: S +# Default-Stop: 0 6 +### END INIT INFO +EOF + +insertscript killprocs <<'EOF' +### BEGIN INIT INFO +# Provides: killprocs +# Required-Start: $local_fs +# Required-Stop: +# Default-Start: 1 +# Default-Stop: +### END INIT INFO +EOF + +insertscript single <<'EOF' +### BEGIN INIT INFO +# Provides: single +# Required-Start: $local_fs killprocs $all +# Required-Stop: +# Default-Start: 1 +# Default-Stop: +### END INIT INFO +EOF + +insertscript needlocalfs <<'EOF' +### BEGIN INIT INFO +# Provides: needlocalfs +# Required-Start: $local_fs +# Required-Stop: $local_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +### END INIT INFO +EOF + +insertscript needallfs <<'EOF' +### BEGIN INIT INFO +# Provides: needallfs +# Required-Start: $remote_fs +# Required-Stop: $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +### END INIT INFO +EOF + +insertscript sysklogd <<'EOF' +### BEGIN INIT INFO +# Provides: syslog +# Required-Start: $remote_fs +# Required-Stop: $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +### END INIT INFO +EOF + +insertscript reboot <<'EOF' +### BEGIN INIT INFO +# Provides: reboot +# Required-Start: +# Required-Stop: +# Default-Start: +# Default-Stop: 6 +### END INIT INFO +EOF + +insertscript halt <<'EOF' +### BEGIN INIT INFO +# Provides: halt +# Required-Start: +# Required-Stop: +# Default-Start: +# Default-Stop: 0 +### END INIT INFO +EOF + +insertscript umountroot <<'EOF' +### BEGIN INIT INFO +# Provides: umountroot +# Required-Start: +# Required-Stop: +# Should-Stop: halt reboot +# Default-Start: +# Default-Stop: 0 6 +### END INIT INFO +EOF + +insertscript umountfs <<'EOF' +### BEGIN INIT INFO +# Provides: umountfs +# Required-Start: +# Required-Stop: umountroot +# Default-Start: +# Default-Stop: 0 6 +### END INIT INFO +EOF + +insertscript umountnfs <<'EOF' +### BEGIN INIT INFO +# Provides: umountnfs +# Required-Start: +# Required-Stop: umountfs +# Should-Stop: $network $portmap nfs-common +# Default-Start: +# Default-Stop: 0 6 +### END INIT INFO +EOF + +insertscript needallfs2 <<'EOF' +### BEGIN INIT INFO +# Provides: needallfs2 +# Required-Start: $remote_fs +# Required-Stop: $remote_fs +# X-Start-Before: needallfs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +### END INIT INFO +EOF + +insertscript kexec <<'EOF' +### BEGIN INIT INFO +# Provides: kexec +# Required-Start: +# Required-Stop: reboot +# X-Stop-After: umountroot +# Default-Start: +# Default-Stop: 6 +### END INIT INFO +EOF + +insertscript networking <<'EOF' +### BEGIN INIT INFO +# Provides: networking +# Required-Start: mountkernfs ifupdown $local_fs +# Required-Stop: ifupdown $local_fs +# Default-Start: S +# Default-Stop: 0 6 +### END INIT INFO +EOF + +insertscript nolsbheader <<'EOF' +EOF + +list_rclinks + +check_order S mountkernfs.sh mountdevsubfs.sh +check_order S ifupdown-clean ifupdown +check_order S ifupdown-clean ifupdown +check_order S mountall.sh mountnfs.sh +check_order S mountall.sh beforenfs +check_order S beforenfs mountnfs.sh + +check_order 0 needallfs umountnfs +check_order 0 umountroot halt + +check_order 1 killprocs single +check_order 1 needallfs killprocs + +check_order 2 needlocalfs needallfs +check_order 2 needlocalfs nolsbheader +check_order 2 sysklogd nolsbheader +check_order 2 needallfs2 needallfs + +check_order 6 needallfs umountnfs +check_order 6 nolsbheader umountnfs +check_order 6 umountfs umountroot +check_order 6 umountnfs networking +check_order 6 networking ifupdown +check_order 6 umountnfs umountfs +check_order 6 umountroot reboot +check_order 6 umountroot kexec +check_order 6 kexec reboot +} +########################################################################## +test_override_files() { +echo +echo "info: test if override files replace headers in the file" +echo + +initdir_purge + +# Two scripts with a loop between them +insertscript base <<'EOF' || true +### BEGIN INIT INFO +# Provides: base +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +insertscript mover <<'EOF' || true +### BEGIN INIT INFO +# Provides: mover +# Required-Start: base +# Required-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +check_order S base mover + +mkdir -p $overridedir +cat <<'EOF' > $overridedir/mover +### BEGIN INIT INFO +# Provides: mover +# Required-Start: +# Required-Stop: +# X-Start-Before: base +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +insserv_reg mover + +list_rclinks + +# Make sure the override file moved mover before base +check_order S mover base +rm -rf $overridedir +} +########################################################################## +test_override_loop() { +echo +echo "info: testing to insert scripts with a loop, and the effect of an override file" +echo + +initdir_purge + +# Two scripts with a loop between them +if insertscript loop1 <<'EOF' ; then +### BEGIN INIT INFO +# Provides: loop1 +# Required-Start: loop2 +# Required-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + error "inserting script with missing dependencies did not fail" +fi + +insertscript loop2 <<'EOF' || true +### BEGIN INIT INFO +# Provides: loop2 +# Required-Start: loop1 +# Required-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +# Test if override file can be used to break the loop +mkdir -p $overridedir +cat <<'EOF' > $overridedir/loop1 +### BEGIN INIT INFO +# Provides: loop1 +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +check_script_not_present S loop1 +check_script_not_present S loop2 + +insserv_reg loop1 || true +insserv_reg loop2 || true + +check_order S loop1 loop2 +rm -rf $overridedir +} +########################################################################## + +test_override_remove() { +echo +echo "info: Try to reproduce BTS #540866" +echo + +initdir_purge + +addscript testscript <<'EOF' +### BEGIN INIT INFO +# Provides: testscript +# Required-Start: +# Required-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +### END INIT INFO +EOF + +mkdir -p ${overridedir}/. +cat >${overridedir}/testscript <<'EOF' +### BEGIN INIT INFO +# Provides: testscript +# Required-Start: +# Required-Stop: +# Default-Start: 2 4 5 +# Default-Stop: 0 1 6 +### END INIT INFO +EOF + +insserv_reg testscript + +list_rclinks + +check_script_not_present 3 testscript + +echo info: Trying to remove the script + +insserv_del testscript + +list_rclinks + +check_script_not_present 3 testscript +} + +########################################################################## +test_long_loop() { +echo +echo "info: testing to insert scripts with a longer loop, making sure it fail" +echo + +initdir_purge + +# Three scripts with a loop between them, make sure introducing the +# loop fail, as it will make insserv generate a unstable and broken +# boot and shutdown sequence. +insertscript loop1 <<'EOF' +### BEGIN INIT INFO +# Provides: loop1 +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +insertscript loop2 <<'EOF' || true +### BEGIN INIT INFO +# Provides: loop2 +# Required-Start: loop1 +# Required-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +if insertscript loop3 <<'EOF' ; then +### BEGIN INIT INFO +# Provides: loop3 +# Required-Start: loop2 +# Required-Stop: +# X-Start-Before: loop1 +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + error "inserting script causing a loop did not fail" +fi +} +########################################################################## +test_combined_loop() { +# Test real loop in the combined start and stop sequence. There is no +# loop in the start sequence, and no loop in the stop sequence, but in +# the combined graph insserv is creating internally, there is a loop. +# This make sense, as scripts need to be installed in dependency +# order, and there is no way to install these scripts that make sure +# both start and stop dependencies are fulfilled. +echo +echo "info: test handling of loops in the combination of start and stop sequences" +echo + +initdir_purge + +insertscript startfirst <<'EOF' || true +### BEGIN INIT INFO +# Provides: startfirst +# Required-Start: +# Required-Stop: startsecond +# Default-Start: S +# Default-Stop: 6 +### END INIT INFO +EOF + +insertscript startsecond <<'EOF' || true +### BEGIN INIT INFO +# Provides: startsecond +# Required-Start: startfirst +# Required-Stop: +# Default-Start: S +# Default-Stop: 6 +### END INIT INFO +EOF + +list_rclinks + +test_order S startfirst startsecond +test_order 6 startsecond startfirst +} +########################################################################## +test_fake_loop() { +# Test another fake loop. This one should work, as it is possible to +# install the two scripts in sequence because one of the dependencies +# are optional. It does not with insserv today. +echo +echo "info: test handling of 'fake' loops in the combination of start and stop sequences" +echo + +initdir_purge + +insertscript startfirst_stopfirst <<'EOF' || true +### BEGIN INIT INFO +# Provides: startfirst_stopfirst +# Required-Start: +# Required-Stop: +# Should-Stop: startsecond_stoplast +# Default-Start: S +# Default-Stop: 6 +### END INIT INFO +EOF + +insertscript startsecond_stoplast <<'EOF' || true +### BEGIN INIT INFO +# Provides: startsecond_stoplast +# Required-Start: startfirst_stopfirst +# Required-Stop: +# Default-Start: S +# Default-Stop: 6 +### END INIT INFO +EOF + +list_rclinks + +check_order S startfirst_stopfirst startsecond_stoplast +check_order 6 startfirst_stopfirst startsecond_stoplast +} +########################################################################## +test_fake_loop_reverse() { +# Test another fake loop using reverse dependencies to document that +# it can happen based on information provided in one package only. +# This should work, as it is possible to install the two scripts in +# sequence because one of the dependencies are optional. It does not +# with insserv today. Note thought that the generated order is +# different from the one above. + +echo +echo "info: test handling of 'fake' loops using reverse depends" +echo + +initdir_purge + +insertscript startfirst_stopfirst <<'EOF' || true +### BEGIN INIT INFO +# Provides: startfirst_stopfirst +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: 6 +### END INIT INFO +EOF + +insertscript startsecond_stoplast <<'EOF' || true +### BEGIN INIT INFO +# Provides: startsecond_stoplast +# Required-Start: startfirst_stopfirst +# Required-Stop: +# X-Stop-After: startfirst_stopfirst +# Default-Start: S +# Default-Stop: 6 +### END INIT INFO +EOF + +list_rclinks + +# #458582 +check_order S startfirst_stopfirst startsecond_stoplast +check_order 6 startfirst_stopfirst startsecond_stoplast +} +########################################################################## +test_badscript() { +echo +echo "info: test if bad script in init.d/ with no symlinks in rc*.d/ make problems" +echo + +initdir_purge + +addscript sitelocal <<'EOF' || true +### BEGIN INIT INFO +# Provides: duplicate +# Required-Start: $remote_fs +# Required-Stop: $remote_fs +# Default-Start: S +# Default-Stop: 6 +### END INIT INFO +EOF + +insertscript distroglobal <<'EOF' || true +### BEGIN INIT INFO +# Provides: dublicate +# Required-Start: $remote_fs +# Required-Stop: $remote_fs +# Default-Start: S +# Default-Stop: 6 +### END INIT INFO +EOF + +list_rclinks + +check_script_present S distroglobal +} +########################################################################## +test_onlystart() { +echo +echo "info: check that it work to insert scripts with only start runlevels" +echo + +initdir_purge + +insertscript onlystart <<'EOF' || true +### BEGIN INIT INFO +# Provides: onlystart +# Required-Start: $remote_fs +# Required-Stop: $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: +### END INIT INFO +EOF + +list_rclinks + +check_script_present 2 onlystart +check_script_present 3 onlystart +check_script_present 4 onlystart +check_script_present 5 onlystart + +check_script_not_present 0 onlystart +check_script_not_present 1 onlystart +check_script_not_present 6 onlystart +} +########################################################################## +test_onlystop() { +echo +echo "info: check that it work to insert scripts with only stop runlevels" +echo +# This test check that the common way to update the runlevels used by +# a given script is working. It simulates these calls to update-rc.d: +# update-rc.d oldscript default +# update-rc.d -f oldscript remove +# update-rc.d oldscript start 20 2 3 4 5 . stop 20 1 . + +initdir_purge + +insertscript onlystop <<'EOF' || true +### BEGIN INIT INFO +# Provides: onlystop +# Required-Start: $remote_fs +# Required-Stop: $remote_fs +# Default-Start: +# Default-Stop: 0 6 +### END INIT INFO +EOF + +list_rclinks + +check_script_present 0 onlystop +check_script_present 6 onlystop + +check_script_not_present 1 onlystop +check_script_not_present 2 onlystop +check_script_not_present 3 onlystop +check_script_not_present 4 onlystop +check_script_not_present 5 onlystop +check_script_not_present S onlystop +} +########################################################################## +test_removal() { +echo +echo "info: test if script removal removes all symlinks." +echo +# This test check that the common way to update the runlevels used by +# a given script is working. It simulates these calls to update-rc.d: +# update-rc.d oldscript default +# update-rc.d -f oldscript remove +# update-rc.d oldscript start 20 2 3 4 5 . stop 20 1 . + +initdir_purge + +insertscript oldscript <<'EOF' || true +### BEGIN INIT INFO +# Provides: oldscript +# Required-Start: $remote_fs +# Required-Stop: $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +### END INIT INFO +EOF + +# Check that the problematic symlinks are presend, as well as one that +# is OK. +check_script_present 0 oldscript +check_script_present 1 oldscript +check_script_present 3 oldscript +check_script_present 6 oldscript + +set +C +addscript oldscript <<'EOF' || true +### BEGIN INIT INFO +# Provides: oldscript +# Required-Start: $remote_fs +# Required-Stop: $remote_fs +# Default-Start: 2 4 5 +# Default-Stop: 1 +### END INIT INFO +EOF +set -C + +# Remove old symlinks +insserv_del oldscript +# Insert new ones, this time without runlevel 0 and 6 +insserv_reg oldscript + +list_rclinks + +check_script_not_present 0 oldscript +check_script_present 1 oldscript +check_script_present 2 oldscript +check_script_not_present 3 oldscript +check_script_not_present 6 oldscript +} + +########################################################################## +test_segfault_virtfac() { +echo +echo "info: detect segfault caused by script providing virtual facility." +echo + +initdir_purge + +insertscript badheaderscript <<'EOF' || true +### BEGIN INIT INFO +# Provides: $syslog +# Required-Start: +# Required-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +### END INIT INFO +EOF + +# Problem is only triggered if there are start or stop symlinks for +# the script present. +mkdir -p $initddir/../rc2.d +ln -s ../init.d/badheaderscript $initddir/../rc2.d/S02badheaderscript + +# This one segfaults +insertscript okscript <<'EOF' || true +### BEGIN INIT INFO +# Provides: okscript +# Required-Start: $syslog +# Required-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +### END INIT INFO +EOF + +list_rclinks + +check_script_present 2 okscript +} +########################################################################## +test_incorrect_startscripts() { +echo +echo "info: Check if insserv add start symlinks for scripts that" +echo "info: currently do not have them. #492526" +echo + +initdir_purge + +insertscript disablestartscript <<'EOF' || true +### BEGIN INIT INFO +# Provides: disablestartscript +# Required-Start: +# Required-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +### END INIT INFO +EOF +list_rclinks + +check_script_present 2 disablestartscript +check_script_present 5 disablestartscript +check_script_not_present S disablestartscript +check_script_present 1 disablestartscript + +rm $initddir/../rc{2,3,4,5}.d/S??disablestartscript + +# Update symlinks, see if it add start symlinks +insserv_reg . + +list_rclinks + +check_script_not_present 2 disablestartscript +check_script_not_present 3 disablestartscript +check_script_not_present 4 disablestartscript +check_script_not_present 5 disablestartscript +check_script_not_present S disablestartscript +check_script_present 0 disablestartscript +check_script_present 1 disablestartscript +} +########################################################################## +test_incorrect_stopscripts() { +echo +echo "info: Check if insserv add stop symlinks for scripts that" +echo "info: currently do not have them." +echo + +initdir_purge + +insertscript disablestopscript <<'EOF' || true +### BEGIN INIT INFO +# Provides: disablestopscript +# Required-Start: +# Required-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +### END INIT INFO +EOF +list_rclinks + +check_script_present 2 disablestopscript +check_script_present 5 disablestopscript +check_script_not_present S disablestopscript +check_script_present 1 disablestopscript + +rm $initddir/../rc{0,1}.d/K??disablestopscript + +# Update symlinks, see if it add stop symlinks +insserv_reg . + +list_rclinks + +check_script_present 2 disablestopscript +check_script_present 5 disablestopscript +check_script_not_present S disablestopscript +check_script_not_present 0 disablestopscript +check_script_not_present 1 disablestopscript +} +########################################################################## +test_newbug_keepoldorder() { +echo +echo "info: Verify that introducing a loop in a working system do" +echo "info: not change the order of the scripts currently on disk." +echo + +initdir_purge + +insertscript mountall <<'EOF' || true +### BEGIN INIT INFO +# Provides: mountall +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +insertscript needlocal <<'EOF' || true +### BEGIN INIT INFO +# Provides: needlocal +# Required-Start: $local_fs +# Required-Stop: $local_fs +# Default-Start: S +# Default-Stop: 6 +### END INIT INFO +EOF + +insertscript needremote <<'EOF' || true +### BEGIN INIT INFO +# Provides: needremote +# Required-Start: $remote_fs needlocal +# Required-Stop: $remote_fs needlocal +# Default-Start: S +# Default-Stop: 6 +### END INIT INFO +EOF + +insertscript needboth <<'EOF' || true +### BEGIN INIT INFO +# Provides: needboth +# Required-Start: needlocal needremote +# Required-Stop: needlocal needremote +# Default-Start: S +# Default-Stop: 6 +### END INIT INFO +EOF + +list_rclinks + +check_order S mountall needlocal +check_order S mountall needremote +check_order S mountall needboth +check_order S needlocal needremote +check_order S needlocal needboth +check_order S needremote needboth + +# Then introduce buggy dependencies in an existing script +set +C +addscript needboth <<'EOF' || true +### BEGIN INIT INFO +# Provides: needboth +# Required-Start: $remote_fs +# Required-Stop: $remote_fs +# X-Start-Before: $local_fs +# Default-Start: S +# Default-Stop: 6 +### END INIT INFO +EOF +set -C + +echo "info: calling insserv after introducing a bug in script needboth" +insserv_reg needboth || true + +list_rclinks + +# The severity of this test should be fatal, below is explanation about how +# new (1.11.10) and old (1.11.0) insserv version behaviour changed in this +# test. +# +# Hmm ... with this I've found out that the old insserv will +# run on a loop and therefore exit. This loop was caused +# by the system facility $local_fs make the old insserv +# to do an exit ... now the problem is that the new insserv +# expands all system facility to their real requirements. +# This leads to the new behaviour as there is no node during +# the sorting algorithm which would cause such a loop. +# +# In other words: that the old insserv hasn't changed the +# order was simply a side effect of having a ghost node +# whereas the new insserv does not use such nodes anymore. +# +# If you would remove the `X-Start-Before: $local_fs' the +# old insserv will also change the boot order. + +${severity}_order S mountall needlocal +${severity}_order S mountall needremote +${severity}_order S mountall needboth +${severity}_order S needlocal needremote +${severity}_order S needlocal needboth +${severity}_order S needremote needboth +} +########################################################################## +test_start_before() { +echo +echo "info: Verify that X-start-before work as it should." +echo + +initdir_purge + +insertscript startlast <<'EOF' || true +### BEGIN INIT INFO +# Provides: startlast +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +insertscript startfirst <<'EOF' || true +### BEGIN INIT INFO +# Provides: startfirst +# Required-Start: +# Required-Stop: +# X-Start-Before: startlast +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +list_rclinks + +check_order S startfirst startlast +} +########################################################################## +test_stop_after() { +echo +echo "info: Verify that X-stop-after work as it should." +echo + +initdir_purge + +insertscript stopfirst <<'EOF' || true +### BEGIN INIT INFO +# Provides: stopfirst +# Required-Start: +# Required-Stop: +# Default-Start: +# Default-Stop: 0 6 +### END INIT INFO +EOF + +insertscript stopafter <<'EOF' || true +### BEGIN INIT INFO +# Provides: stopafter +# Required-Start: +# Required-Stop: +# X-Stop-After: stopfirst +# Default-Start: +# Default-Stop: 0 6 +### END INIT INFO +EOF + +list_rclinks + +check_order 0 stopfirst stopafter +} +########################################################################## +test_adding_start() { +echo +echo "info: Make sure that adding start levels do not change an existing installation." +echo + +initdir_purge + +insertscript addstartscript <<'EOF' || true +### BEGIN INIT INFO +# Provides: addstartscript +# Required-Start: +# Required-Stop: +# Default-Start: +# Default-Stop: 1 +### END INIT INFO +EOF + +check_script_present 1 addstartscript + +check_script_not_present S addstartscript +check_script_not_present 0 addstartscript +check_script_not_present 2 addstartscript +check_script_not_present 3 addstartscript +check_script_not_present 4 addstartscript +check_script_not_present 5 addstartscript +check_script_not_present 6 addstartscript + +# Then change runlevel in existing script +set +C +addscript addstartscript <<'EOF' || true +### BEGIN INIT INFO +# Provides: addstartscript +# Required-Start: +# Required-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 1 +### END INIT INFO +EOF +set -C + +# Update script after changing the header +insserv_reg addstartscript || true + +list_rclinks + +check_script_present 1 addstartscript + +check_script_not_present S addstartscript +check_script_not_present 0 addstartscript +check_script_not_present 2 addstartscript +check_script_not_present 3 addstartscript +check_script_not_present 4 addstartscript +check_script_not_present 5 addstartscript +check_script_not_present 6 addstartscript +} +########################################################################## +test_removing_start() { +echo +echo "info: Make sure that removing start levels do not change an existing installation." +echo + +initdir_purge + +insertscript remstartscript <<'EOF' || true +### BEGIN INIT INFO +# Provides: remstartscript +# Required-Start: +# Required-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +### END INIT INFO +EOF + +check_script_present 0 remstartscript +check_script_present 1 remstartscript +check_script_present 2 remstartscript +check_script_present 3 remstartscript +check_script_present 4 remstartscript +check_script_present 5 remstartscript +check_script_present 6 remstartscript + +# Then change runlevel in existing script +set +C +addscript remstartscript <<'EOF' || true +### BEGIN INIT INFO +# Provides: remstartscript +# Required-Start: +# Required-Stop: +# Default-Start: +# Default-Stop: 0 1 6 +### END INIT INFO +EOF +set -C + +# Update script after changing the header +insserv_reg remstartscript || true + +list_rclinks + +check_script_present 2 remstartscript +check_script_present 3 remstartscript +check_script_present 4 remstartscript +check_script_present 5 remstartscript +} +########################################################################## +test_adding_stop() { +echo +echo "info: Make sure that adding stop levels do not change an existing installation." +echo + +initdir_purge + +insertscript addstopscript <<'EOF' || true +### BEGIN INIT INFO +# Provides: addstopscript +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +check_script_present S addstopscript +check_script_not_present 0 addstopscript +check_script_not_present 1 addstopscript +check_script_not_present 2 addstopscript +check_script_not_present 3 addstopscript +check_script_not_present 4 addstopscript +check_script_not_present 5 addstopscript +check_script_not_present 6 addstopscript + +# Then change runlevel in existing script +set +C +addscript addstopscript <<'EOF' || true +### BEGIN INIT INFO +# Provides: addstopscript +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: 0 +### END INIT INFO +EOF +set -C + +# Update script after changing the header +insserv_reg addstopscript || true + +list_rclinks + +check_script_present S addstopscript +check_script_not_present 0 addstopscript +check_script_not_present 1 addstopscript +check_script_not_present 2 addstopscript +check_script_not_present 3 addstopscript +check_script_not_present 4 addstopscript +check_script_not_present 5 addstopscript +check_script_not_present 6 addstopscript +} +########################################################################## +test_removing_stop() { +echo +echo "info: Make sure that removing stop levels do not change an existing installation." +echo + +initdir_purge + +insertscript remstopscript <<'EOF' || true +### BEGIN INIT INFO +# Provides: remstopscript +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: 0 6 +### END INIT INFO +EOF + +check_script_present S remstopscript +check_script_present 0 remstopscript +check_script_present 6 remstopscript + +check_script_not_present 1 remstopscript +check_script_not_present 2 remstopscript +check_script_not_present 3 remstopscript +check_script_not_present 4 remstopscript +check_script_not_present 5 remstopscript + +# Then change runlevel in existing script +set +C +addscript remstopscript <<'EOF' || true +### BEGIN INIT INFO +# Provides: remstopscript +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF +set -C + +# Update script after changing the header +insserv_reg remstopscript || true + +list_rclinks + +check_script_present 0 remstopscript +check_script_present 6 remstopscript +} +########################################################################## +test_duplicate_provides() { +echo +echo "info: test two initscripts providing same facility." +echo "info: Not sure if this should fail or not." +echo + +initdir_purge + +addscript one <<'EOF' || true +### BEGIN INIT INFO +# Provides: samefac +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +addscript two <<'EOF' || true +### BEGIN INIT INFO +# Provides: samefac +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +insserv_reg one || true +insserv_reg two || true + +list_rclinks + +check_script_present S one +${severity}_script_not_present S two +} +########################################################################## +test_bogus_facility() { +echo +echo "info: test insertion of script requiring a virtual facility that doesn't exist" +echo + +initdir_purge + +addscript needbogusvirtual <<'EOF' +### BEGIN INIT INFO +# Provides: needbogusvirtual +# Required-Start: $bogusvirtualfacility +# Required-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +insserv_reg needbogusvirtual || true + +list_rclinks + +test_script_not_present S needbogusvirtual +} +########################################################################## +test_insserv_conf_d() { +echo +echo "info: test that /etc/insserv.conf.d/ is used" +echo + +initdir_purge +rm -rf ${insconf}.d +mkdir -p ${insconf}.d + +# add a base service, to ensure check_order() is accurate +insertscript dummy <<'EOF' +### BEGIN INIT INFO +# Provides: dummy +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +cat <<'EOF' > ${insconf}.d/facone +$commvirtfac +facone +EOF + +insertscript facone <<'EOF' || true +### BEGIN INIT INFO +# Provides: facone +# Required-Start: dummy +# Required-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +cat <<'EOF' > ${insconf}.d/factwo +$commvirtfac +factwo +EOF + +insertscript factwo <<'EOF' || true +### BEGIN INIT INFO +# Provides: factwo +# Required-Start: dummy +# Required-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +addscript service <<'EOF' || true +### BEGIN INIT INFO +# Provides: service +# Required-Start: $commvirtfac +# Required-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +insserv_reg service || true + +list_rclinks + +check_script_present S service +check_order S facone service +check_order S factwo service + +rm -rf ${insconf}.d +} +########################################################################## +test_broken_header() { +echo +echo "info: test insertion of script missing Required-{Start,Stop} fields" +echo + +initdir_purge + +addscript badheader <<'EOF' +### BEGIN INIT INFO +# Provides: badheader +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +### END INIT INFO +EOF + +insserv_reg badheader || true + +list_rclinks + +test_script_present 0 badheader +test_script_present 1 badheader +test_script_present 2 badheader +test_script_present 3 badheader +test_script_present 4 badheader +test_script_present 5 badheader +test_script_present 6 badheader +} +########################################################################## +test_noprovides_header() { +echo +echo "info: test insertion of script missing Provides fields" +echo + +initdir_purge + +addscript badheader <<'EOF' +### BEGIN INIT INFO +# Required-Start: +# Required-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +### END INIT INFO +EOF + +insserv_reg badheader || true + +list_rclinks + +test_script_present 0 badheader +test_script_present 1 badheader +test_script_present 2 badheader +test_script_present 3 badheader +test_script_present 4 badheader +test_script_present 5 badheader +test_script_present 6 badheader +} +########################################################################## +test_no_default_start() { +echo +echo "info: test insertion of script missing Default-Start field" +echo + +initdir_purge + +addscript nodefstart <<'EOF' +### BEGIN INIT INFO +# Provides: nodefstart +# Required-Start: +# Required-Stop: +# Default-Stop: 0 6 +### END INIT INFO +EOF + +insserv_reg nodefstart || true + +list_rclinks + +check_script_present 0 nodefstart +check_script_present 6 nodefstart + +check_script_not_present 2 nodefstart +check_script_not_present 3 nodefstart +check_script_not_present 4 nodefstart +check_script_not_present 5 nodefstart +} +########################################################################## +test_no_default_stop() { +echo +echo "info: test insertion of script missing Default-Stop field" +echo + +initdir_purge + +addscript nodefstop <<'EOF' +### BEGIN INIT INFO +# Provides: nodefstop +# Required-Start: +# Required-Stop: +# Default-Start: 2 3 4 5 +### END INIT INFO +EOF + +insserv_reg nodefstop || true + +list_rclinks + +check_script_present 2 nodefstop +check_script_present 3 nodefstop +check_script_present 4 nodefstop +check_script_present 5 nodefstop + +check_script_not_present 0 nodefstop +check_script_not_present 1 nodefstop +check_script_not_present 6 nodefstop +} +########################################################################## +test_initd_symlink() { +echo +echo "info: test that a symlink in /etc/init.d/ to another script does not cause problems" +echo + +initdir_purge + +addscript symlinked <<'EOF' +### BEGIN INIT INFO +# Provides: symlinked +# Required-Start: +# Required-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 1 +### END INIT INFO +EOF + +addscript outsider <<'EOF' +### BEGIN INIT INFO +# Provides: outsider +# Required-Start: +# Required-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 1 +### END INIT INFO +EOF + +#addscript halt <<'EOF' +### BEGIN INIT INFO +# Provides: halt +# Required-Start: +# Required-Stop: +# Default-Start: +# Default-Stop: 0 6 +### END INIT INFO +#EOF + +# Now make an illegal symlink to see if it causes problems, #485045 +ln -s symlinked ${initddir}/symlink + +insserv_reg symlinked || true +insserv_reg symlink || true + +check_script_present 1 symlinked +check_script_present 2 symlinked +check_script_present 3 symlinked +check_script_present 4 symlinked +check_script_present 5 symlinked +check_script_not_present 1 symlink +check_script_not_present 2 symlink +check_script_not_present 3 symlink +check_script_not_present 4 symlink +check_script_not_present 5 symlink + +# Add a /etc/init.d/reboot -> halt symlink, to make sure the SUSE case +# is not broken with stricter symlink sanity checking +#ln -s halt ${initddir}/reboot + +#insserv_reg reboot || true + +#check_script_present 0 reboot +#check_script_present 6 reboot + +# Move outsider to a location other than /etc/init.d/ and create a symlink +# to it. insserv should register it without problems. +mv ${initddir}/outsider ${initddir}/../ +ln -s ../outsider ${initddir}/outsidelink + +insserv_reg outsidelink || true + +list_rclinks + +check_script_present 1 outsidelink +check_script_present 2 outsidelink +check_script_present 3 outsidelink +check_script_present 4 outsidelink +check_script_present 5 outsidelink + +rm -f ${initddir}/../outsider +} +########################################################################## +test_deterministic_order() { +echo +echo "info: test two or more initscripts providing same facility, making sure" +echo "info: that the first script can be registered with insserv, but others fail." +echo + +initdir_purge + +addscript abc <<'EOF' || true +### BEGIN INIT INFO +# Provides: service +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +addscript xyz <<'EOF' || true +### BEGIN INIT INFO +# Provides: service +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +addscript hjk <<'EOF' || true +### BEGIN INIT INFO +# Provides: service +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO +EOF + +insserv_reg xyz || true +insserv_reg hjk || true +insserv_reg abc || true + +list_rclinks + +# #494514 +check_script_present S xyz +check_script_not_present S abc +check_script_not_present S hjk +} +########################################################################## +test_all_keyword() { +echo +echo "info: test behaviour of a script depending on another with the \$all keyword" +echo "info: #491391" +echo + +initdir_purge + +# Insert a few scripts to flesh out $initdir +for script in one two three +do +insertscript $script < $insconf +$local_fs +mountall +nonexisting +$remote_fs $local_fs +EOF +set -C + +insertscript mountall <<'EOF' +### BEGIN INIT INFO +# Provides: mountall +# Required-Start: +# Required-Stop: +# Default-Start: 1 +# Default-Stop: +### END INIT INFO +EOF + +insertscript dbus <<'EOF' +### BEGIN INIT INFO +# Provides: dbus +# Required-Start: +# Required-Stop: +# Default-Start: 1 +# Default-Stop: +### END INIT INFO +EOF + +insertscript hal <<'EOF' +### BEGIN INIT INFO +# Provides: hal +# Required-Start: $remote_fs dbus +# Required-Stop: +# Default-Start: 1 +# Default-Stop: +### END INIT INFO +EOF + +list_rclinks + +if ! grep -q "^hal: mountall dbus" ${initddir}/.depend.start ; then + msg="hal should depend on dbus and mountall in .depend.start:" + if [ test = "$severity" ] ; then + warning "$msg" + else + error "$msg" + fi + grep "^hal: " ${initddir}/.depend.start | sed 's/^/ /' +fi + +update_conf +} + +######################### + +test_insserv_virt_loop() { +echo +echo "info: test insserv handle virtual facilities depending on itself." +echo + +initdir_purge + +list_rclinks + +# If $local_fs depend on itself, the error is triggered. +set +C +cat <<'EOF' > $insconf +$local_fs +mountall $local_fs +EOF +set -C + +# This used to hang and use unlimited amount of memory. Now return +# error instead. +insertscript testscript <<'EOF' || true +### BEGIN INIT INFO +# Provides: testscript +# Required-Start: $local_fs +# Required-Stop: +# Default-Start: 1 +# Default-Stop: +### END INIT INFO +EOF + +list_rclinks + +update_conf +} + +########################################################################## +test_local_virtual() { +echo +echo "info: Test if home made virtual facilities work as they should." +echo + +initdir_purge + +mkdir $insconf.d + +insertscript test1 <<'EOF' || true +### BEGIN INIT INFO +# Provides: test1 +# Required-Start: $mail-transport-agent +# Required-Stop: +# Default-Start: 1 +# Default-Stop: +### END INIT INFO +EOF + +insertscript test2 <<'EOF' || true +### BEGIN INIT INFO +# Provides: test2 +# Required-Start: $mail-transport-agent +# Required-Stop: +# Default-Start: 1 +# Default-Stop: +### END INIT INFO +EOF + +list_rclinks + +set +C +cat <<'EOF' > $insconf.d/test3 +$mail-transport-agent test3 +EOF +insertscript test3 <<'EOF' || true +### BEGIN INIT INFO +# Provides: test3 +# Required-Start: +# Required-Stop: +# Default-Start: 1 +# Default-Stop: +### END INIT INFO +EOF + +cat <<'EOF' > $insconf.d/test4 +$mail-transport-agent +test4 +EOF +set -C +insertscript test4 <<'EOF' || true +### BEGIN INIT INFO +# Provides: test4 +# Required-Start: test3 +# Required-Stop: +# Default-Start: 1 +# Default-Stop: +### END INIT INFO +EOF + +list_rclinks + +check_order 1 test3 test1 +check_order 1 test3 test2 +check_order 1 test4 test1 +check_order 1 test4 test2 + +} +########################################################################## +test_insserv_upstart() { +echo +echo "info: test if insserv handle upstart jobs properly." +echo + +initdir_purge + +list_rclinks + +# This used to hang and use unlimited amount of memory. Now return +# error instead. +upstartdir=${tmpdir}/etc/init + +upstartjob="${tmpdir}/lib/init/upstart-job" + +# Add upstart config +oldconf="$insconf" +insconf="$insconf -u $upstartjob" + +# Dummy entry +mkdir -p $(dirname $upstartjob) +cat > $upstartjob < $upstartdir/$name + ln -s $upstartjob $initddir/$name + insserv_reg $name +} + +# XXX Someone that understand upstart need to fill in sensible stuff +# here +insert_upstart_job upstart-test <" + exit 1 +fi + +oldtar="$(tar tzf $1)" +for i in S $(seq 0 6); do + echo "Runlevel $i" + new="$(cd /etc/rc$i.d; ls -1 [KS]* | sort | nl)" + old="$(echo "$oldtar" | grep "^rc$i.d/[KS]" | cut -d/ -f2 | sort | nl)" + case $i in + S|0|6) + old="$(echo "$old" | sed -r "s/[KS][0-9]+//")" + new="$(echo "$new" | sed -r "s/[KS][0-9]+//")" + ;; + *) + old="$(echo "$old" | sed -r "s/([KS])[0-9]+/\1_/")" + new="$(echo "$new" | sed -r "s/([KS])[0-9]+/\1_/")" + ;; + esac + echo "$new" | while read num cmd; do + oldnum=$(echo "$old" | grep "[[:space:]]$cmd$" | awk '{print $1}') + if [ "$oldnum" ]; then + diff=$(($num - $oldnum)) + else + oldnum="---" + diff="" + fi + if [ ${#cmd} -ge 16 ]; then + echo -e "$cmd\t$num\t$oldnum\t$diff" + elif [ ${#cmd} -ge 8 ]; then + echo -e "$cmd\t\t$num\t$oldnum\t$diff" + else + echo -e "$cmd\t\t\t$num\t$oldnum\t$diff" + fi + done + echo "$old" | while read num cmd; do + if ! echo "$new" | grep -q "[[:space:]]$cmd$"; then + if [ ${#cmd} -ge 16 ]; then + echo -e "$cmd\t---\t$oldnum" + elif [ ${#cmd} -ge 8 ]; then + echo -e "$cmd\t\t---\t$oldnum" + else + echo -e "$cmd\t\t\t---\t$oldnum" + fi + fi + done + echo +done diff --git a/debian/update-bootsystem-insserv b/debian/update-bootsystem-insserv new file mode 100644 index 0000000..5b20a17 --- /dev/null +++ b/debian/update-bootsystem-insserv @@ -0,0 +1,24 @@ +#!/bin/sh +# +# Author: Petter Reinholdtsen +# Date: 2009-08-04 +# +# Transition script only to be used by sysv-rc version 2.87dsf-2 if +# insserv is upgraded without sysv-rc being upgraded too. + +set -e + +case "$1" in + enable|'') + exit 0 + ;; + check) + exit 1 + ;; + *) + echo "error: Unknown argument '$1'" + exit 1 + ;; +esac + +exit 0 diff --git a/debian/update-rc.d-insserv b/debian/update-rc.d-insserv new file mode 100644 index 0000000..1853251 --- /dev/null +++ b/debian/update-rc.d-insserv @@ -0,0 +1,593 @@ +#! /usr/bin/perl +# +# update-rc.d Update the links in /etc/rc[0-9S].d/ +# + +use strict; +use warnings; + +my $initd = "/etc/init.d"; +my $etcd = "/etc/rc"; +my $notreally = 0; + +# Save last action to this directory +my $archive = "/var/lib/update-rc.d"; + +# Print usage message and die. + +sub usage { + print STDERR "update-rc.d: error: @_\n" if ($#_ >= 0); + print STDERR < remove + update-rc.d [-n] defaults [NN | SS KK] + update-rc.d [-n] start|stop NN runlvl [runlvl] [...] . + update-rc.d [-n] disable|enable [S|2|3|4|5] + -n: not really + -f: force + +The disable|enable API is not stable and might change in the future. +EOF + exit (1); +} + +# Dependency based boot sequencing is the default, but upgraded +# systems might keep the legacy ordering until the sysadm choose to +# migrate to the new ordering method. sysv-rc version 2.87dsf-2 will +# remove /var/lib/insserv/using-insserv and this divert, thus transfering +# the responsibility for dependency based update-rc.d to sysv-rc. +if ( -f "/var/lib/insserv/using-insserv" && ! -f "/etc/init.d/.legacy-bootordering" ) { + info("using dependency based boot sequencing"); + exit insserv_updatercd(@ARGV); +} + +# Check out options. +my $force; + +my @orig_argv = @ARGV; + +while($#ARGV >= 0 && ($_ = $ARGV[0]) =~ /^-/) { + shift @ARGV; + if (/^-n$/) { $notreally++; next } + if (/^-f$/) { $force++; next } + if (/^-h|--help$/) { &usage; } + &usage("unknown option"); +} + +sub save_last_action { + my ($script, @arguments) = @_; + + return if $notreally; + + open(FILE, ">", "$archive/${script}.new") || die "unable to write to $archive/${script}.new"; + print FILE join(" ","update-rc.d",@arguments), "\n"; + close(FILE); + rename "$archive/${script}.new", "$archive/${script}"; +} + +sub remove_last_action { + my ($script) = @_; + unlink "$archive/$script"; +} + +# Action. + +&usage() if ($#ARGV < 1); +my $bn = shift @ARGV; + +unless ($bn =~ m/[a-zA-Z0-9+.-]+/) { + print STDERR "update-rc.d: illegal character in name '$bn'\n"; + exit (1); +} + +if ($ARGV[0] ne 'remove') { + if (! -f "$initd/$bn") { + print STDERR "update-rc.d: $initd/$bn: file does not exist\n"; + exit (1); + } + &parse_lsb_header("$initd/$bn"); + &cmp_args_with_defaults($bn, $ARGV[0], @ARGV); +} elsif (-f "$initd/$bn") { + if (!$force) { + printf STDERR "update-rc.d: $initd/$bn exists during rc.d purge (use -f to force)\n"; + exit (1); + } +} + +my @startlinks; +my @stoplinks; + +$_ = $ARGV[0]; +if (/^remove$/) { &checklinks ("remove"); remove_last_action($bn); } +elsif (/^defaults$/) { &defaults (@ARGV); &makelinks; save_last_action($bn, @orig_argv); } +elsif (/^(start|stop)$/) { &startstop (@ARGV); &makelinks; save_last_action($bn, @orig_argv); } +elsif (/^(dis|en)able$/) { &toggle (@ARGV); &makelinks; save_last_action($bn, @orig_argv); } +else { &usage; } + +exit (0); + +sub info { + print STDOUT "update-rc.d: @_\n"; +} + +sub warning { + print STDERR "update-rc.d: warning: @_\n"; +} + +sub error { + print STDERR "update-rc.d: error: @_\n"; + exit (1); +} + +sub error_code { + my $rc = shift; + print STDERR "update-rc.d: error: @_\n"; + exit ($rc); +} + +# Check if there are links in /etc/rc[0-9S].d/ +# Remove if the first argument is "remove" and the links +# point to $bn. + +sub is_link () { + my ($op, $fn, $bn) = @_; + if (! -l $fn) { + warning "$fn is not a symbolic link\n"; + return 0; + } else { + my $linkdst = readlink ($fn); + if (! defined $linkdst) { + die ("update-rc.d: error reading symbolic link: $!\n"); + } + if (($linkdst ne "../init.d/$bn") && ($linkdst ne "$initd/$bn")) { + warning "$fn is not a link to ../init.d/$bn or $initd/$bn\n"; + return 0; + } + } + return 1; +} + +sub checklinks { + my ($i, $found, $fn, $islnk); + + print " Removing any system startup links for $initd/$bn ...\n" + if (defined $_[0] && $_[0] eq 'remove'); + + $found = 0; + + foreach $i (0..9, 'S') { + unless (chdir ("$etcd$i.d")) { + next if ($i =~ m/^[789S]$/); + die("update-rc.d: chdir $etcd$i.d: $!\n"); + } + opendir(DIR, "."); + my $saveBN=$bn; + $saveBN =~ s/\+/\\+/g; + foreach $_ (readdir(DIR)) { + next unless (/^[SK]\d\d$saveBN$/); + $fn = "$etcd$i.d/$_"; + $found = 1; + $islnk = &is_link ($_[0], $fn, $bn); + next unless (defined $_[0] and $_[0] eq 'remove'); + if (! $islnk) { + print " $fn is not a link to ../init.d/$bn; not removing\n"; + next; + } + print " $etcd$i.d/$_\n"; + next if ($notreally); + unlink ("$etcd$i.d/$_") || + die("update-rc.d: unlink: $!\n"); + } + closedir(DIR); + } + $found; +} + +sub parse_lsb_header { + my $initdscript = shift; + my %lsbinfo; + my $lsbheaders = "Provides|Required-Start|Required-Stop|Default-Start|Default-Stop"; + open(INIT, "<$initdscript") || die "error: unable to read $initdscript"; + while () { + chomp; + $lsbinfo{'found'} = 1 if (m/^\#\#\# BEGIN INIT INFO\s*$/); + last if (m/\#\#\# END INIT INFO\s*$/); + if (m/^\# ($lsbheaders):\s*(\S?.*)$/i) { + $lsbinfo{lc($1)} = $2; + } + } + close(INIT); + + # Check that all the required headers are present + if (!$lsbinfo{found}) { + printf STDERR "update-rc.d: warning: $initdscript missing LSB information\n"; + printf STDERR "update-rc.d: see \n"; + } else { + for my $key (split(/\|/, lc($lsbheaders))) { + if (!exists $lsbinfo{$key}) { + warning "$initdscript missing LSB keyword '$key'\n"; + } + } + } +} + + +# Process the arguments after the "enable" or "disable" keyword. + +sub toggle { + my @argv = @_; + my ($action, %lvls, @start, @stop, @xstartlinks); + + if (!&checklinks) { + print " System start/stop links for $initd/$bn do not exist.\n"; + exit (0); + } + + $action = $argv[0]; + if ($#argv > 1) { + while ($#argv > 0 && shift @argv) { + if ($argv[0] =~ /^[S2-5]$/) { + $lvls{$argv[0]}++; + } else { + &usage ("expected 'S' '2' '3' '4' or '5'"); + } + } + } else { + $lvls{$_}++ for ('S', '2', '3', '4', '5'); + } + + push(@start, glob($etcd . '[2-5S].d/[KS][0-9][0-9]' . $bn)); + + foreach (@start) { + my $islink = &is_link (undef, $_, $bn); + next if !$islink; + + next unless my ($lvl, $sk, $seq) = m/^$etcd([2-5S])\.d\/([SK])([0-9]{2})$bn$/; + $startlinks[$lvl] = $sk . $seq; + + if ($action eq 'disable' and $sk eq 'S' and $lvls{$lvl}) { + $xstartlinks[$lvl] = 'K' . sprintf "%02d", (100 - $seq); + } elsif ($action eq 'enable' and $sk eq 'K' and $lvls{$lvl}) { + $xstartlinks[$lvl] = 'S' . sprintf "%02d", -($seq - 100); + } else { + $xstartlinks[$lvl] = $sk . $seq; + } + } + + push(@stop, glob($etcd . '[016].d/[KS][0-9][0-9]' . $bn)); + + foreach (@stop) { + my $islink = &is_link (undef, $_, $bn); + next if !$islink; + + next unless my ($lvl, $sk, $seq) = m/^$etcd([016])\.d\/([SK])([0-9]{2})$bn$/; + $stoplinks[$lvl] = $sk . $seq; + } + + if ($action eq 'disable') { + print " Disabling system startup links for $initd/$bn ...\n"; + } elsif ($action eq 'enable') { + print " Enabling system startup links for $initd/$bn ...\n"; + } + + &checklinks ("remove"); + @startlinks = @xstartlinks; + + 1; +} + +# Process the arguments after the "defaults" keyword. + +sub defaults { + my @argv = @_; + my ($start, $stop) = (20, 20); + + &usage ("defaults takes only one or two codenumbers") if ($#argv > 2); + $start = $stop = $argv[1] if ($#argv >= 1); + $stop = $argv[2] if ($#argv >= 2); + &usage ("codenumber must be a number between 0 and 99") + if ($start !~ /^\d\d?$/ || $stop !~ /^\d\d?$/); + + $start = sprintf("%02d", $start); + $stop = sprintf("%02d", $stop); + + $stoplinks[$_] = "K$stop" for (0, 1, 6); + $startlinks[$_] = "S$start" for (2, 3, 4, 5); + + 1; +} + +# Process the arguments after the start or stop keyword. + +sub startstop { + my @argv = @_; + my($letter, $NN, $level); + + while ($#argv >= 0) { + if ($argv[0] eq 'start') { $letter = 'S'; } + elsif ($argv[0] eq 'stop') { $letter = 'K'; } + else { + &usage("expected start|stop"); + } + + if ($argv[1] !~ /^\d\d?$/) { + &usage("expected NN after $argv[0]"); + } + $NN = sprintf("%02d", $argv[1]); + + if ($argv[-1] ne '.') { + &usage("start|stop arguments not terminated by \".\""); + } + + shift @argv; shift @argv; + $level = shift @argv; + do { + if ($level !~ m/^[0-9S]$/) { + &usage( + "expected runlevel [0-9S] (did you forget \".\" ?)"); + } + if (! -d "$etcd$level.d") { + print STDERR + "update-rc.d: $etcd$level.d: no such directory\n"; + exit(1); + } + $level = 99 if ($level eq 'S'); + $startlinks[$level] = "$letter$NN" if ($letter eq 'S'); + $stoplinks[$level] = "$letter$NN" if ($letter eq 'K'); + } while (($level = shift @argv) ne '.'); + } + 1; +} + +# Create the links. + +sub makelinks { + my($t, $i); + my @links; + + if (&checklinks) { + print " System start/stop links for $initd/$bn already exist.\n"; + return 0; + } + print " Adding system startup for $initd/$bn ...\n"; + + # nice unreadable perl mess :) + + for($t = 0; $t < 2; $t++) { + @links = $t ? @startlinks : @stoplinks; + for($i = 0; $i <= $#links; $i++) { + my $lvl = $i; + $lvl = 'S' if ($i == 99); + next if (!defined $links[$i] or $links[$i] eq ''); + print " $etcd$lvl.d/$links[$i]$bn -> ../init.d/$bn\n"; + next if ($notreally); + symlink("../init.d/$bn", "$etcd$lvl.d/$links[$i]$bn") + || die("update-rc.d: symlink: $!\n"); + } + } + + 1; +} + +## Dependency based +sub insserv_updatercd { + my @args = @_; + my @opts; + my $scriptname; + my $action; + my $notreally = 0; + + my @orig_argv = @args; + + while($#args >= 0 && ($_ = $args[0]) =~ /^-/) { + shift @args; + if (/^-n$/) { push(@opts, $_); $notreally++; next } + if (/^-f$/) { push(@opts, $_); next } + if (/^-h|--help$/) { &usage; } + usage("unknown option"); + } + + usage("not enough arguments") if ($#args < 1); + + $scriptname = shift @args; + $action = shift @args; + if ("remove" eq $action) { + if ( -f "/etc/init.d/$scriptname" ) { + my $rc = system("insserv", @opts, "-r", $scriptname) >> 8; + if (0 == $rc && !$notreally) { + remove_last_action($scriptname); + } + error_code($rc, "insserv rejected the script header") if $rc; + exit $rc; + } else { + # insserv removes all dangling symlinks, no need to tell it + # what to look for. + my $rc = system("insserv", @opts) >> 8; + if (0 == $rc && !$notreally) { + remove_last_action($scriptname); + } + error_code($rc, "insserv rejected the script header") if $rc; + exit $rc; + } + } elsif ("defaults" eq $action || "start" eq $action || + "stop" eq $action) { + # All start/stop/defaults arguments are discarded so emit a + # message if arguments have been given and are in conflict + # with Default-Start/Default-Stop values of LSB comment. + cmp_args_with_defaults($scriptname, $action, @args); + + if ( -f "/etc/init.d/$scriptname" ) { + my $rc = system("insserv", @opts, $scriptname) >> 8; + if (0 == $rc && !$notreally) { + save_last_action($scriptname, @orig_argv); + } + error_code($rc, "insserv rejected the script header") if $rc; + exit $rc; + } else { + error("initscript does not exist: /etc/init.d/$scriptname"); + } + } elsif ("disable" eq $action || "enable" eq $action) { + insserv_toggle($notreally, $action, $scriptname, @args); + # Call insserv to resequence modified links + my $rc = system("insserv", @opts, $scriptname) >> 8; + if (0 == $rc && !$notreally) { + save_last_action($scriptname, @orig_argv); + } + error_code($rc, "insserv rejected the script header") if $rc; + exit $rc; + } else { + usage(); + } +} + +sub parse_def_start_stop { + my $script = shift; + my (%lsb, @def_start_lvls, @def_stop_lvls); + + open my $fh, '<', $script or error("unable to read $script"); + while (<$fh>) { + chomp; + if (m/^### BEGIN INIT INFO$/) { + $lsb{'begin'}++; + } + elsif (m/^### END INIT INFO$/) { + $lsb{'end'}++; + last; + } + elsif ($lsb{'begin'} and not $lsb{'end'}) { + if (m/^# Default-Start:\s*(\S?.*)$/) { + @def_start_lvls = split(' ', $1); + } + if (m/^# Default-Stop:\s*(\S?.*)$/) { + @def_stop_lvls = split(' ', $1); + } + } + } + close($fh); + + return (\@def_start_lvls, \@def_stop_lvls); +} + +sub lsb_header_for_script { + my $name = shift; + + foreach my $file ("/etc/insserv/overrides/$name", "/etc/init.d/$name", + "/usr/share/insserv/overrides/$name") { + return $file if -s $file; + } + + error("cannot find a LSB script for $name"); +} + +sub cmp_args_with_defaults { + my ($name, $act) = (shift, shift); + my ($lsb_start_ref, $lsb_stop_ref, $arg_str, $lsb_str); + my (@arg_start_lvls, @arg_stop_lvls, @lsb_start_lvls, @lsb_stop_lvls); + + ($lsb_start_ref, $lsb_stop_ref) = parse_def_start_stop("/etc/init.d/$name"); + @lsb_start_lvls = @$lsb_start_ref; + @lsb_stop_lvls = @$lsb_stop_ref; + return if (!@lsb_start_lvls and !@lsb_stop_lvls); + + if ($act eq 'defaults') { + @arg_start_lvls = (2, 3, 4, 5); + @arg_stop_lvls = (0, 1, 6); + } elsif ($act eq 'start' or $act eq 'stop') { + my $start = $act eq 'start' ? 1 : 0; + my $stop = $act eq 'stop' ? 1 : 0; + + # The legacy part of this program passes arguments starting with + # "start|stop NN x y z ." but the insserv part gives argument list + # starting with sequence number (ie. strips off leading "start|stop") + # Start processing arguments immediately after the first seq number. + my $argi = $_[0] eq $act ? 2 : 1; + + while (defined $_[$argi]) { + my $arg = $_[$argi]; + + # Runlevels 0 and 6 are always stop runlevels + if ($arg eq 0 or $arg eq 6) { + $start = 0; $stop = 1; + } elsif ($arg eq 'start') { + $start = 1; $stop = 0; $argi++; next; + } elsif ($arg eq 'stop') { + $start = 0; $stop = 1; $argi++; next; + } elsif ($arg eq '.') { + next; + } + push(@arg_start_lvls, $arg) if $start; + push(@arg_stop_lvls, $arg) if $stop; + } continue { + $argi++; + } + } + + if ($#arg_start_lvls != $#lsb_start_lvls or + join("\0", sort @arg_start_lvls) ne join("\0", sort @lsb_start_lvls)) { + $arg_str = @arg_start_lvls ? "@arg_start_lvls" : "none"; + $lsb_str = @lsb_start_lvls ? "@lsb_start_lvls" : "none"; + warning "$name start runlevel arguments ($arg_str) do not match", + "LSB Default-Start values ($lsb_str)"; + } + if ($#arg_stop_lvls != $#lsb_stop_lvls or + join("\0", sort @arg_stop_lvls) ne join("\0", sort @lsb_stop_lvls)) { + $arg_str = @arg_stop_lvls ? "@arg_stop_lvls" : "none"; + $lsb_str = @lsb_stop_lvls ? "@lsb_stop_lvls" : "none"; + warning "$name stop runlevel arguments ($arg_str) do not match", + "LSB Default-Stop values ($lsb_str)"; + } +} + +sub insserv_toggle { + my ($dryrun, $act, $name) = (shift, shift, shift); + my (@toggle_lvls, $start_lvls, $stop_lvls, @symlinks); + my $lsb_header = lsb_header_for_script($name); + + # Extra arguments to disable|enable action are runlevels. If none + # given parse LSB info for Default-Start value. + if ($#_ >= 0) { + @toggle_lvls = @_; + } else { + ($start_lvls, $stop_lvls) = parse_def_start_stop($lsb_header); + @toggle_lvls = @$start_lvls; + if ($#toggle_lvls < 0) { + error("$name Default-Start contains no runlevels, aborting."); + } + } + + # Find symlinks in rc.d directories. Refuse to modify links in runlevels + # not used for normal system start sequence. + for my $lvl (@toggle_lvls) { + if ($lvl !~ /^[S2345]$/) { + warning("$act action will have no effect on runlevel $lvl"); + next; + } + push(@symlinks, $_) for glob("/etc/rc$lvl.d/[SK][0-9][0-9]$name"); + } + + if (!@symlinks) { + error("no runlevel symlinks to modify, aborting!"); + } + + # Toggle S/K bit of script symlink. + for my $cur_lnk (@symlinks) { + my $sk; + my @new_lnk = split(//, $cur_lnk); + + if ("disable" eq $act) { + $sk = rindex($cur_lnk, '/S') + 1; + next if $sk < 1; + $new_lnk[$sk] = 'K'; + } else { + $sk = rindex($cur_lnk, '/K') + 1; + next if $sk < 1; + $new_lnk[$sk] = 'S'; + } + + if ($dryrun) { + printf("rename(%s, %s)\n", $cur_lnk, join('', @new_lnk)); + next; + } + + rename($cur_lnk, join('', @new_lnk)) or error($!); + } +} diff --git a/debian/update-rc.d-insserv.8 b/debian/update-rc.d-insserv.8 new file mode 100644 index 0000000..3e62e77 --- /dev/null +++ b/debian/update-rc.d-insserv.8 @@ -0,0 +1,14 @@ +.\" Copyright 2008,2009 Petter Reinholdtsen +.\" May be distributed under the GNU General Public License +.TH "update-bootsystem-insserv" "8" "28 July 2009" "Petter Reinholdtsen" "" +.SH "NAME" +update\-rc.d\-insserv \- obsolete +.SH "DESCRIPTION" +.B update\-rc.d\-insserv +is an obsolete implementation of the update-rc.d interface for the dependency +based boot sequencing system insserv. The implementation was moved into the +sysv-rc update-rc.d implementation. +.SH "SEE ALSO" +update\-rc.d(8), insserv(8), update-bootsystem-insserv(8) +.SH "AUTHOR" +Petter Reinholdtsen, diff --git a/debian/watch b/debian/watch new file mode 100644 index 0000000..e47cd30 --- /dev/null +++ b/debian/watch @@ -0,0 +1,6 @@ +# Run the "uscan" command to check for upstream updates and more. +# See uscan(1) for format + +version=2 + +ftp://ftp.suse.com/pub/projects/init/insserv-(.*).tar.gz debian uupdate diff --git a/init-functions b/init-functions new file mode 100644 index 0000000..ba21100 --- /dev/null +++ b/init-functions @@ -0,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}" +} + diff --git a/insserv-1.12.0.lsm b/insserv-1.12.0.lsm new file mode 100644 index 0000000..7699a30 --- /dev/null +++ b/insserv-1.12.0.lsm @@ -0,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 +Maintained-by: Werner Fink +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 diff --git a/insserv.8.in b/insserv.8.in new file mode 100644 index 0000000..3e79a5f --- /dev/null +++ b/insserv.8.in @@ -0,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\ ] +.RB [ \-p\ ] +.RB [ \-d ] +.RB [ \-f ] +.RI [[ / ] path/to/init.d/ ] script \ ... +.PP +.B insserv +.RB [ \-v ] +.RB [ \-c\ ] +.RB [ \-p\ ] +@@BEGIN_SUSE@@ +.RI [[ / ] path/to/init.d/ ] script [ ,start= [ ,\ ... ] +@@ELSE_SUSE@@ +.RI [[ / ] path/to/init.d/ ] script [ ,start= [ ,\ ... ] ,stop= [ ,\ ... ]] +@@END_SUSE@@ +.PP +.B insserv +.RB [ \-v ] +.RB [ \-c\ ] +.RB [ \-p\ ] +.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 + 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 +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\ +Specify path to the insserv.conf file and the insserv.conf.d +directory. Useful for testing. +.TP +.BR \-o\ ,\ \-\-override\ +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\ +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= [ , ]]\ ... +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 ,\ ,\ ... +are the known runlevels explained above. +The extension +.IR ,stop= [ , ]] +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= [ , ]] +and +.IR ,stop= [ , ]] +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 diff --git a/insserv.c b/insserv.c new file mode 100644 index 0000000..8b647ee --- /dev/null +++ b/insserv.c @@ -0,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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(USE_RPMLIB) && (USE_RPMLIB > 0) +# include +# include +#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("", 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 [] [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 to replace " INITDIR ".\n"); + printf(" -o , --override Path to replace " OVERRIDEDIR ".\n"); + printf(" -c , --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] + */ + 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; +} diff --git a/insserv.conf b/insserv.conf new file mode 100644 index 0000000..2efcc60 --- /dev/null +++ b/insserv.conf @@ -0,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 +# + boot.crypto boot.localfs boot.rootfsck apache apache2 kdump diff --git a/install_initd b/install_initd new file mode 100755 index 0000000..49703c0 --- /dev/null +++ b/install_initd @@ -0,0 +1,2 @@ +#!/bin/sh +exec /sbin/insserv ${1+"$@"} diff --git a/listing.c b/listing.c new file mode 100644 index 0000000..6451e0e --- /dev/null +++ b/listing.c @@ -0,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 +#include +#include +#include +#include +#include +#include +#include +#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; +} diff --git a/listing.h b/listing.h new file mode 100644 index 0000000..3cd10f5 --- /dev/null +++ b/listing.h @@ -0,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 +#include +#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 \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 diff --git a/packaging/10_nosuse.patch b/packaging/10_nosuse.patch new file mode 100644 index 0000000..faad0a8 --- /dev/null +++ b/packaging/10_nosuse.patch @@ -0,0 +1,17 @@ +Purpose: Disable the SUSE flag. +Fixes: None, made as part of Debian porting. +Status: Debian specific, showed to upstream. +--- +Index: insserv/Makefile +=================================================================== +--- insserv.orig/Makefile 2009-09-26 22:35:26.000000000 +0200 ++++ insserv/Makefile 2009-09-26 22:35:45.000000000 +0200 +@@ -9,7 +9,7 @@ + #DESTDIR = /tmp/root + #DEBUG = -DDEBUG=1 -Wpacked + DEBUG = +-ISSUSE = -DSUSE ++ISSUSE = -DNOTSUSE + DESTDIR = + VERSION = 1.12.0 + DATE = $(shell date +'%d%b%y' | tr '[:lower:]' '[:upper:]') diff --git a/packaging/11_debian_conf.patch b/packaging/11_debian_conf.patch new file mode 100644 index 0000000..5ca0d2a --- /dev/null +++ b/packaging/11_debian_conf.patch @@ -0,0 +1,55 @@ +Purpose: Adjust the insserv configuration for Debian init.d script names. +Fixes: None, made as part of Debian porting. +Status: Debian specific, showed to upstream. +--- +Index: insserv/insserv.conf +=================================================================== +--- insserv.orig/insserv.conf 2009-09-26 22:35:26.000000000 +0200 ++++ insserv/insserv.conf 2009-09-26 22:35:39.000000000 +0200 +@@ -1,29 +1,29 @@ + # + # All local filesystems are mounted (done during boot phase) + # +-$local_fs boot.localfs ++$local_fs +mountall +mountoverflowtmp +umountfs + + # + # Low level networking (ethernet card) + # +-$network network +pcmcia +hotplug ++$network +networking +ifupdown + + # + # Named is operational + # +-$named +named +dnsmasq +lwresd $network ++$named +named +dnsmasq +lwresd +bind9 $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 ++$remote_fs $local_fs +mountnfs +mountnfs-bootclean +umountnfs +sendsigs + + # + # System logger is operational + # +-$syslog syslog ++$syslog +rsyslog +sysklogd +syslog-ng +dsyslog +inetutils-syslogd + + # + # SunRPC portmapper available +@@ -33,9 +33,9 @@ + # + # The system time has been set correctly + # +-$time boot.clock +xntpd ++$time +hwclock + + # + # Services which need to be interactive + # +- boot.crypto boot.localfs boot.rootfsck apache apache2 kdump ++ glibc udev console-screen keymap keyboard-setup console-setup cryptdisks cryptdisks-early checkfs-loop diff --git a/packaging/20_install_perms_fixup.patch b/packaging/20_install_perms_fixup.patch new file mode 100644 index 0000000..c3ac3c8 --- /dev/null +++ b/packaging/20_install_perms_fixup.patch @@ -0,0 +1,29 @@ +Purpose: Use correct permissions for installing /sbin/insserv and + /etc/insserv.conf +Authour: Kel Modderman +Fixes: - +Status: Not yet submitted upstream. + +Index: insserv/Makefile +=================================================================== +--- insserv.orig/Makefile 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/Makefile 2009-09-26 22:35:39.000000000 +0200 +@@ -41,14 +41,14 @@ + RM = rm -f + MKDIR = mkdir -p + RMDIR = rm -rf +- INSTBINFLAGS = -m 0700 ++ INSTBINFLAGS = -m 0755 + INSTBIN = install $(INSTBINFLAGS) +- INSTSRPFLAGS = -m 0700 ++ INSTSRPFLAGS = -m 0755 + INSTSRP = install $(INSTSRPFLAGS) +- INSTDOCFLAGS = -c -m 0444 ++ INSTDOCFLAGS = -c -m 0644 + INSTDOC = install $(INSTDOCFLAGS) + INSTCONFLAGS = -c -m 0644 +- INSTCON = install $(INSTDOCFLAGS) ++ INSTCON = install $(INSTCONFLAGS) + LINK = ln -sf + # + SDOCDIR = $(DESTDIR)/usr/share/man/man8 diff --git a/packaging/21_tests_suite_new_functions.patch b/packaging/21_tests_suite_new_functions.patch new file mode 100644 index 0000000..14c0f23 --- /dev/null +++ b/packaging/21_tests_suite_new_functions.patch @@ -0,0 +1,36 @@ +Purpose: Add some extra functions used by Debian test suite script +Authour: Kel Modderman +Fixes: - +Status: Should be sent upstream + +Index: insserv/tests/suite +=================================================================== +--- insserv.orig/tests/suite 2009-09-26 22:35:26.000000000 +0200 ++++ insserv/tests/suite 2009-09-26 22:35:39.000000000 +0200 +@@ -94,6 +94,12 @@ + $insserv $debug -c $insconf -p $initddir -o $overridedir -r $script + } + ++initdir_purge () ++{ ++ rm -rf ${initddir}/../rc*.d ${initddir} ++ mkdir -p ${initddir} ++} ++ + relpath () + { + local OLDIFS IFS +@@ -201,6 +207,13 @@ + chmod u+w,a+rx $script + } + ++remscript () ++{ ++ local scriptname=$1 ++ local script=${initddir}/$scriptname ++ rm -f $script ++} ++ + insertscript () + { + local scriptname=$1 diff --git a/packaging/30_deterministic_order.patch b/packaging/30_deterministic_order.patch new file mode 100644 index 0000000..5e52033 --- /dev/null +++ b/packaging/30_deterministic_order.patch @@ -0,0 +1,77 @@ +Purpose: Defend against undeterministic directory stream sequence + returned by readdir(3). Make sure script which is being + registered is processed before all others. +Fixes: #494514 +Status: Applied upstream. +--- +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:25.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:44.000000000 +0200 +@@ -2238,6 +2238,7 @@ + boolean del = false; + boolean defaults = false; + boolean ignore = false; ++ boolean loadarg = false; + + myname = basename(*argv); + +@@ -2305,7 +2306,9 @@ + argv += optind; + argc -= optind; + +- if (!argc && del) ++ if (argc) ++ loadarg = true; ++ else if (del) + error("usage: %s [[-r] init_script|init_directory]\n", myname); + + if (*argv) { +@@ -2490,17 +2493,45 @@ + /* + * 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); ++ for (;;) { + service_t * service = (service_t*)0; + char * token; + char * begin = (char*)0; /* hold start pointer of strings handled by strsep() */ + boolean hard = false; ++ boolean isarg = false; + uchar lsb = 0; + #if defined(DEBUG) && (DEBUG > 0) + int nobug = 0; + #endif + ++ if ((d = readdir(initdir)) == (struct dirent*)0) { ++ /* ++ * If first script in argument list was loaded in advance, then ++ * rewind the init.d/ directory stream and attempt to load all ++ * other scripts. ++ */ ++ if (loadarg) { ++ loadarg = false; ++ rewinddir(initdir); ++ continue; ++ } ++ break; ++ } ++ ++ isarg = chkfor(d->d_name, argv, argc); ++ ++ /* ++ * Load first script in argument list before all other scripts. This ++ * avoids problems with loading scripts in underterministic sequence ++ * returned by readdir(3). ++ */ ++ if (loadarg && !isarg) ++ continue; ++ if (loadarg && isarg && (curr_argc != 0)) ++ continue; ++ if (!loadarg && isarg && (curr_argc == 0)) ++ continue; ++ + if (*d->d_name == '.') + continue; + errno = 0; diff --git a/packaging/40_badboy_segfault.patch b/packaging/40_badboy_segfault.patch new file mode 100644 index 0000000..cd36055 --- /dev/null +++ b/packaging/40_badboy_segfault.patch @@ -0,0 +1,21 @@ +Purpose: Defend against corrupt or invalid scripts living in + /etc/rc[S0-6].d/ +Fixes: #493202 +Status: Acked by upstream. +--- +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:44.000000000 +0200 +@@ -1696,6 +1696,11 @@ + } + + lsb = scan_script_defaults(dfd, d->d_name, override_path, &name, true, ignore); ++ if (!name) { ++ warn("warning: script is corrupt or invalid: %s/%s%s\n", path, rcd, d->d_name); ++ continue; ++ } ++ + if (!script_inf.provides || script_inf.provides == empty) + script_inf.provides = xstrdup(ptr); + diff --git a/packaging/50_symlink_in_initddir.patch b/packaging/50_symlink_in_initddir.patch new file mode 100644 index 0000000..11ee33e --- /dev/null +++ b/packaging/50_symlink_in_initddir.patch @@ -0,0 +1,67 @@ +Purpose: Defend against symlinks in init.d/ to other scripts in init.d/ +Fixes: #485045 +Status: Work in progress. +--- +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:44.000000000 +0200 +@@ -2542,11 +2542,12 @@ + errno = 0; + + /* d_type seems not to work, therefore use (l)stat(2) */ +- if (xstat(dfd, d->d_name, &st_script) < 0) { ++ if (xlstat(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_ISLNK(st_script.st_mode) && !S_ISREG(st_script.st_mode)) || ++ !(S_IXUSR & st_script.st_mode)) + { + if (S_ISDIR(st_script.st_mode)) + continue; +@@ -2555,6 +2556,43 @@ + continue; + } + ++ /* ++ * Do extra sanity checking of symlinks in init.d/ dir, except if it ++ * is named reboot, as that is a special case on SUSE ++ */ ++ if (S_ISLNK(st_script.st_mode) && ((strcmp(d->d_name, "reboot") != 0))) ++ { ++ char * base; ++ char linkbuf[PATH_MAX+1]; ++ int linklen; ++ ++ linklen = xreadlink(dfd, d->d_name, linkbuf, sizeof(linkbuf)-1); ++ if (linklen < 0) ++ continue; ++ linkbuf[linklen] = '\0'; ++ ++ /* skip symbolic links to other scripts in this relative path */ ++ if (!(base = strrchr(linkbuf, '/'))) { ++ if (isarg) ++ warn("script %s is a symlink to another script, skipped!\n", ++ d->d_name); ++ continue; ++ } ++ ++ /* stat the symlink target and make sure it is a valid script */ ++ if (xstat(dfd, d->d_name, &st_script) < 0) ++ 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); diff --git a/packaging/61_interactive_keyword.patch b/packaging/61_interactive_keyword.patch new file mode 100644 index 0000000..3d85384 --- /dev/null +++ b/packaging/61_interactive_keyword.patch @@ -0,0 +1,132 @@ +Purpose: Add support for a X-Interactive keyword to avoid specifying it in insserv.conf +Fixes: #458224 +Status: Work in progress. +--- + +Index: insserv/insserv.8.in +=================================================================== +--- insserv.orig/insserv.8.in 2009-09-26 22:35:25.000000000 +0200 ++++ insserv/insserv.8.in 2009-09-26 22:35:43.000000000 +0200 +@@ -76,6 +76,7 @@ + # 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 ...] ++ # X-Interactive: true + # Short-Description: single_line_description + # Description: multiline_description + ### END INIT INFO +@@ -117,6 +118,11 @@ + these tags is stopped. + @@END_SUSE@@ + .PP ++The optional X\-Interactive keyword implies that the script using this ++keyword should be started alone in a concurrent boot configuration ++because it interact with the user at the console. Only the value ++`true' is recogniced. All other are ignored. ++.PP + The optional + .B X\-Start\-Before + keyword implies that the script using this keyword +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:43.000000000 +0200 +@@ -97,6 +97,7 @@ + #define DEFAULT_START DEFAULT START VALUE + #define DEFAULT_STOP DEFAULT STOP VALUE + #define DESCRIPTION COMM "description" VALUE ++#define INTERACTIVE COMM "x-interactive" VALUE + + /* System facility search within /etc/insserv.conf */ + #define EQSIGN "([[:blank:]]*[=:][[:blank:]]*|[[:blank:]]+)" +@@ -133,6 +134,7 @@ + char *default_start; + char *default_stop; + char *description; ++ char *interactive; + } attribute((aligned(sizeof(char*)))) lsb_t; + + /* Search results points here */ +@@ -147,6 +149,7 @@ + regex_t def_start; + regex_t def_stop; + regex_t desc; ++ regex_t interact; + } attribute((aligned(sizeof(regex_t)))) reg_t; + + typedef struct creg_struct { +@@ -1132,6 +1135,7 @@ + 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); ++ regcompiler(®.interact, INTERACTIVE, REG_EXTENDED|REG_ICASE|REG_NEWLINE); + } + + static inline void scan_script_reset(void) attribute((always_inline)); +@@ -1147,6 +1151,7 @@ + xreset(script_inf.default_start); + xreset(script_inf.default_stop); + xreset(script_inf.description); ++ xreset(script_inf.interactive); + } + + #define FOUND_LSB_HEADER 0x01 +@@ -1177,6 +1182,7 @@ + #define default_start script_inf.default_start + #define default_stop script_inf.default_stop + #define description script_inf.description ++#define interactive script_inf.interactive + + info("Loading %s\n", path); + +@@ -1273,6 +1279,14 @@ + description = empty; + } + ++ if (!interactive && regexecutor(®.interact, COMMON_ARGS) == true) { ++ if (val->rm_so < val->rm_eo) { ++ *(pbuf+val->rm_eo) = '\0'; ++ interactive = xstrdup(pbuf+val->rm_so); ++ } else ++ interactive = empty; ++ } ++ + /* Skip scanning below from LSB magic end */ + if ((end = strstr(buf, "### END INIT INFO"))) + break; +@@ -1341,6 +1355,7 @@ + #undef default_start + #undef default_stop + #undef description ++#undef interactive + return ret; + } + +@@ -1503,6 +1518,7 @@ + regfree(®.def_start); + regfree(®.def_stop); + regfree(®.desc); ++ regfree(®.interact); + } + + static struct { +@@ -1781,6 +1797,9 @@ + if (script_inf.stop_after && script_inf.stop_after != empty) { + reversereq(service, REQ_SHLD|REQ_KILL, script_inf.stop_after); + } ++ if (script_inf.interactive && 0 == strcmp(script_inf.interactive, "true")) { ++ service->attr.flags |= SERV_INTRACT; ++ } + } + + if (name) +@@ -2881,6 +2900,9 @@ + if (script_inf.should_stop && script_inf.should_stop != empty) { + rememberreq(service, REQ_SHLD|REQ_KILL, script_inf.should_stop); + } ++ if (script_inf.interactive && 0 == strcmp(script_inf.interactive, "true")) { ++ service->attr.flags |= SERV_INTRACT; ++ } + } + + if (script_inf.start_before && script_inf.start_before != empty) { diff --git a/packaging/62_upstart_job.patch b/packaging/62_upstart_job.patch new file mode 100644 index 0000000..2c0570e --- /dev/null +++ b/packaging/62_upstart_job.patch @@ -0,0 +1,170 @@ +Purpose: Add support for upstart jobs. +Fixes: #547235 +Status: Work in progress, not submitted upstream yet. +--- + +Index: insserv/insserv.8.in +=================================================================== +--- insserv.orig/insserv.8.in 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.8.in 2009-09-26 22:35:42.000000000 +0200 +@@ -266,6 +266,10 @@ + .BR \-f ,\ \-\-force + Ignore if a required service is missed. + .TP ++.BR \-u\ ,\ \-\-upstart-job\ ++Path to replace existing upstart job path. (default path is ++.IR /lib/init/upstart-job ). ++.TP + .BR \-h ,\ \-\-help + Print out short usage message. + .PP +@@ -339,6 +343,12 @@ + name as the boot or init script in the directory + .IR /etc/insserv/overrides/ . + .\" ++.SH UPSTART JOB COMPATIBILITY ++To allow upstart jobs to work as init.d scripts, insserv will ++recognize a symlink from path/to/init.d/script to ++/lib/init/upstart-job as upstart jobs, and instead of reading the ++header from the file will run the script with the argument lsb-header ++to get the script header. + .SH EXIT CODES + The exit codes have the following conditions: + .RS 7 +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:43.000000000 +0200 +@@ -70,6 +70,8 @@ + # define INSCONF "/etc/insserv.conf" + #endif + ++const char *upstartjob_path = "/lib/init/upstart-job"; ++ + /* + * For a description of regular expressions see regex(7). + */ +@@ -1154,6 +1156,43 @@ + xreset(script_inf.interactive); + } + ++static char *is_upstart_job_recursive(const char *path, ++ const char *basenamestr) ++{ ++ struct stat statbuf; ++ if (-1 == lstat(path, &statbuf)) { ++ return 0; ++ } ++ if (S_ISLNK(statbuf.st_mode)) { ++ char buf[2048]; ++ int len = readlink(path, buf, sizeof(buf)-1); ++ if (0 < len) { ++ buf[len] = '\0'; ++ if (0 == strcmp(buf, upstartjob_path)) { ++ /* upstart job, return base name of original symlink */ ++ return strdup(basenamestr); ++ } else ++ return is_upstart_job_recursive(buf, basenamestr); ++ } ++ } ++ return 0; ++} ++ ++/* ++ * return name of upstart job if the script is a symlink to ++ * /lib/init/upstart-job, or NULL if path do not point to an ++ * upstart job. ++ */ ++static char* is_upstart_job(const char *path) ++{ ++ ++ char *basenamestr = basename(path); /* GNU basename */ ++ char *retval = is_upstart_job_recursive(path, basenamestr); ++ if (retval) ++ info("script '%s' is upstart job\n", basenamestr); ++ return retval; ++} ++ + #define FOUND_LSB_HEADER 0x01 + #define FOUND_LSB_DEFAULT 0x02 + #define FOUND_LSB_OVERRIDE 0x04 +@@ -1170,7 +1209,8 @@ + char *pbuf = buf; + FILE *script; + uchar ret = 0; +- int fd; ++ int fd = -1; ++ char *upstart_job = NULL; + + #define provides script_inf.provides + #define required_start script_inf.required_start +@@ -1186,12 +1226,23 @@ + + 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 (NULL != (upstart_job = is_upstart_job(path))) { ++ char cmd[2048]; ++ int len; ++ len = snprintf(cmd, sizeof(cmd), ++ "%s %s lsb-header", upstartjob_path, upstart_job); ++ if (len < 0 || sizeof(cmd) == len) ++ error("snprintf: insufficient buffer for %s\n", path); ++ if ((FILE*)0 == (script = popen(cmd, "r"))) ++ error("popen(%s): %s\n", path, strerror(errno)); ++ } else { ++ 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); ++ (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 +@@ -1303,7 +1354,12 @@ + (void)posix_fadvise(fd, 0, 0, POSIX_FADV_NOREUSE); + #endif + +- fclose(script); ++ if (upstart_job) { ++ pclose(script); ++ free(upstart_job); ++ upstart_job = 0; ++ } else ++ fclose(script); + + if (begin && end) + ret |= FOUND_LSB_HEADER; +@@ -2224,6 +2280,7 @@ + {"force", 0, (int*)0, 'f'}, + {"path", 1, (int*)0, 'p'}, + {"override",1, (int*)0, 'o'}, ++ {"upstart-job",1, (int*)0, 'u'}, + {"help", 0, (int*)0, 'h'}, + { 0, 0, (int*)0, 0 }, + }; +@@ -2277,7 +2334,7 @@ + for (c = 0; c < argc; c++) + argr[c] = (char*)0; + +- while ((c = getopt_long(argc, argv, "c:dfrhvno:p:", long_options, (int *)0)) != -1) { ++ while ((c = getopt_long(argc, argv, "c:dfrhvno:p:u:", long_options, (int *)0)) != -1) { + size_t l; + switch (c) { + case 'c': +@@ -2317,6 +2374,11 @@ + override_path = optarg; + set_override = true; + break; ++ case 'u': ++ if (optarg == (char*)0 || *optarg == '\0') ++ goto err; ++ upstartjob_path = optarg; ++ break; + case '?': + err: + error("For help use: %s -h\n", myname); diff --git a/packaging/70_req_start_all_depends.patch b/packaging/70_req_start_all_depends.patch new file mode 100644 index 0000000..2144003 --- /dev/null +++ b/packaging/70_req_start_all_depends.patch @@ -0,0 +1,30 @@ +Purpose: Correct dependency information written to .depend.* files + for scripts which declare Required-Start: $all +Fixes: nil +Status: Applied upstream. +--- +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:42.000000000 +0200 +@@ -776,9 +776,6 @@ + continue; + #endif /* not MINIMAL_RULES */ + +- if (list_empty(&serv->sort.req)) +- continue; +- + if (serv->start->lvl & LVL_BOOT) + out = boot; + else +@@ -820,6 +817,10 @@ + fprintf(out, " %s", name); + } + } else { ++ ++ if (list_empty(&serv->sort.req)) ++ continue; ++ + np_list_for_each(pos, &serv->sort.req) { + req_t * req = getreq(pos); + service_t * dep = req->serv; diff --git a/packaging/71_complete_makefile.patch b/packaging/71_complete_makefile.patch new file mode 100644 index 0000000..7b13a54 --- /dev/null +++ b/packaging/71_complete_makefile.patch @@ -0,0 +1,56 @@ +Purpose: Make sure the .depend.* files have complete dependencies when + recursive virtual facilities are used. +Fixes: #534526 +Status: From upstream. +--- +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:42.000000000 +0200 +@@ -2109,33 +2109,26 @@ + 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); ++ if (*deep > 10) { ++ warn("The nested level of the system facilities in the insserv.conf file(s) is to large\n"); ++ goto out; + } ++ (*deep)++; ++ expand_faci(tmp, head, deep); ++ (*deep)--; ++ } else if (*deep > 0) { ++ repl_t *restrict subst; ++ if (posix_memalign((void*)&subst, sizeof(void*), alignof(repl_t)) != 0) ++ error("%s", strerror(errno)); ++ insert(&subst->r_list, head->prev); ++ subst->r[0] = rnxt->r[0]; ++ (*subst->r[0].ref) = 1; + } + } + out: +- (*deep)--; + return; + } + diff --git a/packaging/81_lessverbose.patch b/packaging/81_lessverbose.patch new file mode 100644 index 0000000..e8ed476 --- /dev/null +++ b/packaging/81_lessverbose.patch @@ -0,0 +1,157 @@ +Purpose: Reduce verbosity level (drop Loading... messages) +Fixes: - +Status: Not yet submitted upstream. +--- + +Index: insserv/listing.h +=================================================================== +--- insserv.orig/listing.h 2009-09-26 22:35:25.000000000 +0200 ++++ insserv/listing.h 2009-09-26 22:35:39.000000000 +0200 +@@ -283,7 +283,7 @@ + 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 void info (int level, const char *restrict fmt, ...) attribute((format(printf,2,3))); + 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); +@@ -312,23 +312,23 @@ + (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); })) ++ info(1, "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); })) ++ info(1, "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); })) ++ info(1, "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); })) ++ info(1, "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); })) +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:41.000000000 +0200 +@@ -114,8 +114,8 @@ + /* The main line buffer if unique */ + static char buf[LINE_MAX]; + +-/* When to be verbose */ +-static boolean verbose = false; ++/* When to be verbose, and what level of verbosity */ ++static int verbose = 0; + + /* When to be verbose */ + static boolean dryrun = false; +@@ -690,9 +690,9 @@ + + if (dryrun) { + #ifdef USE_KILL_IN_BOOT +- info("dryrun, not creating .depend.boot, .depend.start, .depend.halt, and .depend.stop\n"); ++ info(1, "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"); ++ info(1, "dryrun, not creating .depend.boot, .depend.start, and .depend.stop\n"); + #endif /* not USE_KILL_IN_BOOT */ + return; + } +@@ -707,8 +707,8 @@ + return; + } + +- info("creating .depend.boot\n"); +- info("creating .depend.start\n"); ++ info(1, "creating .depend.boot\n"); ++ info(1, "creating .depend.start\n"); + + lsort('S'); /* Sort into start order, set new sorder */ + +@@ -874,9 +874,9 @@ + return; + } + +- info("creating .depend.halt\n"); ++ info(1, "creating .depend.halt\n"); + #endif /* USE_KILL_IN_BOOT */ +- info("creating .depend.stop\n"); ++ info(1, "creating .depend.stop\n"); + + lsort('K'); /* Sort into stop order, set new korder */ + +@@ -1014,9 +1014,9 @@ + /* + * Print message when verbose is enabled + */ +-void info(const char *fmt, ...) { ++void info(int level, const char *fmt, ...) { + va_list ap; +- if (!verbose) ++ if (level > verbose) + goto out; + va_start(ap, fmt); + _logger(fmt, ap); +@@ -1062,7 +1062,7 @@ + + if (stat(rcpath, &st) < 0) { + if (errno == ENOENT) { +- info("creating directory '%s'\n", rcpath); ++ info(1, "creating directory '%s'\n", rcpath); + if (!dryrun) + mkdir(rcpath, (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)); + } else +@@ -1190,7 +1190,7 @@ + char *basenamestr = basename(path); /* GNU basename */ + char *retval = is_upstart_job_recursive(path, basenamestr); + if (retval) +- info("script '%s' is upstart job\n", basenamestr); ++ info(2, "script '%s' is upstart job\n", basenamestr); + return retval; + } + +@@ -1225,7 +1225,7 @@ + #define description script_inf.description + #define interactive script_inf.interactive + +- info("Loading %s\n", path); ++ info(2, "Loading %s\n", path); + + if (NULL != (upstart_job = is_upstart_job(path))) { + char cmd[2048]; +@@ -1882,7 +1882,7 @@ + regmatch_t subloc[SUBCONFNUM], *val = (regmatch_t*)0; + FILE *conf; + +- info("Loading %s\n", file); ++ info(2, "Loading %s\n", file); + + do { + const char * fptr = file; +@@ -2347,10 +2347,10 @@ + ignore = true; + break; + case 'v': +- verbose = true; ++ verbose ++; + break; + case 'n': +- verbose = true; ++ verbose ++; + dryrun = true; + break; + case 'p': diff --git a/packaging/82_loop_exit_msg.patch b/packaging/82_loop_exit_msg.patch new file mode 100644 index 0000000..2c8dd66 --- /dev/null +++ b/packaging/82_loop_exit_msg.patch @@ -0,0 +1,20 @@ +Purpose: Make message printed when loops are detected look more like + the messages printed when other errors are detected ("exiting + now!"), to make it easier for piuparts to discover these errors too. +Fixes: - +Status: Not yet submitted upstream. +--- + +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:41.000000000 +0200 +@@ -3250,7 +3250,7 @@ + */ + follow_all(); + if (is_loop_detected() && !ignore) +- error("exiting without changing boot order!\n"); ++ error("exiting now without changing boot order!\n"); + + /* + * Be sure that interactive scripts are the only member of diff --git a/packaging/91_kfreebsd_nofadvice.patch b/packaging/91_kfreebsd_nofadvice.patch new file mode 100644 index 0000000..ec8a447 --- /dev/null +++ b/packaging/91_kfreebsd_nofadvice.patch @@ -0,0 +1,22 @@ +Purpose: Get insserv building on kfreebsd, missing the argument values for posix_fadvise(). +Fixes: #? +Status: Not yet submitted upstream. +--- +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:40.000000000 +0200 +@@ -40,6 +40,13 @@ + #endif /* USE_RPMLIB */ + #include "listing.h" + ++#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600 ++/* kfreebsd fail to provide working posix_fadvise */ ++# ifndef POSIX_FADV_SEQUENTIAL ++# define posix_fadvise(fd, off, len, adv) (-1) ++# endif ++#endif ++ + #ifdef SUSE + # define DEFAULT_START_LVL "3 5" + # define DEFAULT_STOP_LVL "3 5" diff --git a/packaging/92_m68k_alignment.patch b/packaging/92_m68k_alignment.patch new file mode 100644 index 0000000..ef4fe3c --- /dev/null +++ b/packaging/92_m68k_alignment.patch @@ -0,0 +1,20 @@ +Purpose: Get insserv building on m68k, dropping some problematic + alignments (error: requested alignment is not a power of 2) +Fixes: #493637 +Status: Not yet submitted upstream. +--- +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:40.000000000 +0200 +@@ -131,6 +131,10 @@ + static boolean set_override = false; + static boolean set_insconf = false; + ++#ifdef __m68k__ /* Fix #493637 */ ++# define aligned(a) ++#endif ++ + /* Search results points here */ + typedef struct lsb_struct { + char *provides; diff --git a/packaging/93_hurd_no_path_max.patch b/packaging/93_hurd_no_path_max.patch new file mode 100644 index 0000000..bad0d1a --- /dev/null +++ b/packaging/93_hurd_no_path_max.patch @@ -0,0 +1,19 @@ +Purpose: Try to get insserv building on hurd, by faking a PATH_MAX value. +Status: Not yet submitted upstream. +--- +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:40.000000000 +0200 +@@ -1427,6 +1427,11 @@ + return ret; + } + ++#ifndef PATH_MAX ++/* for example hurd. Should really dynamically aligh the buffer. */ ++# define PATH_MAX 1024 ++#endif ++ + /* + * Follow symlinks, return the basename of the file pointed to by + * symlinks or the basename of the current path if no symlink. diff --git a/packaging/94_v1_12_2.patch b/packaging/94_v1_12_2.patch new file mode 100644 index 0000000..7b6c970 --- /dev/null +++ b/packaging/94_v1_12_2.patch @@ -0,0 +1,82 @@ +Patch from upstream to detect and reject loops in virtual +facilities (#541613) and warn about indirect dependencies to $all. + +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:39.000000000 +0200 +@@ -233,6 +233,7 @@ + typedef struct repl { + list_t r_list; + string_t r[1]; ++ ushort flags; + } __align repl_t; + #define getrepl(arg) list_entry((arg), struct repl, r_list) + +@@ -1946,6 +1947,7 @@ + if (posix_memalign((void*)&subst, sizeof(void*), alignof(repl_t)) != 0) + error("%s", strerror(errno)); + insert(&subst->r_list, r_list->prev); ++ subst->flags = 0; + r = &subst->r[0]; + if (posix_memalign((void*)&r->ref, sizeof(void*), alignof(typeof(r->ref))+strsize(token)) != 0) + error("%s", strerror(errno)); +@@ -1975,6 +1977,7 @@ + error("%s", strerror(errno)); + insert(&subst->r_list, r_list->prev); + r = &subst->r[0]; ++ subst->flags = 0; + if (posix_memalign((void*)&r->ref, sizeof(void*), alignof(typeof(r->ref))+strsize(token)) != 0) + error("%s", strerror(errno)); + *r->ref = 1; +@@ -2127,13 +2130,19 @@ + + list_for_each_safe(tmp, safe, ptr) { + repl_t * rnxt = getrepl(tmp); ++ if (rnxt->flags & 0x0001) { ++ error("Loop detected during expanding system facilities in the insserv.conf file(s): %s\n", ++ rnxt->r[0].name); ++ } + if (*rnxt->r[0].name == '$') { + if (*deep > 10) { + warn("The nested level of the system facilities in the insserv.conf file(s) is to large\n"); + goto out; + } + (*deep)++; ++ rnxt->flags |= 0x0001; + expand_faci(tmp, head, deep); ++ rnxt->flags &= ~0x0001; + (*deep)--; + } else if (*deep > 0) { + repl_t *restrict subst; +@@ -2154,9 +2163,12 @@ + 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 == '$') { ++ repl_t * tmp = getrepl(rlist); ++ if (*tmp->r[0].name == '$') { + int deep = 0; ++ tmp->flags |= 0x0001; + expand_faci(rlist, rlist, &deep); ++ tmp->flags &= ~0x0001; + } + } + } +Index: insserv/listing.c +=================================================================== +--- insserv.orig/listing.c 2009-09-26 22:35:24.000000000 +0200 ++++ insserv/listing.c 2009-09-26 22:35:39.000000000 +0200 +@@ -398,6 +398,12 @@ + break; /* Loop detected, stop recursion */ + } + ++ if ((mode == 'S') && (attof(tmp)->flags & SERV_ALL)) { ++ warn("%s depends on %s and therefore on system facility `$all' which can not be true!\n", ++ target->script ? target->script : target->name, tmp->script ? tmp->script : tmp->name); ++ continue; ++ } ++ + if (ptrg->deep >= deep) /* Nothing new */ + continue; + /* The inner recursion */ diff --git a/packaging/95_stop_all.patch b/packaging/95_stop_all.patch new file mode 100644 index 0000000..d78eb41 --- /dev/null +++ b/packaging/95_stop_all.patch @@ -0,0 +1,159 @@ +Patch from upstream making $all work for stop sequences, placing +scripts first in the stop sequence. This patch invalidates +60_all_keyword_start_only.patch + +Fixes #542043 + +Index: insserv/insserv.c +=================================================================== +--- insserv.orig/insserv.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/insserv.c 2009-09-26 22:35:39.000000000 +0200 +@@ -308,7 +308,10 @@ + break; + case '$': + if (strcasecmp(token, "$all") == 0) { +- serv->attr.flags |= SERV_ALL; ++ if (bit & REQ_KILL) ++ serv->attr.flags |= SERV_FIRST; ++ else ++ serv->attr.flags |= SERV_ALL; + break; + } + /* Expand the `$' token recursively down */ +@@ -630,8 +633,7 @@ + } + + /* +- * Last but not least the `$all' scripts will be set to the +- * end of the current start order. ++ * 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) +@@ -688,6 +690,50 @@ + } + + /* ++ * Last but not least the `$all' scripts will be set to the ++ * beginning of the current stop order. ++ */ ++static inline void first_script(void) attribute((always_inline)); ++static inline void first_script(void) ++{ ++ list_t * pos; ++ ++ list_for_each(pos, s_start) { ++ service_t * serv = getservice(pos); ++ list_t * tmp; ++ ++ if (serv->attr.flags & SERV_DUPLET) ++ continue; /* Duplet */ ++ ++ if (!(serv->attr.flags & SERV_FIRST)) ++ continue; ++ ++ if (serv->attr.script == (char*)0) ++ continue; ++ ++ 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 == serv) ++ continue; ++ ++ if (cur->attr.flags & SERV_FIRST) ++ continue; ++ ++ rememberreq(serv, REQ_SHLD|REQ_KILL, cur->name); ++ } ++ ++ setorder(serv->attr.script, 'K', 1, false); ++ } ++} ++ ++/* + * Make the dependency files + */ + static inline void makedep(void) attribute((always_inline)); +@@ -3274,6 +3320,11 @@ + nonlsb_script(); + + /* ++ * Move the `$all' stop scripts to the very beginning ++ */ ++ first_script(); ++ ++ /* + * Now generate for all scripts the dependencies + */ + follow_all(); +Index: insserv/listing.c +=================================================================== +--- insserv.orig/listing.c 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/listing.c 2009-09-26 22:35:39.000000000 +0200 +@@ -317,6 +317,7 @@ + } + + for (tmp = dir; tmp; tmp = getnextlink(l_list)) { ++ const typeof(attof(tmp)->flags) sflags = attof(tmp)->flags; + register boolean recursion = true; + handle_t * ptmp = (mode == 'K') ? &tmp->stopp : &tmp->start; + uchar * order = &ptmp->deep; +@@ -381,6 +382,7 @@ + np_list_for_each(dent, l_list) { + dir_t * target = getlink(dent)->target; + handle_t * ptrg = (mode == 'K') ? &target->stopp : &target->start; ++ const typeof(attof(target)->flags) kflags = attof(target)->flags; + + if ((peg->run.lvl & ptrg->run.lvl) == 0) + continue; /* Not same boot level */ +@@ -398,10 +400,18 @@ + break; /* Loop detected, stop recursion */ + } + +- if ((mode == 'S') && (attof(tmp)->flags & SERV_ALL)) { +- warn("%s depends on %s and therefore on system facility `$all' which can not be true!\n", +- target->script ? target->script : target->name, tmp->script ? tmp->script : tmp->name); +- continue; ++ if (mode == 'K') { ++ if (kflags & SERV_FIRST) { ++ warn("Stopping %s depends on %s and therefore on system facility `$all' which can not be true!\n", ++ tmp->script ? tmp->script : tmp->name, target->script ? target->script : target->name); ++ continue; ++ } ++ } else { ++ if (sflags & SERV_ALL) { ++ warn("Starting %s depends on %s and therefore on system facility `$all' which can not be true!\n", ++ target->script ? target->script : target->name, tmp->script ? tmp->script : tmp->name); ++ continue; ++ } + } + + if (ptrg->deep >= deep) /* Nothing new */ +@@ -847,7 +857,7 @@ + list_for_each(tmp, d_start) { + maxorder = &maxstart; + guess_order(getdir(tmp), 'S'); +- maxorder = &maxstart; ++ maxorder = &maxstop; + guess_order(getdir(tmp), 'K'); + } + } +Index: insserv/listing.h +=================================================================== +--- insserv.orig/listing.h 2009-09-26 22:35:39.000000000 +0200 ++++ insserv/listing.h 2009-09-26 22:35:39.000000000 +0200 +@@ -368,6 +368,7 @@ + #define SERV_SCRIPT 0x0080 + #define SERV_NOSTOP 0x0100 + #define SERV_CMDLINE 0x0200 ++#define SERV_FIRST 0x0400 + + /* + * Bits of the runlevels diff --git a/packaging/96_hurd_no_at_funcs.patch b/packaging/96_hurd_no_at_funcs.patch new file mode 100644 index 0000000..bcf2e75 --- /dev/null +++ b/packaging/96_hurd_no_at_funcs.patch @@ -0,0 +1,50 @@ +Purpose: Try to get insserv building on hurd, by avoiding the dummy *at + functions which exist in libc but always return an error. +Status: Not yet submitted upstream. + +--- +Index: insserv/listing.h +=================================================================== +--- insserv.orig/listing.h 2009-09-27 15:45:38.000000000 +0200 ++++ insserv/listing.h 2009-09-27 15:45:38.000000000 +0200 +@@ -307,7 +307,7 @@ + #define xreset(ptr) \ + {char *restrict tmp = (char *restrict)ptr; if (ptr && *tmp) free(ptr);} ptr = NULL + +-#if defined(HAS_unlinkat) && defined(_ATFILE_SOURCE) ++#if defined(HAS_unlinkat) && defined(_ATFILE_SOURCE) && !defined(__stub_unlinkat) + # 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)); \ +@@ -319,7 +319,7 @@ + else \ + info(1, "remove service %s/%s%s\n", path, rcd, x); })) + #endif +-#if defined(HAS_symlinkat) && defined(_ATFILE_SOURCE) ++#if defined(HAS_symlinkat) && defined(_ATFILE_SOURCE) && !defined(__stub_symlinkat) + # 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 \ +@@ -330,19 +330,19 @@ + else \ + info(1, "enable service %s -> %s/%s%s\n", x, path, rcd, y); })) + #endif +-#if defined(HAS_fstatat) && defined(_ATFILE_SOURCE) ++#if defined(HAS_fstatat) && defined(_ATFILE_SOURCE) && !defined(__stub_fstatat) + # 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) ++#if defined(HAS_readlinkat) && defined(_ATFILE_SOURCE) && !defined(__stub_readlinkat) + # 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) ++#if defined(HAS_openat) && defined(_ATFILE_SOURCE) && !defined(__stub_openat) + # define xopen(d,x,f) (__extension__ ({ openat(d,x,f); })) + #else + # define xopen(d,x,f) (__extension__ ({ open(x,f); })) diff --git a/packaging/bash-completion b/packaging/bash-completion new file mode 100644 index 0000000..68c0ef3 --- /dev/null +++ b/packaging/bash-completion @@ -0,0 +1,36 @@ +# insserv(8) completion +# +# Copyright (c) 2009 Kel Modderman +# + +have insserv && +_insserv() +{ + local cur prev sysvdir services options + + cur=`_get_cword` + prev=${COMP_WORDS[COMP_CWORD-1]} + + [ -d /etc/rc.d/init.d ] && sysvdir=/etc/rc.d/init.d \ + || sysvdir=/etc/init.d + + services=( $(echo $sysvdir/!(README*|*.dpkg*|*.rpm@(orig|new|save))) ) + services=( ${services[@]#$sysvdir/} ) + options=( -c --config -d -f -n -o --override -p --path -r -v ) + + case "$prev" in + -c|--config) + _filedir + ;; + -o|--override|-p|--path) + _filedir -d + ;; + *) + COMPREPLY=( $( compgen -W '${options[@]} ${services[@]}' -- \ + $cur ) ) + ;; + esac + + return 0 +} && +complete -F _insserv insserv diff --git a/packaging/check-archive-initd-scripts b/packaging/check-archive-initd-scripts new file mode 100644 index 0000000..343a718 --- /dev/null +++ b/packaging/check-archive-initd-scripts @@ -0,0 +1,247 @@ +#!/usr/bin/perl +# +# Check the consistency of all init.d scripts in the archive. Run +# this on bellini.debian.org. + +use warnings; +use strict; +use File::Basename; + +my $warn = 1; + +my $basedir = "/org/lintian.debian.org/laboratory/binary"; + +my @scripts = @ARGV; +@scripts = <$basedir/*/init.d/*> unless (@scripts); + +my %scriptinfo; +my %provides; + +my @virts = qw($local_fs $remote_fs $syslog $time $named + $portmap $network $all + $mail-transport-agent $x-font-server + ); +my @harddepheaders = qw(required-start required-stop); +my @softdepheaders = qw(should-start + should-stop x-start-before x-stop-after); +my $lsbheaders = "Provides|Required-Start|Required-Stop|Default-Start|Default-Stop"; +my $optheaders = "x-start-before|x-stop-after|should-start|should-stop"; + +for my $virt (@virts) { + $provides{$virt} = ['insserv/etc/insserv.conf']; +} + +# Ignore obsolete scripts, as these are unlikely to cause problems. +for my $old (qw(glibc evms raid2 ldm sdm)) { + $provides{$old} = ['obsolete']; +} + +# First pass to load the database +for my $initdscript (@scripts) { + next if $initdscript =~ m%/rc|/rcS|/README%; + my %lsbinfo = parse_lsb_header($initdscript); + $scriptinfo{$initdscript} = \%lsbinfo; + next unless ($lsbinfo{'found'}); + + my %checked; + for my $provide (split(/[ ,\t]+/, $lsbinfo{provides})) { + if (exists $provides{$provide}) { + push(@{$provides{$provide}}, $initdscript) + } else { + $provides{$provide} = [$initdscript]; + } + $checked{$provide} = 1; + } +} + +for my $provide (sort keys %provides) { + if (1 < scalar @{$provides{$provide}}) { + my %script; + map { $script{basename($_)} = 1; } @{$provides{$provide}}; + if (1 < scalar keys %script) { + error(sprintf("scripts %s provide duplicate '%s'", + join(",", short_name(@{$provides{$provide}})), + $provide)); + } + } +} + +# Second pass, to see which dependencies are missing +for my $initdscript (@scripts) { + next unless ($scriptinfo{$initdscript}->{'found'}); + my $short = short_name($initdscript); + my %checked; + my @hardmissing = (); + for my $header (@harddepheaders) { + my $list = $scriptinfo{$initdscript}->{$header}; + next unless defined $list; + for my $facility (split(/[ ,\t]+/, $list)) { + next if exists $checked{$facility}; + $checked{$facility} = 1; + push(@hardmissing, $facility) + unless exists $provides{$facility}; + } + } + error("script $short depend on non-existing provides: " + . join(" ", @hardmissing)) if (@hardmissing); + my @softmissing = (); + for my $header (@softdepheaders) { + my $list = $scriptinfo{$initdscript}->{$header}; + next unless defined $list; + for my $facility (split(/[ ,\t]+/, $list)) { + next if exists $checked{$facility}; + $checked{$facility} = 1; + push(@softmissing, $facility) + unless exists $provides{$facility}; + } + } + warning("script $short relate to non-existing provides: " + . join(" ", @softmissing)) if (@softmissing); + + if (exists $checked{'$syslog'} + && $scriptinfo{$initdscript}->{'default-start'} =~ m/s/i) { + error("script $short depend on \$syslog and start from rcS.d/"); + } + if (!exists $checked{'$remote_fs'} + && !exists $checked{'$syslog'} + && $scriptinfo{$initdscript}->{'need_remove_fs'} + && $scriptinfo{$initdscript}->{'default-start'} =~ m/s/i) { + warning("script $short possibly missing dependency on \$remote_fs"); + } elsif (!exists $checked{'$local_fs'} + && !exists $checked{'$remote_fs'} + && !exists $checked{'$syslog'} + && $scriptinfo{$initdscript}->{'need_local_fs'} + && $scriptinfo{$initdscript}->{'default-start'} =~ m/s/i) { + warning("script $short possibly missing dependency on \$local_fs"); + } + + my %provided; + for my $provide (split(/[ ,\t]+/, + $scriptinfo{$initdscript}->{provides})) { + $provided{$provide} = 1; + if ($provide =~ m/\$/) { + error("script $short provide virtual facility $provide"); + } + } + + my $basename = basename($initdscript, ".sh"); + warning("script $short does not provide its own name") + unless exists $provided{$basename}; + + # Detect common problems with runlevel settings. + my @startrl = sort split(/\s+/, lc($scriptinfo{$initdscript}->{'default-start'})); + my @stoprl = sort split(/\s+/, lc($scriptinfo{$initdscript}->{'default-stop'})); + + # Scripts starting in rcS.d/ normally do not stop or only stop + # during hald and shutdown. + if ((array_equal(['s'], \@startrl) && array_equal([], \@stoprl)) + || ( array_equal(['s'], \@startrl) + && array_equal(['0','6'], \@stoprl))) { + # OK + } else { + # Most scripts either start in rcS.d, or in runlevels 2-5 + if (!array_equal(['2', '3', '4', '5'], \@startrl) && + !array_equal(['s'], \@startrl) && + (!array_equal([], \@startrl) && @stoprl)) { + warning("script $short does not start in the usual runlevels: ", + join(" ", @startrl)); + } + + # And most scripts stop in runlevel (1) runlevels (0, 1, 6), + # only starts or only stops in (0) or (6). + if (!array_equal(['0', '1', '6'], \@stoprl) && + !array_equal(['1'], \@stoprl) && + !array_equal(['0', '6'], \@stoprl) && + !(array_equal(['0'], \@stoprl) && !@startrl) && + !(array_equal(['6'], \@stoprl) && !@startrl) && + !(array_equal([], \@stoprl) && @startrl)) { + warning("script $short does not stop in the usual runlevels: ", + join(" ", @stoprl)); + } + } +} + +exit 0; + +sub parse_lsb_header { + my $initdscript = shift; + my $short = short_name($initdscript); + my %lsbinfo; + unless (open(INIT, "<", $initdscript)) { + error("script $short is unreadable"); + return (); + } + my $inheader = 0; + while () { +# print; + chomp; + if (m/^\#\#\# BEGIN INIT INFO\s*$/) { + $lsbinfo{'found'} = 1; + $inheader = 1; + } + $inheader = 0 if (m/\#\#\# END INIT INFO$/); + if ($inheader + && m/^\# ($lsbheaders|$optheaders):\s*(\S?.*)$/i) { +# print "$1\n"; + $lsbinfo{lc($1)} = $2; + } + s/\#.*$//; # Remove comments + $lsbinfo{'need_remove_fs'} = 1 if m%/usr/s?bin/%; + $lsbinfo{'need_local_fs'} = 1 if m%/var/%; + + # Detect the use of tools resting in /usr/ + $lsbinfo{'need_remove_fs'} = 1 if m%awk%; + $lsbinfo{'need_remove_fs'} = 1 if m%which%; + } + close(INIT); + + # Check that all the required headers are present + if (!$lsbinfo{'found'}) { + error("script $short is missing LSB header"); + } else { + for my $key (split(/\|/, lc($lsbheaders))) { + if (!exists $lsbinfo{$key}) { + error("script $short missing LSB keyword '$key'"); + } + } + } + return %lsbinfo +} + +sub short_name { + my @scripts; + for my $script ( @_ ) { + my $copy = $script; + $copy =~ s%$basedir/%%g; + push @scripts, $copy; + } + if (wantarray) { + return @scripts; + } else { + return $scripts[0]; + } +} + +sub array_equal { + my ($a1, $a2) = @_; + return 0 if (scalar @{$a1} != scalar @{$a2}); + + my $i = 0; + while ($i < scalar @{$a1}) { + return 0 if $a1->[$i] ne $a2->[$i]; + $i++; + } + return 1; +} + +sub info { + print "info: @_\n"; +} + +sub warning { + print "warning: @_\n" if $warn; +} + +sub error { + print "error: @_\n"; +} diff --git a/packaging/check-initd-order b/packaging/check-initd-order new file mode 100644 index 0000000..e7d0ef6 --- /dev/null +++ b/packaging/check-initd-order @@ -0,0 +1,425 @@ +#!/usr/bin/perl +# +# Author: Petter Reinholdtsen +# Date: 2005-08-21 +# +# Read LSM init.d headers in SysV init.d scripts, and verify correct +# start order for all runlevels. It can also provide a graph. +# +# To generate a graph, run it like this +# +# check-initd-order -g > initorder.dotty && dotty initorder.dotty + +use strict; +use warnings; + +my $rcbase = "/etc"; + +my $overridepath = "/usr/share/insserv/overrides"; +my $hostoverridepath = "/etc/insserv/overrides"; + +my $debug = 0; +my $errors = 0; + +my %rcmap = + ( + 'B' => 'rc.boot', + 'S' => 'rcS.d', + '1' => 'rc1.d', + '2' => 'rc2.d', + '3' => 'rc3.d', + '4' => 'rc4.d', + '5' => 'rc5.d', + '6' => 'rc6.d', + ); + +my %sysmap; + +my %provideslist; +my %scriptorder; +my %opts; + +# Used to draw graphs +my %gotrevdeps; +my %allprovides; + +while($#ARGV >= 0 && ($_ = $ARGV[0]) =~ /^-/) { + shift @ARGV; + if (/^-([cdgko])$/) { $opts{$1}++; next } + if (/^-b$/) { $rcbase = shift; next } + if (/^-h|--help$/) { &usage; } + &usage("unknown option"); +} + +load_sysmap("$rcbase/insserv.conf"); + +$debug = $opts{'d'}; +my $useoverrides = $opts{'o'} ? 0 : 1; + +if ($opts{'g'}) { + graph_generate(); + exit 0; +} + +check_bootorder(); +exit $errors > 0 ? 1 : 0; + +sub usage { + print STDERR "check-initd-order: error: @_\n" if ($#_ >= 0); + print STDERR <) { + chomp; + s/\#.*$//; + next if m/^\s*$/; + if (m/^(\$\S+)\s+(\S.*\S*)\S*$/) { + my $virt = $1; + for my $dep (split(/\s+/, $2)) { + $dep =~ s/^\+//g; + $sysmap{$dep} = $virt; + } + } + } + close(CONF); +} + +sub graph_addnode { + my ($isstopseq, $lsbinforef) = @_; + my %lsbinfo = %{$lsbinforef}; + + unless ($lsbinfo{'provides'}) { + error "File ". $lsbinfo{'file'} . " is missing the provides header\n"; + $lsbinfo{'provides'} = $lsbinfo{'file'}; + $lsbinfo{'provides'} =~ s/^[SK]\d{2}//; + } + + my $key = $opts{'k'} ? 'stop' : 'start'; + my $revkey = $opts{'k'} ? 'stop-after' : 'start-before'; + my @provides = split(/\s+/, $lsbinfo{'provides'}); + for my $name (@provides) { + if (exists $sysmap{$name}) { + graph_addnode($isstopseq, + {'provides' => $sysmap{$name}, + "required-$key" => $name}); + } + } + + if (1 < @provides) { + my @providescopy = @provides; + my $lastprovide = shift @providescopy; + for my $provide (@providescopy) { + graph_addnode($isstopseq, + {'provides' => $lastprovide, + "required-$key" => $provide}); + graph_addnode($isstopseq, + {'provides' => $provide, + "required-$key" => $lastprovide}); + } + } + + for my $provide (@provides) { + my $provideesc = $provide; $provideesc =~ s/"/\\"/g; + my %deps = + ( + "required-$key" => 'blue', + "should-$key" => 'springgreen', + "$revkey" => 'yellow' + ); + + for $key (keys %deps) { + if (exists $lsbinfo{$key} && $lsbinfo{$key}) { + my @depends = split(/\s+/, $lsbinfo{$key}); + + my $dependonall = 0; + for my $pkg (@depends) { + $dependonall = 1 if ($pkg eq '$all'); + } + + for my $pkg (@depends) { + my $pkgesc = $pkg; $pkgesc =~ s/"/\\"/g; + my $color = $deps{$key}; + if ($revkey eq $key) { + print "\"$provideesc\" -> \"$pkgesc\"[color=$color] ;\n"; + $gotrevdeps{$pkg} = 1 unless $dependonall; + } else { + print "\"$pkgesc\" -> \"$provideesc\"[color=$color] ;\n"; + $gotrevdeps{$provide} = 1 unless $dependonall; + } + } + } + } + + print "\"$provideesc\" [shape=box];\n" unless $allprovides{$provide}; + $allprovides{$provide} = 1; + } +} + +sub graph_generate_mode { + my ($isstopseq) = @_; + my @dirs = $isstopseq ? $rcmap{6} : ($rcmap{S}, $rcmap{2}); + for my $rcdir (@dirs) { + chdir "$rcbase/$rcdir/."; + my @scripts = $isstopseq ? : ; + for my $script (@scripts) { + my $lsbinforef = load_lsb_tags("$rcbase/$rcdir/$script", + $useoverrides); + + unless (defined $lsbinforef) { + error "LSB header missing in $rcbase/$rcdir/$script\n"; + $script =~ s/^[SK]\d{2}//; + $lsbinforef = {'provides' => $script, + 'required-start' => '$remote_fs $syslog', + 'required-stop' => '$remote_fs $syslog'}; + } + graph_addnode($isstopseq, $lsbinforef); + } + } + # Mark all packages without any reverse dependencies as depending + # on $all + for my $provide (keys %allprovides) { + next unless (exists $gotrevdeps{$provide}); + my $lsbinforef = {'provides' => '$all', + 'required-start' => "$provide", + 'required-stop' => "$provide"}; + graph_addnode($isstopseq, $lsbinforef); + } +} + +sub graph_generate { + print "# Generating graph\n"; + print < $bootorder)) { + my $deporder; + if (exists $scriptorder{$tag}{$dep}) { + $deporder = $scriptorder{$tag}{$dep} + } else { + $deporder = exists $provideslist{$dep} ? $provideslist{$dep} : "?"; + } + error(sprintf("Incorrect order %s@%s %s %s%s\n", + $dep, $deporder, 'S' eq $tag ? '>' : '<', + $name, $order)); + } + } + } + } +} + +sub check_bootorder { + my $bootorder = 0; + my @dirs = $opts{'k'} ? $rcmap{6} : ($rcmap{S}, $rcmap{2}); + my @scripts; + for my $rcdir (@dirs) { + push(@scripts, $opts{'k'} ? <$rcbase/$rcdir/K*> : <$rcbase/$rcdir/S*>); + } + + if ($opts{'k'}) { + $scriptorder{'K'}{'$all'} = 1; + } else { + # Calculate script order for the script before the scripts + # with the last boot sequence number. + my $tmpbootorder = 0; + my $allorder = 0; + my $maxorder = 0; + my $maxbootorder = 0; + for my $scriptpath (@scripts) { + my $script = $scriptpath; + $script =~ s%^.*/([^/]+)$%$1%; + $tmpbootorder++; + my ($tag, $order, $name) = $script =~ m/^(.)(\d{2})(.+)$/; + if ($order > $maxorder) { + $allorder = $maxbootorder; + $maxbootorder = $tmpbootorder; + $maxorder = $order; + } + + my $lsbinforef = load_lsb_tags($scriptpath, + $useoverrides); + + if (exists $lsbinforef->{'provides'} + && $lsbinforef->{'provides'}) { + for my $provide (split(/\s+/, $lsbinforef->{'provides'})) { + $provideslist{$provide} = $order; + } + } else { + $provideslist{$script} = $order; + } + } + $scriptorder{'S'}{'$all'} = $allorder; + } + for my $scriptpath (@scripts) { + my $script = $scriptpath; + $script =~ s%^.*/([^/]+)$%$1%; + $bootorder++; + my ($tag, $order, $name) = $script =~ m/^(.)(\d{2})(.+)$/; + + $scriptorder{$tag}{$name} = $bootorder; + $scriptorder{$tag}{$sysmap{$name}} = $bootorder + if (exists $sysmap{$name}); + +# print "$script\n"; +# print "T: $tag O: $order N: $name\n"; + my $lsbinforef = load_lsb_tags($scriptpath, + $useoverrides); + + unless (defined $lsbinforef) { + error "LSB header missing in $scriptpath\n"; + next; + } + my %lsbinfo = %{$lsbinforef}; + + if (exists $lsbinfo{'provides'} && $lsbinfo{'provides'}) { + for my $provide (split(/\s+/, $lsbinfo{'provides'})) { + $scriptorder{$tag}{$provide} = $bootorder; + $scriptorder{$tag}{$sysmap{$provide}} = $bootorder + if (exists $sysmap{$provide}); + } + } else { + error "no LSB header provides value in script $scriptpath\n"; + } + + if ('S' eq $tag) { + check_deps($lsbinforef, $tag, $order, $bootorder, 'required-start', 1); + check_deps($lsbinforef, $tag, $order, $bootorder, 'should-start', 0); +# check_deps($lsbinforef, 'K', $order, $bootorder, 'start-before', 0); + } + if ('K' eq $tag) { + check_deps($lsbinforef, $tag, $order, $bootorder, 'required-stop', 1); + check_deps($lsbinforef, $tag, $order, $bootorder, 'should-stop', 0); +# check_deps($lsbinforef, 'S', $order, $bootorder, 'stop-after', 0); + } + } +} + +sub load_lsb_tags { + my ($initfile, $useoverrides) = @_; + my $lsbinforef = load_lsb_tags_from_file($initfile); + + if ($useoverrides) { + # Try override file + $initfile = readlink($initfile) if (-l $initfile); + my $basename = basename($initfile); + + # Only read shipped override file when initscript does not + # contain LSB tags. + if (! defined($lsbinforef) && -f "$overridepath/$basename") { + print STDERR "Override $overridepath/$basename\n" if $debug; + $lsbinforef = load_lsb_tags_from_file("$overridepath/$basename"); + } + + # Always read the host override in $hostoverridepath. + if (-f "$hostoverridepath/$basename") { + print STDERR "Override $hostoverridepath/$basename\n" if $debug; + $lsbinforef = load_lsb_tags_from_file("$hostoverridepath/$basename"); + } + + } + return $lsbinforef; +} + +sub load_lsb_tags_from_file { + my ($file) = @_; + print STDERR "Loading $file\n" if $debug; + ### BEGIN INIT INFO + # Provides: xdebconfigurator + # Required-Start: $syslog + # Required-Stop: $syslog + # Default-Start: 2 3 4 5 + # Default-Stop: 1 6 + # Short-Description: Genererate xfree86 configuration at boot time + # Description: Preseed X configuration and use dexconf to + # genereate a new configuration file. + ### END INIT INFO + unless (open(FILE, "<$file")) { + warn "error: Unable to read $file"; + return; + } + my $found = 0; + my ($provides, $requiredstart, $requiredstop, $shouldstart, $shouldstop); + my ($startbefore, $stopafter); + while () { + chomp; + $found = 1 if (m/\#\#\# BEGIN INIT INFO/); + next unless $found; + last if (m/\#\#\# END INIT INFO/); + + $provides = $1 if (m/^\# provides:\s+(\S*.*\S+)\s*$/i); + $requiredstart = $1 if (m/^\# required-start:\s+(\S*.*\S+)\s*$/i); + $requiredstop = $1 if (m/^\# required-stop:\s+(\S*.*\S+)\s*$/i); + $shouldstart = $1 if (m/^\# should-start:\s+(\S*.*\S+)\s*$/i); + $shouldstop = $1 if (m/^\# should-stop:\s+(\S*.*\S+)\s*$/i); + $startbefore = $1 if (m/^\# X-Start-Before:\s+(\S*.*\S+)\s*$/i); + $stopafter = $1 if (m/^\# X-Stop-After:\s+(\S*.*\S+)\s*$/i); + } + close(FILE); + + return undef unless ($found); + +# print "Provides: $provides\n" if $provides; + return { + 'provides' => $provides, + 'required-start' => $requiredstart, + 'required-stop' => $requiredstop, + 'should-start' => $shouldstart, + 'should-stop' => $shouldstop, + 'start-before' => $startbefore, + 'stop-after' => $stopafter, + 'file' => $file, + }; +} diff --git a/packaging/devfsd b/packaging/devfsd new file mode 100644 index 0000000..ed36858 --- /dev/null +++ b/packaging/devfsd @@ -0,0 +1,8 @@ +### BEGIN INIT INFO +# Provides: devfsd +# Required-Start: mountdevsubfs +# Required-Stop: reboot +# Default-Start: S 1 2 3 4 5 +# Default-Stop: 0 6 +### END INIT INFO +# Reported to BTS as bug #324671 diff --git a/packaging/hotplug b/packaging/hotplug new file mode 100644 index 0000000..9e7b8d1 --- /dev/null +++ b/packaging/hotplug @@ -0,0 +1,7 @@ +### BEGIN INIT INFO +# Provides: hotplug +# Required-Start: mountdevsubfs checkroot $local_fs +# Required-Stop: $local_fs +# Default-Start: S +# Default-Stop: 0 6 +### END INIT INFO diff --git a/packaging/hotplug-net b/packaging/hotplug-net new file mode 100644 index 0000000..6f612d3 --- /dev/null +++ b/packaging/hotplug-net @@ -0,0 +1,7 @@ +### BEGIN INIT INFO +# Provides: hotplug-net +# Required-Start: $local_fs ifupdown +# Required-Stop: $local_fs +# Default-Start: S +# Default-Stop: 0 6 +### END INIT INFO diff --git a/packaging/initrd-tools.sh b/packaging/initrd-tools.sh new file mode 100644 index 0000000..2f4a800 --- /dev/null +++ b/packaging/initrd-tools.sh @@ -0,0 +1,7 @@ +### BEGIN INIT INFO +# Provides: initrd-tools +# Required-Start: mountdevsubfs +# Required-Stop: +# Default-Start: S +# Default-Stop: +### END INIT INFO diff --git a/packaging/insserv.spec b/packaging/insserv.spec new file mode 100644 index 0000000..951c1a4 --- /dev/null +++ b/packaging/insserv.spec @@ -0,0 +1,109 @@ +Name: insserv +License: GPL v2 or later +Group: System/Base +Provides: /sbin/insserv +Version: 1.12.0 +Release: 1 +Summary: A Program to Arrange Initialization Scripts + +Source0: insserv-%{version}.tar.gz +Source1: devfsd +Source2: hotplug +Source3: hotplug-net +Source4: initrd-tools.sh +Source5: modutils +Source6: check-initd-order +Source7: check-archive-initd-scripts +Source8: seq-changes +Source9: make-testsuite +Source10: update-bootsystem-insserv +Source11: update-rc.d-insserv +Source12: bash-completion + +Patch0: 10_nosuse.patch +Patch1: 11_debian_conf.patch +Patch2: 20_install_perms_fixup.patch +Patch3: 21_tests_suite_new_functions.patch +Patch4: 30_deterministic_order.patch +Patch5: 40_badboy_segfault.patch +Patch6: 50_symlink_in_initddir.patch +Patch7: 61_interactive_keyword.patch +Patch8: 62_upstart_job.patch +Patch9: 70_req_start_all_depends.patch +Patch10: 71_complete_makefile.patch +Patch11: 81_lessverbose.patch +Patch12: 82_loop_exit_msg.patch +Patch13: 91_kfreebsd_nofadvice.patch +Patch14: 92_m68k_alignment.patch +Patch15: 93_hurd_no_path_max.patch +Patch16: 94_v1_12_2.patch +Patch17: 95_stop_all.patch +Patch18: 96_hurd_no_at_funcs.patch + +%description +Insserv enables an installed system init script (boot script) by +reading the comment header of the script and calculating the +dependencies between all scripts. + + +%prep +%setup + +%patch0 -p1 -b .10_nosuse +%patch1 -p1 -b .11_debian_conf.patch +%patch2 -p1 -b .20_install_perms_fixup.patch +%patch3 -p1 -b .21_tests_suite_new_functions.patch +%patch4 -p1 -b .30_deterministic_order.patch +%patch5 -p1 -b .40_badboy_segfault.patch +%patch6 -p1 -b .50_symlink_in_initddir.patch +%patch7 -p1 -b .61_interactive_keyword.patch +%patch8 -p1 -b .62_upstart_job.patch +%patch9 -p1 -b .70_req_start_all_depends.patch +%patch10 -p1 -b .71_complete_makefile.patch +%patch11 -p1 -b .81_lessverbose.patch +%patch12 -p1 -b .82_loop_exit_msg.patch +%patch13 -p1 -b .91_kfreebsd_nofadvice.patch +%patch14 -p1 -b .92_m68k_alignment.patch +%patch15 -p1 -b .93_hurd_no_path_max.patch +%patch16 -p1 -b .94_v1_12_2.patch +%patch17 -p1 -b .95_stop_all.patch +%patch18 -p1 -b .96_hurd_no_at_funcs.patch + + +%build +make INITDIR=%{_sysconfdir}/init.d INSCONF=%{_sysconfdir}/insserv.conf + +%install +make install DESTDIR=%{buildroot} + +# Install overrides +install -d %{buildroot}/%{_datadir}/%{name}/overrides/ +for src in %SOURCE1 %SOURCE2 %SOURCE3 %SOURCE4 %SOURCE5; do + install -m 644 $src %{buildroot}/%{_datadir}/%{name}/overrides/ +done + +# install +for src in %SOURCE6 %SOURCE7 %SOURCE8 %SOURCE9; do + install $src %{buildroot}/%{_datadir}/%{name}/ +done + +install -d %{buildroot}/%{_sbindir} +install %SOURCE10 %{buildroot}/%{_sbindir}/ +install %SOURCE11 %{buildroot}/%{_sbindir}/ + +# Install bash(1) completion +install -d %{buildroot}/%{_sysconfdir}/bash_completion.d +install -m 644 %SOURCE12 %{buildroot}/%{_sysconfdir}/bash_completion.d/insserv + +install -d %{buildroot}/var/lib/update-rc.d %{buildroot}/%{_sysconfdir}/insserv.conf.d + +%files +%defattr(-,root,root) +%config %{_sysconfdir}/%{name}.conf +/sbin/insserv +%{_sbindir}/* +%{_datadir}/%{name}/* +%{_mandir}/man8/insserv.8.gz +%dir /var/lib/update-rc.d +%dir %{_sysconfdir}/insserv.conf.d +%{_sysconfdir}/bash_completion.d/insserv diff --git a/packaging/make-testsuite b/packaging/make-testsuite new file mode 100644 index 0000000..c4aec47 --- /dev/null +++ b/packaging/make-testsuite @@ -0,0 +1,33 @@ +#!/bin/sh +# +# Extract key information from the current to try to generate a test +# suite script to demonstrate detected bugs. + +echo "cat <<'EOF' > \$tmpdir\$insconf" +grep -v '#' /etc/insserv.conf |grep -v '^$' +echo "EOF" + +for f in /etc/init.d/*; do + name=$(basename $f) + case $name in + README|rc|rcS|skeleton) + ;; + *) + echo "addscript $name <" + exit 1 +fi + +oldtar="$(tar tzf $1)" +for i in S $(seq 0 6); do + echo "Runlevel $i" + new="$(cd /etc/rc$i.d; ls -1 [KS]* | sort | nl)" + old="$(echo "$oldtar" | grep "^rc$i.d/[KS]" | cut -d/ -f2 | sort | nl)" + case $i in + S|0|6) + old="$(echo "$old" | sed -r "s/[KS][0-9]+//")" + new="$(echo "$new" | sed -r "s/[KS][0-9]+//")" + ;; + *) + old="$(echo "$old" | sed -r "s/([KS])[0-9]+/\1_/")" + new="$(echo "$new" | sed -r "s/([KS])[0-9]+/\1_/")" + ;; + esac + echo "$new" | while read num cmd; do + oldnum=$(echo "$old" | grep "[[:space:]]$cmd$" | awk '{print $1}') + if [ "$oldnum" ]; then + diff=$(($num - $oldnum)) + else + oldnum="---" + diff="" + fi + if [ ${#cmd} -ge 16 ]; then + echo -e "$cmd\t$num\t$oldnum\t$diff" + elif [ ${#cmd} -ge 8 ]; then + echo -e "$cmd\t\t$num\t$oldnum\t$diff" + else + echo -e "$cmd\t\t\t$num\t$oldnum\t$diff" + fi + done + echo "$old" | while read num cmd; do + if ! echo "$new" | grep -q "[[:space:]]$cmd$"; then + if [ ${#cmd} -ge 16 ]; then + echo -e "$cmd\t---\t$oldnum" + elif [ ${#cmd} -ge 8 ]; then + echo -e "$cmd\t\t---\t$oldnum" + else + echo -e "$cmd\t\t\t---\t$oldnum" + fi + fi + done + echo +done diff --git a/packaging/update-bootsystem-insserv b/packaging/update-bootsystem-insserv new file mode 100644 index 0000000..5b20a17 --- /dev/null +++ b/packaging/update-bootsystem-insserv @@ -0,0 +1,24 @@ +#!/bin/sh +# +# Author: Petter Reinholdtsen +# Date: 2009-08-04 +# +# Transition script only to be used by sysv-rc version 2.87dsf-2 if +# insserv is upgraded without sysv-rc being upgraded too. + +set -e + +case "$1" in + enable|'') + exit 0 + ;; + check) + exit 1 + ;; + *) + echo "error: Unknown argument '$1'" + exit 1 + ;; +esac + +exit 0 diff --git a/packaging/update-rc.d-insserv b/packaging/update-rc.d-insserv new file mode 100644 index 0000000..1853251 --- /dev/null +++ b/packaging/update-rc.d-insserv @@ -0,0 +1,593 @@ +#! /usr/bin/perl +# +# update-rc.d Update the links in /etc/rc[0-9S].d/ +# + +use strict; +use warnings; + +my $initd = "/etc/init.d"; +my $etcd = "/etc/rc"; +my $notreally = 0; + +# Save last action to this directory +my $archive = "/var/lib/update-rc.d"; + +# Print usage message and die. + +sub usage { + print STDERR "update-rc.d: error: @_\n" if ($#_ >= 0); + print STDERR < remove + update-rc.d [-n] defaults [NN | SS KK] + update-rc.d [-n] start|stop NN runlvl [runlvl] [...] . + update-rc.d [-n] disable|enable [S|2|3|4|5] + -n: not really + -f: force + +The disable|enable API is not stable and might change in the future. +EOF + exit (1); +} + +# Dependency based boot sequencing is the default, but upgraded +# systems might keep the legacy ordering until the sysadm choose to +# migrate to the new ordering method. sysv-rc version 2.87dsf-2 will +# remove /var/lib/insserv/using-insserv and this divert, thus transfering +# the responsibility for dependency based update-rc.d to sysv-rc. +if ( -f "/var/lib/insserv/using-insserv" && ! -f "/etc/init.d/.legacy-bootordering" ) { + info("using dependency based boot sequencing"); + exit insserv_updatercd(@ARGV); +} + +# Check out options. +my $force; + +my @orig_argv = @ARGV; + +while($#ARGV >= 0 && ($_ = $ARGV[0]) =~ /^-/) { + shift @ARGV; + if (/^-n$/) { $notreally++; next } + if (/^-f$/) { $force++; next } + if (/^-h|--help$/) { &usage; } + &usage("unknown option"); +} + +sub save_last_action { + my ($script, @arguments) = @_; + + return if $notreally; + + open(FILE, ">", "$archive/${script}.new") || die "unable to write to $archive/${script}.new"; + print FILE join(" ","update-rc.d",@arguments), "\n"; + close(FILE); + rename "$archive/${script}.new", "$archive/${script}"; +} + +sub remove_last_action { + my ($script) = @_; + unlink "$archive/$script"; +} + +# Action. + +&usage() if ($#ARGV < 1); +my $bn = shift @ARGV; + +unless ($bn =~ m/[a-zA-Z0-9+.-]+/) { + print STDERR "update-rc.d: illegal character in name '$bn'\n"; + exit (1); +} + +if ($ARGV[0] ne 'remove') { + if (! -f "$initd/$bn") { + print STDERR "update-rc.d: $initd/$bn: file does not exist\n"; + exit (1); + } + &parse_lsb_header("$initd/$bn"); + &cmp_args_with_defaults($bn, $ARGV[0], @ARGV); +} elsif (-f "$initd/$bn") { + if (!$force) { + printf STDERR "update-rc.d: $initd/$bn exists during rc.d purge (use -f to force)\n"; + exit (1); + } +} + +my @startlinks; +my @stoplinks; + +$_ = $ARGV[0]; +if (/^remove$/) { &checklinks ("remove"); remove_last_action($bn); } +elsif (/^defaults$/) { &defaults (@ARGV); &makelinks; save_last_action($bn, @orig_argv); } +elsif (/^(start|stop)$/) { &startstop (@ARGV); &makelinks; save_last_action($bn, @orig_argv); } +elsif (/^(dis|en)able$/) { &toggle (@ARGV); &makelinks; save_last_action($bn, @orig_argv); } +else { &usage; } + +exit (0); + +sub info { + print STDOUT "update-rc.d: @_\n"; +} + +sub warning { + print STDERR "update-rc.d: warning: @_\n"; +} + +sub error { + print STDERR "update-rc.d: error: @_\n"; + exit (1); +} + +sub error_code { + my $rc = shift; + print STDERR "update-rc.d: error: @_\n"; + exit ($rc); +} + +# Check if there are links in /etc/rc[0-9S].d/ +# Remove if the first argument is "remove" and the links +# point to $bn. + +sub is_link () { + my ($op, $fn, $bn) = @_; + if (! -l $fn) { + warning "$fn is not a symbolic link\n"; + return 0; + } else { + my $linkdst = readlink ($fn); + if (! defined $linkdst) { + die ("update-rc.d: error reading symbolic link: $!\n"); + } + if (($linkdst ne "../init.d/$bn") && ($linkdst ne "$initd/$bn")) { + warning "$fn is not a link to ../init.d/$bn or $initd/$bn\n"; + return 0; + } + } + return 1; +} + +sub checklinks { + my ($i, $found, $fn, $islnk); + + print " Removing any system startup links for $initd/$bn ...\n" + if (defined $_[0] && $_[0] eq 'remove'); + + $found = 0; + + foreach $i (0..9, 'S') { + unless (chdir ("$etcd$i.d")) { + next if ($i =~ m/^[789S]$/); + die("update-rc.d: chdir $etcd$i.d: $!\n"); + } + opendir(DIR, "."); + my $saveBN=$bn; + $saveBN =~ s/\+/\\+/g; + foreach $_ (readdir(DIR)) { + next unless (/^[SK]\d\d$saveBN$/); + $fn = "$etcd$i.d/$_"; + $found = 1; + $islnk = &is_link ($_[0], $fn, $bn); + next unless (defined $_[0] and $_[0] eq 'remove'); + if (! $islnk) { + print " $fn is not a link to ../init.d/$bn; not removing\n"; + next; + } + print " $etcd$i.d/$_\n"; + next if ($notreally); + unlink ("$etcd$i.d/$_") || + die("update-rc.d: unlink: $!\n"); + } + closedir(DIR); + } + $found; +} + +sub parse_lsb_header { + my $initdscript = shift; + my %lsbinfo; + my $lsbheaders = "Provides|Required-Start|Required-Stop|Default-Start|Default-Stop"; + open(INIT, "<$initdscript") || die "error: unable to read $initdscript"; + while () { + chomp; + $lsbinfo{'found'} = 1 if (m/^\#\#\# BEGIN INIT INFO\s*$/); + last if (m/\#\#\# END INIT INFO\s*$/); + if (m/^\# ($lsbheaders):\s*(\S?.*)$/i) { + $lsbinfo{lc($1)} = $2; + } + } + close(INIT); + + # Check that all the required headers are present + if (!$lsbinfo{found}) { + printf STDERR "update-rc.d: warning: $initdscript missing LSB information\n"; + printf STDERR "update-rc.d: see \n"; + } else { + for my $key (split(/\|/, lc($lsbheaders))) { + if (!exists $lsbinfo{$key}) { + warning "$initdscript missing LSB keyword '$key'\n"; + } + } + } +} + + +# Process the arguments after the "enable" or "disable" keyword. + +sub toggle { + my @argv = @_; + my ($action, %lvls, @start, @stop, @xstartlinks); + + if (!&checklinks) { + print " System start/stop links for $initd/$bn do not exist.\n"; + exit (0); + } + + $action = $argv[0]; + if ($#argv > 1) { + while ($#argv > 0 && shift @argv) { + if ($argv[0] =~ /^[S2-5]$/) { + $lvls{$argv[0]}++; + } else { + &usage ("expected 'S' '2' '3' '4' or '5'"); + } + } + } else { + $lvls{$_}++ for ('S', '2', '3', '4', '5'); + } + + push(@start, glob($etcd . '[2-5S].d/[KS][0-9][0-9]' . $bn)); + + foreach (@start) { + my $islink = &is_link (undef, $_, $bn); + next if !$islink; + + next unless my ($lvl, $sk, $seq) = m/^$etcd([2-5S])\.d\/([SK])([0-9]{2})$bn$/; + $startlinks[$lvl] = $sk . $seq; + + if ($action eq 'disable' and $sk eq 'S' and $lvls{$lvl}) { + $xstartlinks[$lvl] = 'K' . sprintf "%02d", (100 - $seq); + } elsif ($action eq 'enable' and $sk eq 'K' and $lvls{$lvl}) { + $xstartlinks[$lvl] = 'S' . sprintf "%02d", -($seq - 100); + } else { + $xstartlinks[$lvl] = $sk . $seq; + } + } + + push(@stop, glob($etcd . '[016].d/[KS][0-9][0-9]' . $bn)); + + foreach (@stop) { + my $islink = &is_link (undef, $_, $bn); + next if !$islink; + + next unless my ($lvl, $sk, $seq) = m/^$etcd([016])\.d\/([SK])([0-9]{2})$bn$/; + $stoplinks[$lvl] = $sk . $seq; + } + + if ($action eq 'disable') { + print " Disabling system startup links for $initd/$bn ...\n"; + } elsif ($action eq 'enable') { + print " Enabling system startup links for $initd/$bn ...\n"; + } + + &checklinks ("remove"); + @startlinks = @xstartlinks; + + 1; +} + +# Process the arguments after the "defaults" keyword. + +sub defaults { + my @argv = @_; + my ($start, $stop) = (20, 20); + + &usage ("defaults takes only one or two codenumbers") if ($#argv > 2); + $start = $stop = $argv[1] if ($#argv >= 1); + $stop = $argv[2] if ($#argv >= 2); + &usage ("codenumber must be a number between 0 and 99") + if ($start !~ /^\d\d?$/ || $stop !~ /^\d\d?$/); + + $start = sprintf("%02d", $start); + $stop = sprintf("%02d", $stop); + + $stoplinks[$_] = "K$stop" for (0, 1, 6); + $startlinks[$_] = "S$start" for (2, 3, 4, 5); + + 1; +} + +# Process the arguments after the start or stop keyword. + +sub startstop { + my @argv = @_; + my($letter, $NN, $level); + + while ($#argv >= 0) { + if ($argv[0] eq 'start') { $letter = 'S'; } + elsif ($argv[0] eq 'stop') { $letter = 'K'; } + else { + &usage("expected start|stop"); + } + + if ($argv[1] !~ /^\d\d?$/) { + &usage("expected NN after $argv[0]"); + } + $NN = sprintf("%02d", $argv[1]); + + if ($argv[-1] ne '.') { + &usage("start|stop arguments not terminated by \".\""); + } + + shift @argv; shift @argv; + $level = shift @argv; + do { + if ($level !~ m/^[0-9S]$/) { + &usage( + "expected runlevel [0-9S] (did you forget \".\" ?)"); + } + if (! -d "$etcd$level.d") { + print STDERR + "update-rc.d: $etcd$level.d: no such directory\n"; + exit(1); + } + $level = 99 if ($level eq 'S'); + $startlinks[$level] = "$letter$NN" if ($letter eq 'S'); + $stoplinks[$level] = "$letter$NN" if ($letter eq 'K'); + } while (($level = shift @argv) ne '.'); + } + 1; +} + +# Create the links. + +sub makelinks { + my($t, $i); + my @links; + + if (&checklinks) { + print " System start/stop links for $initd/$bn already exist.\n"; + return 0; + } + print " Adding system startup for $initd/$bn ...\n"; + + # nice unreadable perl mess :) + + for($t = 0; $t < 2; $t++) { + @links = $t ? @startlinks : @stoplinks; + for($i = 0; $i <= $#links; $i++) { + my $lvl = $i; + $lvl = 'S' if ($i == 99); + next if (!defined $links[$i] or $links[$i] eq ''); + print " $etcd$lvl.d/$links[$i]$bn -> ../init.d/$bn\n"; + next if ($notreally); + symlink("../init.d/$bn", "$etcd$lvl.d/$links[$i]$bn") + || die("update-rc.d: symlink: $!\n"); + } + } + + 1; +} + +## Dependency based +sub insserv_updatercd { + my @args = @_; + my @opts; + my $scriptname; + my $action; + my $notreally = 0; + + my @orig_argv = @args; + + while($#args >= 0 && ($_ = $args[0]) =~ /^-/) { + shift @args; + if (/^-n$/) { push(@opts, $_); $notreally++; next } + if (/^-f$/) { push(@opts, $_); next } + if (/^-h|--help$/) { &usage; } + usage("unknown option"); + } + + usage("not enough arguments") if ($#args < 1); + + $scriptname = shift @args; + $action = shift @args; + if ("remove" eq $action) { + if ( -f "/etc/init.d/$scriptname" ) { + my $rc = system("insserv", @opts, "-r", $scriptname) >> 8; + if (0 == $rc && !$notreally) { + remove_last_action($scriptname); + } + error_code($rc, "insserv rejected the script header") if $rc; + exit $rc; + } else { + # insserv removes all dangling symlinks, no need to tell it + # what to look for. + my $rc = system("insserv", @opts) >> 8; + if (0 == $rc && !$notreally) { + remove_last_action($scriptname); + } + error_code($rc, "insserv rejected the script header") if $rc; + exit $rc; + } + } elsif ("defaults" eq $action || "start" eq $action || + "stop" eq $action) { + # All start/stop/defaults arguments are discarded so emit a + # message if arguments have been given and are in conflict + # with Default-Start/Default-Stop values of LSB comment. + cmp_args_with_defaults($scriptname, $action, @args); + + if ( -f "/etc/init.d/$scriptname" ) { + my $rc = system("insserv", @opts, $scriptname) >> 8; + if (0 == $rc && !$notreally) { + save_last_action($scriptname, @orig_argv); + } + error_code($rc, "insserv rejected the script header") if $rc; + exit $rc; + } else { + error("initscript does not exist: /etc/init.d/$scriptname"); + } + } elsif ("disable" eq $action || "enable" eq $action) { + insserv_toggle($notreally, $action, $scriptname, @args); + # Call insserv to resequence modified links + my $rc = system("insserv", @opts, $scriptname) >> 8; + if (0 == $rc && !$notreally) { + save_last_action($scriptname, @orig_argv); + } + error_code($rc, "insserv rejected the script header") if $rc; + exit $rc; + } else { + usage(); + } +} + +sub parse_def_start_stop { + my $script = shift; + my (%lsb, @def_start_lvls, @def_stop_lvls); + + open my $fh, '<', $script or error("unable to read $script"); + while (<$fh>) { + chomp; + if (m/^### BEGIN INIT INFO$/) { + $lsb{'begin'}++; + } + elsif (m/^### END INIT INFO$/) { + $lsb{'end'}++; + last; + } + elsif ($lsb{'begin'} and not $lsb{'end'}) { + if (m/^# Default-Start:\s*(\S?.*)$/) { + @def_start_lvls = split(' ', $1); + } + if (m/^# Default-Stop:\s*(\S?.*)$/) { + @def_stop_lvls = split(' ', $1); + } + } + } + close($fh); + + return (\@def_start_lvls, \@def_stop_lvls); +} + +sub lsb_header_for_script { + my $name = shift; + + foreach my $file ("/etc/insserv/overrides/$name", "/etc/init.d/$name", + "/usr/share/insserv/overrides/$name") { + return $file if -s $file; + } + + error("cannot find a LSB script for $name"); +} + +sub cmp_args_with_defaults { + my ($name, $act) = (shift, shift); + my ($lsb_start_ref, $lsb_stop_ref, $arg_str, $lsb_str); + my (@arg_start_lvls, @arg_stop_lvls, @lsb_start_lvls, @lsb_stop_lvls); + + ($lsb_start_ref, $lsb_stop_ref) = parse_def_start_stop("/etc/init.d/$name"); + @lsb_start_lvls = @$lsb_start_ref; + @lsb_stop_lvls = @$lsb_stop_ref; + return if (!@lsb_start_lvls and !@lsb_stop_lvls); + + if ($act eq 'defaults') { + @arg_start_lvls = (2, 3, 4, 5); + @arg_stop_lvls = (0, 1, 6); + } elsif ($act eq 'start' or $act eq 'stop') { + my $start = $act eq 'start' ? 1 : 0; + my $stop = $act eq 'stop' ? 1 : 0; + + # The legacy part of this program passes arguments starting with + # "start|stop NN x y z ." but the insserv part gives argument list + # starting with sequence number (ie. strips off leading "start|stop") + # Start processing arguments immediately after the first seq number. + my $argi = $_[0] eq $act ? 2 : 1; + + while (defined $_[$argi]) { + my $arg = $_[$argi]; + + # Runlevels 0 and 6 are always stop runlevels + if ($arg eq 0 or $arg eq 6) { + $start = 0; $stop = 1; + } elsif ($arg eq 'start') { + $start = 1; $stop = 0; $argi++; next; + } elsif ($arg eq 'stop') { + $start = 0; $stop = 1; $argi++; next; + } elsif ($arg eq '.') { + next; + } + push(@arg_start_lvls, $arg) if $start; + push(@arg_stop_lvls, $arg) if $stop; + } continue { + $argi++; + } + } + + if ($#arg_start_lvls != $#lsb_start_lvls or + join("\0", sort @arg_start_lvls) ne join("\0", sort @lsb_start_lvls)) { + $arg_str = @arg_start_lvls ? "@arg_start_lvls" : "none"; + $lsb_str = @lsb_start_lvls ? "@lsb_start_lvls" : "none"; + warning "$name start runlevel arguments ($arg_str) do not match", + "LSB Default-Start values ($lsb_str)"; + } + if ($#arg_stop_lvls != $#lsb_stop_lvls or + join("\0", sort @arg_stop_lvls) ne join("\0", sort @lsb_stop_lvls)) { + $arg_str = @arg_stop_lvls ? "@arg_stop_lvls" : "none"; + $lsb_str = @lsb_stop_lvls ? "@lsb_stop_lvls" : "none"; + warning "$name stop runlevel arguments ($arg_str) do not match", + "LSB Default-Stop values ($lsb_str)"; + } +} + +sub insserv_toggle { + my ($dryrun, $act, $name) = (shift, shift, shift); + my (@toggle_lvls, $start_lvls, $stop_lvls, @symlinks); + my $lsb_header = lsb_header_for_script($name); + + # Extra arguments to disable|enable action are runlevels. If none + # given parse LSB info for Default-Start value. + if ($#_ >= 0) { + @toggle_lvls = @_; + } else { + ($start_lvls, $stop_lvls) = parse_def_start_stop($lsb_header); + @toggle_lvls = @$start_lvls; + if ($#toggle_lvls < 0) { + error("$name Default-Start contains no runlevels, aborting."); + } + } + + # Find symlinks in rc.d directories. Refuse to modify links in runlevels + # not used for normal system start sequence. + for my $lvl (@toggle_lvls) { + if ($lvl !~ /^[S2345]$/) { + warning("$act action will have no effect on runlevel $lvl"); + next; + } + push(@symlinks, $_) for glob("/etc/rc$lvl.d/[SK][0-9][0-9]$name"); + } + + if (!@symlinks) { + error("no runlevel symlinks to modify, aborting!"); + } + + # Toggle S/K bit of script symlink. + for my $cur_lnk (@symlinks) { + my $sk; + my @new_lnk = split(//, $cur_lnk); + + if ("disable" eq $act) { + $sk = rindex($cur_lnk, '/S') + 1; + next if $sk < 1; + $new_lnk[$sk] = 'K'; + } else { + $sk = rindex($cur_lnk, '/K') + 1; + next if $sk < 1; + $new_lnk[$sk] = 'S'; + } + + if ($dryrun) { + printf("rename(%s, %s)\n", $cur_lnk, join('', @new_lnk)); + next; + } + + rename($cur_lnk, join('', @new_lnk)) or error($!); + } +} diff --git a/remove_initd b/remove_initd new file mode 100755 index 0000000..ef869cf --- /dev/null +++ b/remove_initd @@ -0,0 +1,2 @@ +#!/bin/sh +exec /sbin/insserv -r ${1+"$@"} diff --git a/tests/suite b/tests/suite new file mode 100644 index 0000000..5a27309 --- /dev/null +++ b/tests/suite @@ -0,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 + 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 + 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 +} + -- 2.7.4