### ### 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 () { 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: Control PSGConf::Control::InitScripts =head1 DESCRIPTION The B module provides a B 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 object. It registers the following data objects: =over 4 =item I A B of Hashes, where the primary key is the name of the RC script to process. Sub keys include: =over 4 =item I A B object taking the values F, F or F. =item I A B which contains the fully qualfied file name for the script (or the script to disable in the case of F on AIX systems). =item I A B object describing what the script does. This will be used in the F formatting information put into the script itself. =item I A B object containing the variable to put into the F file on FreeBSD. Values will be set to C or C, determined by what I is set to (C or C). =item I A B object telling this Control module whether or not to maintain the sym links in the C directories. Gets F from the I hash. =item I A B 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 A B object telling this Control module to create the RC script, based on what the I and I are set to. =item I A B object with the command to execute when this RC script is run at boot time. =item I A B object with the command to execute when this RC script is run at shutdown time. =item I A B object with the command to execute when this service needs to be restarted. Defaults to running the I followed by the I. =item I A B 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, respectively. Also it supports expansion of any B directive via I<%{directive}> syntax. =item I A B 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, respectively. Also it supports expansion of any B directive via I<%{directive}> syntax. =item I A B 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, respectively. Also it supports expansion of any B directive via I<%{directive}> syntax. =item I A B 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, respectively. Also it supports expansion of any B directive via I<%{directive}> syntax. =back =item I A B object to determine what to do with RC scripts that have been found on the system but are not in the I hash. Valid values are I, I and I. The default is I. =item I A B 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. =item I A B 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 Updates the I hash to have all RC scripts that were found by I command and sets their I to the value if I, if it is not set to C. =item I Updates the I hash (B) with the values using the I and I values in the I hash. =back =item decide() Instantiates and registers action objects, as follows: =over 4 =item * A B or B Action object to generate the RC script for each script B is going to maintain. =item * A B Action to enable or disable the RC script, depending on the result from the I or I command. =item * A B or B Action object to maintain the I sym links. =back =back =head1 SEE ALSO L L L L L L L L L L =cut