#! /usr/bin/perl
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2008 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 

# @(#)77   1.9   src/rsct/trace/lstrsp.perl, trace, rsct_rfos, rfos0838a 7/21/08 16:02:40
# Search on "sub help" and/or "sub usage" for script description.

use Getopt::Long;
use Fcntl ':mode';
use Time::Local;

my $total_spool_files = 0;
my $total_spool_files_bytes = 0;
my @unsorted_hits = ();

my $spool_dir, $cluster_name, $cluster_id, $node_name, $node_id, $daemon_name, $megabytes, $from, $to, $previous, $tar, $gzip, $help, $tar_ticks, $no_usage, $show_file_bytes;

if (!GetOptions("spool_dir=s" => \$spool_dir, "cluster_name=s" => \$cluster_name, "cluster_id=s" => \$cluster_id, "node_name=s" => \$node_name, "node_id=s" => \$node_id, "daemon_name=s" => \$daemon_name, "megabytes=i" => \$megabytes, "from=s" => \$from, "to=s" => \$to, "previous=i" => \$previous, "tar=s" => \$tar, "gzip" => \$gzip, "help" => \$help, "h" =>\$help, "tar_ticks" => \$tar_ticks, "no_usage" => \$no_usage, "show_file_bytes" => \$show_file_bytes))
{
	usage(1);
}

if (undef ne $help)
{
	help();
}

if (undef eq $spool_dir)
{
	$spool_dir = ".";
}

if (undef eq $cluster_name)
{
	$cluster_name = ".*";
}

if (undef eq $cluster_id)
{
	$cluster_id = ".*";
}

if (undef eq $node_name)
{
	$node_name = ".*";
}

if (undef eq $node_id)
{
	$node_id = ".*";
}

if (undef eq $daemon_name)
{
	$daemon_name = ".*";
}

if ((undef ne $previous) && ((undef ne $from) || (undef ne $to)))
{
		usage(1);
}

if (undef ne $from)
{
	if (! ($from =~ /^\d{2}-\d{2}-\d{4}$/))
	{
		usage(1);
	}
}

if (undef ne $to)
{
	if (! ($to =~ /^\d{2}-\d{2}-\d{4}$/))
	{
		usage(1);
	}
}

if (undef ne $gzip)
{
	if (undef eq $tar)
	{
		usage(1);
	}
}

if (undef ne $tar_ticks)
{
	if (undef eq $tar)
	{
		usage(1);
	}

	$tar_ticks = "1>/dev/null 2>/dev/null";
}

my $tar_path_prefix;

if ("/" eq substr($spool_dir, 0, 1))
{
	$tar_path_prefix = ".";
}

descend($spool_dir, 5);

if ((undef ne $megabytes) || (undef ne $show_file_bytes))
{
	my @sorted_hits = ();

	if (undef eq $show_file_bytes)
	{
		@sorted_hits = sort {
			(@$b[1] =~ /^.+\.\d+\.sp\.(\d{4}_\d{2}_\d{2}_\d{2}_\d{2}_\d{2}\.\d+)$/)[0]
			cmp
			(@$a[1] =~ /^.+\.\d+\.sp\.(\d{4}_\d{2}_\d{2}_\d{2}_\d{2}_\d{2}\.\d+)$/)[0];
		} @unsorted_hits;
	}
	else
	{
		@sorted_hits = sort {
			(@$a[1] =~ /^.+\.\d+\.sp\.(\d{4}_\d{2}_\d{2}_\d{2}_\d{2}_\d{2}\.\d+)$/)[0]
			cmp
			(@$b[1] =~ /^.+\.\d+\.sp\.(\d{4}_\d{2}_\d{2}_\d{2}_\d{2}_\d{2}\.\d+)$/)[0];
		} @unsorted_hits;
	}

	foreach $arrayref (@sorted_hits)
	{
		if ((undef ne $megabytes) && ($total_spool_files_bytes + @$arrayref[2] > $megabytes*1024*1024))
		{
			last;
		}

		process_entry(@$arrayref[0], @$arrayref[1], @$arrayref[2]);

		if (undef ne $megabytes)
		{
			$total_spool_files_bytes += @$arrayref[2];
		}
	}
}

if ((undef ne $tar_ticks) && ($total_spool_files))
{
	print "\n";
}

if (undef ne $gzip)
{
	system("gzip -f $tar");
}

exit 0;

sub help
{
	print STDERR <<HELP;
This utility lists trace spool files matching selection criteria,
and either outputs their paths to stdout, one per line (default),
or puts the files in a tar archive (--tar option).

HELP
	usage(0);
}

sub usage
{
	if (undef eq $no_usage)
	{
		print STDERR <<USAGE;
Usage:
lstrsp [--spool_dir <spool directory>]
       [--cluster_name <cluster name pattern>]
       [--cluster_id <cluster id pattern>]
       [--node_name <node name pattern>]
       [--node_id <node id pattern>]
       [--daemon_name <daemon_name name pattern>]
       [--previous <number of days before today>] | [--from <from date (mm-dd-yyyy)> [--to <to date (mm-dd-yyyy)>]]
       [--megabytes <maximum megabytes>]
       [--tar <tarfile_name>] [--tar_ticks]
       [--show_file_bytes]
       [--gzip]
       [--no_usage]
Notes:
  - expected patterns are quoted Perl regular expressions
  - pattern defaults are '.*'
  - --tar_ticks prints a '.' instead of a file name for each matching file
  - --no_usage suppresses usage statement errata
  - --show_file_bytes forces an "oldest to latest" sort
USAGE
	}

	if (undef ne $_[0])
	{
		exit $_[0];
	}
}

# args: parent_directory, recurse_depth (counts down to 0)
# returns: 0=okay 1=hit_megabytes_limit
sub descend
{
	local (*DIR); # makes the handle distinct across recursive calls
	my $match_expression;
	
	if (5 == $_[1])
	{
		$match_expression = sprintf("^%s\$", $cluster_name);
	}
	elsif (4 == $_[1])
	{
		$match_expression = sprintf("^%s\$", $cluster_id);
	}
	elsif (3 == $_[1])
	{
		$match_expression = sprintf("^%s\$", $node_name);
	}
	elsif (2 == $_[1])
	{
		$match_expression = sprintf("^%s\$", $node_id);
	}
	elsif (1 == $_[1])
	{
		$match_expression = sprintf("^%s\$", $daemon_name);
	}
	elsif (0 == $_[1])
	{
		$match_expression = "^.+\\.\\d+\\.sp\\.\\d{4}_\\d{2}_\\d{2}_\\d{2}_\\d{2}_\\d{2}\\.\\d+\$";
	}

	if (! opendir DIR, "$_[0]")
	{
		printf(STDERR "Error: cannot open spool directory(%s).\n", $_[0]);
		exit 2;
	}
	
	while (my $entry = readdir(DIR))
	{
		if (("." ne $entry) && (".." ne $entry))
		{
			if ($entry =~ /$match_expression/)
			{
				my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks) = stat("$_[0]/$entry");
	
				# on 0th recurse_depth we're checking spool file names
				if ((0 == $_[1]) && (S_ISREG($mode)))
				{
					if ((undef ne $previous) || (undef ne $from) || (undef ne $to))
					{
						# split out file name from timedate stamp because file name may contain periods
						$entry =~ /^(.+)\.(\d+\.sp\.\d{4}_\d{2}_\d{2}_\d{2}_\d{2}_\d{2}\.\d+)$/;
						my $file_name = $1;
						my $file_timedate_stamp = $2;
						my ($file_number, $sp, $file_date, $file_microseconds) = split(/\./, $file_timedate_stamp, 4);
						my ($file_year, $file_month, $file_day, $file_hour, $file_minute, $file_second) = split(/_/, $file_date, 6);

						my $from_midnight_epoch_seconds = 0;

						if (undef ne $previous)
						{
							$from_midnight_epoch_seconds = todays_midnight_epoch_seconds() - $previous*24*60*60;
						}
						elsif (undef ne $from)
						{
							my ($from_month, $from_day, $from_year) = split(/\-/, $from, 3);

							$from_midnight_epoch_seconds = midnight_epoch_seconds($from_month, $from_day, $from_year);
						}

						if (midnight_epoch_seconds($file_month, $file_day, $file_year) < $from_midnight_epoch_seconds)
						{
							next;
						}

						if (undef ne $to)
						{
							my ($to_month, $to_day, $to_year) = split(/\-/, $to, 3);

							if (midnight_epoch_seconds($file_month, $file_day, $file_year) > midnight_epoch_seconds($to_month, $to_day, $to_year))
							{
								next;
							}
						}
					}

					if ((undef ne $megabytes) || (undef ne $show_file_bytes))
					{
						push(@unsorted_hits, [$_[0], $entry, $size]);
					}
					else
					{
						process_entry($_[0], $entry, $size);
					}
				}
				elsif (S_ISDIR($mode))
				{
					if (my $rc = descend("$_[0]/$entry", $_[1]-1))
					{
						return $rc;
					}
				}
			}
		}
	}
	
	close DIR;

	return 0;
}

sub todays_midnight_epoch_seconds
{
	my ($current_second, $current_minute, $current_hour, $current_day, $current_month, $current_year, $wday, $yday, $isdst) = localtime(time);
	return timelocal(0, 0, 0, $current_day, $current_month, $current_year);
}

# arguments: month (1-12), day (1-31), year
sub midnight_epoch_seconds
{
	# note that we subtract 1 from the 1-12 month here to fit
	# timelocal()'s argument requirements
	return timelocal(0, 0, 0, $_[1], $_[0]-1, $_[2]);
}

sub process_entry
{
	my $path = shift;
	my $entry = shift;
	my $entry_bytes = shift;

	if (undef eq $tar)
	{
		if (undef eq $show_file_bytes)
		{
			print "$path/$entry\n";
		}
		else
		{
			print "$entry_bytes $path/$entry\n";
		}
	}
	else
	{
		if ($total_spool_files)
		{
			system("tar -uvf $tar $tar_path_prefix$path/$entry $tar_ticks");
		}
		else
		{
			system("tar -cvf $tar $tar_path_prefix$path/$entry $tar_ticks");
		}

		if (undef ne $tar_ticks)
		{
			print ".";
		}
	}

	$total_spool_files++;
}
