~ubuntu-branches/ubuntu/karmic/sysvinit/karmic-updates

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Scott James Remnant
  • Date: 2009-09-07 19:56:53 UTC
  • mfrom: (1.1.4 upstream) (2.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20090907195653-2i6t0j91wfbf1f0d
Tags: 2.87dsf-4ubuntu1
* Merge from debian unstable, remaining changes:
  - Support Cell processor:
    + debian/initscripts/postinst: Create spu system group and /spu mount
      point if we are running on a Cell processor.
    + debian/initscripts/etc/init.d/mountkernfs.sh: Mount spufs if Cell
      processor is detected.
    + debian/initscripts/lib/init/mount-functions.sh: Modprobe spufs
      if not available.
    + debian/control: Add initscripts dependency 'passwd' for groupadd.
    (Forwarded to Debian #483399)
  - Use tmpfs mounts for /var/lock and /var/run:
    + debian/initscripts/share/default.rcS: Enable RAMRUN and RAMLOCK by
      default.
    + debian/initscripts.postinst: Enable RAMRUN and RAMLOCK in
      /etc/default/rcS on upgrades. This needs to be kept until the next
      LTS.
    + debian/initscripts/etc/init.d/mountkernfs.sh: Propagate files from the
      initramfs to our new /var/run, so that we can populate
      /var/run/sendsigs.omit from initramfs.
  - Boot ordering differences:
    + mountkernfs.sh: 02 -> 01
    + mountdevsubfs.sh: 04 -> 11
    + bootlogd: disabled by default
    + checkroot.sh: 10 -> 20
    + mtab.sh: 12 -> 22
  - debian/patches/91_sulogin_lockedpw.dpatch: Disable "root account is
    locked" warning, since this is the default in Ubuntu. Document this in
    sulogin.8.
  - debian/control: Drop Essential: yes from packages since we use Upstart.
  - debian/control: Conflict/Replace sysvconfig which has also previously
    provided service(8).
  - debian/control, debian/rules: Previous name for sysvinit-utils was
    'sysvutils' in Ubuntu, so Conflict/Replace/Provide it. Also create a
    dummy sysvutils package, since Hardy has reverse versioned dependencies
    to it. This needs to be kept until after the next LTS.
  - debian/control: Depend on lsb-base (>= 3.2-14) for status_of_proc()
    function.
  - debian/initscripts/etc/init.d/checkfs.sh: Don't depend on hwclockfirst
    which Ubuntu does not have.
  - debian/initscripts/etc/init.d/mountkernfs.sh: Always mount devpts, and
    do not touch /dev/ptmx (which is already managed by udev).
  - debian/initscripts/etc/init.d/mountkernfs.sh: mount fusectl if it is
    available
  - debian/initscripts/etc/init.d/mountkernfs.sh: mount securityfs if it is
    available. This allows for easier AppArmor confinement of applications
    early in the boot process. LP: #399954
  - debian/initscripts/etc/init.d/mountkernfs.sh: mount debugfs if it is
    available.
  - debian/initscripts/etc/init.d/ondemand: Sleep for 60 seconds, then
    set CPU Frequency Scaling governor to "ondemand".   LP: #341573.
  - debian/initscripts/etc/init.d/umountfs: Don't unmount filesystems
    that precede root or use force for some mountpoints.
  - debian/initscripts/etc/network/if-up.d/mountnfs: Rename ifstate
    file to /var/run/network/ifstate
  - ./debian/initscripts/lib/init/usplash-fsck-functions.sh: Use blkid,
    vol_id is gone.
  - debian/initscripts.{pre,postinst}: waitnfs.sh -> mountnfs.sh renaming
    transition. This needs to be kept until after the next LTS.

LP: #32455, #94120, #160197, #382097 (amongst others).

* debian/sysv-rc/sbin/update-rc.d: Dropped support for "multiuser"
  command-line option.
* debian/rules: Compat symlink from /usr/bin/service to /usr/sbin/service
* debian/initscripts.postinst: Transition from bootlogs.sh to bootlogs

* debian/sysv-rc.postinst: Don't try and use insserv by default, though
  everything's in place for you to try if you like.  It can be activated
  with:
      USEINSSERV=yes dpkg-reconfigure sysv-rc

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
usage: update-rc.d [-n] [-f] <basename> remove
19
19
       update-rc.d [-n] <basename> defaults [NN | SS KK]
20
20
       update-rc.d [-n] <basename> start|stop NN runlvl [runlvl] [...] .
 
21
       update-rc.d [-n] <basename> disable|enable [S|2|3|4|5]
21
22
                -n: not really
22
23
                -f: force
 
24
 
 
25
The disable|enable API is not stable and might change in the future.
23
26
EOF
24
27
        exit (1);
25
28
}
26
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
 
27
38
# Check out options.
28
39
my $force;
29
40
 
 
41
my @orig_argv = @ARGV;
 
42
 
30
43
while($#ARGV >= 0 && ($_ = $ARGV[0]) =~ /^-/) {
31
44
        shift @ARGV;
32
45
        if (/^-n$/) { $notreally++; next }
35
48
        &usage("unknown option");
36
49
}
37
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
 
38
63
# Action.
39
64
 
40
65
&usage() if ($#ARGV < 1);
51
76
        exit (1);
52
77
    }
53
78
    &parse_lsb_header("$initd/$bn");
 
79
    &cmp_args_with_defaults($bn, $ARGV[0], @ARGV);
54
80
} elsif (-f "$initd/$bn") {
55
81
    if (!$force) {
56
82
        printf STDERR "update-rc.d: $initd/$bn exists during rc.d purge (use -f to force)\n";
62
88
my @stoplinks;
63
89
 
64
90
$_ = $ARGV[0];
65
 
if    (/^remove$/)       { &checklinks ("remove"); }
66
 
elsif (/^defaults$/)     { &defaults; &makelinks }
67
 
elsif (/^multiuser$/)    { &multiuser; &makelinks }
68
 
elsif (/^(start|stop)$/) { &startstop; &makelinks; }
 
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); }
69
95
else                     { &usage; }
70
96
 
71
97
exit (0);
72
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
 
73
112
# Check if there are links in /etc/rc[0-9S].d/ 
74
113
# Remove if the first argument is "remove" and the links 
75
114
# point to $bn.
77
116
sub is_link () {
78
117
    my ($op, $fn, $bn) = @_;
79
118
    if (! -l $fn) {
80
 
        print STDERR "update-rc.d: warning: $fn is not a symbolic link\n";
 
119
        warning "$fn is not a symbolic link\n";
81
120
        return 0;
82
121
    } else {
83
122
        my $linkdst = readlink ($fn);
85
124
            die ("update-rc.d: error reading symbolic link: $!\n");
86
125
        }
87
126
        if (($linkdst ne "../init.d/$bn") && ($linkdst ne "$initd/$bn")) {
88
 
            print STDERR "update-rc.d: warning: $fn is not a link to ../init.d/$bn or $initd/$bn\n";
 
127
            warning "$fn is not a link to ../init.d/$bn or $initd/$bn\n";
89
128
            return 0;
90
129
        }
91
130
    }
135
174
    open(INIT, "<$initdscript") || die "error: unable to read $initdscript";
136
175
    while (<INIT>) {
137
176
        chomp;
138
 
        $lsbinfo{'found'} = 1 if (m/^\#\#\# BEGIN INIT INFO$/);
139
 
        last if (m/\#\#\# END INIT INFO$/);
 
177
        $lsbinfo{'found'} = 1 if (m/^\#\#\# BEGIN INIT INFO\s*$/);
 
178
        last if (m/\#\#\# END INIT INFO\s*$/);
140
179
        if (m/^\# ($lsbheaders):\s*(\S?.*)$/i) {
141
180
        $lsbinfo{lc($1)} = $2;
142
181
        }
150
189
    } else {
151
190
        for my $key (split(/\|/, lc($lsbheaders))) {
152
191
            if (!exists $lsbinfo{$key}) {
153
 
                print STDERR "update-rc.d: warning: $initdscript missing LSB keyword '$key'\n";
 
192
                warning "$initdscript missing LSB keyword '$key'\n";
154
193
            }
155
194
        }
156
195
    }
157
196
}
158
197
 
159
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
 
160
263
# Process the arguments after the "defaults" keyword.
161
264
 
162
265
sub defaults {
 
266
    my @argv = @_;
163
267
    my ($start, $stop) = (20, 20);
164
268
 
165
 
    &usage ("defaults takes only one or two codenumbers") if ($#ARGV > 2);
166
 
    $start = $stop = $ARGV[1] if ($#ARGV >= 1);
167
 
    $stop  =         $ARGV[2] if ($#ARGV >= 2);
 
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);
168
272
    &usage ("codenumber must be a number between 0 and 99")
169
273
        if ($start !~ /^\d\d?$/ || $stop  !~ /^\d\d?$/);
170
274
 
177
281
    1;
178
282
}
179
283
 
180
 
# Process the arguments after the "multiuser" keyword.
181
 
 
182
 
sub multiuser {
183
 
    my ($start, $stop) = (20, 20);
184
 
 
185
 
    print STDERR "update-rc.d: warning: multiuser is deprecated; specify runlevels manually\n";
186
 
    &usage ("multiuser takes only one or two codenumbers") if ($#ARGV > 2);
187
 
    $start = $stop = $ARGV[1] if ($#ARGV >= 1);
188
 
    $stop  =         $ARGV[2] if ($#ARGV >= 2);
189
 
    &usage ("codenumber must be a number between 0 and 99")
190
 
        if ($start !~ /^\d\d?$/ || $stop  !~ /^\d\d?$/);
191
 
 
192
 
    $start = sprintf("%02d", $start);
193
 
    $stop  = sprintf("%02d", $stop);
194
 
 
195
 
    $stoplinks[1] = "K$stop";
196
 
    $startlinks[2] = $startlinks[3] =
197
 
        $startlinks[4] = $startlinks[5] = "S$start";
198
 
 
199
 
    1;
200
 
}
201
 
 
202
284
# Process the arguments after the start or stop keyword.
203
285
 
204
286
sub startstop {
205
 
 
 
287
    my @argv = @_;
206
288
    my($letter, $NN, $level);
207
289
 
208
 
    while ($#ARGV >= 0) {
209
 
        if    ($ARGV[0] eq 'start') { $letter = 'S'; }
210
 
        elsif ($ARGV[0] eq 'stop')  { $letter = 'K' }
 
290
    while ($#argv >= 0) {
 
291
        if    ($argv[0] eq 'start') { $letter = 'S'; }
 
292
        elsif ($argv[0] eq 'stop')  { $letter = 'K'; }
211
293
        else {
212
294
            &usage("expected start|stop");
213
295
        }
214
296
 
215
 
        if ($ARGV[1] !~ /^\d\d?$/) {
216
 
            &usage("expected NN after $ARGV[0]");
217
 
        }
218
 
        $NN = sprintf("%02d", $ARGV[1]);
219
 
 
220
 
        shift @ARGV; shift @ARGV;
221
 
        $level = shift @ARGV;
222
 
        &usage("action with list of runlevels not terminated by \".\"")
223
 
            if ($ARGV[$#ARGV] ne '.');
 
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;
224
308
        do {
225
309
            if ($level !~ m/^[0-9S]$/) {
226
310
                &usage(
234
318
            $level = 99 if ($level eq 'S');
235
319
            $startlinks[$level] = "$letter$NN" if ($letter eq 'S');
236
320
            $stoplinks[$level]  = "$letter$NN" if ($letter eq 'K');
237
 
        } while (($level = shift @ARGV) ne '.');
 
321
        } while (($level = shift @argv) ne '.');
238
322
    }
239
323
    1;
240
324
}
246
330
    my @links;
247
331
 
248
332
    if (&checklinks) {
249
 
        print " System startup links for $initd/$bn already exist.\n";
250
 
        exit (0);
 
333
        print " System start/stop links for $initd/$bn already exist.\n";
 
334
        return 0;
251
335
    }
252
336
    print " Adding system startup for $initd/$bn ...\n";
253
337
 
268
352
 
269
353
    1;
270
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
}