~ubuntu-branches/debian/experimental/sysvinit/experimental

« back to all changes in this revision

Viewing changes to debian/sysv-rc/sbin/update-rc.d

  • Committer: Bazaar Package Importer
  • Author(s): Petter Reinholdtsen
  • Date: 2009-09-13 00:13:49 UTC
  • Revision ID: james.westby@ubuntu.com-20090913001349-c4hnvhp0titxdpw9
Tags: 2.87dsf-5
* Uploading to experimental, to test the new build rules.

* Make sysv-rc postinst report detected problems to stderr too when
  failing to migrate.
* Fix typo in error message from postinst (Closes: #545409).
* Make initscripts depend on sysvinit-utils (>= 2.86.ds1-64), to
  make sure the fstab-decode program is available (Closes: #545356).
* Make sure the calls to 'update-rc.d X remove' in initscripts
  postinst do not ignore errors (Closes: #406361).
* Make sysvinit depend on sysvinit-utils (>= 2.86.ds1-66) to avoid
  that bootlogd disappear during partial upgrades (Closes: #545368).
* Restructure source package to make it possible to use debhelper in
  the common way to build the source, by moving debian/initscripts/
  and debian/sysv-rc/ into debian/src/.  Restructure build rules to
  use debhelper more, and migrate to debhelper 7.
* New patch 98_installtarget.patch to improve the sysvinit install
  target.
* Remove /etc/init.d/.depend.* in prerm, not postrm, to avoid
  surprises.
* Remove /var/lib/update-rc.d/* when the package is purged.
* Change cut-off point for the trimmed changelog entries in
  sysvinit-utils, initscripts and sysv-rc from version 2.84-3 to
  version 2.86.ds1-47, to reduce the package sizes.
* Drop hurd specific dependency on libc0.3 (>= 2.3.2.ds1-12).  It is
  no longer needed according to Michael Bunk.  Patch from Michael
  Biebl.
* Remove information about scripts in /var/lib/update-rc.d/ when
  their runlevel symlinks are removed (Closes: #545949).  Remove
  such files left behind earlier during upgrade.
* Bootlogd now starts as late as possible (Closes: #265801)
* Drop the binary /lib/init/readlink from initscripts and depend on
  coreutils (>= 5.93) instead.  Adjust scripts to use the program
  from coreutils from now on (Closes: #239342).
* Make sure insserv exit values propagate through update-rc.d to make
  sure packages with errors fail to install.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#! /usr/bin/perl
2
 
#
3
 
# update-rc.d   Update the links in /etc/rc[0-9S].d/
4
 
#
5
 
 
6
 
use strict;
7
 
use warnings;
8
 
 
9
 
my $initd = "/etc/init.d";
10
 
my $etcd  = "/etc/rc";
11
 
my $notreally = 0;
12
 
 
13
 
# Print usage message and die.
14
 
 
15
 
sub usage {
16
 
        print STDERR "update-rc.d: error: @_\n" if ($#_ >= 0);
17
 
        print STDERR <<EOF;
18
 
usage: update-rc.d [-n] [-f] <basename> remove
19
 
       update-rc.d [-n] <basename> defaults [NN | SS KK]
20
 
       update-rc.d [-n] <basename> start|stop NN runlvl [runlvl] [...] .
21
 
       update-rc.d [-n] <basename> disable|enable [S|2|3|4|5]
22
 
                -n: not really
23
 
                -f: force
24
 
 
25
 
The disable|enable API is not stable and might change in the future.
26
 
EOF
27
 
        exit (1);
28
 
}
29
 
 
30
 
# Dependency based boot sequencing is the default, but upgraded
31
 
# systems might keep the legacy ordering until the sysadm choose to
32
 
# migrate to the new ordering method.
33
 
if ( ! -f "/etc/init.d/.legacy-bootordering" ) {
34
 
    info("using dependency based boot sequencing");
35
 
    exit insserv_updatercd(@ARGV);
36
 
}
37
 
 
38
 
# Check out options.
39
 
my $force;
40
 
 
41
 
my @orig_argv = @ARGV;
42
 
 
43
 
while($#ARGV >= 0 && ($_ = $ARGV[0]) =~ /^-/) {
44
 
        shift @ARGV;
45
 
        if (/^-n$/) { $notreally++; next }
46
 
        if (/^-f$/) { $force++; next }
47
 
        if (/^-h|--help$/) { &usage; }
48
 
        &usage("unknown option");
49
 
}
50
 
 
51
 
sub save_last_action {
52
 
    my ($script, @arguments) = @_;
53
 
    my $archive = "/var/lib/update-rc.d";
54
 
 
55
 
    return if $notreally;
56
 
 
57
 
    open(FILE, ">", "$archive/${script}.new") || die;
58
 
    print FILE join(" ","update-rc.d",@arguments), "\n";
59
 
    close(FILE);
60
 
    rename "$archive/${script}.new", "$archive/${script}";
61
 
}
62
 
 
63
 
# Action.
64
 
 
65
 
&usage() if ($#ARGV < 1);
66
 
my $bn = shift @ARGV;
67
 
 
68
 
unless ($bn =~ m/[a-zA-Z0-9+.-]+/) {
69
 
    print STDERR "update-rc.d: illegal character in name '$bn'\n";
70
 
    exit (1);
71
 
}
72
 
 
73
 
if ($ARGV[0] ne 'remove') {
74
 
    if (! -f "$initd/$bn") {
75
 
        print STDERR "update-rc.d: $initd/$bn: file does not exist\n";
76
 
        exit (1);
77
 
    }
78
 
    &parse_lsb_header("$initd/$bn");
79
 
    &cmp_args_with_defaults($bn, $ARGV[0], @ARGV);
80
 
} elsif (-f "$initd/$bn") {
81
 
    if (!$force) {
82
 
        printf STDERR "update-rc.d: $initd/$bn exists during rc.d purge (use -f to force)\n";
83
 
        exit (1);
84
 
    }
85
 
}
86
 
 
87
 
my @startlinks;
88
 
my @stoplinks;
89
 
 
90
 
$_ = $ARGV[0];
91
 
if    (/^remove$/)       { &checklinks ("remove"); save_last_action($bn, @orig_argv); }
92
 
elsif (/^defaults$/)     { &defaults (@ARGV); &makelinks; save_last_action($bn, @orig_argv); }
93
 
elsif (/^(start|stop)$/) { &startstop (@ARGV); &makelinks; save_last_action($bn, @orig_argv); }
94
 
elsif (/^(dis|en)able$/) { &toggle (@ARGV); &makelinks; save_last_action($bn, @orig_argv); }
95
 
else                     { &usage; }
96
 
 
97
 
exit (0);
98
 
 
99
 
sub info {
100
 
    print STDOUT "update-rc.d: @_\n";
101
 
}
102
 
 
103
 
sub warning {
104
 
    print STDERR "update-rc.d: warning: @_\n";
105
 
}
106
 
 
107
 
sub error {
108
 
    print STDERR "update-rc.d: error: @_\n";
109
 
    exit (1);
110
 
}
111
 
 
112
 
# Check if there are links in /etc/rc[0-9S].d/ 
113
 
# Remove if the first argument is "remove" and the links 
114
 
# point to $bn.
115
 
 
116
 
sub is_link () {
117
 
    my ($op, $fn, $bn) = @_;
118
 
    if (! -l $fn) {
119
 
        warning "$fn is not a symbolic link\n";
120
 
        return 0;
121
 
    } else {
122
 
        my $linkdst = readlink ($fn);
123
 
        if (! defined $linkdst) {
124
 
            die ("update-rc.d: error reading symbolic link: $!\n");
125
 
        }
126
 
        if (($linkdst ne "../init.d/$bn") && ($linkdst ne "$initd/$bn")) {
127
 
            warning "$fn is not a link to ../init.d/$bn or $initd/$bn\n";
128
 
            return 0;
129
 
        }
130
 
    }
131
 
    return 1;
132
 
}
133
 
 
134
 
sub checklinks {
135
 
    my ($i, $found, $fn, $islnk);
136
 
 
137
 
    print " Removing any system startup links for $initd/$bn ...\n"
138
 
        if (defined $_[0] && $_[0] eq 'remove');
139
 
 
140
 
    $found = 0;
141
 
 
142
 
    foreach $i (0..9, 'S') {
143
 
        unless (chdir ("$etcd$i.d")) {
144
 
            next if ($i =~ m/^[789S]$/);
145
 
            die("update-rc.d: chdir $etcd$i.d: $!\n");
146
 
        }
147
 
        opendir(DIR, ".");
148
 
        my $saveBN=$bn;
149
 
        $saveBN =~ s/\+/\\+/g;
150
 
        foreach $_ (readdir(DIR)) {
151
 
            next unless (/^[SK]\d\d$saveBN$/);
152
 
            $fn = "$etcd$i.d/$_";
153
 
            $found = 1;
154
 
            $islnk = &is_link ($_[0], $fn, $bn);
155
 
            next unless (defined $_[0] and $_[0] eq 'remove');
156
 
            if (! $islnk) {
157
 
                print "   $fn is not a link to ../init.d/$bn; not removing\n"; 
158
 
                next;
159
 
            }
160
 
            print "   $etcd$i.d/$_\n";
161
 
            next if ($notreally);
162
 
            unlink ("$etcd$i.d/$_") ||
163
 
                die("update-rc.d: unlink: $!\n");
164
 
        }
165
 
        closedir(DIR);
166
 
    }
167
 
    $found;
168
 
}
169
 
 
170
 
sub parse_lsb_header {
171
 
    my $initdscript = shift;
172
 
    my %lsbinfo;
173
 
    my $lsbheaders = "Provides|Required-Start|Required-Stop|Default-Start|Default-Stop";
174
 
    open(INIT, "<$initdscript") || die "error: unable to read $initdscript";
175
 
    while (<INIT>) {
176
 
        chomp;
177
 
        $lsbinfo{'found'} = 1 if (m/^\#\#\# BEGIN INIT INFO\s*$/);
178
 
        last if (m/\#\#\# END INIT INFO\s*$/);
179
 
        if (m/^\# ($lsbheaders):\s*(\S?.*)$/i) {
180
 
        $lsbinfo{lc($1)} = $2;
181
 
        }
182
 
    }
183
 
    close(INIT);
184
 
 
185
 
    # Check that all the required headers are present
186
 
    if (!$lsbinfo{found}) {
187
 
        printf STDERR "update-rc.d: warning: $initdscript missing LSB information\n";
188
 
        printf STDERR "update-rc.d: see <http://wiki.debian.org/LSBInitScripts>\n";
189
 
    } else {
190
 
        for my $key (split(/\|/, lc($lsbheaders))) {
191
 
            if (!exists $lsbinfo{$key}) {
192
 
                warning "$initdscript missing LSB keyword '$key'\n";
193
 
            }
194
 
        }
195
 
    }
196
 
}
197
 
 
198
 
 
199
 
# Process the arguments after the "enable" or "disable" keyword.
200
 
 
201
 
sub toggle {
202
 
    my @argv = @_;
203
 
    my ($action, %lvls, @start, @stop, @xstartlinks);
204
 
 
205
 
    if (!&checklinks) {
206
 
        print " System start/stop links for $initd/$bn do not exist.\n";
207
 
        exit (0);
208
 
    }
209
 
 
210
 
    $action = $argv[0];
211
 
    if ($#argv > 1) {
212
 
        while ($#argv > 0 && shift @argv) {
213
 
            if ($argv[0] =~ /^[S2-5]$/) {
214
 
                $lvls{$argv[0]}++;
215
 
            } else {
216
 
                &usage ("expected 'S' '2' '3' '4' or '5'");
217
 
            }
218
 
        }
219
 
    } else {
220
 
        $lvls{$_}++ for ('S', '2', '3', '4', '5');
221
 
    }
222
 
 
223
 
    push(@start, glob($etcd . '[2-5S].d/[KS][0-9][0-9]' . $bn));
224
 
 
225
 
    foreach (@start) {
226
 
        my $islink = &is_link (undef, $_, $bn);
227
 
        next if !$islink;
228
 
 
229
 
        next unless my ($lvl, $sk, $seq) = m/^$etcd([2-5S])\.d\/([SK])([0-9]{2})$bn$/;
230
 
        $startlinks[$lvl] = $sk . $seq;
231
 
 
232
 
        if ($action eq 'disable' and $sk eq 'S' and $lvls{$lvl}) {
233
 
            $xstartlinks[$lvl] = 'K' . sprintf "%02d", (100 - $seq);
234
 
        } elsif ($action eq 'enable' and $sk eq 'K' and $lvls{$lvl}) {
235
 
            $xstartlinks[$lvl] = 'S' . sprintf "%02d", -($seq - 100);
236
 
        } else {
237
 
            $xstartlinks[$lvl] = $sk . $seq;
238
 
        }
239
 
    }
240
 
 
241
 
    push(@stop, glob($etcd . '[016].d/[KS][0-9][0-9]' . $bn));
242
 
 
243
 
    foreach (@stop) {
244
 
        my $islink = &is_link (undef, $_, $bn);
245
 
        next if !$islink;
246
 
 
247
 
        next unless my ($lvl, $sk, $seq) = m/^$etcd([016])\.d\/([SK])([0-9]{2})$bn$/;
248
 
        $stoplinks[$lvl] = $sk . $seq;
249
 
    }
250
 
 
251
 
    if ($action eq 'disable') {
252
 
        print " Disabling system startup links for $initd/$bn ...\n";
253
 
    } elsif ($action eq 'enable') {
254
 
        print " Enabling system startup links for $initd/$bn ...\n";
255
 
    }
256
 
 
257
 
    &checklinks ("remove");
258
 
    @startlinks = @xstartlinks;
259
 
 
260
 
    1;
261
 
}
262
 
 
263
 
# Process the arguments after the "defaults" keyword.
264
 
 
265
 
sub defaults {
266
 
    my @argv = @_;
267
 
    my ($start, $stop) = (20, 20);
268
 
 
269
 
    &usage ("defaults takes only one or two codenumbers") if ($#argv > 2);
270
 
    $start = $stop = $argv[1] if ($#argv >= 1);
271
 
    $stop  =         $argv[2] if ($#argv >= 2);
272
 
    &usage ("codenumber must be a number between 0 and 99")
273
 
        if ($start !~ /^\d\d?$/ || $stop  !~ /^\d\d?$/);
274
 
 
275
 
    $start = sprintf("%02d", $start);
276
 
    $stop  = sprintf("%02d", $stop);
277
 
 
278
 
    $stoplinks[$_]  = "K$stop"  for (0, 1, 6);
279
 
    $startlinks[$_] = "S$start" for (2, 3, 4, 5);
280
 
 
281
 
    1;
282
 
}
283
 
 
284
 
# Process the arguments after the start or stop keyword.
285
 
 
286
 
sub startstop {
287
 
    my @argv = @_;
288
 
    my($letter, $NN, $level);
289
 
 
290
 
    while ($#argv >= 0) {
291
 
        if    ($argv[0] eq 'start') { $letter = 'S'; }
292
 
        elsif ($argv[0] eq 'stop')  { $letter = 'K'; }
293
 
        else {
294
 
            &usage("expected start|stop");
295
 
        }
296
 
 
297
 
        if ($argv[1] !~ /^\d\d?$/) {
298
 
            &usage("expected NN after $argv[0]");
299
 
        }
300
 
        $NN = sprintf("%02d", $argv[1]);
301
 
 
302
 
        if ($argv[-1] ne '.') {
303
 
            &usage("start|stop arguments not terminated by \".\"");
304
 
        }
305
 
 
306
 
        shift @argv; shift @argv;
307
 
        $level = shift @argv;
308
 
        do {
309
 
            if ($level !~ m/^[0-9S]$/) {
310
 
                &usage(
311
 
                       "expected runlevel [0-9S] (did you forget \".\" ?)");
312
 
            }
313
 
            if (! -d "$etcd$level.d") {
314
 
                print STDERR
315
 
                    "update-rc.d: $etcd$level.d: no such directory\n";
316
 
                exit(1);
317
 
            }
318
 
            $level = 99 if ($level eq 'S');
319
 
            $startlinks[$level] = "$letter$NN" if ($letter eq 'S');
320
 
            $stoplinks[$level]  = "$letter$NN" if ($letter eq 'K');
321
 
        } while (($level = shift @argv) ne '.');
322
 
    }
323
 
    1;
324
 
}
325
 
 
326
 
# Create the links.
327
 
 
328
 
sub makelinks {
329
 
    my($t, $i);
330
 
    my @links;
331
 
 
332
 
    if (&checklinks) {
333
 
        print " System start/stop links for $initd/$bn already exist.\n";
334
 
        return 0;
335
 
    }
336
 
    print " Adding system startup for $initd/$bn ...\n";
337
 
 
338
 
    # nice unreadable perl mess :)
339
 
 
340
 
    for($t = 0; $t < 2; $t++) {
341
 
        @links = $t ? @startlinks : @stoplinks;
342
 
        for($i = 0; $i <= $#links; $i++) {
343
 
            my $lvl = $i;
344
 
            $lvl = 'S' if ($i == 99);
345
 
            next if (!defined $links[$i] or $links[$i] eq '');
346
 
            print "   $etcd$lvl.d/$links[$i]$bn -> ../init.d/$bn\n";
347
 
            next if ($notreally);
348
 
            symlink("../init.d/$bn", "$etcd$lvl.d/$links[$i]$bn")
349
 
                || die("update-rc.d: symlink: $!\n");
350
 
        }
351
 
    }
352
 
 
353
 
    1;
354
 
}
355
 
 
356
 
## Dependency based
357
 
sub insserv_updatercd {
358
 
    my @args = @_;
359
 
    my @opts;
360
 
    my $scriptname;
361
 
    my $action;
362
 
    my $notreally = 0;
363
 
 
364
 
    my @orig_argv = @args;
365
 
 
366
 
    while($#args >= 0 && ($_ = $args[0]) =~ /^-/) {
367
 
        shift @args;
368
 
        if (/^-n$/) { push(@opts, $_); $notreally++; next }
369
 
        if (/^-f$/) { push(@opts, $_); next }
370
 
        if (/^-h|--help$/) { &usage; }
371
 
        usage("unknown option");
372
 
    }
373
 
 
374
 
    usage("not enough arguments") if ($#args < 1);
375
 
 
376
 
    $scriptname = shift @args;
377
 
    $action = shift @args;
378
 
    if ("remove" eq $action) {
379
 
        if ( -f "/etc/init.d/$scriptname" ) {
380
 
            my $rc = system "insserv", @opts, "-r", $scriptname;
381
 
            if (0 == $rc && !$notreally) {
382
 
                save_last_action($scriptname, @orig_argv);
383
 
            }
384
 
            exit $rc;
385
 
        } else {
386
 
            # insserv removes all dangling symlinks, no need to tell it
387
 
            # what to look for.
388
 
            my $rc = system "insserv", @opts;
389
 
            if (0 == $rc && !$notreally) {
390
 
                save_last_action($scriptname, @orig_argv);
391
 
            }
392
 
            exit $rc;
393
 
        }
394
 
    } elsif ("defaults" eq $action || "start" eq $action ||
395
 
             "stop" eq $action) {
396
 
        # All start/stop/defaults arguments are discarded so emit a
397
 
        # message if arguments have been given and are in conflict
398
 
        # with Default-Start/Default-Stop values of LSB comment.
399
 
        cmp_args_with_defaults($scriptname, $action, @args);
400
 
 
401
 
        if ( -f "/etc/init.d/$scriptname" ) {
402
 
            my $rc = system "insserv", @opts, $scriptname;
403
 
            if (0 == $rc && !$notreally) {
404
 
                save_last_action($scriptname, @orig_argv);
405
 
            }
406
 
            exit $rc;
407
 
        } else {
408
 
            error("initscript does not exist: /etc/init.d/$scriptname");
409
 
        }
410
 
    } elsif ("disable" eq $action || "enable" eq $action) {
411
 
        insserv_toggle($notreally, $action, $scriptname, @args);
412
 
        # Call insserv to resequence modified links
413
 
        my $rc = system "insserv", @opts, $scriptname;
414
 
        if (0 == $rc && !$notreally) {
415
 
            save_last_action($scriptname, @orig_argv);
416
 
        }
417
 
        exit $rc;
418
 
    } else {
419
 
        usage();
420
 
    }
421
 
}
422
 
 
423
 
sub parse_def_start_stop {
424
 
    my $script = shift;
425
 
    my (%lsb, @def_start_lvls, @def_stop_lvls);
426
 
 
427
 
    open my $fh, '<', $script or error("unable to read $script");
428
 
    while (<$fh>) {
429
 
        chomp;
430
 
        if (m/^### BEGIN INIT INFO$/) {
431
 
            $lsb{'begin'}++;
432
 
        }
433
 
        elsif (m/^### END INIT INFO$/) {
434
 
            $lsb{'end'}++;
435
 
            last;
436
 
        }
437
 
        elsif ($lsb{'begin'} and not $lsb{'end'}) {
438
 
            if (m/^# Default-Start:\s*(\S?.*)$/) {
439
 
                @def_start_lvls = split(' ', $1);
440
 
            }
441
 
            if (m/^# Default-Stop:\s*(\S?.*)$/) {
442
 
                @def_stop_lvls = split(' ', $1);
443
 
            }
444
 
        }
445
 
    }
446
 
    close($fh);
447
 
 
448
 
    return (\@def_start_lvls, \@def_stop_lvls);
449
 
}
450
 
 
451
 
sub lsb_header_for_script {
452
 
    my $name = shift;
453
 
 
454
 
    foreach my $file ("/etc/insserv/overrides/$name", "/etc/init.d/$name",
455
 
                      "/usr/share/insserv/overrides/$name") {
456
 
        return $file if -s $file;
457
 
    }
458
 
 
459
 
    error("cannot find a LSB script for $name");
460
 
}
461
 
 
462
 
sub cmp_args_with_defaults {
463
 
    my ($name, $act) = (shift, shift);
464
 
    my ($lsb_start_ref, $lsb_stop_ref, $arg_str, $lsb_str);
465
 
    my (@arg_start_lvls, @arg_stop_lvls, @lsb_start_lvls, @lsb_stop_lvls);
466
 
 
467
 
    ($lsb_start_ref, $lsb_stop_ref) = parse_def_start_stop("/etc/init.d/$name");
468
 
    @lsb_start_lvls = @$lsb_start_ref;
469
 
    @lsb_stop_lvls  = @$lsb_stop_ref;
470
 
    return if (!@lsb_start_lvls and !@lsb_stop_lvls);
471
 
 
472
 
    if ($act eq 'defaults') {
473
 
        @arg_start_lvls = (2, 3, 4, 5);
474
 
        @arg_stop_lvls  = (0, 1, 6);
475
 
    } elsif ($act eq 'start' or $act eq 'stop') {
476
 
        my $start = $act eq 'start' ? 1 : 0;
477
 
        my $stop = $act eq 'stop' ? 1 : 0;
478
 
 
479
 
        # The legacy part of this program passes arguments starting with
480
 
        # "start|stop NN x y z ." but the insserv part gives argument list
481
 
        # starting with sequence number (ie. strips off leading "start|stop")
482
 
        # Start processing arguments immediately after the first seq number.
483
 
        my $argi = $_[0] eq $act ? 2 : 1;
484
 
 
485
 
        while (defined $_[$argi]) {
486
 
            my $arg = $_[$argi];
487
 
 
488
 
            # Runlevels 0 and 6 are always stop runlevels
489
 
            if ($arg eq 0 or $arg eq 6) {
490
 
                $start = 0; $stop = 1; 
491
 
            } elsif ($arg eq 'start') {
492
 
                $start = 1; $stop = 0; $argi++; next;
493
 
            } elsif ($arg eq 'stop') {
494
 
                $start = 0; $stop = 1; $argi++; next;
495
 
            } elsif ($arg eq '.') {
496
 
                next;
497
 
            }
498
 
            push(@arg_start_lvls, $arg) if $start;
499
 
            push(@arg_stop_lvls, $arg) if $stop;
500
 
        } continue {
501
 
            $argi++;
502
 
        }
503
 
    }
504
 
 
505
 
    if ($#arg_start_lvls != $#lsb_start_lvls or
506
 
        join("\0", sort @arg_start_lvls) ne join("\0", sort @lsb_start_lvls)) {
507
 
        $arg_str = @arg_start_lvls ? "@arg_start_lvls" : "none";
508
 
        $lsb_str = @lsb_start_lvls ? "@lsb_start_lvls" : "none";
509
 
        warning "$name start runlevel arguments ($arg_str) do not match",
510
 
                "LSB Default-Start values ($lsb_str)";
511
 
    }
512
 
    if ($#arg_stop_lvls != $#lsb_stop_lvls or
513
 
        join("\0", sort @arg_stop_lvls) ne join("\0", sort @lsb_stop_lvls)) {
514
 
        $arg_str = @arg_stop_lvls ? "@arg_stop_lvls" : "none";
515
 
        $lsb_str = @lsb_stop_lvls ? "@lsb_stop_lvls" : "none";
516
 
        warning "$name stop runlevel arguments ($arg_str) do not match",
517
 
                "LSB Default-Stop values ($lsb_str)";
518
 
    }
519
 
}
520
 
 
521
 
sub insserv_toggle {
522
 
    my ($dryrun, $act, $name) = (shift, shift, shift);
523
 
    my (@toggle_lvls, $start_lvls, $stop_lvls, @symlinks);
524
 
    my $lsb_header = lsb_header_for_script($name);
525
 
 
526
 
    # Extra arguments to disable|enable action are runlevels. If none
527
 
    # given parse LSB info for Default-Start value.
528
 
    if ($#_ >= 0) {
529
 
        @toggle_lvls = @_;
530
 
    } else {
531
 
        ($start_lvls, $stop_lvls) = parse_def_start_stop($lsb_header);
532
 
        @toggle_lvls = @$start_lvls;
533
 
        if ($#toggle_lvls < 0) {
534
 
            error("$name Default-Start contains no runlevels, aborting.");
535
 
        }
536
 
    }
537
 
 
538
 
    # Find symlinks in rc.d directories. Refuse to modify links in runlevels
539
 
    # not used for normal system start sequence.
540
 
    for my $lvl (@toggle_lvls) {
541
 
        if ($lvl !~ /^[S2345]$/) {
542
 
            warning("$act action will have no effect on runlevel $lvl");
543
 
            next;
544
 
        }
545
 
        push(@symlinks, $_) for glob("/etc/rc$lvl.d/[SK][0-9][0-9]$name");
546
 
    }
547
 
 
548
 
    if (!@symlinks) {
549
 
        error("no runlevel symlinks to modify, aborting!");
550
 
    }
551
 
 
552
 
    # Toggle S/K bit of script symlink.
553
 
    for my $cur_lnk (@symlinks) {
554
 
        my $sk;
555
 
        my @new_lnk = split(//, $cur_lnk);
556
 
 
557
 
        if ("disable" eq $act) {
558
 
            $sk = rindex($cur_lnk, '/S') + 1;
559
 
            next if $sk < 1;
560
 
            $new_lnk[$sk] = 'K';
561
 
        } else {
562
 
            $sk = rindex($cur_lnk, '/K') + 1;
563
 
            next if $sk < 1;
564
 
            $new_lnk[$sk] = 'S';
565
 
        }
566
 
 
567
 
        if ($dryrun) {
568
 
            printf("rename(%s, %s)\n", $cur_lnk, join('', @new_lnk));
569
 
            next;
570
 
        }
571
 
 
572
 
        rename($cur_lnk, join('', @new_lnk)) or error($!);
573
 
    }
574
 
}