#!/usr/local/bin/perl
###
### Copyright 2000-2007 University of Illinois Board of Trustees
### All rights reserved.
###
### psgconf - driver script for psgconf framework
###
### Campus Information Technologies and Educational Services
### University of Illinois at Urbana-Champaign
###
use strict;
use warnings;
use Getopt::Long;
use POSIX;
use File::Basename;
use File::stat;
use PSGConf;
our $VERSION = '3.2.4';
###############################################################################
### Initialization
###############################################################################
my ($psgconf, %opts, $ignore_lock, $created_lock);
my ($display_policy_methods, $display_data_objs, $display_data_objs_and_vals);
my ($num_changed);
$0 = basename $0;
my $lockfile = '/usr/local/etc/psgconf.lock';
$| = 1;
umask 0022;
%opts = (
myname => $0,
update_pkgs => 1,
restart_daemons => 1,
rm_tmpfiles => 1
);
### Parse command line
Getopt::Long::Configure('bundling');
GetOptions(
'c=s' => \$opts{config_file},
'd' => \$opts{do_diffs},
'D' => \$display_data_objs,
'E:s' => \$display_data_objs_and_vals,
'e' => sub { $opts{update_pkgs} = 0; },
'f' => \$opts{do_fix},
'F=s' => \$opts{files_dir},
'h' => sub { print_usage(); },
'I=s' => \$opts{config_dir},
'l:s' => sub {
$opts{lock_msg} = $_[1];
$opts{verbose} = 1;
lock_set();
exit 0;
},
'L' => \$ignore_lock,
'm=s' => \$opts{modules_file},
'o=s' => \%opts,
'P' => \$display_policy_methods,
'R' => sub { $opts{restart_daemons} = 0 },
't' => sub { $opts{rm_tmpfiles} = 0 },
'T' => \$opts{trace},
'u' => sub {
$opts{verbose} = 1;
lock_clear();
exit 0;
},
'v+' => \$opts{verbose},
'V' => sub {
print "psgconf-$VERSION by the University of Illinois\n";
exit 0;
}
);
### special checking for fix mode
if ($opts{do_fix})
{
### only root can run in fix mode
die $0 . ": must be root to run in fix mode\n"
if ($> != 0);
### create lockfile
if (! $ignore_lock)
{
lock_set();
$created_lock = 1;
}
}
$SIG{'INT'} = \&die_on_signal;
$SIG{'QUIT'} = \&die_on_signal;
$SIG{'HUP'} = \&die_on_signal;
$SIG{'PIPE'} = \&die_on_signal;
$SIG{'TERM'} = \&die_on_signal;
$SIG{__DIE__} = \&die_on_signal;
###############################################################################
### initialize PSGConf module
###############################################################################
$psgconf = PSGConf->new(%opts)
|| die "cannot instantiate PSGConf module\n";
if ($display_data_objs)
{
my $href = $psgconf->get_all_data();
printf("%-25s %-25s %-25s\n", 'NAME', 'TYPE', 'OWNER');
map {
printf("%-25s %-25s %-25s\n", $_, @{$href->{$_}});
} sort keys %$href;
exit(0);
}
if ($display_policy_methods)
{
my $href = $psgconf->get_all_policy();
printf("%-35s %s\n", 'NAME', 'OWNER');
map {
printf("%-35s %s\n", $_, ref($href->{$_}->{control_obj}));
} sort keys %$href;
exit(0);
}
$psgconf->access_data_stores();
$psgconf->enforce_policy();
if (defined $display_data_objs_and_vals)
{
my ($href, $h, $res);
if ( $display_data_objs_and_vals gt 0 ) {
$href = { $display_data_objs_and_vals => undef };
} else {
$href = $psgconf->get_all_data();
printf("%-25s %-25s\n", 'NAME', 'VALUE');
}
foreach $h ( sort keys %$href )
{
$res = &_print_element ($psgconf->data_obj($h)->get());
printf "%-25s %s\n", $h, ($res)? "$res;": '';
}
exit(0);
}
$psgconf->instantiate_actions();
$psgconf->process_actions();
$num_changed = $psgconf->cleanup();
lock_clear()
if ($created_lock);
exit($num_changed);
########################################################################
### Subroutines
########################################################################
# die_on_signal
#
# Arguments: $_[0] - signal to handle or die/warn msg string.
# Returns: if we are in an eval block, otherwise does not.
sub die_on_signal
{
my ($sig) = @_;
###
### Check to see if we are in an eval block
### or really 'die'ing (being in an eval block
### $^S is set to 1, not depends on the version
### of perl (undef in 5.6.x, 0 in 5.8.x))
###
if ( ! defined $^S || $^S != 1 ) {
###
### Call cleanup explicitly because undef $psgconf
### is not doing it for us. This prevents the cleanup
### code being called after the lock has been released,
### in most cases (except when you <CTRL>C in DataStore::
### routines).
###
$psgconf->cleanup()
if ( defined $psgconf );
&lock_clear()
if ($created_lock);
###
### Massage the error message if we caught a signal
###
$sig = $0 . ": caught SIG" . $sig
if ( $sig =~ /^[A-Z]*$/o );
die "\n\n$sig\n";
exit (1);
}
}
# lock_test
#
# See if the lock is already set, and if so, print a message
sub lock_test
{
if (-f $lockfile && ! $ignore_lock)
{
my ($stat, $time, $text);
($stat) = stat($lockfile);
$time = localtime($stat->ctime);
open (LOCKFILE, $lockfile)
|| die "Could not read lockfile $lockfile\n";
$text = join ('', <LOCKFILE>);
close LOCKFILE;
warn $0 . ": lockfile '$lockfile' exists (created $time)\n$text";
return 1;
}
return 0;
}
# lock_set
#
# Create lockfile and exit
sub lock_set
{
if (! &lock_test()) {
die $0 . ": open('$lockfile')"
if (!open(LOCKFILE, ">$lockfile"));
if ( defined $opts{lock_msg} ) {
printf LOCKFILE "By Admin: %s\n%s\n",
(exists $ENV{'USER'})
? $ENV{'USER'}
: (exists $ENV{'LOGNAME'})
? $ENV{'LOGNAME'}
: 'root',
$opts{lock_msg};
} else {
printf LOCKFILE "By PID: $$\n";
}
close LOCKFILE;
print $0 . ": created lockfile '$lockfile'\n"
if ( $opts{verbose} );
} else {
exit 1;
}
}
# lock_clear
#
# Remove lockfile and exit
sub lock_clear
{
if ( -f $lockfile ) {
unlink($lockfile) ||
die $0 . ": unlink('$lockfile')";
print $0 . ": removed lockfile '$lockfile'\n"
if ( $opts{verbose} );
}
}
# print_usage
#
# Does what you think it does
sub print_usage
{
print STDERR <<EOF;
Usage: $0 [options]
Options:
-c file Use config file "file" (default is /usr/local/etc/psg.conf)
-d Show changes psgconf would make to system files
-D Display known data objects and exit without doing anything
-e Don't update software packages
-E [DIR] Display the value of all the known directives or DIR
-f Perform fix operations (not just system check)
-F dir Specifies the location of the files directory
-h Show this text and exit
-I dir Specifies the location of the config directory
-l [MSG] Lock (creates lockfile, recording optional message, MSG)
-L Ignore lock file in fix mode
-m file Use module list from "file" (default is /usr/local/etc/psgconf_modules)
-o opt=val Set option "opt" to value "val"
-P Display known policy methods and exit without doing anything
-R Don't restart daemons when config files change
-t Leave intermediate files behind for inspection
-T Trace object interactions (useful for debugging)
-u Unlock (removes lockfile)
-v Verbose output
-V Print version and exit
EOF
exit(1);
}
sub _print_element {
my ($e) = @_;
my ($res);
if ( ref ($e) eq 'ARRAY' ) {
$res = '[ ' if ( scalar @$e);
map {
$res .= (($res ne '[ ')? ', ': '') . &_print_element ($_);
} @$e;
$res .= ' ]' if ( scalar @$e);
} elsif ( ref ($e) eq 'HASH' ) {
$res = '{ ' if ( scalar %$e);
map {
$res .= (($res ne '{ ')? ', ': '')
. &_print_element ($_) .
((defined ($e->{$_}))? ' => ' .
&_print_element ($e->{$_}): '');
} sort keys %$e;
$res .= ' }' if ( scalar %$e);
} elsif ( defined $e ) {
$res = (($e =~ /[\.\/\-\* ]/o )? "\"": '')
. $e
. (($e =~ /[\.\/\-\* ]/o )? "\"": '');
}
return $res;
}
###############################################################################
### documentation
###############################################################################
__END__
=head1 NAME
psgconf - modular, object-oriented system configuration framework
=head1 SYNOPSIS
psgconf [-dDefLPRtTv] [-E [DIR]] [-m modulesfile] [-c cfgfile] [-I cfgdir]
[-F filedir] [-o option=value]
psgconf -l
psgconf -u
=head1 DESCRIPTION
The B<psgconf> program is a simple command-line driver for the
B<PSGConf> module, which is the central object in the B<psgconf>
configuration system. For more information on the B<psgconf> system,
see L<psgconf-intro>.
The B<psgconf> program supports the following options:
=over 4
=item -c configfile
Use an alternate config file instead of F</usr/local/etc/psg.conf>.
Note that this has no effect when not using the
B<PSGConf::DataStore::ConfigFile> module.
This option is shorthand for C<-o config_file=configfile>.
=item -d
Show detailed information about necessary changes.
This option is shorthand for C<-o do_diffs=1>.
=item -D
Once all of the Control and DataStore modules are loaded, display a list
of all known Data objects. For each object, list the class of the
object and the Control module that registered it. When the list is
complete, exit without doing anything else.
=item -E [DIR]
Once all of the Control and DataStore modules are loaded, display a list
of all known Data objects and their values, unless I<DIR> is specified,
then just display that Data object.
=item -e
Do not update software packages.
This option is shorthand for C<-o update_pkgs=0>.
=item -f
Fix mode. This will actually implement the necessary changes on the
system.
This option is shorthand for C<-o do_fix=1>.
=item -F files_directory
Sets the path to the library directory. The default is
F</usr/local/share/psgconf/files>.
This option is shorthand for C<-o files_dir=files_directory>.
=item -I config_directory
Sets the path to the config directory. The default is
F</usr/local/share/psgconf/config>. Note that this has no effect when
not using the B<PSGConf::DataStore::ConfigFile> module.
This option is shorthand for C<-o config_dir=config_directory>.
=item -l
Create lockfile. B<psgconf> checks the lockfile in fix mode, so the
lockfile can be used to ensure that multiple copies of B<psgconf> do not
run at the same time. However, if the lockfile is more than 24 hours
old, it will be automatically deleted, and processing will continue.
=item -L
Ignore lockfile in fix mode.
=item -m modulesfile
Use an alternate modules file instead of F</usr/local/etc/psgconf_modules>.
This option is shorthand for C<-o modules_file=modulesfile>.
=item -o opt=val
Set option I<opt> to value I<val>.
=item -P
Once all of the Control modules are loaded, display a list of all known
policy methods. For each method, list the Control module that registered
it. When the list is complete, exit without doing anything else.
=item -R
Do not restart daemons when their configuration files change.
This option is shorthand for C<-o restart_daemons=0>.
=item -t
Do no remove temp files. This is sometimes useful for debugging.
This option is shorthand for C<-o rm_tmpfiles=0>.
=item -T
Trace object interactions. This is sometimes useful for debugging.
This option is shorthand for C<-o trace=1>.
=item -u
Remove lockfile.
=item -v
Verbose mode.
This option is shorthand for C<-o verbose=1>.
=item -V
Print version number and exit.
=back
=head1 SEE ALSO
L<perl>
L<PSGConf>
L<psgconf-intro>
=cut
syntax highlighted by Code2HTML, v. 0.9.1