sub pid_file_cleanup { my ($ind,@temp_files) = @_; # An implicit argument is environment variable $pid_file_cleanup_debug. # If set, this program does not delete any files, but prints the ones it # would have deleted # Explicit arguments are: # 1) A "temp indicator"; a string whose presence in a file spec # means that the file is to be treated by this routine. # Often a pid. # 2) An array of filenames to be considered for cleanup ### # Clean up temp files (does not do temp directories) # We could just delete the ones in @temp_files, but that would be # too easy. Idea is that we'd like the files to stay around a while # in case we want to look at them, but delete them if they aren't looked # at. Rather than trying to save a list of exactly what's eligible for # deletion, we apply the following algorithm: # 1) Only look at files in @temp_files # 2) Of those, only look at the ones with this proc's PID in them # Assumption is that presence of PID is indicator that file really # is temporary & that a bunch of them might exist. # Further assumption is that PID only appears once (fails safe- # no such files will be deleted unless PIDs have recycled) # 3) Logically replace PID with * # 4) Look at those files, and delete the ones that haven't been # accessed in 7 days. Use access date to prolong life of those # that have been looked at after creation... which are probably # the ones we REALLY want to save! local $thisdir = ""; local $debug = $ENV{"PID_FILE_CLEANUP_DEBUG"}; local @del_files; # local DIR; Investigate how to localize this my ($dir,$before_ind,$after_ind); my ($ind,@temp_files) = @_; if ($debug) {open(DEBUG,">/tmp/pid_file_debug_$$") || die} # Loop for those files w/PID in them. Sort so all files in a directory # are together. foreach ( sort( grep(/$ind/,@temp_files) ) ) { $debug && print DEBUG "temp file ... $_\n"; # ?=/ means don't include the last / ($dir) = m"(.*(?=/))"; ($before_ind,$after_ind) = /(.*)$ind(.*)/; $debug && print DEBUG "dir = $dir; before = $before_ind; aft = $after_ind\n"; if ($dir eq "") { $dir = "."; } else { # Be sure that PID is in file spec, not just directory # (test is that if whole directory does not appear before PID, do # next loop iteration). While we're at it, save the file spec portion # (stuff after directory) ($before_ind !~ /$dir(.*)/) && next $file_before_ind = $1; } # Conceptually, following logic is # opendir # find files matching # proc_dir those files # closedir # Actual logic attempts to avoid extra opens and closes since we # expect many files in each directory if ($dir ne $thisdir) { $debug && print DEBUG " ... New dir $dir\n"; &proc_dir; undef(@del_files); $thisdir = $dir; opendir (DIR,$thisdir) || die "Bad opendir : $!\n"; $start_dir_pos = telldir(DIR); } # "Rewind" directory file seekdir (DIR,$start_dir_pos); push ( @del_files, grep(/^$file_before_ind.+$after_ind$/,readdir(DIR)) ); } &proc_dir; $debug && close DEBUG; } sub proc_dir { my $file; if ($thisdir ne "") { closedir (DIR); # Didn't want to unlink files w/directory open. Have no # particular knowledge about this... foreach $file (@del_files) { $file = "$thisdir/$file"; debug && print DEBUG " .. del_file candidate $file\n"; if (-A $file > 7) { if ($debug) { print DEBUG " ... would unlink $file\n" } else { unlink $file } } } } } # Next line needed if you intend to require this file 1;