Package: debian-policy Version: 3.2.1.0 Severity: wishlist -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
This issue has been discussed in both debian-devel and debian-policy, and all threads seem to have stalled. Therefore, I am submitting it to the BTS. Should this proposal be accepted, manpages for invoke-rc.d will be written. Also, compatibility scripts for file-rc will be written (by me, if nobody else objects). Attached are also the interface description for invoke-rc.d and policy-rc.d, and a sample implementation of invoke-rc.d for sysvinit (not file-rc). - -- System Information Debian Release: woody Architecture: i386 Kernel: Linux godzillah.rivendell.sol 2.2.17 #1 Wed Sep 6 17:08:58 BRT 2000 i586 Versions of packages debian-policy depends on: ii fileutils 4.0.31-1 GNU file management utilities. - -- "One disk to rule them all, One disk to find them. One disk to bring them all and in the darkness grind them. In the Land of Redmond where the shadows lie." -- The Silicon Valley Tarot Henrique Holschuh -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.0.4 (GNU/Linux) Comment: For info see http://www.gnupg.org iEYEARECAAYFAjoOxk0ACgkQ7iXePxzbD+MYZACfQu4ULiDpnepDZKCHZwHsiPV7 tWIAnRgvlgMnhhD7TEs/ehXLKa26nohp =Fh4A -----END PGP SIGNATURE-----
--- policy.text.orig Fri Nov 3 11:52:27 2000 +++ policy.text Mon Nov 6 17:25:08 2000 @@ -1041,7 +1041,12 @@ stop the service, `restart' - stop and restart the service, + stop and restart the service (note that the service may be + started even if it was not running before), + + `restart-if-running' + stop the service, and if the service was running before being + stopped by restart-if-running, restart it, `reload' cause the configuration of the service to be reloaded without @@ -1052,8 +1057,8 @@ this, otherwise restart the service. The `start', `stop', `restart', and `force-reload' options should be - supported by all scripts in `/etc/init.d', the `reload' option is - optional. + supported by all scripts in `/etc/init.d', the `reload' and + `restart-if-running' options are optional. The `init.d' scripts should ensure that they will behave sensibly if invoked with `start' when the service is already running, or with @@ -1076,8 +1081,19 @@ test -f <program-executed-later-in-script> || exit 0 -3.3.3. Managing the links -------------------------- +3.3.3. Interfacing with the initscript system +--------------------------------------------- + + Maintainers should use the abstraction layer provided by the + `update-rc.d' and `invoke-rc.d' programs to deal with initscripts in + their packages' scripts such as `postinst', 'prerm' and `postrm'. + + Directly managing the /etc/rc?.d links and directly invoking the + /etc/init.d/ initscripts should be done only by packages providing the + initscript subsystem (such as `sysvinit' and `file-rc'). + +3.3.3.1. Managing the links +--------------------------- The program `update-rc.d' is provided to make it easier for package maintainers to arrange for the proper creation and removal of @@ -1118,6 +1134,48 @@ For more information about using `update-rc.d', please consult its manpage update-rc.d(8). + +3.3.3.2. Running initscripts +---------------------------- + + The program `invoke-rc.d' is provided to make it easier for package + maintainers to properly invoke an initscript, obeying runlevel and + other locally-defined constrains that might limit a package's right to + start, stop and otherwise manage services. This program may be used by + maintainers in their packages' scripts. + + The use of `invoke-rc.d' to invoke the `/etc/init.d/*' initscripts + is strongly recommended[1], instead of calling them directly. + + Footnote [1] In the future, the use of invoke-rc.d to invoke + initscripts shall be made mandatory. Maintainers are advised to + switch to invoke-rc.d as soon as possible. + + By default, `invoke-rc.d' will pass any action requests (start, stop, + reload, restart...) to the /etc/init.d script, filtering out requests + to start a service out of its intended runlevels as defined by + `update-rc.d' and the system administrator. Also, requests to restart a + service out of its intended runlevels are changed to a + restart-if-running request. + + Most packages will simply need to change: + + /etc/init.d/<package> <action> + + in their `postinst' and `prerm' scripts to: + + if [ -x /usr/sbin/invoke-rc.d ] ; then + invoke-rc.d <package> <action> + else + /etc/init.d/<package> <action> + fi + + A package should register its initscript services using `update-rc.d' + before it tries to invoke them using `invoke-rc.d'. Invocation of + unregistered services may fail. + + For more information about using `invoke-rc.d', please consult its + manpage invoke-rc.d(8). 3.3.4. Boot-time initialization -------------------------------
The interface for all implementations of invoke-rc.d is mandated by the base implementation in the sysvinit package, just like it is done for update-rc.d. There is a provision for a "local initscript policy layer" (read: a call to /usr/sbin/policy-rc.d if this executable is present in the local system), which allows the local system administrator to control the behaviour of invoke-rc.d for every initscript id and action. It is assumed that this script is OPTIONAL and will by written and provided by packages other than the initscript system (sysvinit and file-rc packages). The basic interface for all implementations of policy-rc.d is mandated by the requirements of the base implementation of invoke-rc.d. This interface will be described either in the manpage of invoke-rc.d, or in a text file stored in /usr/share/doc/sysvinit/ by package sysvinit (which will host the base implementation of invoke-rc.d). Proposed script interfaces (to be rewritten as manpages): invoke-rc.d [options] <basename> <action> [extra initscript parameters...] basename - Initscript ID, as per update-rc.d(8) action - Initscript action. Known actions are: start, [force-]stop, restart[-if-running], [force-]reload, status (status is there because of the LSB. Debian does not use it). extra initscript parameters: These parameters are passed to the initscript as is, after the action parameter. <action> is always the first paramenter to the initscript, and may be modified by fallback actions or policy-rc.d requests. Note, however, that the extra parameters are not dropped or modified even if the action (first parameter) is modified. Options: --quiet Quiet mode, no error messages are generated by invoke-rc.d; policy-rc.d is also called with --quiet if this option is in effect. --force Try to run init script regardless of policy and non-fatal errors. Use of this option in automated scripts is severely discouraged as it bypasses integrity checks. If the initscript cannot be executed, error status 102 is returned. Do note that the policy layer call (policy-rc.d) is NOT skipped, although its results are ignored. --try-anyway Try to run the initscript even if a non-fatal subsystem error is detected (e.g: bad rc.d symlinks). A 102 status exit code will result if init script fails to execute anyway). Unlike --force, policy is still enforced with --try-anyway. --disclose-deny Return status code 101 instead of status code 0 if initscript action is denied by local policy rules or runlevel constrains. --query Returns one of status codes 100-106, does not execute the init.d script. Implies --disclose-deny and --nofallback. Status codes 104-106 are only generated by this option. Note many messages are still sent to stderr in --query mode, including those regarding policy overrides and subsystem errors. Use --quiet if silent --query operation is desired. --no-fallback The policy layer (policy-rc.d) may return fallback actions to be run instead of the requested action. If this option is active, a fallback action request will be ignored and a "action not allowed" reply used in its place. This is probably a BAD idea unless you know exactly what you're doing. --help Outputs help message to stdout Unknown actions generate warnings, but are passed to the underlying initscript anyway. The reason for the warning is simple: It is very unlikely that an unknown action (by invoke-rc.d) will be known to the policy layer (policy-rc.d), and therefore it may cause an initscript to execute an action which the local system administrator would have not allowed (but cannot forbid without editing the initscript). Should an initscript be executed, invoke-rc.d ALWAYS returns the status code returned by the initscript. Initscripts should not return status codes in the 100+ range (I didn't add this to the policy diff because the LSB will cause us to add it later anyway). Exit status codes (LSB compatible): 0 : success either the init script was run and returned exit status 0 (note that a fallback action may have been run instead of the one given in the command line), or it was not run because of runlevel/local policy constrains and --disclose-deny is not in effect. 1 - 99 : reserved for init.d script 100 : init script ID (basename) unknown init script not registered sucessfully through update-rc.d or init script does not exist. This error is fatal for most initscript systems. 101 : action not allowed requested action will not be performed because of runlevel or local policy constrains, and --disclose-deny is in effect. Note that a fallback action is NOT considered "action not allowed", unless --nofalback is in effect. 102 : subsystem error initscript (or policy) subsystem malfuncion. (e.g. broken /sbin/runlevel). Also, forced initscript execution due to --try-anyway or --force failed. 103 : syntax error 104 : action allowed --query is in effect; init script would be run if not for --query. 105 : behaviour uncertain cannot determine if action should be carried out or not, and --query in effect. 106 : fallback action requested the policy layer denied the requested action, and supplied an allowed fallback action. Policy layer (policy-rc.d) interface (rev 2): Changelog: o Fallback now may return more than one action to be tried one-at-a-time. Most Debian systems will not have this script as the need for a policy layer is not very common. Most people using chroot jails just need a one-line script which returns an exit status of 101 as the jailed /usr/sbin/policy-rc.d script. The /usr/sbin/policy-rc.d file *must* be managed through the alternatives system (/usr/sbin/update-alternatives). /usr/sbin/policy-rc.d [options] <initscript ID> <actions> [<runlevel>] /usr/sbin/policy-rc.d [options] --list <initscript ID> [<runlevel> ...] Options: --quiet no error messages are generated. --list instead of verifying policy, list (in a "human parseable" way) all policies defined for the given initscript id (for all runlevels if no runlevels are specified; otherwise, list it only for the runlevels specified), as well as all known actions and their fallbacks for the given initscript id (note that actions and fallback actions might be global and not particular to a single initscript id). <actions> is a space-separated list of actions (usually only one). Note that the list is passed in a single parameter and not as multiple parameters! The following actions are always known (even if specifying a policy for them is not supported by whatever policy-rc.d system is in use): start, [force-]stop, restart[-if-running], [force-]reload, status. The runlevel parameters are optional. If a runlevel is not specified, it is considered to be unknown/undefined. Note that for sysv-like initscript systems, an undefined runlevel is very likely to cause a 105 exit status. A runlevel for update-rc.d is defined as a character string, of which the usual INIT one-character runlevels are only a subset. It may contain embedded blanks. stdout is used to output a single line containing fallback actions, or to output --list results. stderr is used to output error messages stdin is not to be used, this is not an interactive interface. Exit status codes: 0 - action allowed 1 - unknown action (therefore, undefined policy) 100 - unknown initscript id 101 - action forbidden by policy 102 - subsystem error 103 - syntax error 104 - [reserved] 105 - behaviour uncertain, policy undefined. 106 - action not allowed. Use the returned fallback actions (which are implied to be "allowed") instead. When in doubt (policy-rc.d returned status 105 or status 1), invoke-rc.d will assume an action is allowed, but it will warn the user of the problem. Returning fallback information: Fallback actions are returned in the first line sent to stdout (other lines will be discarded). Multiple actions to be tried are allowed, and must be space-separated. Multiple actions are carried out one at a time, until one is sucessful. e.g.: returning status 106 and "restart-if-running stop" in stdout (without the quotes) will cause invoke-rc.d to attempt action "restart-if-running", and then only if "restart-if-running" failed, attempt action "stop". invoke-rc.d built-in policy rules: To shield policy-rc.d of the underlying initscript system (file-rc, links in /etc/rc?.d or something else), invoke-rc.d implements the following built-in rules: 1. action "start" out of runlevel is denied; 2. action "restart" out of runlevel fallbacks to "restart-if-running"; 3. any action for a non-executable initscript is denied. policy-rc.d is called with an action of "restart-if-running" if rule 2 is in effect. The other built-in rules are not overridable.
#!/bin/sh # # invoke-rc.d.sysvinit - Executes initscript actions # $Id: invoke-rc.d,v 1.8 2000/11/06 19:34:04 hmh Exp $ # # SysVinit /etc/rc?.d version for Debian's sysvinit package # # invoke-rc.d.sysvinit - Executes initscript actions # Copyright (C) 2000 Henrique de Moraes Holschuh <[EMAIL PROTECTED]> # # 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 # Constants RUNLEVEL=/sbin/runlevel POLICYHELPER=/usr/sbin/policy-rc.d INITDPREFIX=/etc/init.d/ RCDPREFIX=/etc/rc # Options BEQUIET= MODE= ACTION= FALLBACK= NOFALLBACK= FORCE= RETRY= RETURNFAILURE= RC= # Shell options set +e dohelp () { # # outputs help and usage # cat <<EOF invoke-rc.d, Debian/SysVinit (/etc/rc?.d) initscript subsystem. Copyright (c) 2000 Henrique de Moraes Holschuh Usage: invoke-rc.d [options] <basename> <action> [extra parameters] basename - Initscript ID, as per update-rc.d(8) action - Initscript action. Known actions are: start, [force-]stop, restart[-if-running], [force-]reload, status WARNING: not all initscripts implement all of the above actions. extra parameters are passed as is to the initscript, following the action (first initscript parameter). Options: --quiet Quiet mode, no error messages are generated. --force Try to run the initscript regardless of policy and subsystem non-fatal errors. --try-anyway Try to run init script even if a non-fatal error is found. --disclose-deny Return status code 101 instead of status code 0 if initscript action is denied by local policy rules or runlevel constrains. --query Returns one of status codes 100-106, does not run the initscript. Implies --disclose-deny and --no-fallback. --no-fallback Ignores any fallback action requests by the policy layer. Warning: this is usually a very *bad* idea for any actions other than "start". --help Outputs help message to stdout EOF } printerror () { # # prints an error message # $* - error message # if test x${BEQUIET} = x ; then echo `basename $0`: "$*" >&2 fi } formataction () { # # formats a list in $* into $printaction # for human-friendly printing to stderr # and sets $naction to action or actions # printaction=`echo $* | sed 's/ /, /g'` if test $# -eq 1 ; then naction=action else naction=actions fi } querypolicy () { # # queries policy database # returns: $RC = 104 - ok, run # $RC = 101 - ok, do not run # other - exit with status $RC, maybe run if $RETRY # if test "x${POLICYHELPER}" != x -a -x "${POLICYHELPER}" ; then FALLBACK=`${POLICYHELPER} ${BEQUIET} ${INITSCRIPTID} "${ACTION}" ${RL}` RC=$? formataction ${ACTION} case ${RC} in 0) RC=104 ;; 1) RC=105 ;; 101) if test x${FORCE} != x ; then printerror policy-rc.d denied execution of ${printaction}. printerror Overriding because of --force. RC=104 fi ;; esac if test x${MODE} != xquery ; then case ${RC} in 105) printerror policy-rc.d query returned \"behaviour undefined\", printerror assuming \"${printaction}\" is allowed. RC=104 ;; 106) formataction ${FALLBACK} if test x${FORCE} = x ; then if test x${NOFALLBACK} = x ; then ACTION="${FALLBACK}" printerror executing ${naction} \"${printaction}\" instead due to policy-rc.d request. RC=104 else printerror ignoring policy-rc.d fallback request: ${printaction}. RC=101 fi else printerror ignoring policy-rc.d fallback request: ${printaction}. RC=104 fi ;; esac fi case ${RC} in 100|101|102|103|104|105|106) ;; *) printerror WARNING: policy-rc.d returned unexpected error status ${RC}, 102 used instead. RC=102 ;; esac else if test x${RC} = x ; then RC=104 fi fi return } verifyparameter () { # # Verifies if $1 is not null, and $# = 1 # if test $# -eq 0 ; then printerror syntax error: invalid empty parameter exit 103 elif test $# -ne 1 ; then printerror syntax error: embedded blanks are not allowed in \"$*\" exit 103 fi return } ## ## main ## ## Verifies command line arguments if test $# -eq 0 ; then printerror syntax error: missing required parameter, --help assumed dohelp exit 103 fi state=I while test $# -gt 0 -a ${state} != III ; do case "$1" in --help) dohelp exit 0 ;; --quiet) BEQUIET=--quiet ;; --force) FORCE=yes RETRY=yes ;; --try-anyway) RETRY=yes ;; --disclose-deny) RETURNFAILURE=yes ;; --query) MODE=query RETURNFAILURE=yes ;; --no-fallback) NOFALLBACK=yes ;; --*) printerror syntax error: unknown option \"$i\" exit 103 ;; *) case ${state} in I) verifyparameter $1 INITSCRIPTID=$1 ;; II) verifyparameter $1 ACTION=$1 ;; esac state=${state}I ;; esac shift done if test ${state} != III ; then printerror syntax error: missing required parameter exit 103 fi #NOTE: It may not be obvious, but "$@" from this point on must expand #to the extra initscript parameters, except inside functions. ## sanity checks and just-in-case warnings. case ${ACTION} in start|stop|force-stop|restart|restart-if-running|reload|force-reload|status) ;; *) printerror action ${ACTION} is unknown, but proceeding anyway. ;; esac ## Verifies if the given initscript ID is known ## For sysvinit, this error is critical if test ! -f "${INITDPREFIX}${INITSCRIPTID}" ; then printerror unknown initscript, ${INITDPREFIX}${INITSCRIPTID} not found. exit 100 fi ## Queries sysvinit for the current runlevel RL=`${RUNLEVEL} | sed 's/.*\ //'` if test ! $? ; then printerror "could not determine current runlevel" if test x${RETRY} = x ; then exit 102 fi RL= fi ## Handles shutdown sequences VERY safely ## i.e.: forget about policy, and do all we can to run the script. ## BTW, why the heck are we being run in a shutdown runlevel?! if test x${RL} = x0 -o x${RL} = x6 ; then FORCE=yes RETRY=yes POLICYHELPER= BEQUIET= printerror ---------------------------------------------------- printerror WARNING: invoke-rc.d called during shutdown sequence printerror enabling safe mode: initscript policy layer disabled printerror ---------------------------------------------------- fi ## Verifies the existance of proper S??initscriptID and K??initscriptID ## *links* in the proper /etc/rc?.d/ directory verifyrclink () { # # verifies if parameters are non-dangling symlinks # all parameters are verified # doexit= while test $# -gt 0 ; do if test ! -L "$1" ; then printerror not a symlink: $1 doexit=102 fi if test ! -f "$1" ; then printerror dangling symlink: $1 doexit=102 fi shift done if test x${doexit} != x -a x${RETRY} = x; then exit ${doexit} fi return 0 } # we do handle multiple links per runlevel # but we don't handle embedded blanks in link names :-( if test x${RL} != x ; then SLINK=`ls -d -Q ${RCDPREFIX}${RL}.d/S[0-9][0-9]${INITSCRIPTID} 2>/dev/null | xargs` KLINK=`ls -d -Q ${RCDPREFIX}${RL}.d/K[0-9][0-9]${INITSCRIPTID} 2>/dev/null | xargs` SSLINK=`ls -d -Q ${RCDPREFIX}S.d/S[0-9][0-9]${INITSCRIPTID} 2>/dev/null | xargs` verifyrclink ${SLINK} ${KLINK} ${SSLINK} fi testexec () { # # returns true if any of the parameters is # executable (after following links) # while test $# -gt 0 ; do if test -x "$1" ; then return 0 fi shift done return 1 } RC= ### ### LOCAL INITSCRIPT POLICY: Enforce need of a Sxx link ### in either rcS.d or current runlevel to allow start ### or restart. ### case ${ACTION} in start|restart) if testexec ${SLINK} ; then RC=104 elif testexec ${KLINK} ; then RC=101 elif testexec ${SSLINK} ; then RC=104 fi ;; esac ### ### LOCAL INITSCRIPT POLICY: Restart is downgraded to ### restart-if-running if restart is not allowed. ### if test ${ACTION} = restart -a x${RC} = x101 -a x${FORCE} = x ; then # be more verbose than the strictly needed to explain # to the user what the hell is happening. printerror \"restart\" of ${INITSCRIPTID} attempted out of runlevel. if test x${NOFALLBACK} != x ; then printerror fallback request to \"restart-if-running\" ignored. RC=101 else printerror using fallback \"restart-if-running\" instead of \"restart\". ACTION="restart-if-running" if test x${MODE} = xquery ; then RC=106 else RC=104 fi fi fi # test if /etc/init.d/initscript is actually executable if testexec "${INITDPREFIX}${INITSCRIPTID}" ; then if test x${RC} = x -a x${MODE} = xquery ; then RC=105 fi # call policy layer if test x${RC} = x104 -o x${RC} = x106 -o x${RC} = x; then querypolicy case ${RC} in 101|104) ;; *) if test x${MODE} != xquery ; then printerror policy-rc.d returned error status ${RC} if test x${RETRY} = x ; then exit ${RC} else RC=102 fi fi ;; esac fi else ### ### LOCAL INITSCRIPT POLICY: non-executable initscript; deny exec. ### (this is common sense, actually :^P ) ### RC=101 fi ## Handles --query if test x${MODE} = xquery ; then exit ${RC} fi setechoactions () { if test $# -gt 1 ; then echoaction=true else echoaction= fi } getnextaction () { saction=$1 shift ACTION="$@" } ## Executes initscript ## note that $ACTION is a space-separated list of actions ## to be attempted in order until one suceeds. if test x${FORCE} != x -o ${RC} -eq 104 ; then if testexec "${INITDPREFIX}${INITSCRIPTID}" ; then RC=102 setechoactions ${ACTION} while test ! -z "${ACTION}" ; do getnextaction ${ACTION} if test ! -z ${echoaction} ; then printerror executing initscript action \"${saction}\"... fi "${INITDPREFIX}${INITSCRIPTID}" "${saction}" "$@" && exit 0 RC=$? if test ! -z "${ACTION}" ; then printerror action \"${saction}\" failed, trying next action... fi done printerror initscript ${INITSCRIPTID}, action \"${saction}\" failed. exit ${RC} fi exit 102 fi formataction ${ACTION} printerror initscript ${naction} \"${printaction}\" not executed. ## Handles --disclose-deny if test ${RC} -eq 101 -a x${RETURNFAILURE} = x ; then RC=0 fi exit ${RC}