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];
109 croak "Internal error: $function: $msg" if $msg;
114 sub EnterDaemonMode(;$$$) {
115 my ($logfile, $errorlog, $pidfile) = @_;
119 =head2 EnterDaemonMode ($logfile, $errorlog)
121 There is a right way to enter "daemon mode" and this routine is for that. If you
122 call EnterDaemonMode your process will be disassociated from the terminal and
123 enter into a background mode just like a good daemon.
127 =for html <blockquote>
133 File name of where to redirect STDOUT for the daemon (Default: $NULL)
137 File name of where to redirect STDERR for the daemon (Default: $NULL)
141 =for html </blockquote>
145 =for html <blockquote>
153 =for html </blockquote>
162 # Redirect STDIN to $NULL
163 open STDIN, '<', $NULL
164 or error "Can't read $NULL ($!)", 1;
166 # Redirect STDOUT to logfile
167 open STDOUT, '>>', $logfile
168 or error "Can't write to $logfile ($!)", 1;
170 # Redirect STDERR to errorlog
171 open STDERR, '>>', $errorlog
172 or error "Can't write to $errorlog ($!)", 1;
174 # Change the current directory to /
175 my $ROOT = $ARCHITECTURE eq "windows" ? "C:\\" : "/";
177 or error "Can't chdir to $ROOT ($!), 1";
182 # Now fork the daemon
183 defined (my $pid = fork)
184 or error "Can't create daemon ($!)", 1;
186 # Now the parent exits
189 # Write pidfile if specified
191 $pidfile = File::Spec->rel2abs ($pidfile);
193 open $file, '>', $pidfile
194 or warning "Unable to open pidfile $pidfile for writing - $!";
201 # Set process to be session leader
203 or error "Can't start a new session ($!)", 1;
213 =head2 Execute ($command)
215 We all execute OS commands and then have to deal with the output and return
216 codes and the like. How about an easy Execute subroutine. It takes one
217 parameter, the command to execute, executes it and returns two parameters, the
218 output in a nice chomped array and the status.
222 =for html <blockquote>
232 =for html </blockquote>
236 =for html <blockquote>
240 =item A status scalar and an array of lines output from the command (if any).
242 Note, no redirection of STDERR is included. If you want STDERR included in
243 STDOUT then do so in the $command passed in.
247 =for html </blockquote>
251 local $SIG{CHLD} = 'DEFAULT';
258 wantarray ? return ($status, @output) : $status;
261 sub GetChildren(;$) {
266 =head2 GetChildren ($pid)
268 Returns an array of children pids for the passed in $pid.
270 NOTE: This assumes that the utility pstree exists and is in the callers PATH.
274 =for html <blockquote>
280 $pid to return the subtree of (Default: pid of init)
284 =for html </blockquote>
288 =for html <blockquote>
292 =item Array of children pids
296 =for html </blockquote>
304 my @output = `pstree -ap $pid`;
306 return @children if $? == 0;
311 # Skip the pstree process and the parent process - we want only
313 next if /pstree/ or /\($pid\)/;
323 sub GetPassword(;$) {
328 =head2 GetPassword (;$prompt)
330 Prompt for a password
334 =for html <blockquote>
340 Prompt string to use (Default: "Password:")
344 =for html </blockquote>
348 =for html <blockquote>
356 =for html </blockquote>
360 $prompt ||= 'Password';
368 $SIG{INT} = \&_restoreTerm;
375 while (not defined ($key = ReadKey -1)) { }
377 if ($key =~ /(\r|\n)/) {
384 if ($key eq chr(127)) {
385 unless ($password eq '') {
397 ReadMode 'restore'; # Reset tty mode before exiting.
399 $SIG{INT} = 'DEFAULT';
405 my ($item, @array) = @_;
409 =head2 InArray ($item, @array)
411 Find an item in an array.
415 =for html <blockquote>
429 =for html </blockquote>
433 =for html <blockquote>
437 =item $TRUE if found - $FALSE otherwise
441 =for html </blockquote>
446 return $TRUE if $item eq $_;
458 Return an array of the 1, 5, and 15 minute load averages.
462 =for html <blockquote>
470 =for html </blockquote>
474 =for html <blockquote>
478 =item An array of the 1, 5, and 15 minute load averages in a list context.
479 In a scalar context just the 1 minute load average.
483 =for html </blockquote>
486 # TODO: Make it work on Windows...
487 return if $^O =~ /win/i;
489 open my $loadAvg, '<', '/proc/loadavg'
490 or croak "Unable to open /proc/loadavg\n";
492 my $load = <$loadAvg>;
496 my @loadAvgs = split /\s/, $load;
501 return $loadAvgs[0]; # This is the 1 minute average
506 my ($to, $existingPipe) = @_;
510 =head2 StartPipe ($to, $existingPipe)
516 =for html <blockquote>
522 String representing the other end of the pipe
526 Already existing pipe handle (from a previous call to StartPipe)
530 =for html </blockquote>
534 =for html <blockquote>
538 =item A $pipe to used for PipeOutput
542 =for html </blockquote>
549 open $existingPipe, '|-', $to
550 or error "Unable to open pipe - $!", 1;
552 return $existingPipe;
554 open $pipe, '|-', $to
555 or error "Unable to open pipe - $!", 1;
561 sub PipeOutputArray($@) {
562 my ($to, @output) = @_;
566 =head2 PipeOutputArray ($to, @ouput)
572 =for html <blockquote>
578 String representing the other end of the pipe to pipe @output to
586 =for html </blockquote>
590 =for html <blockquote>
598 =for html </blockquote>
602 open my $pipe, '|-', $to
603 or error "Unable to open pipe - $!", 1;
614 sub PipeOutput($;$) {
615 my ($line, $topipe) = @_;
619 =head2 PipeOutput ($line, $topipe)
621 Pipes a single line to $topipe
625 =for html <blockquote>
631 Line to output to $topipe.
635 A pipe returned by StartPipe (or our $pipe) to which the $line is piped.
639 =for html </blockquote>
643 =for html <blockquote>
651 =for html </blockquote>
657 chomp $line; chop $line if $line =~ /\r$/;
659 print $pipe "$line\n";
665 my ($pipeToStop) = @_;
669 =head2 StopPipe ($pipe)
675 =for html <blockquote>
685 =for html </blockquote>
689 =for html <blockquote>
697 =for html </blockquote>
701 $pipeToStop ||= $pipe;
703 close $pipeToStop if $pipeToStop;
713 =head2 PageOutput (@ouput)
715 Pages output to the screen
719 =for html <blockquote>
729 =for html </blockquote>
733 =for html <blockquote>
741 =for html </blockquote>
746 PipeOutputArray $ENV{PAGER}, @output;
755 sub RedirectOutput($$@) {
756 my ($to, $mode, @output) = @_;
760 =head2 RedirectOutput ($to, @ouput)
762 Pages output to the screen
766 =for html <blockquote>
772 Where to send the output
780 =for html </blockquote>
784 =for html <blockquote>
792 =for html </blockquote>
796 croak 'Mode must be > or >>'
797 unless ($mode eq '>' or $mode eq '>>');
799 open my $out, $mode, $to
800 or croak "Unable to open $to for writing - $!";
815 =head2 ReadFile ($filename)
817 How many times have you coded a Perl subroutine, or just staight inline Perl to
818 open a file, read all the lines into an array and close the file. This routine
819 does that very thing along with the associated and proper checking of open
820 failure and even trims the lines in the output array of trailing newlines? This
821 routine returns an array of the lines in the filename passed in.
825 =for html <blockquote>
835 =for html </blockquote>
839 =for html <blockquote>
843 =item Array of lines in the file
847 =for html </blockquote>
851 open my $file, '<', $filename
852 or error "Unable to open $filename ($!)", 1;
860 or error "Unable to close $filename ($!)", 1;
867 push @cleansed_lines, $_ if !/^#/; # Discard comment lines
870 return @cleansed_lines;
879 my ($total, $log) = @_;
883 =head2 Stats ($total, $log)
885 Reports runtime stats
889 =for html <blockquote>
895 Reference to a hash of total counters. The keys of the hash will be the labels
896 and the values of the hash will be the counters.
900 Logger object to log stats to (if specified). Note: if the Logger object has
901 errors or warnings then they will be automatically included in the output.
905 =for html </blockquote>
909 =for html <blockquote>
917 =for html </blockquote>
921 my $msg = "$FindBin::Script Run Statistics:";
923 if ($log and ref $log eq 'Logger') {
924 $total->{errors} = $log->{errors};
925 $total->{warnings} = $log->{warnings};
929 # Display statistics (if any)
936 for (sort keys %$total) {
937 $msg = $total->{$_} . "\t $_";
940 $log->msg ($total->{$_} . "\t $_");
957 Reports usage using perldoc
961 =for html <blockquote>
967 Message to output before doing perldoc
971 =for html </blockquote>
975 =for html <blockquote>
979 =item Does not return
983 =for html </blockquote>
987 display $msg if $msg;
994 sub RequiredFields($$) {
998 =head2 RequiredFields($total, $log)
1000 Check if a list of fields are contained in a hash
1004 =for html <blockquote>
1010 Array reference to a list of field names that are required
1014 Hash reference whose key values we are checking
1018 =for html </blockquote>
1022 =for html <blockquote>
1028 Returns either an empty string or a string naming the first missing required
1033 =for html </blockquote>
1037 my ($fields, $rec) = @_;
1039 for my $fieldname (@$fields) {
1043 if ($fieldname eq $_) {
1049 return "$fieldname is required" unless $found;
1061 =head1 CONFIGURATION AND ENVIRONMENT
1069 L<File::Spec|File::Spec>
1075 =head2 ClearSCM Perl Modules
1077 =for html <p><a href="/php/scm_man.php?file=lib/Display.pm">Display</a></p>
1079 =for html <p><a href="/php/scm_man.php?file=lib/Logger.pm">Logger</a></p>
1081 =for html <p><a href="/php/scm_man.php?file=lib/OSDep.pm">OSDep</a></p>
1083 =head1 INCOMPATABILITIES
1087 =head1 BUGS AND LIMITATIONS
1089 There are no known bugs in this module.
1091 Please report problems to Andrew DeFaria <Andrew@ClearSCM.com>.
1093 =head1 LICENSE AND COPYRIGHT
1095 This Perl Module is freely available; you can redistribute it and/or modify it
1096 under the terms of the GNU General Public License as published by the Free
1097 Software Foundation; either version 2 of the License, or (at your option) any
1100 This Perl Module is distributed in the hope that it will be useful, but WITHOUT
1101 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1102 FOR A PARTICULAR PURPOSE. See the GNU General Public License
1103 (L<http://www.gnu.org/copyleft/gpl.html>) for more details.
1105 You should have received a copy of the GNU General Public License along with
1106 this Perl Module; if not, write to the Free Software Foundation, Inc., 59
1107 Temple Place - Suite 330, Boston, MA 02111-1307, USA. reserved.