[Michael Biebl]
> The problem here is, how a mixed system would work.

Mixed in what way?  There are only two options here:

 * /sbin/init is sysvinit, and the upstart jobs appear as init.d
   scripts, and are called by sysvinit.

 * /sbin/init is upstart, and the upstart jobs are called first, and
   the init.d scripts later.

There is no way I can see that we can support /sbin/init as upstart
with the current implementation, and allow dependencies to mix between
upstart jobs and init.d scripts.

Note that with the announcement of systemd, I am unsure if upstart is
the best event based boot system to switch to for Debian.  I have not
had time to test systemd, but its support for init.d scripts seemed to
be better than the one in upstart, leading to less work when

> Say, we already have converted dbus or rsyslog to native upstart jobs,
> and a legacy sysv init script which declares a dependency
> (Should-Start/Required-Start) in its LSB header.

Such situation can not be allowed to be introduced in Debian.  Random
init.d scripts can not be converted to upstart jobs with a sensible
result.  When upstart is provided as /sbin/init, the debian
maintainers can start migrating init.d scripts to upstart jobs, but
the ones started first in the boot need to be migrated first.  So
rsyslog and dbus can not be migrated before all the init.d scripts
they depend on are migrated first.  For rsyslog it might be all
scripts started from rcS.d/ (and perhaps a few started later), while
for dbus it would be only the first halft of rcS.d/.

> The idea afaicr was, that insserv would utilize upstart-job to get
> the LSB header information via the "lsb-header" argument.  So, for
> an init script /etc/init.d/<service> which points to
> /lib/init/upstart-job, insserv would run "/etc/init.d/<service>
> lsb-header", which would output the LSB header information on
> stdout.

Note that insserv calls /lib/init/upstart-job <service> lsb-header,
not "/etc/init.d/<service> lsb-header".

> Open questions:
> 1/ Would we still need compat symlinks for rsyslog/dbus in /etc/rc?.d/
> for insserv to work?
> If we don't install those compat symlinks and someone decides to
> deinstall upstart and install sysvinit, should the sysvinit
> maintainer-scripts reinstall those symlinks?

update-rc.d will insert these symlinks automatically when the package
is installed, and this should stay like this.

> 2/ How do we ensure the correct ordering? Take the dbus/rsyslog
> example again. When can we start the legacy sysv rc2 stage and be
> sure that the upstart jobs are up?

With the current way upstart handle init.d scripts, we need to migrate
init.d scripts to upstart jobs one by one, starting at the first
script executed during boot, and working our way forward in the
boot. :)

> 3/ How do we get the LSB header information from an upstart job?
> a) Add the LSB header to the upstart *.conf file (they are comments
> after all) and let "lsb-header" simply output that. If no LSB header is
> defined, output a standard LSB header like:
> Provides: <upstart job name>
> Requires: $syslog, $remote_fs
> Default-Start: 2 3 4 5
> Default-Stop: 0 6
> b) Try to infer the LSB header information from what is encoded in
> upstart's native start on, stop on (runlevel) information. What about
> upstart jobs, that react on special events where there is no sysvinit
> equivalent, like hardware/network events?

I would prefer to generate it based on the 'start on' lines, but
adding it as a comment in the upstart job would work too.  It would
also solve the problem that there is nothing in an upstart job that
would give us the values for default-start and default-stop.

> How do we implement the "status" and "stop" action for services, i.e.
> how do we get the pid?

By creating a pid file (either using start-stop-daemon or asking the
service to generate it on its own).

> Also, there are certain types of upstart jobs, which can't be
> handled by upstart-job. It's basically the "rcS" stage in a fully
> upstartified boot process where we can't rely on upstart-job but we
> probably need to keep that kind of functionality as legacy sysvinit
> scripts. For that we will have to split that functionality from the
> "initscripts" package into a separate one.

I am not quite sure what you have in mind here, so please provide more
details.  I guess we will need to have a way to allow some upstart
jobs to not do anything when not being called from upstart, and also
have some init.d scripts that behave like no-opts when called from
upstart, for the rare cases.  But I hope those can be avoided, to
avoid the chance of code rot with mostly unused code.

> 1/ When we install upstart, check against a list of md5sums if
> /etc/inittab is pristine or not. If unmodified, simply remove the file.
> We'd need such a list of md5sums for the last Debian releases (and
> architectures). Petter, can you get such a list for me?

Not quite sure.  The svn repository for pkg-sysvinit might be a source
for this, <URL: svn://svn.debian.org/pkg-sysvinit/sysvinit/trunk >.

> I have an alternate suggestion: Generate the upstart job files from
> /etc/inittab, store them in /etc/init/ *and* keep a state file, where we
> store the md5sums of /etc/inittab and the generated upstart job files.
> During boot, if /etc/inittab has not been modified, we can simply skip
> the conversion process -> faster
> If /etc/inittab has been modified, we check the md5sums of the generated
> upstart job files and only update them, if they haven't been changed ->
> we preserve admin changes to the upstart job files
> If /etc/inittab has been modified and the upstart job files are
> pristine, we update them.
> I would not only run this conversion process during boot, but also when
> the admin runs telinit q.
> Does this sound like an acceptable plan or is there a preference of
> using the original idea of a separate tmpfs in /lib/init/rw?

I am not convinced this is a good idea.  I would rather there is a
speed penalty for having /etc/inittab around while using upstart, to
ensure that sysadmins take the time to convert it, and also do not
want the inittab configuration several places on the disk (to avoid
conflict handling).  Say that both the inittab file and the tty
entries in /etc/init/ are edited with your proposal.  Which version
should be used?  I believe it is better to have the information in
either /etc/inittab or in /etc/init/, and have a speed penalty on the
first option to encourage people to switch.

> So, what currently exists is a upstart-job implementation for upstart
> which supports, start/stop/restart/status/reload.

Where is it?

> Missing is:
> 1/ "lsb-header" support in upstart-job
> 2/ upstart-job implementation for sysvinit (e.g. needed currently for
> kfreebsd)
> 3/ the /etc/inittab conversion bits.
> 4/ layout of the initscripts package which makes it suitable for both
> upstart and legacy sysvinit.
> I started working on 3/ some time ago, but got side tracked. It's
> something though, which I think I could finish in time for squeeze.
> For 1/, we basically need to agree, how we get the LSB header
> information (implicit/explicit). If we opt for adding LSB header
> information to the upstart job files, the implementation would be trivial.
> For 2/ I would definitely appreciate help and it is imo the main blocker.
> 4/ needs help from Petter but only really makes sense if 1-3 are in place.

I started on a draft version of 2).  It is only working for the sssd
upstart job at the moment, but might give you some idea of where I
believe we should be heading.

Here it is.


use warnings;
use strict;
use File::Basename;

use vars qw($rc);

print STDERR "cmd: $0 ", join(" ", @ARGV), "\n";

my $upstartjob;
if ("/lib/init/upstart-job" ne "$0") {
    my $basename = basename($0);
    $upstartjob = "/etc/init/$basename";
} else {
    $upstartjob = "/etc/init/$ARGV[0]";

#$upstartjob = 

my $inforef = parse_upstart_job($upstartjob);
$rc = 0;

for my $k (sort keys %{$inforef}) { print STDERR "$k: $inforef->{$k}\n";}

my %operation =
     'lsb-header' => \&print_lsb_header,
     'start'      => \&service_start,
     'stop'       => \&service_stop,
     'status'     => \&service_status,

if (exists $operation{$ARGV[0]}) {
    $operation{$ARGV[0]}($inforef, $ARGV[0]);
} else {
    unsupported($inforef, $ARGV[0]);

exit $rc;

sub parse_upstart_job {
    my $jobpath = shift;
    my %info;
    if (open(my $fh, "<", $jobpath)) {
        while (<$fh>) {
            next if (/^\s*$/);
            $info{description} = $1 if /^description\s+"(.+)"$/;
            $info{respawn} = 1 if /^respawn$/;
            $info{start} = $1 if /^start\s+(.+)$/;
            $info{stop} = $1 if /^stop\s+(.+)$/;
            $info{exec} = $1 if /^exec\s+(.+)$/;
        $info{basename} = basename($jobpath);
        $info{pidfile} = "/var/run/" . $info{basename} . ".pid";
    } else {
        print STDERR "Problems reading $jobpath\n";
    return \%info;

sub print_lsb_header {
    my $inforef = shift;
    my %lsbheader;

    # Fake dependencies
    if ($inforef->{'start'} eq "on filesystem") {
        $lsbheader{'required-start'} = '$remote_fs';
        $lsbheader{'required-stop'}  = '$remote_fs';
    unless (exists $lsbheader{'basename'}) {
        $lsbheader{'provides'}  = $inforef->{basename};

    # Need way to generate this from upstart job
    $lsbheader{'default-start'} = "2 3 4 5";
    $lsbheader{'default-stop'} = "0 1 6";

    print "### BEGIN INIT INFO\n";
    for my $h (qw(provides required-start required-stop
                  should-start should-stop default-start default-stop
                  x-start-before x-stop-after x-interactive)) {
        printf "# %-20s %s\n", "$h:", $lsbheader{$h} if exists $lsbheader{$h};
    print "### END INIT INFO\n";

sub service_start {
    my $inforef = shift;
    print STDERR "Starting service: ", $inforef->{exec}, "\n";
    my ($cmd, $opts) = split(/\s+/, $inforef->{exec}, 2);
    my $pidfile = $inforef->{pidfile};
    print STDERR "start-stop-daemon --start --quiet --pidfile $pidfile --exec 
$cmd -- $opts\n";

sub service_stop {
    my $inforef = shift;
    print STDERR "Stopping service: ", $inforef->{exec}, "\n";
    my ($cmd, $opts) = split(/\s+/, $inforef->{exec}, 2);
    my $pidfile = $inforef->{pidfile};
    print STDERR "start-stop-daemon --oknodo --stop --quiet --pidfile $pidfile 
--exec $cmd\n";

sub service_status {
    my $inforef = shift;
    print STDERR "Service status: ", $inforef->{exec}, "\n";

sub unsupported {
    my ($inforef, $arg) = @_;
    print STDERR "Unsupported action '$arg'.\n";

Happy hacking,
Petter Reinholdtsen

initscripts-ng-devel mailing list

Reply via email to