1## Graph.pm is a graphing package that supports on-the-fly graphing 2## from the gnuplot, xrt, and xmgrace graphing packages. 3## 4## $Id: Utils.pm,v 1.24 2006/06/07 21:09:33 emile Exp $ $Name: $ 5## 6## This software product is developed by Michael Young and David Moore, 7## and copyrighted(C) 1998 by the University of California, San Diego 8## (UCSD), with all rights reserved. UCSD administers the CAIDA grant, 9## NCR-9711092, under which part of this code was developed. 10## 11## There is no charge for this software. You can redistribute it and/or 12## modify it under the terms of the GNU General Public License, v. 2 dated 13## June 1991 which is incorporated by reference herein. This software is 14## distributed WITHOUT ANY WARRANTY, IMPLIED OR EXPRESS, OF MERCHANTABILITY 15## OR FITNESS FOR A PARTICULAR PURPOSE or that the use of it will not 16## infringe on any third party's intellectual property rights. 17## 18## You should have received a copy of the GNU GPL along with this program. 19## 20## 21## IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY 22## PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL 23## DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS 24## SOFTWARE, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF 25## THE POSSIBILITY OF SUCH DAMAGE. 26## 27## THE SOFTWARE PROVIDED HEREIN IS ON AN "AS IS" BASIS, AND THE 28## UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, 29## SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. THE UNIVERSITY 30## OF CALIFORNIA MAKES NO REPRESENTATIONS AND EXTENDS NO WARRANTIES 31## OF ANY KIND, EITHER IMPLIED OR EXPRESS, INCLUDING, BUT NOT LIMITED 32## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A 33## PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE 34## ANY PATENT, TRADEMARK OR OTHER RIGHTS. 35## 36## 37## Contact: graph-dev@caida.org 38## 39## 40package Chart::Graph::Utils; 41use Exporter (); 42 43@ISA = qw(Exporter); 44%EXPORT_TAGS = (UTILS => [qw($gnuplot $xmgrace $convert $ppmtogif 45 $xwdtopnm $xrt $xvfb $ppmtojpg $pnmtopng 46 $use_xvfb 47 $tmpcount 48 &_make_tmpdir &_cleanup_tmpdir &_get_path 49 &_chk_status &_mesh_opts &_make_tmpfile 50 &_number_to_eng)], 51 52 # variables that user may set 53 USER => [qw($gnuplot $convert $xmgrace $ppmtogif $pnmtopng 54 $ppmtojpg $xwdtopnm $xrt $xvfb 55 $use_xvfb)] 56 ); 57 58# add symbols from tags into @EXPORT_OK 59Exporter::export_ok_tags('UTILS'); 60 61use Carp; # for carp() and croak() 62use File::Path; # for rmtree() 63 64$cvs_Id = '$Id: Utils.pm,v 1.24 2006/06/07 21:09:33 emile Exp $'; 65$cvs_Author = '$Author: emile $'; 66$cvs_Name = '$Name: $'; 67$cvs_Revision = '$Revision: 1.24 $'; 68 69$VERSION = 3.2; 70 71use strict; 72 73# default don't use xvfb by default, use their own display environment 74use vars qw($use_xvfb); 75$use_xvfb = 0; 76 77# hold paths to programs 78# user may choose to set paths to these programs 79# if paths are not set then we will attempt to search 80# PATH for the programs 81use vars qw($gnuplot $xvfb $convert $xwdtopnm $ppmtogif $ppmtojpg $pnmtopng); 82# Store names of converters programs until either user sets path or 83# path is automatically assigned to these variables. These will be overridden 84# by users if another path is desired. 85$convert = "convert"; 86$xwdtopnm = "xwdtopnm"; 87$ppmtogif = "ppmtogif"; 88$ppmtojpg = "ppmtojpeg"; 89$pnmtopng = "pnmtopng"; 90 91# 92# remove tmp files in case program exits abnormally 93# 94END { 95 _cleanup_tmpdir(); 96} 97 98# 99# remove tmp files in case of a signal interrupt (ctrl-C) 100# 101$SIG{INT} = \&_handle_sigint; 102#$SIG{INT} = 'DEFAULT'; 103 104# 105# general purpose global variables 106# 107 108use vars qw($tmpcount $tmpdir @clean_tmpdirs); 109$tmpcount = 0; # used to create unique tmp filenames 110@clean_tmpdirs = (); # Storage for every tmp directory to be eventually 111 # removed. 112 113# 114# 115# general purpose subroutines - these are subroutines shared across 116# all packages 117# 118 119# 120# Subroutine: make_tmpdir() 121# 122# Description: creates temporary dir for storage 123# of temporary files with read, write, 124# and execute for user and group 125sub _make_tmpdir { 126 my $package = shift; 127 die 'Too many arguments\n' if @_; 128 129 my $PID = $$; 130 if (not defined($ENV{TMPDIR})) { 131 while(-d "/tmp/Graph$package$PID") {$PID++ } 132 $tmpdir = "/tmp/Graph$package$PID"; 133 } else { 134 while(-d "/tmp/Graph$package$PID") {$PID++ } 135 $tmpdir = "$ENV{TMPDIR}/Graph$package$$"; 136 } 137 138 if (not mkdir($tmpdir, 0770)) { 139 croak "could not make temporary directory: `$tmpdir'"; 140 $tmpdir = undef; 141 } 142 143 # Add directory to list of directories to remove 144 push @clean_tmpdirs, $tmpdir; 145 return $tmpdir; 146} 147 148# 149# Subroutine: cleanup_tmpdir() 150# 151# Description: remove the tmp dir we created for 152# tmp files 153 154sub _cleanup_tmpdir { 155 156 my $count = 1; # Convenience variable for comments. 157 158 # Loop through every temporary directory created and either 159 # report to the user it was created or remove the tree structure. 160 foreach my $tmp_dir (@clean_tmpdirs) { 161 if ($Chart::Graph::save_tmpfiles) { 162 if (defined($tmp_dir) and -d $tmp_dir ) { 163 print "Set $count of tmp files are in $tmp_dir\n"; 164 } 165 } elsif (defined($tmp_dir) and -d $tmp_dir ) { 166 # remove directory and associated files. 167 unless ( rmtree ($tmp_dir, 0, 1) ) { 168 carp "Unable to successfully remove set $count of " . 169 "temporary files"; 170 } # Careful not to change permissions but not unlink files. 171 } 172 $count++; 173 } 174} 175 176# 177# Subroutine: make_tmpfile() 178# Description: create temporary filenames with unique extensions 179# 180# 181sub _make_tmpfile { 182 my ($file, $ext) = @_; 183 $tmpcount++; 184 if (not defined($ext)) { 185 $ext = ""; 186 } elsif ($ext ne "") { 187 $ext = ".$ext" 188 }; 189 return "$tmpdir/$file.$tmpcount$ext"; 190} 191 192# 193# Subroutine: get_path() 194# 195# Description: searches PATH for specified program given as arg 196# 197# 198# 199# 200sub _get_path { 201 my ($exe) = @_; 202 my @path = split (/:/, $ENV{PATH}); 203 my $program; 204 205 foreach my $i(@path){ 206 $program = "$i/$exe"; 207 if (-x $program) { 208 return $program; 209 } 210 } 211 212 carp "program not found in search path: $exe"; 213 return 0; 214} 215 216# 217# Subroutine: chk_status 218# 219# Description: checks the exit status of system() calls for errors 220# 221# 222sub _chk_status { 223 my ($status) = @_; 224 if ($status) { 225 my $exit_value = $? >> 8; 226 my $signal_num = $? & 127; 227 my $dumped_core = $? & 128; 228 carp "exit value = $exit_value\nsignal number = $signal_num\ndumped core = $dumped_core\n"; 229 return 0; 230 } 231 return 1; 232} 233 234# 235# Subroutine: mesh_opts 236# 237# Description: merges user and default option for 238# gnuplot and or xrt options 239# 240 241sub _mesh_opts { 242 my ($user_opts_ref, $default_opts_ref) = @_; 243 my %user_opts = %{$user_opts_ref}; 244 my %default_opts = %{$default_opts_ref}; 245 my %opts; 246 247 # check user opts against defaults and mesh 248 # the basic algorithm here is to override the 249 # the default options against the ones that 250 # the user has passed in. 251 while (my ($key, $value) = each %default_opts) { 252 if (exists($user_opts{$key})) { 253 $opts{$key} = $user_opts{$key}; 254 delete $user_opts{$key}; # remove options 255 # that are matching 256 } else { 257 $opts{$key} = $default_opts{$key}; 258 } 259 } 260 261 # any left over options in the table are unknown 262 # if the user passes in illegal options then we 263 # warn them with an error message but still 264 # proceed. 265 while (my ($key, $value) = each %user_opts) { 266 carp "unknown option: $key"; 267 } 268 269 return %opts; 270} 271 272 273# 274# Subroutine: _number_to_eng 275# 276# Description: returns the correct suffix for 277# numerics, ie, 1st, 2nd, 3rd, 4th.. 278# 279 280sub _number_to_eng { 281 my $number = shift @_; 282 my $retval; 283 284 if ($number == 1) { 285 $retval = $number . "st"; 286 } elsif ($number == 2) { 287 $retval = $number . "nd"; 288 } elsif ($number == 3) { 289 $retval = $number . "rd"; 290 } else { 291 $retval = $number . "th"; 292 } 293 294 return $retval; 295} 296 297# 298# Subroutine: _handle_sigint 299# 300# Description: cleans up if ctrl c detected 301# 302# 303 304sub _handle_sigint { 305 warn "\nSIGINT detected: tmp files cleaned up\n"; 306 _cleanup_tmpdir(); 307 $SIG{INT} = 'DEFAULT'; 308 exit; 309 310} 311 3121; 313