#!/usr/bin/perl # Author: Avalon Johnson # Date: Aug 21st 2006 # Version: 0.1 beta # Notes: Needs to be tested # it may be faster to use pvfs2-ls rather # than perl's "opendir/readdir" combo # should we comment out the debug statements # to try and speed up the code (no extra "tests") use strict; use Getopt::Std; sub SetGlobals() { my $hostname = `hostname`; if ($hostname =~ /^shc/) { $main::LINUX_MKDIR="/bin/mkdir"; $main::PVFS_COPY="/usr/local/pvfs2/bin/pvfs2-cp"; $main::PVFS_MKDIR="/usr/local/pvfs2/bin/pvfs2-mkdir"; $main::PVFS_STAT="/usr/local/pvfs2/bin/pvfs2-stat"; $main::MOUNT="/bin/mount"; }elsif ($hostname =~ /^tg/) { $main::PVFS_COPY="/usr/bin/pvfs2-cp"; $main::PVFS_MKDIR="/usr/bin/pvfs2-mkdir"; $main::PVFS_STAT="/usr/bin/pvfs2-stat"; }else { return 0; } } # test # $main::PVFS_COPY="/bin/cp"; # $main::PVFS_MKDIR="/bin/mkdir"; $main::DEBUG = 5; $main::DebugLevel = 0; $main::MKDIR = ""; # Should we follow symbolic links $main::Dereference = 1; sub Debug($) { my $str = shift; printf STDERR "\n" . $str . "\n" if $main::DebugLevel > $main::DEBUG; } sub Error($) { my $str = shift; printf STDERR "\n\t" . $str . "\n\n"; exit 1; } sub Usage() { printf "\n\tUsage: $0 [-dhLP] \n\n"; printf "\t\t-d: Turn debugging on\n"; printf "\t\t-L: Always de-reference symbolic links (default)\n"; printf "\t\t-P: Never de-reference symbolic links\n\n"; exit 1; } sub ToPvfs($) { my $to = shift; my $is_pvfs = 0; my @mount; my $mount_pt; my $type; my %pvfs_filesystems; my $line; Debug "ToPvfs ($to)"; @mount = `$main::MOUNT`; foreach $line (@mount) { ($mount_pt, $type) = $line =~ /.*\s+on\s+([\w\/\:0-9\-]+)\s+type\s+(\w+).*/; $pvfs_filesystems{$mount_pt} = $mount_pt if $type =~ /^pvfs/i; } foreach $mount_pt (keys %pvfs_filesystems) { $is_pvfs = 1 and last if ($to =~ /$mount_pt/); } return $is_pvfs; } sub DoCopy($$) { my $from = shift; my $to = shift; Debug "DoCopy ($from, $to)"; (-f $from ) || return -1; if ((-e $to) and !(-d $to or -f $to)) { warn "$to exists and is not a directory or file"; return 0; } if (system ($main::PVFS_COPY, $from, $to) != 0) { warn "Failed to copy $from to $to\n"; return 0; } return 1; } sub PvfsCopy($$) { my $from = shift; my $to = shift; my $from_file; my $to_file; my $fn; my @files; Debug "PvfsCopy ($from, $to)"; Debug "Dereferencing" if $main::Dereference; if (-f $from) { if ( $main::Dereference || !(-l $from)){ DoCopy ($from, $to); }elsif ( -l $from ){ my $towhat; if ( defined($towhat = readlink $from)){ if ( ! symlink $towhat, $to ) { warn "Can\'t create symlink from: $to to $towhat"; return 0; } } else { warn "Can't readlink $from: $!"; return 0; } }else { warn "Copy failed: Can't determine filetype of $from"; } }elsif ( -d $from ) { if ( !(-d $to) ) { if (system ($main::MKDIR, $to) != 0) { warn "Failed to copy make dest directory $to\n"; return 0; } Debug "Created Directory $to"; } opendir(DIR, $from) || Error ("Can\'t open directory: $from"); @files = readdir(DIR); # do this so that we don't have too many open directories closedir(DIR) || Error ("Whoa Nelly: Can\'t close directory $from!!!"); foreach $fn (@files) { next if ($fn =~ /^\.$/ or $fn =~ /^\.\.$/); $from_file = ${from} . "/" . $fn; $to_file = ${to} . "/" . $fn; PvfsCopy ($from_file, $to_file); } }else { warn "Can\'t copy. \"$from\" must be a file,directory of symlink"; return 0; } return 1; } sub Main() { my $from; my $to; Getopt::Std::getopts ('dhPL'); SetGlobals() or die "\nCan't set global parameters. Runnable only on shc/tg clusters\n\n"; Usage if $Getopt::Std::opt_d; $main::DebugLevel = 10 if $Getopt::Std::opt_d; $main::Dereference = 0 if $Getopt::Std::opt_P; # ignore -L we dereference by default Usage() if $#ARGV != 1; $from = $ARGV[0]; $to = $ARGV[1]; if ( -d $to) { $to = $from; $to =~ s/.*\///; $to = $ARGV[1] . '/' . $to; } printf STDERR "\nCopying files from \"$from\" to \"$to\" using pvfs2-cp\n"; printf "\n"; $main::MKDIR = ToPvfs($to) ? $main::PVFS_MKDIR : $main::LINUX_MKDIR ; PvfsCopy ($from, $to); } Main();