#!/usr/bin/perl $OSDEF = `uname` ; chomp($OSDEF); use Getopt::Long ; use subs qw( error_exit usage precheck generic_check perl_module_check print_ok print_notok print_info print_verbose ); $VERSION = "1.0" ; @Default_Tools_List = ( [ 'gzip' ,'app', '' , 'generic_check' ], [ 'gunzip' ,'app', '' , 'generic_check' ], [ 'tar', ,'app', '' , 'generic_check' ], [ 'tr', ,'app', '' , 'generic_check' ], [ 'date' ,'app', '' , 'generic_check' ], [ 'ps', ,'app', '' , 'generic_check' ], [ 'cat', ,'app', '' , 'generic_check' ], [ 'id', ,'app', '' , 'generic_check' ], [ 'echo' ,'app', '' , 'generic_check' ], [ 'pwd', ,'app', '' , 'generic_check' ], [ 'chmod' ,'app', '' , 'generic_check' ], [ 'ln', ,'app', '' , 'generic_check' ], [ 'cp', ,'app', '' , 'generic_check' ], [ 'rpm', ,'app', '' , 'generic_check' ], [ 'clear' ,'app', '' , 'generic_check' ], [ 'dirname' ,'app', '' , 'generic_check' ], [ 'df' ,'app', '' , 'generic_check' ], [ 'Carp' ,'perlm', 'Perl Module - Carp', 'perl_module_check' ], ) ; $Tools_Hash = \@Default_Tools_List ; $Debug = 1; @default_paths = qw( /bin /usr/bin /usr/sbin /usr/local/bin ); $progname = "ensure" ; $KSH = "/bin/ksh" ; $PERL = "/usr/bin/perl" ; %precheck_stuff = ($KSH, $PERL); $res = GetOptions( "v" => \$verbose, "q" => \$quiet, "h" => \$help, "s" => \$skip_default_checking, "o" => \$check_only_mypath, "l" => \$list_items, "e=s" => \$exclude_list, "c=s" => \$implicit_list, "p=s" => \$more_paths, "x=s" => \$extra_tools, "f=s" => \$tools_from_file, ); #------ Option Processing ----------------# if(! $res || defined($help)) { usage(); exit(1); } if (defined($check_only_mypath)) { $ENV{'PATH'} = "." ; } else { $ENV{'PATH'} = join(":", ($ENV{'PATH'}, @default_paths)); } @paths_to_check = split(/:/, $ENV{'PATH'}); if (defined($more_paths)) { chomp($more_paths); my @more_paths = split(/\s+/, $more_paths); foreach my $path (@more_paths) { if( -d $path || -l $path ) { push(@paths_to_check, $path ); } } } $Debug = 2 if(defined($verbose)); $Debug = 0 if(defined($quiet)) ; if(!defined($skip_default_checking)) { foreach my $comp ( @{$Tools_Hash} ) { my $entity = $comp->[0] ; $things_to_check{$entity} = 1 ; } } if (defined($extra_tools)) { chomp($extra_tools); my @extra_tools_tochk = split(/\s+/, $extra_tools); foreach $elem (@extra_tools_tochk) { push(@{$Tools_Hash}, [ $elem, 'app', $elem, 'generic_check']); $things_to_check{$elem} = 1; } } if (defined($tools_from_file)) { chomp($tools_from_file); open(TL,"$tools_from_file") or die "Can't open file $tools_from_file for reading: $!\n" ; my @TList = ; close(TL); my @extra_tools_tochk ; foreach my $l (@TList) { chomp($l); push (@extra_tools_tochk, split(/\s+/, $l)); } foreach my $elem (@extra_tools_tochk) { push(@{$Tools_Hash}, [ $elem, 'app', $elem, 'generic_check']); $things_to_check{$elem} = 1; } } if (defined($exclude_list)) { chomp($exclude_list); my @exclude_checks = split(/\s+/, $exclude_list); foreach $elem (@exclude_checks) { $things_to_check{$elem} = 0 ; } } if (defined($implicit_list)) { chomp($implicit_list); my @implicit_checks = split(/\s+/, $implicit_list); if(@implicit_checks) { foreach $elem (keys(%things_to_check)) { $things_to_check{$elem} = 0 ; } } foreach $elem (@implicit_checks) { if(!exists($things_to_check{$elem})) { push(@{$Tools_Hash}, [ $elem, 'app', $elem, 'generic_check']); } $things_to_check{$elem} = 1 ; } } if(defined($list_items)) { foreach my $t ( keys(%things_to_check) ) { print "$t\n" if($things_to_check{$t} == 1); } exit(0); } #-------------- START: Main Program -------------------# $Failed = 0; $cf_flen = 40 ; precheck(); # its funny to check for perl inside a perl program :) foreach $component ( @{$Tools_Hash} ) { my $entity = $component->[0] ; # first thing is the entity to check. if($things_to_check{$entity} == 1 ) { $check_function = $component->[-1] ; # last thing is the function to check. $ret = \&$check_function($entity, splice(@{$component},1,-1)); #rest of the inbetween things are args to function. } } if($Failed == 1) { exit(1); } else { exit(0); } #------------- END: Main Program -------------------# sub error_exit { print STDERR @_ , "\n" ; exit(1); } sub usage { print < ] [ -c ] [ -x ] [ -f ] -l list the checking items -q deal quiet. just give the final return status. -v verbose output. -h show this help message. -e exclude checking list of items (separated by space. use '') -s skip default tools checking. (check only implicit or from file) -c check only listed items (separated by space. use '' ) -x additionaly check the listed items ( separated by space. use '') -f read the additional tools list from file ( one per line) -p add the provided paths (space separated ) to the list of search path. -o search only in given paths (otherwise, dont check in default paths). HELP } # Check to see, if we can check others. sub precheck { my $ret = 0; for $ent (@precheck_stuff) { if( ! -f $ent ) { print_info "$ent not found\n" ; $ret = 1 if($ret == 0); } } error_exit("Exiting") if($ret); return(0); } # This is generic_check for all tools. It will search for a particular tool in all directory in PATH variable, # and also in user provided directories if anything. sub generic_check { my($entity, @ent_args ) = @_ ; my $found = 0; ($type, $string ) = @ent_args ; $string = $entity if($string eq "" ) ; $show_user = "Checking for $string ..."; print_info sprintf "%-${cf_flen}s", $show_user ; $| = 1; # first check for simple existence. if found set status and return # else foreach path - attach the entity and check for existence -f . if found stop checking set status and return. # if not found return 1 print_verbose("\n checking for $entity ") ; if( -f $entity ) { $found = 1 ; print_verbose(" found\n"); } else { print_verbose("\n"); foreach $path (@paths_to_check) { $abscmd = "$path/$entity" ; print_verbose(" checking for $abscmd ") ; if( -f $abscmd ) { $found = 1 ; print_verbose(" found\n"); last ; } else { print_verbose("\n"); } } } if($found) { print_ok(); return(0); } else { $Failed = 1; print_notok(); return(1); } } sub perl_module_check { my($entity, @ent_args ) = @_ ; ($type, $string ) = @ent_args ; $string = $entity if($string eq "" ) ; $show_user = "Checking for $string ..."; print_info sprintf "%-${cf_flen}s", $show_user ; $| = 1; $ret = system("$KSH -c '$PERL -M$entity -e 0' 2>/dev/null"); if(($ret >> 8) == 0) { print_ok(); return(0); } else { $Failed = 1; print_notok(); return(1); } } sub print_ok { print_info " ok\n" ; } sub print_notok { print_info " not found\n" ; } sub print_info { if($Debug > 0) { print STDOUT @_ ; } } sub print_verbose { if($Debug > 1) { print STDOUT @_ ; } } __END__ =pod =head1 NAME ensure - Ensure that the environment is good. =head1 SYNOPSIS ensure [-lqvhso ] [-e ] [ -c ] [ -x ] [ -f ] [-p ] -l list the checking items -q deal quiet. just give the final return status. -v verbose output. -h show this help message. -s skip default tools checking. (check only implicit or from file) -o search only in given paths (otherwise, dont check in default paths). -e exclude checking list of items (separated by space. use '') -c check only listed items (separated by space. use '' ) -x additionaly check the listed items ( separated by space. use '') -f read the additional tools list from file ( one per line) -p additional paths to search for. (space separated ) =head1 DESCRIPTION This tool checks for necessary programs in the environment ( aka. PATH ) like gzip, tar, ls, cp, rm, etc., and report if anything is not found. It also returns '1' in case of failure and 0 if all tools are found. This tool can be used as pre checking script before attempting any shell script/perl related installation, upgrade of any software. In case of failure you can just abort the task and report the user to make it available. This is inspired by "configure" script in Open source packages (C, C++ ) which checks for the system for minimum requirement before even compiling the software. =head1 OPTIONS -l - list the name of the tools prepared to check and exit. Don't check actually. -q - Do everything in quiet mode, dont display anything. Just return 0 or 1 on sucess or failure respectively. -v - show what is happening internally, verbose display. -h - display help message and exit. -e - exclude the list of provided items for checking. For eg. ./ensure -e 'gzip tar md5sum' -c - check only list of provided items. This can be useful for single tool testing. For eg. ./ensure -c 'gzip tar md5sum' -x - In addition to default tools, check also the listed items with this option. For eg. ./ensure -x 'gzip tar md5sum' -f - Take the list of items to check from the provided file. (separated by one of "\n\t") -o - check only in the given paths,( see -p ) not in default $PATH content. -p - add provided (space separated paths) to the list of paths to search. -s - skip default tools checking. (check only provided list. see -c -x -f ) =head1 EXAMPLES =head2 Simple Run [user@host:~]$ ./ensure Checking for gzip ... ok Checking for gunzip ... ok Checking for tar ... ok Checking for tr ... ok Checking for date ... ok Checking for ps ... ok Checking for cat ... ok Checking for id ... ok Checking for echo ... ok Checking for pwd ... ok Checking for chmod ... ok Checking for ln ... ok Checking for cp ... ok Checking for rpm ... ok Checking for clear ... ok Checking for dirname ... ok Checking for df ... ok Checking for Perl Module - Carp ... ok =head2 Exclude checking [user@host:~]$ ./ensure -e 'df gunzip gzip cat rpm clear dirname' Checking for tar ... ok Checking for tr ... ok Checking for date ... ok Checking for ps ... ok Checking for id ... ok Checking for echo ... ok Checking for pwd ... ok Checking for chmod ... ok Checking for ln ... ok Checking for cp ... ok Checking for Perl Module - Carp ... ok =head2 Implicit Checking [user@host:~]$ ./ensure -c 'ls rm cp' Checking for cp ... ok Checking for ls ... ok Checking for rm ... ok =head2 Skip Default checking and pick the list from provided file (stdin) [user@host:~]$ ./ensure -s -f - fdisk awk at atrm crontab ^D Checking for fdisk ... ok Checking for awk ... ok Checking for at ... ok Checking for atrm ... ok Checking for crontab ... ok [user@host:~]$ =head2 Skip default checking(-s), Search only in provided paths (-o, -p), Check only listed items. The following checking failed, because all the listed tools are available in /bin [user@host:~]$ ./ensure -o -s -p '/usr/bin' -c 'ls cp rm' Checking for cp ... not found Checking for ls ... not found Checking for cp ... not found Checking for rm ... not found [user@host:~]$ =head1 TODO As of now only default tools existence check can be added or removed. For any other Perl Module existence checking, we need to add the elements in array inside the program. This needs to be customized. Needs to check anything, even particular options to programs. =head1 AUTHOR S.Murali Krishnan