Apache-Logmonster
view release on metacpan or search on metacpan
lib/Apache/Logmonster/Utility.pm view on Meta::CPAN
use Carp;
use English qw( -no_match_vars );
use File::Basename;
use File::Copy;
use File::Path;
use File::Spec;
use File::stat;
use Params::Validate qw(:all);
use Scalar::Util qw( openhandle );
use URI;
use lib 'lib';
use vars qw/ $log %std_opts /;
sub new {
my $class = shift;
# globally scoped hash, populated with defaults as requested by the caller
%std_opts = (
'fatal' => { type => BOOLEAN, optional => 1, default => 1 },
'debug' => { type => BOOLEAN, optional => 1, default => 1 },
'quiet' => { type => BOOLEAN, optional => 1, default => 0 },
'test_ok' => { type => BOOLEAN, optional => 1 },
);
my %p = validate( @_,
{ toaster=> { type => OBJECT, optional => 1 },
%std_opts,
}
);
my $toaster = $p{toaster};
my $self = {
debug => $p{debug},
fatal => $p{fatal},
};
bless $self, $class;
$log = $self->{log} = $self;
$log->audit( $class . sprintf( " loaded by %s, %s, %s", caller ) );
return $self;
}
sub ask {
my $self = shift;
my $question = shift;
my %p = validate(
@_,
{ default => { type => SCALAR|UNDEF, optional => 1 },
timeout => { type => SCALAR, optional => 1 },
password => { type => BOOLEAN, optional => 1, default => 0 },
test_ok => { type => BOOLEAN, optional => 1 },
}
);
my $pass = $p{password};
my $default = $p{default};
if ( ! $self->is_interactive() ) {
$log->audit( "not running interactively, can not prompt!");
return $default;
}
return $log->error( "ask called with \'$question\' which looks unsafe." )
if $question !~ m{\A \p{Any}* \z}xms;
my $response;
return $p{test_ok} if defined $p{test_ok};
PROMPT:
print "Please enter $question";
print " [$default]" if ( $default && !$pass );
print ": ";
system "stty -echo" if $pass;
if ( $p{timeout} ) {
eval {
local $SIG{ALRM} = sub { die "alarm\n" };
alarm $p{timeout};
$response = <STDIN>;
alarm 0;
};
if ($EVAL_ERROR) {
$EVAL_ERROR eq "alarm\n" ? print "timed out!\n" : warn;
}
}
else {
$response = <STDIN>;
}
if ( $pass ) {
print "Please enter $question (confirm): ";
my $response2 = <STDIN>;
unless ( $response eq $response2 ) {
print "\nPasswords don't match, try again.\n";
goto PROMPT;
}
system "stty echo";
print "\n";
}
chomp $response;
return $response if $response; # if they typed something, return it
return $default if $default; # return the default, if available
return ''; # return empty handed
}
sub audit {
my $self = shift;
my $mess = shift;
my %p = validate( @_, { %std_opts } );
if ($mess) {
push @{ $log->{audit} }, $mess;
print "$mess\n" if $self->{debug} || $p{debug};
}
lib/Apache/Logmonster/Utility.pm view on Meta::CPAN
};
#$r = system $cmd;
$r = `$cmd 2>&1`;
alarm 0 if defined $p{timeout};
};
if ($EVAL_ERROR) {
if ( $EVAL_ERROR eq "alarm\n" ) {
$log->audit("timed out");
}
else {
return $log->error( "unknown error '$EVAL_ERROR'", %args);
}
}
$ENV{PATH} = $before_path; # set PATH back to original value
my @caller = caller;
return $self->syscmd_exit_code( $r, $CHILD_ERROR, \@caller, \%args );
}
sub syscmd_exit_code {
my $self = shift;
my ($r, $err, $caller, $args) = @_;
$log->audit( "r: $r" );
my $exit_code = sprintf ("%d", $err >> 8);
return 1 if $exit_code == 0; # success
#print 'error # ' . $ERRNO . "\n"; # $! == $ERRNO
$log->error( "$err: $r",fatal=>0);
if ( $err == -1 ) { # check $? for "normal" errors
$log->error( "failed to execute: $ERRNO", fatal=>0);
}
elsif ( $err & 127 ) { # check for core dump
printf "child died with signal %d, %s coredump\n", ( $? & 127 ),
( $? & 128 ) ? 'with' : 'without';
}
return $log->error( "$err: $r", location => join( ", ", @$caller ), %$args );
};
sub yes_or_no {
my $self = shift;
my $question = shift;
my %p = validate(
@_,
{ 'timeout' => { type => SCALAR, optional => 1 },
'force' => { type => BOOLEAN, optional => 1, default => 0 },
%std_opts
},
);
# for 'make test' testing
return 1 if $question eq "test";
# force if interactivity testing is not working properly.
if ( !$p{force} && !$self->is_interactive ) {
carp "not running interactively, can't prompt!";
return;
}
my $response;
print "\nYou have $p{timeout} seconds to respond.\n" if $p{timeout};
print "\n\t\t$question";
# I wish I knew why this is not working correctly
# eval { local $SIG{__DIE__}; require Term::ReadKey };
# if ($@) { #
# require Term::ReadKey;
# Term::ReadKey->import();
# print "yay, Term::ReadKey is present! Are you pleased? (y/n):\n";
# use Term::Readkey;
# ReadMode 4;
# while ( not defined ($key = ReadKey(-1)))
# { # no key yet }
# print "Got key $key\n";
# ReadMode 0;
# };
if ( $p{timeout} ) {
eval {
local $SIG{ALRM} = sub { die "alarm\n" };
alarm $p{timeout};
do {
print "(y/n): ";
$response = lc(<STDIN>);
chomp($response);
} until ( $response eq "n" || $response eq "y" );
alarm 0;
};
if ($@) {
$@ eq "alarm\n" ? print "timed out!\n" : carp;
}
return ($response && $response eq "y") ? 1 : 0;
}
do {
print "(y/n): ";
$response = lc(<STDIN>);
chomp($response);
} until ( $response eq "n" || $response eq "y" );
return ($response eq "y") ? 1 : 0;
}
1;
__END__
=head1 SYNOPSIS
use Apache::Logmonster::Utility;
my $toaster = Apache::Logmonster::Utility->new;
$util->file_write($file, lines=> @lines);
This is just one of the many handy little methods I have amassed here. Rather than try to remember all of the best ways to code certain functions and then attempt to remember them, I have consolidated years of experience and countless references from...
=head1 DESCRIPTION
This Apache::Logmonster::Utility package is my most frequently used one. Each method has its own documentation but in general, all methods accept as input a hashref with at least one required argument and a number of optional arguments.
=head1 DIAGNOSTICS
All methods set and return error codes (0 = fail, 1 = success) unless otherwise stated.
Unless otherwise mentioned, all methods accept two additional parameters:
debug - to print status and verbose error messages, set debug=>1.
fatal - die on errors. This is the default, set fatal=>0 to override.
=head1 DEPENDENCIES
Perl.
Scalar::Util - built-in as of perl 5.8
Almost nothing else. A few of the methods do require certian things, like extract_archive requires tar and file. But in general, this package (Apache::Logmonster::Utility) should run flawlessly on any UNIX-like system. Because I recycle this package ...
=head1 METHODS
=over
=item new
To use any of the methods below, you must first create a utility object. The methods can be accessed via the utility object.
############################################
# Usage : use Apache::Logmonster::Utility;
# : my $util = Apache::Logmonster::Utility->new;
# Purpose : create a new Apache::Logmonster::Utility object
# Returns : a bona fide object
# Parameters : none
############################################
=item ask
Get a response from the user. If the user responds, their response is returned. If not, then the default response is returned. If no default was supplied, 0 is returned.
############################################
# Usage : my $ask = $util->ask( "Would you like fries with that",
# default => "SuperSized!",
# timeout => 30
# );
# Purpose : prompt the user for information
#
# Returns : S - the users response (if not empty) or
# : S - the default ask or
# : S - an empty string
#
# Parameters
# Required : S - question - what to ask
# Optional : S - default - a default answer
# : I - timeout - how long to wait for a response
# Throws : no exceptions
# See Also : yes_or_no
=item extract_archive
Decompresses a variety of archive formats using your systems built in tools.
############### extract_archive ##################
# Usage : $util->extract_archive( 'example.tar.bz2' );
# Purpose : test the archiver, determine its contents, and then
# use the best available means to expand it.
# Returns : 0 - failure, 1 - success
# Parameters : S - archive - a bz2, gz, or tgz file to decompress
=item cwd_source_dir
Changes the current working directory to the supplied one. Creates it if it does not exist. Tries to create the directory using perl's builtin mkdir, then the system mkdir, and finally the system mkdir with sudo.
############ cwd_source_dir ###################
# Usage : $util->cwd_source_dir( "/usr/local/src" );
# Purpose : prepare a location to build source files in
# Returns : 0 - failure, 1 - success
# Parameters : S - dir - a directory to build programs in
=item check_homedir_ownership
Checks the ownership on all home directories to see if they are owned by their respective users in /etc/password. Offers to repair the permissions on incorrectly owned directories. This is useful when someone that knows better does something like "ch...
######### check_homedir_ownership ############
# Usage : $util->check_homedir_ownership();
# Purpose : repair user homedir ownership
# Returns : 0 - failure, 1 - success
# Parameters :
# Optional : I - auto - no prompts, just fix everything
# See Also : sysadmin
Comments: Auto mode should be run with great caution. Run it first to see the results and then, if everything looks good, run in auto mode to do the actual repairs.
=item chown_system
The advantage this sub has over a Pure Perl implementation is that it can utilize sudo to gain elevated permissions that we might not otherwise have.
############### chown_system #################
# Usage : $util->chown_system( dir=>"/tmp/example", user=>'matt' );
# Purpose : change the ownership of a file or directory
# Returns : 0 - failure, 1 - success
# Parameters : S - dir - the directory to chown
# : S - user - a system username
# Optional : S - group - a sytem group name
# : I - recurse - include all files/folders in directory?
# Comments : Uses the system chown binary
# See Also : n/a
=item clean_tmp_dir
############## clean_tmp_dir ################
# Usage : $util->clean_tmp_dir( $dir );
# Purpose : clean up old build stuff before rebuilding
# Returns : 0 - failure, 1 - success
# Parameters : S - $dir - a directory or file.
# Throws : die on failure
# Comments : Running this will delete its contents. Be careful!
=item get_mounted_drives
############# get_mounted_drives ############
# Usage : my $mounts = $util->get_mounted_drives();
# Purpose : Uses mount to fetch a list of mounted drive/partitions
# Returns : a hashref of mounted slices and their mount points.
=item archive_file
############### archive_file #################
# Purpose : Make a backup copy of a file by copying the file to $file.timestamp.
# Usage : my $archived_file = $util->archive_file( $file );
# Returns : the filename of the backup file, or 0 on failure.
# Parameters : S - file - the filname to be backed up
# Comments : none
=item chmod
Set the permissions (ugo-rwx) of a file. Will use the native perl methods (by default) but can also use system calls and prepend sudo if additional permissions are needed.
$util->chmod(
file_or_dir => '/etc/resolv.conf',
mode => '0755',
( run in 0.814 second using v1.01-cache-2.11-cpan-6aa56a78535 )