#!/usr/bin/env perl use utf8; use strict; use warnings; use 5.10.0; use File::Copy qw/copy/; use File::stat; use Net::SFTP; use Getopt::Long; use File::Basename; use constant { OK => 1, }; # --remote # --inversion # --cplist=file my $help = 0; my $remote = 0; my $mode = ""; my $cplist = ""; my $kpath = '.'; ##need path my $vpath = '.'; my %ssh = ( 'ip' => "192.168.8.73", 'user' => "root", 'pass' => "", ); Getopt::Long::Configure ("bundling_override"); my $ret = GetOptions( 'remote|r' => \$remote, #use ssh or local? 'cplist|c:s' => \$cplist, #copy file list 'kpath|k:s' => \$kpath, #cplist key's path 'vpath|v:s' => \$vpath, #cplits value's path 'mode|m=s' => \$mode, #mode = k || v !! k = k | left | up v = v | right | down 'ip|h:s' => \$ssh{'ip'}, 'user|u:s' => \$ssh{'user'}, 'pass|p:s' => \$ssh{'pass'}, 'help|?', => \$help, ); if ($help) { say 'copy.pl --cplist | -c "copy list file config"'; say '--mode | -m = [k | v | up | down | right | left] '; say '[--kpath | -k = ""] [--vpath | -v = ""]'; say '[--remote | -r] [--ip | -h = ""] [--user | -u = ""] [--pass | -p = ""]'; say '[--help | ?]'; exit; } #printOptions(); errExit('Argument parser error') if (!$ret); if (!defined($mode = checkMode($mode))){ errExit("Mode shoud be k or v"); } my %list = (); if ($cplist eq "") { errExit("Need cplist."); } else { %list = readList($cplist); } if ($remote) { if (! &isIp($ssh{'ip'})) { errExit('You lost host ip >_<'); } goto GOTO_LABEL_REMOTE; } else { goto GOTO_LABEL_LOCAL; } my $sftp; GOTO_LABEL_REMOTE: $sftp = Net::SFTP->new($ssh{'ip'}, user => $ssh{'user'}, password => $ssh{'pass'}); if (! $sftp) { die "Can not login $ssh{'user'}\@$ssh{'ip'}!"; } else { say "Connect to $ssh{'ip'}:22 with $ssh{'ip'} ok"; } sshCopyList($mode); exit; GOTO_LABEL_LOCAL: localCopyList($mode); exit; ############################################################# #ssh sub sshCopyList { my $d = shift @_; my @ks = keys(%list); if ($d) { ##1 -> upload foreach (@ks) { upload_ssh_ssh($sftp, $kpath . $_, $vpath . $list{$_}); } } else { foreach (@ks) { download_ssh_ssh($sftp, $kpath . $_, $vpath . $list{$_}); } } } sub upload_ssh_ssh { my ($s, $k, $v) = @_; say 'x' x 100; say "<1 upload $k -----> $v"; ###$k -> $v if (localExist(2, $k)) { sshUnlink($s, 2, $v); sshUpload($s, 3, $k, $v); } say ''; } sub download_ssh_ssh { my ($s, $k, $v, $d) = @_; say 'x' x 100; say "<1 download $k -----> $v"; if (sshExist($s, 2, $k)) { localUnlink(2, $v); sshDownload($s, 3, $k, $v); } say ''; } ############################################################# #local sub localCopyList { my $d = shift @_; my @ks = keys(%list); if ($d) { ## 1 --> left -> right foreach (@ks) { copy_local_local($kpath . $_, $vpath . $list{$_}); } } else { foreach (@ks) { copy_local_local($vpath . $list{$_}, $kpath . $_); } } } sub copy_local_local { my ($k, $v) = @_; say 'x' x 100; say "<1 copy $k -----> $v"; if (localExist(2, $k)) { localUnlink(2, $v); localCopy(3, $k, $v); } say ''; } ############################################################# # other sub part ## sub sshDownload { my ($sftp, $index, $src, $dest) = @_; say "<$index download $src -> $dest"; if (defined($sftp)) { my $ret = $sftp->get($src, $dest); return OK if $ret; } return !OK; } sub sshUpload { my ($sftp, $index, $src, $dest) = @_; say "<$index upload $src -> $dest"; if (defined($sftp)) { my $ret = $sftp->put($src, $dest); return OK if $ret; } return !OK; } sub sshUnlink { my ($sftp, $index, $file) = @_; die " ----- !!! don't unlink root dir / " if $file eq '/'; if (defined($sftp) && sshExist($sftp, $index, $file)) { my $ret = $sftp->do_remove($file); if ($ret) { say "<$index !!: Can not delete $file"; return !OK; } say "<$index unlink $file"; } return OK; } sub sshExist { my ($sftp, $index, $file) = @_; if (defined($sftp)) { my @x = $sftp->ls(dirname($file)); my $base = basename($file); for my $f (@x) { if ($f->{filename} eq $base) { return OK; } } } say "<$index remote file $file not exist."; return !OK; } sub localExist { my ($i, $f) = @_; if (! -e $f) { say "<$i local file $f not exist."; return !OK; } else { return OK; } } sub localUnlink { my $i = shift @_; say "<$i delete @_" if (unlink @_); } sub localCopy { my ($i, $k, $v) = @_; say "<$i copy $k -> $v" if (copy $k, $v); } sub readList { my $file = shift @_; open my $fh, '<', $file or die "Can not open file $file"; my %ret; foreach (<$fh>) { chomp; next if (/\A#/); next if (/\A\Z/); next if (/\A\s*\Z/); my ($k, $v) = split(/\s+/); $ret{$k} = $v; } close($fh); %ret; } sub checkMode { my $mode = shift @_; if ($mode eq "k" || $mode eq "up" || $mode eq "left") { return OK; } if ($mode eq "v" || $mode eq "down" || $mode eq "right") { return !OK; } return undef; } sub printOptions { say 'remote = \'' . $remote . '\''; say 'cplist = \'' . $cplist . '\''; say 'mode = \'' . $mode . '\''; say 'ssh<ip> = \'' . $ssh{'ip'} . '\''; say 'ssh<user> = \'' . $ssh{'user'} . '\''; say 'ssh<pass> = \'' . $ssh{'pass'} . '\''; } sub isIp { $_ = shift @_; if (/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/) { say $_; return OK; } else { return !OK; } } sub errExit { say 'Error in file ' . __FILE__ . ' line ' .__LINE__ . ', Errmsg => [' . (shift @_) . ']'; exit; }