From 07ddb209e66065e6a8e551aa8a8a81dfad1dbbc6 Mon Sep 17 00:00:00 2001 From: milisbir Date: Thu, 7 Apr 2016 01:23:55 +0000 Subject: [PATCH] sysv-rc-conf --- .../genel/sysv-rc-conf/sysv-rc-conf.pl | 1226 +++++++++++++++++ talimatname/genel/sysv-rc-conf/talimat | 16 + 2 files changed, 1242 insertions(+) create mode 100755 talimatname/genel/sysv-rc-conf/sysv-rc-conf.pl create mode 100644 talimatname/genel/sysv-rc-conf/talimat diff --git a/talimatname/genel/sysv-rc-conf/sysv-rc-conf.pl b/talimatname/genel/sysv-rc-conf/sysv-rc-conf.pl new file mode 100755 index 000000000..a68146b3c --- /dev/null +++ b/talimatname/genel/sysv-rc-conf/sysv-rc-conf.pl @@ -0,0 +1,1226 @@ +#!/usr/bin/perl -w +# This program is distributed under the terms of the GNU General Public License +# +# This file is part of sysv-rc-conf. +# +# sysv-rc-conf 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. +# +# sysv-rc-conf 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 sysv-rc-conf; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Copyright 2004 Joe Oppegaard +# +use strict; +use Getopt::Long qw(:config no_ignore_case); + +use Curses; +use Curses::UI; + +use constant { + BOTTOM_LAB_HEIGHT => 2, + BOTTOM_WIN_HEIGHT => 4, + DEFAULT_K_PRI => 80, + DEFAULT_S_PRI => 20, + LABEL_WIDTH => 10, + LIST_SN_LENGTH => 12, + LIST_SN_PAD => 1, + MAX_ROWS => 8, + TOP_LABEL_HEIGHT => 2, +}; + +my $VERSION = "0.98"; + +my %opts = ( + cache_dir => "/var/lib/sysv-rc-conf", + order => 'a', + priority => '', + root => '/', + show => '', + verbose => '', + chkcfg_levels => '2345', # default runlevels to affect if not specified + chkcfg_list => undef, + chkcfg_sn => '', + chkcfg_state => '', +); + +GetOptions("cache=s" => \$opts{cache_dir}, + "level=s" => \$opts{chkcfg_levels}, + "list:s" => \$opts{chkcfg_list}, + "order=s" => \$opts{order}, + "priority" => \$opts{priority}, + "root=s" => \$opts{root}, + "show=s" => \$opts{show}, + "verbose=s" => \$opts{verbose}, + "Version" => sub { print STDERR "$0 $VERSION\n"; exit; }, + ); + +my $runlevel_cmd = '/sbin/runlevel'; + +$opts{verbose} ||= "/dev/null"; +open VERBOSE, "> $opts{verbose}" or die "Can't open $opts{verbose} : $!"; + +my $etc_rc = $opts{root} . "/etc/rc.d/rc"; +my $initd = $opts{root} . "/etc/init.d"; + +my @rls = qw/ 1 2 3 4 5 7 8 9 0 6 S /; + +check_args(); +setup_cache_env(); + +my @show_rls = split //, $opts{show}; + +# Page index +my $current_screen = 0; + +# Page screens +my @s = (); + +# All the runlevel information +my %runlevels = runlevel_status(); + +list_output(%runlevels) if defined $opts{chkcfg_list}; +chkconfig_emulation(); + +my $cui = new Curses::UI( -clear_on_exit => 0, + -color_support => 1, + -default_colors => 1, + ) or die "Can't create base Curses::UI object"; + +create_bottom_box(); + +# Get the service names for each screen +my @snames_per_screen = split_services(); + +create_main_window(); + +my %box_pos = (x => '00', y => '00'); + +$cui->set_binding( \&toggle_help, "h" ); +$cui->set_binding( \&revert_changes, "r") ; +$cui->set_binding( sub { exit }, "q" ); + +$cui->set_binding( \&next_page, "\cN" ); +$cui->set_binding( \&prev_page, "\cP" ); + +$s[$current_screen]->focus(); + +$cui->mainloop(); + +#--- rc access and modification subs ---# +sub update_link +{ + my ($sn, $rl, $sk, $pri) = @_; + + if (defined $sn && defined $rl && defined $sk && defined $pri) { + if (-e "$etc_rc$rl.d/$sk$pri$sn") { + # The symlink we are trying to make already exists + return 'exists'; + } + } + + opendir (RL, "$etc_rc$rl.d") or die "$0: opendir $etc_rc$rl.d : $!"; + + foreach (grep { /[SK]\d\d$sn/i } readdir(RL)) { + verbose("rm $etc_rc$rl.d/$_"); + unlink "$etc_rc$rl.d/$_" + or die "Can't unlink $etc_rc$rl.d/$_ : $!"; + } + + # If in priority mode and are completely deleting the link, $sk will + # be empty. + return 1 if $sk eq ''; + + $pri = get_pri_cache($sn, $rl, $sk) unless $pri; + + unless ($pri =~ /^\d\d$/) { die "Priority isn't two numbers: $pri" } + unless ($sk =~ /^[SK]$/) { die "You have to use S or K to start a link" } + + verbose("symlink $initd/$sn $etc_rc$rl.d/$sk$pri$sn"); + # unlike ln relative symlinks are relative to the target file, not the cwd + symlink "../init.d/$sn", "$etc_rc$rl.d/$sk$pri$sn" + or die "Can't symlink $etc_rc$rl.d/$sk$pri$sn to ../init.d/$sn : $!\n"; +} + +sub usage +{ + print STDERR <] +USAGE +} + +sub chkconfig_emulation +{ + $opts{chkcfg_sn} = $ARGV[0] if defined $ARGV[0]; + $opts{chkcfg_state} = $ARGV[1] if defined $ARGV[1]; + + if ($opts{chkcfg_sn} && not $opts{chkcfg_state}) { + # Check to see if service is configured to run in current rl + # exit true if it is, false if not. + # See chkconfig(8) + my $current_rl = current_runlevel(); + if (exists $runlevels{$opts{chkcfg_sn}}{$current_rl}) { + if ($runlevels{$opts{chkcfg_sn}}{$current_rl} =~ /^S/) { + # Service is configured to start, exit true + exit 0; + } + } + exit 1; + } + + if ($opts{chkcfg_sn} && $opts{chkcfg_state}) { + my $sk = ''; + if ($opts{chkcfg_state} =~ /^on$/i) { + $sk = 'S'; + } + elsif ($opts{chkcfg_state} =~ /^off$/i) { + $sk = 'K'; + } + else { + usage(); + } + + foreach (split //, $opts{chkcfg_levels}) { + update_link($opts{chkcfg_sn}, $_, $sk, undef); + } + + exit 0; + } + + # Program isn't being called like chkconfig, so return to normal + # operation. + return 1; +} + +sub list_output +{ + my (%runlevels) = @_; + + # There was an argument to --list + my $opt_sn = $opts{chkcfg_list}; + foreach my $sn (sort keys %runlevels) { + my $output = substr $sn, 0, LIST_SN_LENGTH; + $output .= " " until length $output >= LIST_SN_LENGTH + LIST_SN_PAD; + + foreach my $rl (sort keys %{$runlevels{$sn}}) { + $output .= "$rl:"; + if ($runlevels{$sn}{$rl} =~ /^[Ss]/) { + $output .= "on"; + } + else { + $output .= "off"; + } + $output .= "\t"; + } + chop($output); + $output .= "\n"; + if ($opt_sn) { + print $output if $sn eq $opt_sn; + } + else { + print $output; + } + } + + exit 0; +} + +sub revert_changes +{ + # Lookup table + my %cache = (); + foreach my $scr (@s) { + for (my $i = 0; $i < max_services() ; $i++) { + for (my $j = 0; $j <= $#show_rls; $j++) { + my $obj = $scr->getobj(zero_pad($i).zero_pad($j)); + my $ud = $obj->userdata(); + + $cache{ $ud->{sn} }{ $ud->{runlevel} } = $obj; + } + } + } + + foreach my $sn (keys %runlevels) { + foreach my $rl (keys %{$runlevels{$sn}}) { + $runlevels{$sn}{$rl} =~ /^([SK])(\d\d)$/; + my ($sk, $pri) = ($1, $2); + + next if update_link($sn, $rl, $sk, $pri) eq 'exists'; + + if (exists($cache{$sn}{$rl})) { + my $box = $cache{$sn}{$rl}; + if ($opts{priority}) { + # Reset the text + $box->text($sk.$pri); + $box->draw(1); + } + else { + # Simple layout, just toggle the box. + $box->toggle(); + $box->draw(1); + } + } + + + } + } + + $cui->dialog("Symlinks restored to original state!"); +} + +sub start_service +{ + my ($widget) = @_; + my $ud = $widget->userdata(); + + st_service($ud->{sn}, 'start'); +} + +sub stop_service +{ + my ($widget) = @_; + my $ud = $widget->userdata(); + + st_service($ud->{sn}, 'stop'); +} + +sub st_service +{ + my ($sn, $st) = @_; + + my $output = `$initd/$sn $st`; + + verbose("$initd/$sn $st : $output"); + $cui->dialog("Results of $initd/$sn $st :\n" . $output); +} + +sub get_pri_cache +{ + my ($sn, $rl, $sk) = @_; + # See if we can get an exact match from the cache, if not try to match + # the S or K except in a different run level, if there still is not a match + # get the opposite of S or K on another runlevel, if still no match return + # the default. + + open CACHE, "< $opts{cache_dir}/services" + or die "Can't open $opts{cache_dir}/services : $!"; + + chomp (my @cache = ); + close CACHE; + + # Try an exact cache match + foreach (@cache) { + # $arg_rl $arg_sk $arg_pri $arg_sn + next unless /^$rl\s+$sk\s+(\d\d)\s+$sn$/; + verbose("Got exact cache match for priority: $_"); + return $1; + } + + # Try an $sk match, except on any runlevel + foreach (@cache) { + next unless /^[\dsS]\s+$sk\s+(\d\d)\s+$sn$/; + verbose("Got differing runlevel cache for priority: $_"); + return $1; + } + + # Ok, try to match on any runlevel with either S or K + foreach (@cache) { + next unless /^[\dsS]\s+([SK])\s+(\d\d)\s+$sn$/; + verbose("Returning difference of 100 and $2: $_"); + # Sequence numbers are usually defined as stop = 100 - start + # So that means that start = 100 - stop + # Above we would have returned if $sk eq $1 so we know that $1 is + # the opposite of $sk. So return 100 - $2. + return zero_pad(100 - $2); + } + + verbose("No cache found, returning default"); + return DEFAULT_S_PRI if $sk eq 'S'; + return DEFAULT_K_PRI if $sk eq 'K'; +} + +sub pri_box_changed +{ + my ($widget) = @_; + + my $ud = $widget->userdata(); + my $new_link = $widget->get(); + + if ($new_link eq $ud->{last_good_text}) { + # Text didn't actually change, just moved out of the box + return 1; + } + + if ($new_link =~ /^([KS])(\d\d)$/ or $new_link =~ /^$/) { + my ($sk, $pri) = ('', ''); + if (defined $1 and defined $2) { + $sk = $1; + $pri = $2; + } + + update_link($ud->{sn}, $ud->{runlevel}, $sk, $pri); + + $ud->{last_good_text} = $new_link; + } + else { + $cui->error("Incorrect format: $new_link\n" . + "The correct format is a K or S followed by two digits!\n" . + "Returning field back to original state." + ); + + # Set the text in the box back to whatever the last good text was. + $widget->{-text} = $ud->{last_good_text}; + } +} + +sub simple_box_changed +{ + my ($box) = @_; + my $userdata = $box->userdata(); + + $userdata->{changed}++; + + if ($box->get()) { + update_link($userdata->{sn}, $userdata->{runlevel}, 'S', undef) + } + else { + update_link($userdata->{sn}, $userdata->{runlevel}, 'K', undef) + } +} + +sub runlevel_status +{ + my %runlevels = (); + + opendir (INITD, $initd) or die "$0: opendir $initd : $!"; + while ( defined(my $service = readdir INITD) ) { + next if $service =~ /\.sh$/; # see the debian policy manual + next if $service =~ /^\.+$/; # ignore . and .. + next unless -x "$initd/$service"; # ignore stuff like README + $runlevels{$service} = { }; + } + closedir INITD or die "$0: closedir $initd : $!"; + + # While 7-9 usually aren't used, init supports it. + foreach my $rl (@rls) { + unless (opendir(DIR, "$etc_rc$rl.d")) { + next if $rl =~ /^[789S]$/; + die "$0: opendir $etc_rc$rl.d : $!"; + } + while ( defined(my $file = readdir DIR) ) { + $file = "$etc_rc$rl.d/$file"; # Add the pathname to the file + next unless -l $file; + next if $file =~ /\.sh$/; + next unless $file =~ /([SK])(\d\d)(.+)$/; + my ($sk, $pri, $sn) = ($1, $2, $3); + $runlevels{$sn}{$rl} = $sk.$pri; + } + closedir DIR or die "$0: closedir $etc_rc$rl.d : $!"; + } + + update_cache(\%runlevels); + return %runlevels; +} + +sub setup_cache_env +{ + unless (-e $opts{cache_dir}) { + verbose("Creating non-existant cache directory: $opts{cache_dir}"); + mkdir $opts{cache_dir} or die "Can't create $opts{cache_dir} : $!"; + } + + unless (-e "$opts{cache_dir}/services") { + # Later we need to open the file with +< which can't create a new file + # so we'll emulate touch. + verbose("Touching $opts{cache_dir}/services"); + open CACHE, "> $opts{cache_dir}/services" + or die "Can't touch $opts{cache_dir}/services : $!"; + close CACHE; + } +} + +sub update_cache +{ + my ($runlevels) = @_; + + open CACHE, "+< $opts{cache_dir}/services" + or die "Can't open $opts{cache_dir}/services for rw access : $!"; + + # Check to see if this service & rl already exists somewhere in this file + # and update the line if so. + my %touched = (); + while () { + chomp; + next unless /^([\dSs])\s+([SK])\s+(\d\d)\s+([^\s]+)$/; + + my ($rl, $sk, $pri, $sn) = ($1, $2, $3, $4); + + if (exists $runlevels->{$sn}{$rl}) { + $runlevels->{$sn}{$rl} =~ /^([SK])(\d\d)$/; + $touched{$sn}{$rl} = 1; + + my ($n_sk, $n_pri) = ($1, $2); + next if $sk eq $n_sk && $pri eq $n_pri; + + s/^.+$/$rl $n_sk $n_pri $sn/; + } + } + + foreach my $sn (sort keys %{$runlevels}) { + foreach my $rl (sort keys %{$runlevels->{$sn}}) { + unless (exists $touched{$sn}{$rl}) { + $runlevels->{$sn}{$rl} =~ /^([SK])(\d\d)$/; + print CACHE "$rl $1 $2 $sn\n"; + } + } + } + + close CACHE or die "Can't close $opts{cache_dir}/services : $!"; +} + +#--- Misc subs ---# +sub check_args +{ + $opts{show} ||= get_default_show(); + + unless ($opts{show} =~ /^[S0-9]*$/) { + die "$0: --show must match [S0-9]\n"; + } + + if (length($opts{show}) > MAX_ROWS) { + die "$0: can only show ". MAX_ROWS . "rows at a time\n"; + } + + return 1; +} + +sub current_runlevel +{ + if (-e $runlevel_cmd) { + my $rl_out = `$runlevel_cmd`; + $rl_out = 1 if $rl_out =~ /unknown/; + $rl_out =~ /^\S\s?([Ss\d])?$/ or + die "Unknown return from $runlevel_cmd : $rl_out"; + return $1; + } + else { + return 1; + } +} + + +sub split_services +{ + # Figure out how many services can fit on the screen, then make + # as many screens as needed to fit all the services. + my @screens = (); + + my @services = (); + + my %o_opts = (); + $o_opts{p} = 1 if $opts{order} =~ /p/; + $o_opts{n} = 1 if $opts{order} =~ /n/; + $o_opts{a} = 1 unless exists $o_opts{p}; + + if ($opts{order} =~ /([Ss\d])/) { + $o_opts{rl} = $1; + } + else { + # If the --order option didn't set a runlevel to sort by, then + # use the current runlevel (from the output of /sbin/runlevel) or + # sort by runlevel 1 if the runlevel command doesn't exsist on this + # system. + $o_opts{rl} = current_runlevel(); + } + + # Process the opts we just set. + if (exists $o_opts{a}) { + if (exists $o_opts{n}) { + # Include the priority num on an alpha sort + foreach my $sn (sort keys %runlevels) { + next unless exists $runlevels{$sn}{$o_opts{rl}}; + next unless $runlevels{$sn}{$o_opts{rl}} =~ /^[SK](\d\d)$/; + push @services, $1.$sn; + } + } + else { + # Standard alpha sort + @services = sort keys %runlevels; + } + } + elsif (exists $o_opts{p}) { + # Sort by priority at runlevel specified or current runlevel + + my @tmp_order = ( [ ], [ ] ); # S is 0 and K is 1 + foreach my $sn (keys %runlevels) { + next unless exists $runlevels{$sn}{$o_opts{rl}}; + next unless $runlevels{$sn}{$o_opts{rl}} =~ /^([SK])(\d\d)$/; + + if ($1 eq 'S') { push @{$tmp_order[0]}, $2.$sn } + elsif ($1 eq 'K') { push @{$tmp_order[1]}, $2.$sn } + } + + foreach (0, 1) { + foreach my $ddsn (sort @{$tmp_order[$_]}) { + $ddsn =~ /^(\d\d)(.+)$/; + if (exists $o_opts{n}) { + # Include the priority num on a pri sort + push @services, $1.$2; + } + else { + push @services, $2; + } + } + } + } + + { + # We could be missing some services if they didn't have a link in the + # runlevel we were sorting by. This happens in all circumstances except + # the default of just 'a' being set. + my %seen = (); + foreach (@services) { + next unless $_ =~ /^(\d\d)?(.+)$/; + $seen{$2} = 1; + } + + foreach (sort keys %runlevels) { + unless (exists $seen{$_}) { + push(@services, $_); + } + } + } + + my $per_screen = max_services(); + + my $i = 0; + do { + $screens[$i] = [ splice(@services, 0, $per_screen) ]; + $i++; + } while @services; + + return @screens; +} + +sub max_services +{ + my $tmp_screen = $cui->add( + undef, 'Window', + -title => "N/A", + -border => 1, + -padtop => 1, + -padbottom => 4, + -ipad => 1, + ); + + my $ms = $tmp_screen->canvasheight() - TOP_LABEL_HEIGHT; + undef $tmp_screen; # Make sure the memory is cleaned up. + + return $ms; +} + +sub get_default_show +{ + my $show = ''; + foreach (@rls) { + if (-e "$etc_rc$_.d") { + $show .= $_; + } + } + return $show; +} + +sub zero_pad { sprintf('%.2u', $_[0]); } + +sub verbose { print VERBOSE $_[0]."\n" if $opts{verbose}; } + + +#--- Screen layout subs ---# +sub create_main_window +{ + create_help_window(); + + my $i = 0; + foreach my $services (@snames_per_screen) { + + # First create the main window all of this page of services goes in + my $id = "window_$i"; + my $screen = $cui->add( + $id, 'Window', + -title => +"SysV Runlevel Config -: stop service =/+: start service h: help q: quit", + -border => 1, + -padtop => 1, + -padbottom => 4, + -ipad => 1, + ); + + # Can't set these globally (on $cui) or else it overrides the + # keybindings on all other objects + $screen->set_binding( \&move_up, KEY_UP(), ); + $screen->set_binding( \&move_down, KEY_DOWN(), ); + $screen->set_binding( \&move_left, KEY_LEFT(), ); + $screen->set_binding( \&move_right, KEY_RIGHT(), ); + + create_top_label($screen); + + my $left_label = ''; + for (my $i = 0; $i < scalar(@$services); $i++) { + $left_label .= $services->[$i] . "\n"; + if ($services->[$i] =~ /^\d\d(.+)$/) { + # If the labels had numbers, we don't need them anymore. + $services->[$i] = $1; + } + } + + my $row = TOP_LABEL_HEIGHT; + + $screen->add( + undef, 'Label', + -text => $left_label, + -y => $row, + -width => LABEL_WIDTH, + -height => last_x() + 1, + ); + + foreach my $sn (@$services) { + if ($opts{priority}) { draw_priority_layout($screen, $sn, $row) } + else { draw_simple_layout($screen, $sn, $row) } + + $row++; + } + + $s[$i] = $screen; + + $i++; + } +} + +sub create_help_window +{ + my $help_text = < +EOF + + my $hw = $cui->add( + 'help_window', 'Window', + -title => +"SysV Runlevel Config -: stop service =/+: start service h: help q: quit", + -border => 1, + -padtop => 1, + -padbottom => 4, + -ipad => 1, + -userdata => 0, + ); + + $hw->add( + 'help_tv', 'TextViewer', + -text => $help_text, + -title => 'sysv-rc-conf help', + -vscrollbar => 1, + ); + +} + +sub draw_simple_layout +{ + my ($screen, $sn, $row) = @_; + + for (my $i = 0, my $right_n = 12; $i <= $#show_rls; $i++, $right_n += 8) { + my $on_or_off = 0; + # We only want to show S\d\d services as selected. + $on_or_off = 1 if exists $runlevels{$sn}{$show_rls[$i]} + && $runlevels{$sn}{$show_rls[$i]} =~ /^S\d\d$/; + + my $box = $screen->add( + zero_pad($row-2).zero_pad($i), 'Checkbox', + -label => '', + -checked => $on_or_off, + -border => 0, + -x => $right_n, + -y => $row, + -width => 5, + #-height => 1, + -userdata => { id => zero_pad($row-2).zero_pad($i), + sn => $sn, + changed => 0, + runlevel => $show_rls[$i], + }, + -onchange => \&simple_box_changed, + -onfocus => \&got_focus, + ); + + $box->set_binding( \&start_service, "=", "+" ); + $box->set_binding( \&stop_service, "-" ); + } +} + +sub draw_priority_layout +{ + my ($screen, $sn, $row) = @_; + + for (my $i = 0, my $right_n = 11; $i <= $#show_rls; $i++, $right_n += 8) { + my $text = exists $runlevels{$sn}{$show_rls[$i]} + ? $runlevels{$sn}{$show_rls[$i]} + : ''; + my $box = $screen->add( + zero_pad($row-2).zero_pad($i), 'TextEntry', + -sbborder => 1, + -x => $right_n, + -y => $row, + -width => 6, + -maxlength => 3, + -regexp => '/^[skSK\d]*$/', + -toupper => 1, + -showoverflow => 0, + -text => $text, + -userdata => { id => zero_pad($row-2).zero_pad($i), + sn => $sn, + changed => 0, + runlevel => $show_rls[$i], + last_good_text => $text, + }, + -onblur => \&pri_box_changed, + -onfocus => \&got_focus, + ); + + $box->set_binding( \&start_service, "=", "+" ); + $box->set_binding( \&stop_service, "-" ); + } +} + +sub create_top_label +{ + my ($window) = @_; + + my @label_rls = @show_rls; + + my $text = 'service ' . shift @label_rls; + foreach (@label_rls) { $text .= " $_" }; + $text .= "\n"; + $text .= "-" x 76; + + $window->add( + undef, 'Label', + -text => $text, + -y => 0, + -x => 0, + -height => TOP_LABEL_HEIGHT, + -textalignment => 'left', + ); +} + +sub create_bottom_box +{ + my $cmd_text = ''; + + if ($opts{priority}) { + $cmd_text = +"Editing: Backspace: bs ^d: delete ^b: backward ^f: forward"; + } + else { + $cmd_text = +" space: toggle service on / off ", + } + + my $exp_window = $cui->add( + 'exp_window', 'Window', + -border => 1, + -y => -1, + -height => BOTTOM_WIN_HEIGHT, + -ipadleft => 1, + -ipadright => 1, + ); + $exp_window->add(undef, 'Label', + -y => 0, + -width => -1, + -height => BOTTOM_LAB_HEIGHT, + -text => +"Use the arrow keys or mouse to move around. ^n: next pg ^p: prev pg\n$cmd_text", + ); +} + +sub toggle_help +{ + my $hw = $cui->getobj('help_window'); + my $hw_data = $hw->userdata(); + + if ($hw_data == 0) { + $hw->userdata($cui->getfocusobj); + $hw->focus(); + } + else { + # The help window is up, so turn it off by focusing the last + # object that was focused on before we pulled up the help window + $hw_data->focus(); + $hw->userdata(0); + } +} + +#--- Movement subs ---# +sub next_page +{ + $current_screen++; + $current_screen = 0 if $current_screen > last_screen(); + verbose("Going to screen $current_screen"); + _move_focus(00, $box_pos{y}); +} + +sub prev_page +{ + $current_screen--; + $current_screen = last_screen() if $current_screen < 0; + verbose("Going to screen $current_screen"); + $box_pos{x} = last_x(); + _move_focus($box_pos{x}, $box_pos{y}); +} + +sub got_focus +{ + my $widget = shift; + # Is there a better way to figure out my own id besides putting it + # in userdata on creation and fetching it? + my $userdata = $widget->userdata(); + my $id = $userdata->{id}; + + $id =~ /^(\d\d)(\d\d)$/; + + $box_pos{x} = $1; + $box_pos{y} = $2; +} + +sub move_left +{ + return if $box_pos{y} eq '00'; + _move_focus($box_pos{x}, $box_pos{y} - 1); +} + +sub move_right +{ + return if $box_pos{y} == scalar(@show_rls)-1; + _move_focus($box_pos{x}, $box_pos{y} + 1); +} + +sub move_up +{ + #return if $box_pos{x} eq '00'; + return prev_page() if $box_pos{x} eq '00'; + _move_focus($box_pos{x} - 1, $box_pos{y}); +} + +sub move_down +{ + # Index starts at 00, so we need one less then the max services that + # are on the screen. + return next_page() if $box_pos{x} == last_x(); + _move_focus($box_pos{x} + 1, $box_pos{y}); +} + +sub _move_focus +{ + $box_pos{x} = $_[0]; + $box_pos{y} = $_[1]; + my $box = $s[$current_screen]->getobj(zero_pad($_[0]).zero_pad($_[1])); + $box->focus(); +} + +sub last_x { return scalar(@{$snames_per_screen[$current_screen]})-1; } + +sub first_screen { return 0 } + +sub last_screen { return scalar(@s)-1 } + +=pod + +=head1 NAME + +B - Run-level configuration for SysV like init script links + +=head1 SYNOPSIS + +B [ I ] + +B [ --level I ] I EIE + +=head1 DESCRIPTION + +B gives an easy to use interface for managing +C symlinks. The interface comes in two different +flavors, one that simply allows turning services on or off and another that +allows for more fine tuned management of the symlinks. It's a replacement for +programs like B or B. + +B can also be used at the command line when the desired changes +to the symlinks are already known. The syntax is borrowed from B. + +=head1 GENERAL OPTIONS + +=over + +=item B<-c> DIRECTORY, B<--cache=>DIRECTORY + +The directory where the priority numbers, old runlevel configuration, etc. +should be stored. This defaults to C. See the FILES +section below. + +=item B<-r> DIRECTORY, B<--root=>DIRECTORY + +The root directory to use. This defaults to C. This comes in handy if the +root file system is mounted somewhere else, such as when using a rescue disk. + +=item B<-v> FILE, B<--verbose=>FILE + +Print verbose information to C + +=item B<-V>, B<--Version> + +Print version information to STDOUT and exit + +=back + +=head1 GUI RELATED OPTIONS + +=over + +=item B<-o> [ see description ], B<--order=>[ see description ] + +Allows various sorting orders and ways to display the rows. The argument can be +made up of any of the following: + +=over + +=item B + +Sort the rows Blphabetically. This is the default if the B<-o> option isn't +specified. + +=item B + +Show the priority numbers along with the name of the service. + +=item B

+ +Sorts by the B

riority numbers. + +=item B + +I can be any runlevel, 0-9 or S. This controls which runlevel the +priority numbers are sorted at. It only makes sense to use this in conjuntion +with B

. If omitted the priority numbers are sorted by the current runlevel +the system is in. + +=back + +=item B<-p>, B<--priority> + +Alternate layout. Instead of just showing a checkbox, the priority of the +service and the S or K are allowed to be edited. This is for more fine tuned +control then the default layout allows. + +=item B<-s> I, B<--show=>I + +Which runlevels to show. This defaults to up to 8 of the runlevels available +on the system. Usually this means it will show 1, 2, 3, 4, 5, 0, 6, and S. +The syntax calls for the runlevels to be allruntogether. For instance, to +show runlevels 3, 4, and 5 the syntax would be C<--show=345>. Also see +B<--order>. + +=back + +=head1 CLI RELATED OPTIONS + +=over + +=item B<--level> I + +The runlevels this operation will affect. I can be any number from +0-9 or S. For example, B<--level 135> will affect runlevels 1, 3, and 5. +If B<--level> is not set, the default is to affect runlevels 2, 3, 4, and 5. +This option is only used for the command line interface, see the section +below labled USING THE CLI for more information. + +=item B<--list> [I] + +This option will list all of the services and if they are stopped or started +when entering each runlevel. If I is specified, only the information +for that service is displayed. + +=back + +=head1 USING THE GUI + +=head2 Using the Default layout + +The default (simple) layout shows in a grid fashion all of the services that +are in C and which runlevels they are turned on at. For example, where +the C row and C<3> column intersect, if there is a checkbox there that +means the service will be turned on when entering runlevel 3. If there is no +checkbox it can mean that either there are no links to the service in that +specific runlevel, or that the service is turned off when entering that +runlevel. If more configuration detail is needed, see the next paragraph and +the B<--priority> option. + +=head2 Using the Priority layout + +The priority (advanced) layout also uses a grid fashion, but instead of +checkboxes there are text boxes that can have a few different values. If the +text box is blank, that means there isn't a symlink in that runlevel for that +service. This means that when changing into that runlevel that the service +will not be started or stopped, which is significant. If the text box starts +with the letter K that means that the service will be stopped when entering +that runlevel. If the text box starts with the letter S that means the service +will be started when entering that runlevel. The two digits following is the +order in which the services are started. That means that C would +start before C. For more information see your system documentation. + +=head2 Controls + +To move around use the arrow keys, or if the terminal support it, the mouse. +Typically there is more then one page of services (unless the terminal screen +is large), to move between the pages use CTRL-n or CTRL-p, or simply arrow key +down or up at the bottom or top of the screen, respectively. The bottom of the +screen also shows these movement commands for quick reference. To restore the +symlinks back to their original state before the B was run, +press the B key. The B key will display a quick reference help screen. + +=head2 Default layout + +When using the default layout use the space bar to toggle the service on / off. + +=head2 Priority layout + +The priority layout uses the default movement keys. In order to edit the fields +you can use CTRL-d to delete the character in front of the cursor or backspace +to backspace. Use CTRL-b or CTRL-f to move the cursor backwards or forwards +within the field. Note that only S, K, or any digit is allowed to be entered +into the field. + +=head2 Starting / Stopping Services + +To start a service, press the C<+> or C<=> key. +To stop a service, press the C<-> key. + +This will call C or C. + +=head1 USING THE CLI + +If the desired modifications to the symlinks are known and only one quick +change is needed, then you can use a CLI interface to B. +Examples: + + # sysv-rc-conf --level 35 ssh off + # sysv-rc-conf atd on + +The first example will turn ssh off on levels 3 and 5. The second example +turns atd on for runlevels 2, 3, 4, and 5. + +=head1 FILES + +B Feel free to skip this section + +B stores a cache of all the symlink information from +C in C (See the --cache +option to change the location of this file). It uses this cache to make an +intelligent decision on what priority number to give the K or S link when they +are changed in the simple layout. This cache is updated/created everytime the +program is launched. The format of the file is as follows: + + RUNLEVEL S|K PRIORITY SERVICE + +Here's a few examples: + + 2 K 74 ntpd + 2 K 50 xinetd + 3 S 08 iptables + 3 S 80 sendmail + +B will first see if it can get an exact match from the cache. +For example, if the symlink for C in runlevel 3 is S89cron and you +uncheck it, B will first see if there is an entry in the cache +that looks like C<3 K nn cron>, if so it will use nn for the priority number. + +If there wasn't a match, B will then see if there is another S or +K (whichever you're switching to, so in this example, K) entry on a different +runlevel - so an entry like C, where i is any runlevel. If found, +the link will use nn. + +If there still wasn't a match, B will look for the opposite of S +or K in any run level, and use 100 - that priority. So in our example, +C. If nn is 20, then it will use 80 (100 - 20), since that is +typically the way that the priority numbers are used. + +If there still isn't a match, the default priority of 20 for S links is used, +and the default priority of 80 for K links is used. + +=head1 COMPATIBILITY + +B should work on any Unix like system that manages services +when changing runlevels by using symlinks in C. Refer +to your system documentation to see if that's the case (usually there's a +C). + +=head1 CAVEATS + +B only manages the symlinks in the C +directories. It's possible that pacakages may have other ways of being +disabled or enabled. + +Because Curses takes over the screen sometimes error messages won't be +seen on the terminal. If you run across any weird problems try redirecting +STDERR to a file when you execute the program. + +For example: + # sysv-rc-conf 2E err.out + +=head1 REPORTING BUGS + +Report bugs to Joe Oppegaard Ejoe@pidone.orgE + +=head1 SEE ALSO + +B, B, B, C + + www: http://sysv-rc-conf.sourceforge.net + ftp: ftp://ftp.pidone.org/sysv-rc-conf + +=head1 AUTHOR + +Joe Oppegaard Ejoe@pidone.orgE diff --git a/talimatname/genel/sysv-rc-conf/talimat b/talimatname/genel/sysv-rc-conf/talimat new file mode 100644 index 000000000..84cd07ab9 --- /dev/null +++ b/talimatname/genel/sysv-rc-conf/talimat @@ -0,0 +1,16 @@ +# Description: sysvinit yonetimi +# URL: http://sysv-rc-conf.sourceforge.net/ +# Maintainer: milisarge +# Packager : milisarge +# Depends on: perl-curses perl-curses-ui + +name=sysv-rc-conf +version=0.98 +release=1 +source=($name.pl) + +build() { + mkdir $PKG/usr + mkdir $PKG/usr/bin + install -m755 $name.pl $PKG/usr/bin/$name +}