###
### Copyright 2000-2007 University of Illinois Board of Trustees
### All rights reserved.
###
### InitScripts.pm - init script module for psgconf
###
### Campus Information Technologies and Educational Services
### University of Illinois at Urbana-Champaign
###
package PSGConf::Control::InitScripts;
use strict;
use PSGConf::Action::GenerateFile::RC_Script;
use PSGConf::Action::Remove;
use PSGConf::Action::Symlink;
use PSGConf::Action::RunCommand;
use PSGConf::Data::Hash;
use PSGConf::Data::String;
use PSGConf::Util;
use File::Basename;
###############################################################################
### Wrapper function for use with RunCommand
###############################################################################
sub _check_info
{
my ($self, $psgconf) = @_;
my ($cmd, $action, $script, $fullname);
$action = $psgconf->get_action($self->{filename});
### First see if we have an action to update the script itself.
return 1
if (defined($action) && $action->changed());
### If not, then we need to run our test.
$cmd = &PSGConf::Util::_expand_tokens( $psgconf, $self->{test} );
$fullname = $self->{filename};
$script = $self->{script};
$cmd =~ s/%f/$fullname/g;
$cmd =~ s/%s/$script/g;
return (!PSGConf::Util::RunCommand($cmd, 1))? 0:1;
}
###############################################################################
### decide() method
###############################################################################
sub decide
{
my ($self, $psgconf) = @_;
my ($script, $cmd, $fullname, $func, $link);
### Process the rc_scripts hash.
foreach $script ( keys %{$psgconf->data_obj('rc_scripts')->get()} ) {
### Verify that we have a state defined for this hash entry
if ( ! exists $psgconf->data_obj('rc_scripts')->find($script)->{state} ) {
warn "\t!!!WARNING: rc_script ($script) does not have a state defined\n";
next;
}
$fullname = $psgconf->data_obj('rc_scripts')->find($script)->{fullname};
# Create any RC scripts we need to create.
if ( exists $psgconf->data_obj('rc_scripts')->find($script)->{create_rc_script} &&
$psgconf->data_obj('rc_scripts')->find($script)->{create_rc_script} eq 'yes' )
{
if ( $psgconf->data_obj('rc_scripts')->find($script)->{state} eq 'enable' )
{
$psgconf->register_actions (
### Create the startup script
PSGConf::Action::GenerateFile::RC_Script->new(
name => $fullname,
command_interp => "#!/bin/sh",
mode => 0755,
rc_echo => $psgconf->data_obj('rc_echo')->get(),
description => $psgconf->data_obj('rc_scripts')->find($script)->{description},
top_cmds => $psgconf->data_obj('rc_scripts')->find($script)->{top_cmds},
start => $psgconf->data_obj('rc_scripts')->find($script)->{start_cmd},
stop => $psgconf->data_obj('rc_scripts')->find($script)->{stop_cmd},
restart => $psgconf->data_obj('rc_scripts')->find($script)->{restart_cmd},
links => $psgconf->data_obj('rc_scripts')->find($script)->{run_levels},
)
);
}
elsif ( $psgconf->data_obj('rc_scripts')->find($script)->{state} eq 'disable' )
{
$psgconf->register_actions (
### Remove the rc script itself.
PSGConf::Action::Remove->new(
name => $fullname
)
);
}
}
# Go through and enable or disable all the scripts we were
# told to.
if ( $psgconf->data_obj('rc_scripts')->find($script)->{state} eq 'enable' &&
exists $psgconf->data_obj('rc_scripts')->find($script)->{enable_cmd} )
{
$cmd = &PSGConf::Util::_expand_tokens(
$psgconf,
$psgconf->data_obj('rc_scripts')->find($script)->{enable_cmd}
);
$cmd =~ s/%f/$fullname/g;
$cmd =~ s/%s/$script/g;
$func =
(defined $psgconf->data_obj('rc_scripts')->find($script)->{enable_test})?
\&_check_info: undef;
$psgconf->register_actions (
PSGConf::Action::RunCommand->new (
name => "Enabling RC Script $script",
command => $cmd,
filename => $fullname,
script => $script,
test => $psgconf->data_obj('rc_scripts')->find($script)->{enable_test},
check_func => $func
)
);
}
elsif ( $psgconf->data_obj('rc_scripts')->find($script)->{state} eq 'disable' &&
defined $psgconf->data_obj('rc_scripts')->find($script)->{disable_cmd} )
{
$cmd = &PSGConf::Util::_expand_tokens(
$psgconf,
$psgconf->data_obj('rc_scripts')->find($script)->{disable_cmd}
);
$cmd =~ s/%f/$fullname/g;
$cmd =~ s/%s/$script/g;
$func =
(defined $psgconf->data_obj('rc_scripts')->find($script)->{disable_test})?
\&_check_info: undef;
$psgconf->register_actions (
PSGConf::Action::RunCommand->new (
name => "Disabling RC Script $script",
command => $cmd,
filename => $fullname,
script => $script,
test => $psgconf->data_obj('rc_scripts')->find($script)->{disable_test},
check_func => $func
)
);
}
# Go through all services we need to manage the RC links for.
if ( exists $psgconf->data_obj('rc_scripts')->find($script)->{manage_links} &&
$psgconf->data_obj('rc_scripts')->find($script)->{manage_links} eq 'yes' ) {
my ($run_levels) = $psgconf->data_obj('rc_scripts')->find($script)->{run_levels};
# Find the base of the rcX.d directories from the fullname
# of the script (and remove the init.d/name from the path.
my ($basedir) = dirname $fullname;
$basedir = dirname $basedir;
foreach $link ( keys %{$run_levels} ) {
my ($linkname) = $basedir . "/rc" . $link . ".d/" .
$run_levels->{$link} . ${script};
if ( $psgconf->data_obj('rc_scripts')->find($script)->{state} eq 'enable' &&
! -l $linkname ) {
$psgconf->register_actions (
PSGConf::Action::Symlink->new (
name => $linkname,
link_to => $fullname
)
);
} elsif ( $psgconf->data_obj('rc_scripts')->find($script)->{state} eq 'disable' &&
-l $linkname ) {
$psgconf->register_actions (
PSGConf::Action::Remove->new (
name => $linkname,
backup => 0
)
);
}
}
}
}
}
###############################################################################
### policy methods
###############################################################################
sub _policy_update_rc_vars
{
my ($self, $psgconf) = @_;
my ($script, $var);
foreach $script ( keys %{$psgconf->data_obj('rc_scripts')->get()} ) {
if ( defined $psgconf->data_obj('rc_scripts')->find($script)->{rc_var} &&
defined $psgconf->data_obj('rc_scripts')->find($script)->{state} &&
$psgconf->data_obj('rc_scripts')->find($script)->{state} ne 'ignore' ) {
$var = $psgconf->data_obj('rc_scripts')->find($script)->{rc_var};
$psgconf->data_obj('rc_vars')->insert(
{ $var =>
($psgconf->data_obj('rc_scripts')->find($script)->{state} eq 'enable')? 'YES': 'NO'
});
}
}
}
sub _policy_add_all_scripts
{
my ($self, $psgconf) = @_;
my ($cmd, $script, $fullname);
local *FP;
return
if ( !defined $psgconf->data_obj('list_rc_scripts_cmd')->get() );
### Collect all the know startup scripts
$cmd = $psgconf->data_obj('list_rc_scripts_cmd')->get();
if (open (FP, "$cmd |" )) {
while (<FP>) {
chomp $_;
### If the string starts with /, then assume it is
### a full path and use the basename of the string
### as the key (and store the full path in the
### structure.
$script = $_;
if ( $script =~ m,^/, ) {
$fullname = $script;
$script = basename $script;
$psgconf->data_obj('rc_scripts')->insert({
$script => { fullname => $fullname }
}) if ( ! defined $psgconf->data_obj('rc_scripts')->find($script)->{fullname} );
}
$psgconf->data_obj('rc_scripts')->insert(
{ $script => { 'state' =>
$psgconf->data_obj('default_script_behavior')->get() }}
) if ( ! defined $psgconf->data_obj('rc_scripts')->find($script)
|| ! defined $psgconf->data_obj('rc_scripts')->find($script)->{state} );
}
close FP;
} else {
warn "Could not run ($cmd)\n";
}
}
###############################################################################
### Constructor
###############################################################################
sub new
{
my ($class, $psgconf) = @_;
my ($self);
$self = {};
bless($self, $class);
$self->{name} = 'InitScripts';
$psgconf->register_data(
rc_scripts => PSGConf::Data::Hash->new(
value_type => 'HASH'
),
default_script_behavior => PSGConf::Data::String->new(
value => 'ignore'
),
rc_echo => PSGConf::Data::String->new(
value => 'print'
),
list_rc_scripts_cmd => PSGConf::Data::String->new()
);
$psgconf->register_policy($self,
init_add_all_scripts => '_policy_add_all_scripts',
update_rc_vars => '_policy_update_rc_vars'
);
return $self;
}
###############################################################################
### documentation
###############################################################################
1;
__END__
=head1 NAME
PSGConf::Control::InitScripts - psgconf control class for Startup scripts
=head1 SYNOPSIS
In F<psgconf_modules>:
Control PSGConf::Control::InitScripts
=head1 DESCRIPTION
The B<PSGConf::Control::InitScripts> module provides a B<psgconf>
control object for configuring the system's Startup scripts. It supports
the following methods:
=over 4
=item new()
The constructor. Its parameter is a reference to the B<PSGConf>
object. It registers the following data objects:
=over 4
=item I<rc_scripts>
A B<PSGConf::Data::Hash> of Hashes, where the primary key is the name
of the RC script to process. Sub keys include:
=over 4
=item I<state>
A B<PSGConf::Data::Enum> object taking the values F<enable>, F<disable>
or F<ignore>.
=item I<fullname>
A B<PSGConf::Data::String> which contains the fully qualfied file name
for the script (or the script to disable in the case of F</etc/rc.tcpip>
on AIX systems).
=item I<description>
A B<PSGConf::Data::String> object describing what the script does. This
will be used in the F<chkconfig> formatting information put into the
script itself.
=item I<rc_var>
A B<PSGConf::Data::String> object containing the variable to put into the
F</etc/rc.conf> file on FreeBSD. Values will be set to C<YES> or C<NO>,
determined by what I<state> is set to (C<enable> or C<disable>).
=item I<manage_links>
A B<PSGConf::Data::Boolean> object telling this Control module whether or
not to maintain the sym links in the C<rcX.d> directories. Gets F<X> from
the I<run_levels> hash.
=item I<run_levels>
A B<PSGConf::Data::Hash> object containing what run levels we need to run
this script at and what to do. The key is what run level to run at (usually
is S,0-9) and the value is in the format of F<[SK]XX> where XX is 00 to 99.
=item I<create_rc_scripts>
A B<PSGConf::Data::Boolean> object telling this Control module to create the
RC script, based on what the I<start_cmd> and I<stop_cmd> are set to.
=item I<start_cmd>
A B<PSGConf::Data::String> object with the command to execute when this
RC script is run at boot time.
=item I<stop_cmd>
A B<PSGConf::Data::String> object with the command to execute when this
RC script is run at shutdown time.
=item I<restart_cmd>
A B<PSGConf::Data::String> object with the command to execute when this
service needs to be restarted. Defaults to running the I<stop_cmd>
followed by the I<start_cmd>.
=item I<enable_cmd>
A B<PSGConf::Data::String> object to enable the RC script in the native
format supported by the OS. This command supports the special tokens
I<%s> and I<%f>, which get expanded to the hash key and I<fullname>,
respectively. Also it supports expansion of any B<PSGConf::Data::String>
directive via I<%{directive}> syntax.
=item I<enable_test>
A B<PSGConf::Data::String> object to test to see if the RC script has
been enabled. This command supports the special tokens
I<%s> and I<%f>, which get expanded to the hash key and I<fullname>,
respectively. Also it supports expansion of any B<PSGConf::Data::String>
directive via I<%{directive}> syntax.
=item I<disable_cmd>
A B<PSGConf::Data::String> object to disable the RC script in the native
format supported by the OS. This command supports the special tokens
I<%s> and I<%f>, which get expanded to the hash key and I<fullname>,
respectively. Also it supports expansion of any B<PSGConf::Data::String>
directive via I<%{directive}> syntax.
=item I<disable_test>
A B<PSGConf::Data::String> object to test to see if the RC script has
been disabled. This command supports the special tokens
I<%s> and I<%f>, which get expanded to the hash key and I<fullname>,
respectively. Also it supports expansion of any B<PSGConf::Data::String>
directive via I<%{directive}> syntax.
=back
=item I<default_script_behavior>
A B<PSGConf::Data::String> object to determine what to do with RC
scripts that have been found on the system but are not in the
I<rc_scripts> hash. Valid values are I<enable>, I<disable> and
I<ignore>. The default is I<ignore>.
=item I<rc_echo>
A B<PSGConf::Data::String> object for a command that we can use in the
RC script to echo to the string. It needs to support the I<\c> syntax
to not print a newline. The default is I<print>.
=item I<list_rc_scripts_cmd>
A B<PSGConf::Data::String> object for a command to list all the RC
scripts on a system. There should be one column of output, and if
the first character is I</>, then assume the object is a fully
qualified file name.
=back
The constructor also registers the following policy methods:
=over 4
=item I<init_add_all_scripts>
Updates the I<rc_scripts> hash to have all RC scripts that were
found by I<list_rc_scripts_cmd> command and sets their I<state>
to the value if I<default_script_behavior>, if it is not set
to C<ignore>.
=item I<update_rc_vars>
Updates the I<rc_vars> hash (B<PSGConf::Control::FreeBSD>) with
the values using the I<rc_var> and I<state> values in the I<rc_scripts>
hash.
=back
=item decide()
Instantiates and registers action objects, as follows:
=over 4
=item *
A B<PSGConf::Action::GenerateFile::RC_Script> or B<PSGConf::Action::Remove>
Action object to generate the RC script for each script B<psgconf> is
going to maintain.
=item *
A B<PSGConf::Action::RunCommand> Action to enable or disable the RC script,
depending on the result from the I<enable_test> or I<disable_test> command.
=item *
A B<PSGConf::Action::Symlink> or B<PSGConf::Action::Remove> Action object
to maintain the I<run_levels> sym links.
=back
=back
=head1 SEE ALSO
L<perl>
L<PSGConf>
L<PSGConf::Action::GenerateFile::RC_Script>
L<PSGConf::Action::Remove>
L<PSGConf::Action::Symlink>
L<PSGConf::Action::RunCommand>
L<PSGConf::Data::Hash>
L<PSGConf::Data::String>
L<psgconf-intro>
L<File::Basename>
=cut
syntax highlighted by Code2HTML, v. 0.9.1