3 =head1 NAME $RCSfile: Utils.pm,v $
5 Utils - Simple and often used utilities
13 Andrew DeFaria <Andrew@ClearSCM.com>
21 Thu Jan 5 15:15:29 PST 2006
25 $Date: 2013/03/28 21:18:55 $
31 This module seeks to encapsulate useful utilities, things that are often done
32 over and over again but who's classification is miscellaneous.
36 my @children = GetChildren ($pid);
38 my @lines = ReadFile ("/tmp/file");
40 print "Found foo!\n" if InArray ("foo", @bar);
42 my ($status, @output) = Execute ("ps -ef");
46 A collection of utility type subroutines.
50 The following routines are exported:
63 use POSIX qw (setsid);
94 # In case the user hits Ctrl-C
95 print "\nControl-C\n";
103 my ($requiredFields, $rec) = @_;
105 my $msg = RequiredFields($requiredFields, $rec);
107 my $function = (caller(1))[3];
108 my $calledFrom = (caller(2))[3];
109 my $lineNbr = (caller(2))[2];
111 croak "Internal error: $function called from $calledFrom:$lineNbr\n\nThe field $msg" if $msg;
116 sub EnterDaemonMode(;$$$) {
117 my ($logfile, $errorlog, $pidfile) = @_;
121 =head2 EnterDaemonMode ($logfile, $errorlog)
123 There is a right way to enter "daemon mode" and this routine is for that. If you
124 call EnterDaemonMode your process will be disassociated from the terminal and
125 enter into a background mode just like a good daemon.
129 =for html <blockquote>
135 File name of where to redirect STDOUT for the daemon (Default: $NULL)
139 File name of where to redirect STDERR for the daemon (Default: $NULL)
143 =for html </blockquote>
147 =for html <blockquote>
155 =for html </blockquote>
164 # Redirect STDIN to $NULL
165 open STDIN, '<', $NULL
166 or error "Can't read $NULL ($!)", 1;
168 # Redirect STDOUT to logfile
169 open STDOUT, '>>', $logfile
170 or error "Can't write to $logfile ($!)", 1;
172 # Redirect STDERR to errorlog
173 open STDERR, '>>', $errorlog
174 or error "Can't write to $errorlog ($!)", 1;
176 # Change the current directory to /
177 my $ROOT = $ARCHITECTURE eq "windows" ? "C:\\" : "/";
179 or error "Can't chdir to $ROOT ($!), 1";
184 # Now fork the daemon
185 defined (my $pid = fork)
186 or error "Can't create daemon ($!)", 1;
188 # Now the parent exits
191 # Write pidfile if specified
193 $pidfile = File::Spec->rel2abs ($pidfile);
195 open $file, '>', $pidfile
196 or warning "Unable to open pidfile $pidfile for writing - $!";
203 # Set process to be session leader
205 or error "Can't start a new session ($!)", 1;
215 =head2 Execute ($command)
217 We all execute OS commands and then have to deal with the output and return
218 codes and the like. How about an easy Execute subroutine. It takes one
219 parameter, the command to execute, executes it and returns two parameters, the
220 output in a nice chomped array and the status.
224 =for html <blockquote>
234 =for html </blockquote>
238 =for html <blockquote>
242 =item A status scalar and an array of lines output from the command (if any).
244 Note, no redirection of STDERR is included. If you want STDERR included in
245 STDOUT then do so in the $command passed in.
249 =for html </blockquote>
253 local $SIG{CHLD} = 'DEFAULT';
260 return wantarray ? ($status, @output) : $status;
263 sub GetChildren(;$) {
268 =head2 GetChildren ($pid)
270 Returns an array of children pids for the passed in $pid.
272 NOTE: This assumes that the utility pstree exists and is in the callers PATH.
276 =for html <blockquote>
282 $pid to return the subtree of (Default: pid of init)
286 =for html </blockquote>
290 =for html <blockquote>
294 =item Array of children pids
298 =for html </blockquote>
306 my @output = `pstree -ap $pid`;
308 return @children if $? == 0;
313 # Skip the pstree process and the parent process - we want only
315 next if /pstree/ or /\($pid\)/;
325 sub GetPassword(;$) {
330 =head2 GetPassword (;$prompt)
332 Prompt for a password
336 =for html <blockquote>
342 Prompt string to use (Default: "Password:")
346 =for html </blockquote>
350 =for html <blockquote>
358 =for html </blockquote>
362 $prompt ||= 'Password';
370 $SIG{INT} = \&_restoreTerm;
377 while (not defined ($key = ReadKey -1)) { }
379 if ($key =~ /(\r|\n)/) {
386 if ($key eq chr(127)) {
387 unless ($password eq '') {
399 ReadMode 'restore'; # Reset tty mode before exiting.
401 $SIG{INT} = 'DEFAULT';
407 my ($item, @array) = @_;
411 =head2 InArray ($item, @array)
413 Find an item in an array.
417 =for html <blockquote>
431 =for html </blockquote>
435 =for html <blockquote>
439 =item $TRUE if found - $FALSE otherwise
443 =for html </blockquote>
448 return $TRUE if $item eq $_;
460 Return an array of the 1, 5, and 15 minute load averages.
464 =for html <blockquote>
472 =for html </blockquote>
476 =for html <blockquote>
480 =item An array of the 1, 5, and 15 minute load averages in a list context.
481 In a scalar context just the 1 minute load average.
485 =for html </blockquote>
488 # TODO: Make it work on Windows...
489 return if $^O =~ /win/i;
491 open my $loadAvg, '<', '/proc/loadavg'
492 or croak "Unable to open /proc/loadavg\n";
494 my $load = <$loadAvg>;
498 my @loadAvgs = split /\s/, $load;
503 return $loadAvgs[0]; # This is the 1 minute average
508 my ($to, $existingPipe) = @_;
512 =head2 StartPipe ($to, $existingPipe)
518 =for html <blockquote>
524 String representing the other end of the pipe
528 Already existing pipe handle (from a previous call to StartPipe)
532 =for html </blockquote>
536 =for html <blockquote>
540 =item A $pipe to used for PipeOutput
544 =for html </blockquote>
551 open $existingPipe, '|-', $to
552 or error "Unable to open pipe - $!", 1;
554 return $existingPipe;
556 open $pipe, '|-', $to
557 or error "Unable to open pipe - $!", 1;
563 sub PipeOutputArray($@) {
564 my ($to, @output) = @_;
568 =head2 PipeOutputArray ($to, @ouput)
574 =for html <blockquote>
580 String representing the other end of the pipe to pipe @output to
588 =for html </blockquote>
592 =for html <blockquote>
600 =for html </blockquote>
604 open my $pipe, '|-', $to
605 or error "Unable to open pipe - $!", 1;
616 sub PipeOutput($;$) {
617 my ($line, $topipe) = @_;
621 =head2 PipeOutput ($line, $topipe)
623 Pipes a single line to $topipe
627 =for html <blockquote>
633 Line to output to $topipe.
637 A pipe returned by StartPipe (or our $pipe) to which the $line is piped.
641 =for html </blockquote>
645 =for html <blockquote>
653 =for html </blockquote>
659 chomp $line; chop $line if $line =~ /\r$/;
661 print $pipe "$line\n";
667 my ($pipeToStop) = @_;
671 =head2 StopPipe ($pipe)
677 =for html <blockquote>
687 =for html </blockquote>
691 =for html <blockquote>
699 =for html </blockquote>
703 $pipeToStop ||= $pipe;
705 close $pipeToStop if $pipeToStop;
715 =head2 PageOutput (@ouput)
717 Pages output to the screen
721 =for html <blockquote>
731 =for html </blockquote>
735 =for html <blockquote>
743 =for html </blockquote>
748 PipeOutputArray $ENV{PAGER}, @output;
757 sub RedirectOutput($$@) {
758 my ($to, $mode, @output) = @_;
762 =head2 RedirectOutput ($to, @ouput)
764 Pages output to the screen
768 =for html <blockquote>
774 Where to send the output
782 =for html </blockquote>
786 =for html <blockquote>
794 =for html </blockquote>
798 croak 'Mode must be > or >>'
799 unless ($mode eq '>' or $mode eq '>>');
801 open my $out, $mode, $to
802 or croak "Unable to open $to for writing - $!";
819 =head2 ReadFile ($filename)
821 How many times have you coded a Perl subroutine, or just staight inline Perl to
822 open a file, read all the lines into an array and close the file. This routine
823 does that very thing along with the associated and proper checking of open
824 failure and even trims the lines in the output array of trailing newlines? This
825 routine returns an array of the lines in the filename passed in.
829 =for html <blockquote>
839 =for html </blockquote>
843 =for html <blockquote>
847 =item Array of lines in the file
851 =for html </blockquote>
855 open my $file, '<', $filename
856 or error "Unable to open $filename ($!)", 1;
864 or error "Unable to close $filename ($!)", 1;
871 push @cleansed_lines, $_ if !/^#/; # Discard comment lines
874 return @cleansed_lines;
883 my ($total, $log) = @_;
887 =head2 Stats ($total, $log)
889 Reports runtime stats
893 =for html <blockquote>
899 Reference to a hash of total counters. The keys of the hash will be the labels
900 and the values of the hash will be the counters.
904 Logger object to log stats to (if specified). Note: if the Logger object has
905 errors or warnings then they will be automatically included in the output.
909 =for html </blockquote>
913 =for html <blockquote>
921 =for html </blockquote>
925 my $msg = "$FindBin::Script Run Statistics:";
927 if ($log and ref $log eq 'Logger') {
928 $total->{errors} = $log->{errors};
929 $total->{warnings} = $log->{warnings};
933 # Display statistics (if any)
940 for (sort keys %$total) {
941 $msg = $total->{$_} . "\t $_";
944 $log->msg ($total->{$_} . "\t $_");
961 Reports usage using perldoc
965 =for html <blockquote>
971 Message to output before doing perldoc
975 =for html </blockquote>
979 =for html <blockquote>
983 =item Does not return
987 =for html </blockquote>
991 display $msg if $msg;
998 sub RequiredFields($$) {
1002 =head2 RequiredFields($total, $log)
1004 Check if a list of fields are contained in a hash
1008 =for html <blockquote>
1014 Array reference to a list of field names that are required
1018 Hash reference whose key values we are checking
1022 =for html </blockquote>
1026 =for html <blockquote>
1032 Returns either an empty string or a string naming the first missing required
1037 =for html </blockquote>
1041 my ($fields, $rec) = @_;
1043 for my $fieldname (@$fields) {
1047 if ($fieldname eq $_) {
1053 return "$fieldname is required" unless $found;
1065 =head1 CONFIGURATION AND ENVIRONMENT
1073 L<File::Spec|File::Spec>
1079 =head2 ClearSCM Perl Modules
1081 =for html <p><a href="/php/scm_man.php?file=lib/Display.pm">Display</a></p>
1083 =for html <p><a href="/php/scm_man.php?file=lib/Logger.pm">Logger</a></p>
1085 =for html <p><a href="/php/scm_man.php?file=lib/OSDep.pm">OSDep</a></p>
1087 =head1 INCOMPATABILITIES
1091 =head1 BUGS AND LIMITATIONS
1093 There are no known bugs in this module.
1095 Please report problems to Andrew DeFaria <Andrew@ClearSCM.com>.
1097 =head1 LICENSE AND COPYRIGHT
1099 This Perl Module is freely available; you can redistribute it and/or modify it
1100 under the terms of the GNU General Public License as published by the Free
1101 Software Foundation; either version 2 of the License, or (at your option) any
1104 This Perl Module is distributed in the hope that it will be useful, but WITHOUT
1105 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1106 FOR A PARTICULAR PURPOSE. See the GNU General Public License
1107 (L<http://www.gnu.org/copyleft/gpl.html>) for more details.
1109 You should have received a copy of the GNU General Public License along with
1110 this Perl Module; if not, write to the Free Software Foundation, Inc., 59
1111 Temple Place - Suite 330, Boston, MA 02111-1307, USA. reserved.