#!/usr/bin/perl # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # bos720 src/bos/usr/bin/cdat/helpers/push_file.pl 1.2 # # Licensed Materials - Property of IBM # # COPYRIGHT International Business Machines Corp. 2010,2011 # 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 # @(#)90 1.2 src/bos/usr/bin/cdat/helpers/push_file.pl, cdat, bos720 7/14/11 20:29:57 use warnings; use strict; use Net::FTP; use File::Basename; # needed for basename use lib '/usr/lib/cdat/'; use cdat; # # Constants. # my $SCP = '/usr/bin/scp'; my $SSH_TIMEOUT = 2; ###################################################################### # Function: usage # Purpose: Display usage. # Tasks: Print usage and exit. # Input: None # Output: None ###################################################################### sub usage { print(STDERR "Usage: push_file SourceFile TargetFile\n"); print(STDERR " push_file SourceFile ... TargetDirectory\n"); exit(1); } ###################################################################### # Function: ftp_put_file # Purpose: Upload a file or directory using FTP. # Tasks: Upload a file or directory using FTP. # Input: Net::FTP handle, local file name, remote destination, # whether destination is a directory or not # Output: 0 if success, 1 otherwise ###################################################################### sub ftp_put_file { my ($ftp, $file, $dest, $isdir) = @_; my $rc; my $base = basename($file); # determine whether filename is a file or directory if (-d $file) { # filename is a directory if (!$isdir) { print(STDERR "cannot upload directory, destination is a file\n"); return 1; } print("Creating directory $dest/$base\n"); if (!$ftp->mkdir("$dest/$base")) { print(STDERR "cannot create directory $dest/$base\n"); return 1; } # Recursively call ourselves for each directory entry my $dirh; # must use a local dir handle here, not DIR! if (!opendir($dirh, $file)) { print(STDERR "cannot list $file content\n"); return 1; } while (defined(my $elem = readdir($dirh))) { next if ($elem eq '.' || $elem eq '..'); # call ourserlves recursively if (ftp_put_file($ftp, "$file/$elem", "$dest/$base", 1)) { return 1; } } closedir($dirh); } else { # filename is a file, upload it if ($isdir) { print("Copying $file to $dest/$base\n"); $rc = $ftp->put($file, "$dest/$base"); } else { print("Copying $file to $dest\n"); $rc = $ftp->put($file, $dest); } if (!$rc) { print(STDERR "could not upload file $file\n"); return 1; } } return 0; } ###################################################################### # Function: ftp_put # Purpose: Upload files/directories using FTP. # Tasks: Connect via FTP to the specified remote node using the # specified login and upload files and directories. # Input: user, host name, local files, remote destination # Output: None ###################################################################### sub ftp_put { my ($hosts, $user, $hostname, $sources, $dest) = @_; my ($rc, $isdir); my $passwd = $hosts->{$hostname}{users}{$user}; if (!defined($passwd)) { $passwd = cdat::get_password("Enter password for \"$user\" user: "); } if (!defined($passwd)) { print(STDERR "No password to connect to $user\@$hostname\n"); exit(1); } my $ftp = Net::FTP->new($hostname); if (!defined($ftp)) { print(STDERR "Cannot open FTP connection to $hostname\n"); exit(1); } $rc = $ftp->login($user, $passwd); if (!$rc) { print(STDERR "FTP to $hostname failed: ".$ftp->message); exit(1); } # check whether destination exists and is a directory or not if ($ftp->cwd($dest)) { $isdir = 1; } else { $isdir = 0; } # If there is more than 1 local file, check that destination # exists and is a directory. if (@$sources > 1 && !$isdir) { print(STDERR "Destination directory \"$dest\" not found.\n"); exit(1); } # Transfer files in binary mode $ftp->binary(); foreach my $file (@$sources) { last if ftp_put_file($ftp, $file, $dest, $isdir); } # Close FTP session $ftp->quit(); } ###################################################################### # Function: scp_put # Purpose: Upload files/directories using SCP. # Tasks: Connect via SSH to the specified remote node using the # specified login and upload files and directories. # Input: user, host name, local files, remote destination # Output: None ###################################################################### sub scp_put { my ($hosts, $user, $hostname, $sources, $dest) = @_; system("$SCP -i $ENV{HOME}/.ssh/id_rsa -o UserKnownHostsFile=$ENV{HOME}/.ssh/known_hosts -o StrictHostKeyChecking=yes -q -r @$sources $user\@$hostname:$dest"); if ($? != 0) { print(STDERR "scp command failed.\n"); exit(1); } } ###################################################################### # Function: main # Purpose: Entry point of the push_file command. # Tasks: Upload the specified files/directories to the # specified remote node using either SCP or FTP. # Input: user, host name, node type, local files, # remote destination # Output: None ###################################################################### sub main { usage() if (@ARGV < 2); my $user = $ENV{CDAT_USER}; my $hostname = $ENV{CDAT_HOST}; my $type = $ENV{CDAT_TYPE}; my $dest = pop @ARGV; # @ARGV now only contains the local files if (!defined($user) || !defined($hostname) || !defined($type)) { printf(STDERR "Bad environment\n"); exit(1); } my %hosts; cdat::read_host_db(\%hosts); my $protocol = $hosts{$hostname}{protocol}; if (!defined($protocol)) { if ( -x $SCP && cdat::check_remote_protocol($hostname, 'ssh')) { $protocol = "ssh"; } elsif (cdat::check_remote_protocol($hostname, 'exec')) { $protocol = "exec"; } else { $protocol = "telnet"; } } print("Uploading ".join(', ', @ARGV)." to $type $hostname using "); if ($protocol eq "ssh") { print("scp\n"); scp_put(\%hosts, $user, $hostname, \@ARGV, $dest); } else { print("ftp\n"); ftp_put(\%hosts, $user, $hostname, \@ARGV, $dest); } } main;