[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Linux startup, Wheezy -- a required script won't run on startup, but can run manually without any trouble



On 06/09/2016 07:46 PM, Andrew McGlashan wrote:
> The order of the scripts alone allowed for everything to be very, very
> simple and no script relied upon any other; they were self dependent.
> If you wanted something to be available before your script, you made
> sure your numeric number after the S in the script name (or rather the
> symlink name back to the /etc/init.d directory file) was higher.  It was
> simple, it worked perfectly,

(In the following, for the most part I'm only going to talk about
sysvinit, ignoring any other init system.)

I think you are suffering from quite a bit of confusion. You need to
separate a few concepts apart:

 - the S**/K** symlinks
 - how they are generated
 - startup parallelization

Since very old versions of Debian (I don't remember which), you could
create symbolic links for init scripts like this:

 - /etc/rcX.d/SYYname -> /etc/init.d/name
 - /etc/rcX.d/KYYname -> /etc/init.d/name

   YY being a number between 00 and 99 here.

When changing a runlevel, first all the K** links (in order) of the
_new_ runlevel are run and then all the S** links (in order), also of
the _new_ runlevel are run. [1]

The symlinks would be generated by calling update-rc.d, e.g. via:

  update-rc.d NAME start 42 2 3 4 5 . stop 75 0 1 6 .

This would generate /etc/rc[2345].d/S42NAME, /etc/rc[016].d/K75NAME.

The main problem with this scheme alone is that the numbers are
actually really arbitrary, so it's not immediately clear which ones to
use when writing an init script.

This lead to multiple problems, most importantly that if you had two
otherwise unrelated services A and B, that don't have any dependency
with each other, so they have the same number, e.g. 20. But then a
service C comes a long that needs to be started before B but after A,
then A and B need to have different numbers regardless. But the numbers
of these services are fixed in the Debian package scripts, so the
maintainer of the package containing service C needed to convince the
maintainers of services A and B to change their number (and if they in
turn depend on other scripts, those have to be adapted, too). And this
doesn't even leave any room for modifications by the admin, who might
need this for local scripts that will never be part of Debian: even if
they could convince the maintainers of the packages they'd need to
squeeze their own script in between, they'd still have to wait for the
next Debian release or do some extensive local modifications.

Which is why people had been working on a replacement for a number of
years (the Debian wiki claims since 2002, but the link doesn't work).
In 2008 an alternative was implemented that was designed to work across
distributions, and the LSB standard for init scripts was born. [2]
(This was way before systemd btw.)

The integration into Debian took a bit longer, and Squeeze was the
first Debian version to fully incorporate that. (Although you could
still choose to use old system in Squeeze IIRC, support for which was
dropped in Wheezy.) Instead of having the numbers fixed, they would be
calculated when services were enabled.

Now, each service has to declare in form of the so-called LSB header
its dependencies relative to other services. Then, when services are
enabled/disabled, these dependencies taken into account and the numbers
are generated accordingly. (Which is why they rarely exceed 30 now,
unless you have really many services.)

This now has the huge advantage that if you squeeze in a service
between others, the numbers will automatically get recalculated.

The following LSB headers are understood in Debian:

 * Provides:
     Alternative names for the service for dependency resolution. For
     example, /etc/init.d/networking has the values 'networking' and
     'ifupdown' in there; so anything that orders against either of
     them will order against networking.

 * Required-Start:
     Anything that must be started before this script. insserv and
     update-rc.d will fail if the required script doesn't exist or is
     not enabled. (It will not enable that script automatically though,
     it will just complain.)

 * Required-Stop:
     Same as Required-Start, but just that these services have to be
     kept around during shutdown. Commonly the same as Required-Start,
     but not necessarily.

 * Should-Start/Should-Stop:
     Same as the Required- version, but if the other script is not
     enabled or not installed, don't consider that to be an error.

 * X-Start-After:/X-Stop-Before:
     The inverse dependency, meaning that
        A: X-Start-After: B
     is equivalent to
        B: Should-Start: A

  * Default-Start:
     List of runlevels where the service should be started in
     by default. Typically 2 3 4 5

  * Default-Stop:
     Typically 0 1 6

To enable a service initially, you'd call

  update-rc.d defaults NAME

And to remove the links:

  update-rc.d remove NAME

Important: only the options defaults, remove, enable and disable for
update-rc.d will add/remove/change type of S/K symlinks for the service
specified. They will never touch the symlinks for other services, and
other options will never add/remove/change type. However, calling
insserv without parameters (which is what update-rc.d does internally)
will cause the existing symlinks to be reordered - so adding a link
S42foo somewhere might be renamed to S12foo later, depending on what 
dependency-based resolution says the number should be.

So when you claim the old system where you just put some numbers in
there worked 'perfectly', I will disagree vehemently. The dependency-
based boot system of Squeeze was a *really* good idea. I remember
Gentoo from the mid-2000s once, and back then (before OpenRC) they were
using sysvinit + a bunch of bash scripts that were nothing like the
standard init scripts used on other distros - instead they'd declare
dependencies logically via bash functions. I clearly remember liking
that idea MUCH more than the numbered links I knew from other distros,
especially when you wanted to write your own script.

So to my view, the LSB init script standard is a clear advantage as
compared to what was going on before - because you can finally
logically declare the relations between services at startup. It's a bit
clumsy (comments that are parsed in init scripts), so it's not perfect,
but a vast improvement IMHO.

Ok, so now that we have dependency-base init script ordering, there's
an additional feature added to Debian, namely parallel startup of init
scripts. (With sysvinit.) This is done via the startpar binary that was
once part of the sysvinit-utils pacakge, but is since Jessie a separate
package on its own (named startpar).

The idea behind it is the following: if all scripts explicitly declare
their dependencies, any script with the same number as another will be
in no relation to that, so it's possible to start both in parallel. For
example, on a wheezy box I have here, the ntp, rsync and ssh have the
same number in /etc/rc3.d, so they can be started at the same time in
parallel - and once all 3 are complete, the next service can be
started.

You can indeed disable this via setting CONCURRENCY=none in the
/etc/default/rcS configuration file. Then the startup wil again be
completely serialized. (In Jessie and onwards, you can choose to remove
the startpar package instead, that will also do the trick.)

> Now I have sysvinit isntalled on wheezy, it is failing to run a simple
> script during system boot (as part of a planed reboot) and I cannot work
> out why.
> 
> # ls -l /etc/{init.d,rc*.d}/*archive*
> -rwxr-xr-x 1 root root 1453 Jun  8 04:12 /etc/init.d/archive-system-mail
> lrwxrwxrwx 1 root root   29 Jun  3 23:30
> /etc/rc2.d/S02archive-system-mail -> ../init.d/archive-system-mail
> lrwxrwxrwx 1 root root   29 Jun  4 03:06
> /etc/rc3.d/S02archive-system-mail -> ../init.d/archive-system-mail
> lrwxrwxrwx 1 root root   29 Jun  4 03:07
> /etc/rc4.d/S02archive-system-mail -> ../init.d/archive-system-mail
> lrwxrwxrwx 1 root root   29 Jun  4 03:08
> /etc/rc5.d/S02archive-system-mail -> ../init.d/archive-system-mail

The low number for a non-rcS service is a very disconcerting, because 
it could mean that your script isn't properly ordered against other
scripts that are started during boot, especially those that mount stuff
and such. This is likely caused due to a lack of dependencies. 02 is
typically at the point where udev is started, when the root filesystem
might still even be mounted read-only. (If you've configured it that
way.)

I believe that's your actual problem: I think either your script is
run, but far too early, or it's not run, because it has a really low
number in a non-rcS runlevel, and startpar doesn't cope with that
well. (Because rcS -> rc2 transition is not a runlevel transition in
Debian, so it's kind of special.)

And if I look at the script, there lies your very problem:

> Now, I want the archiving script to run on system startup, I don't want
> dovecot or exim4 to be running when the script starts, it simply needs
> to have the /backup and /var file systems mounted to do it's required job.

Ok, so if you depend on local or remote file systems, you need to
depend on $local_fs and $remote_fs, respectively. If all your file
systems are local, use $local_fs - otherwise $remote_fs (or both).

(Technically, $syslog might suffice, because all standard syslog
implementations provide $syslog via /etc/insserv.conf, and they
themselves depend on $local_fs at least, but IMHO it's better to
explicitly write out $remote_fs and $local_fs.)

> My script is meant to create a log file in the /var/log directory.  If I
> run the script manually, it works perfectly.  There are some generic
> parts in the script, it is a fairly simple script, even if a little bit
> over complicated.  What do I need to do to fix it?
> 
> Here is the script:
> 
> # cat /etc/init.d/archive-system-mail
> #! /bin/sh
> ### BEGIN INIT INFO
> # Provides:          mailarchive
> # Required-Start:    $syslog
> # Required-Stop:     $syslog

Required-Start: $local_fs $remote_fs $syslog
Required-Stop: $local_fs $remote_fs $syslog

Plus, maybe, if it is supposed to run _before_ exim4, you could also
add the following pseudo-headers:

X-Start-Before: exim4
X-Stop-After: exim4

After the modification, run insserv (without parameters) to have it
reorder the script with respect to numbering (it should get a higher
number now), verify that the numbers of your init scripts are now
reordered accordingly and everything should work. (Assuming the
script is executable.) 

> case "$1" in
>   start)
>         do_main
>         ;;
>   *)
>         echo "Usage: $SCRIPTNAME {start}" >&2
>         exit 3
>         ;;
> esac

This is also not good, because Debian requires you to implement the
start, stop, status, restart and force-reload arguments. Maybe that's
also something that trips up the logic in your case. If you really
don't want them, please at least add something like

stop|status|restart|force-reload) exit 0 ;;

Regards,
Christian

[1] I remember really old versions of SuSE, from before 2000, that used
    a slightly different scheme, which would first run all K** scripts
    of the old runlevel (so a script would have S** and K** symlinks in
    the same runlevel) and then the S** scripts of the new runlevel,
    exluding things that match (so it doesn't stop things that are in
    both). But IIRC that was never in Debian, and I don't know what
    SuSE did with that afterwards.

[2] https://lists.debian.org/debian-devel-announce/2008/01/msg00004.html

Attachment: signature.asc
Description: OpenPGP digital signature


Reply to: