File Coverage

blib/lib/Net/SCP.pm
Criterion Covered Total %
statement 27 115 23.4
branch 0 44 0.0
condition 0 45 0.0
subroutine 9 22 40.9
pod 11 11 100.0
total 47 237 19.8


line stmt bran cond sub pod time code
1             package Net::SCP;
2              
3 1     1   761 use strict;
  1         3  
  1         44  
4 1     1   6 use vars qw($VERSION @ISA @EXPORT_OK $scp $DEBUG);
  1         2  
  1         96  
5 1     1   6 use Exporter;
  1         12  
  1         47  
6 1     1   7 use Carp;
  1         2  
  1         95  
7 1     1   5 use File::Basename;
  1         2  
  1         109  
8 1     1   1070 use String::ShellQuote;
  1         878  
  1         63  
9 1     1   1049 use IO::Handle;
  1         10488  
  1         99  
10 1     1   905 use Net::SSH qw(sshopen3);
  1         26143  
  1         106  
11 1     1   12 use IPC::Open3;
  1         2  
  1         1539  
12              
13             @ISA = qw(Exporter);
14             @EXPORT_OK = qw( scp iscp );
15             $VERSION = '0.08';
16              
17             $scp = "scp";
18              
19             $DEBUG = 0;
20              
21             =head1 NAME
22              
23             Net::SCP - Perl extension for secure copy protocol
24              
25             =head1 SYNOPSIS
26              
27             #procedural interface
28             use Net::SCP qw(scp iscp);
29             scp($source, $destination);
30             iscp($source, $destination); #shows command, asks for confirmation, and
31             #allows user to type a password on tty
32              
33             #OO interface
34             $scp = Net::SCP->new( "hostname", "username" );
35             #with named params
36             $scp = Net::SCP->new( { "host"=>$hostname, "user"=>$username } );
37             $scp->get("filename") or die $scp->{errstr};
38             $scp->put("filename") or die $scp->{errstr};
39             #tmtowtdi
40             $scp = new Net::SCP;
41             $scp->scp($source, $destination);
42              
43             #Net::FTP-style
44             $scp = Net::SCP->new("hostname");
45             $scp->login("user");
46             $scp->cwd("/dir");
47             $scp->size("file");
48             $scp->get("file");
49              
50             =head1 DESCRIPTION
51              
52             Simple wrappers around ssh and scp commands.
53              
54             =head1 SUBROUTINES
55              
56             =over 4
57              
58             =item scp SOURCE, DESTINATION
59              
60             Can be called either as a subroutine or a method; however, the subroutine
61             interface is depriciated.
62              
63             Calls scp in batch mode, with the B<-B> B<-p> B<-q> and B<-r> options.
64             Returns false upon error, with a text error message accessable in
65             $scp->{errstr}.
66              
67             Returns false and sets the B attribute if there is an error.
68              
69             =cut
70              
71             sub scp {
72 0 0   0 1   my $self = ref($_[0]) ? shift : {};
73 0           my($src, $dest, $interact) = @_;
74 0           my $flags = '-p';
75 0 0 0       $flags .= 'r' unless &_islocal($src) && ! -d $src;
76 0           my @cmd;
77 0 0 0       if ( ( defined($interact) && $interact )
      0        
      0        
78             || ( defined($self->{interactive}) && $self->{interactive} ) ) {
79 0           @cmd = ( $scp, $flags, $src, $dest );
80 0           print join(' ', @cmd), "\n";
81 0 0         unless ( &_yesno ) {
82 0           $self->{errstr} = "User declined";
83 0           return 0;
84             }
85             } else {
86 0           $flags .= 'qB';
87 0           @cmd = ( $scp, $flags, $src, $dest );
88             }
89 0           my($reader, $writer, $error ) =
90             ( new IO::Handle, new IO::Handle, new IO::Handle );
91 0           $writer->autoflush(1);# $error->autoflush(1);
92 0           local $SIG{CHLD} = 'DEFAULT';
93 0           my $pid = open3($writer, $reader, $error, @cmd );
94 0           waitpid $pid, 0;
95 0 0         if ( $? >> 8 ) {
96 0           my $errstr = join('', <$error>);
97             #chomp(my $errstr = <$error>);
98 0           $self->{errstr} = $errstr;
99 0           0;
100             } else {
101 0           1;
102             }
103             }
104              
105             =item iscp SOURCE, DESTINATION
106              
107             Can be called either as a subroutine or a method; however, the subroutine
108             interface is depriciated.
109              
110             Prints the scp command to be execute, waits for the user to confirm, and
111             (optionally) executes scp, with the B<-p> and B<-r> flags.
112              
113             Returns false and sets the B attribute if there is an error.
114              
115             =cut
116              
117             sub iscp {
118 0 0   0 1   if ( ref($_[0]) ) {
119 0           my $self = shift;
120 0           $self->{'interactive'} = 1;
121 0           $self->scp(@_);
122             } else {
123 0           scp(@_, 1);
124             }
125             }
126              
127             sub _yesno {
128 0     0     print "Proceed [y/N]:";
129 0           my $x = scalar();
130 0           $x =~ /^y/i;
131             }
132              
133             sub _islocal {
134 0     0     shift !~ /^[^:]+:/
135             }
136              
137             =back
138              
139             =head1 METHODS
140              
141             =over 4
142              
143             =item new HOSTNAME [ USER ] | HASHREF
144              
145             This is the constructor for a new Net::SCP object. You must specify a
146             hostname, and may optionally provide a user. Alternatively, you may pass a
147             hashref of named params, with the following keys:
148              
149             host - hostname
150             user - username
151             interactive - bool
152             cwd - current working directory on remote server
153              
154             =cut
155              
156             sub new {
157 0     0 1   my $proto = shift;
158 0   0       my $class = ref($proto) || $proto;
159 0           my $self;
160 0 0         if ( ref($_[0]) ) {
161 0           $self = shift;
162             } else {
163 0 0         $self = {
164             'host' => shift,
165             'user' => ( scalar(@_) ? shift : '' ),
166             'interactive' => 0,
167             'cwd' => '',
168             };
169             }
170 0           bless($self, $class);
171             }
172              
173             =item login [USER]
174              
175             Compatibility method. Optionally sets the user.
176              
177             =cut
178              
179             sub login {
180 0     0 1   my($self, $user) = @_;
181 0 0         $self->{'user'} = $user if $user;
182             }
183              
184             =item cwd CWD
185              
186             Sets the cwd (used for a subsequent get or put request without a full pathname).
187              
188             =cut
189              
190             sub cwd {
191 0     0 1   my($self, $cwd) = @_;
192 0   0       $self->{'cwd'} = $cwd || '/';
193             }
194              
195             =item get REMOTE_FILE [, LOCAL_FILE]
196              
197             Uses scp to transfer REMOTE_FILE from the remote host. If a local filename is
198             omitted, uses the basename of the remote file.
199              
200             =cut
201              
202             sub get {
203 0     0 1   my($self, $remote, $local) = @_;
204 0 0 0       $remote = $self->{'cwd'}. "/$remote" if $self->{'cwd'} && $remote !~ /^\//;
205 0   0       $local ||= basename($remote);
206 0           my $source = $self->{'host'}. ":$remote";
207 0 0         $source = $self->{'user'}. '@'. $source if $self->{'user'};
208 0           $self->scp($source,$local);
209             }
210              
211             =item mkdir DIRECTORY
212              
213             Makes a directory on the remote server. Returns false and sets the B
214             attribute on errors.
215              
216             (Implementation note: An ssh connection is established to the remote machine
217             and '/bin/mkdir B<-p>' is used to create the directory.)
218              
219             =cut
220              
221             sub mkdir {
222 0     0 1   my($self, $directory) = @_;
223 0 0 0       $directory = $self->{'cwd'}. "/$directory"
224             if $self->{'cwd'} && $directory !~ /^\//;
225 0           my $host = $self->{'host'};
226 0 0         $host = $self->{'user'}. '@'. $host if $self->{'user'};
227 0           my($reader, $writer, $error ) =
228             ( new IO::Handle, new IO::Handle, new IO::Handle );
229 0           $writer->autoflush(1);
230 0           my $pid = sshopen3( $host, $writer, $reader, $error,
231             '/bin/mkdir', '-p ', shell_quote($directory) );
232 0           waitpid $pid, 0;
233 0 0         if ( $? >> 8 ) {
234 0   0       chomp(my $errstr = <$error> || '');
235 0   0       $self->{errstr} = $errstr || "mkdir exited with status ". ($?>>8);
236 0           return 0;
237             }
238 0           1;
239             }
240              
241             =item size FILE
242              
243             Returns the size in bytes for the given file as stored on the remote server.
244             Returns 0 on error, and sets the B attribute. In the case of an actual
245             zero-length file on the remote server, the special value '0e0' is returned,
246             which evaluates to zero when used as a number, but is true.
247              
248             (Implementation note: An ssh connection is established to the remote machine
249             and wc is used to determine the file size.)
250              
251             =cut
252              
253             sub size {
254 0     0 1   my($self, $file) = @_;
255 0 0 0       $file = $self->{'cwd'}. "/$file" if $self->{'cwd'} && $file !~ /^\//;
256 0           my $host = $self->{'host'};
257 0 0         $host = $self->{'user'}. '@'. $host if $self->{'user'};
258 0           my($reader, $writer, $error ) =
259             ( new IO::Handle, new IO::Handle, new IO::Handle );
260 0           $writer->autoflush(1);
261             #sshopen2($host, $reader, $writer, 'wc', '-c ', shell_quote($file) );
262 0           my $pid =
263             sshopen3($host, $writer, $reader, $error, 'wc', '-c ', shell_quote($file) );
264 0           waitpid $pid, 0;
265 0 0         if ( $? >> 8 ) {
266 0           chomp(my $errstr = <$error>);
267 0   0       $self->{errstr} = $errstr || "wc exited with status ". $?>>8;
268 0           0;
269             } else {
270 0   0       chomp( my $size = <$reader> || 0 );
271 0 0         if ( $size =~ /^\s*(\d+)/ ) {
272 0 0         $1 ? $1 : '0e0';
273             } else {
274 0           $self->{errstr} = "unparsable output from remote wc: $size";
275 0           0;
276             }
277             }
278             }
279              
280             =item put LOCAL_FILE [, REMOTE_FILE]
281              
282             Uses scp to trasnfer LOCAL_FILE to the remote host. If a remote filename is
283             omitted, uses the basename of the local file.
284              
285             =cut
286              
287             sub put {
288 0     0 1   my($self, $local, $remote) = @_;
289 0   0       $remote ||= basename($local);
290 0 0 0       $remote = $self->{'cwd'}. "/$remote" if $self->{'cwd'} && $remote !~ /^\//;
291 0           my $dest = $self->{'host'}. ":$remote";
292 0 0         $dest = $self->{'user'}. '@'. $dest if $self->{'user'};
293 0 0         warn "scp $local $dest\n" if $DEBUG;
294 0           $self->scp($local, $dest);
295             }
296              
297             =item binary
298              
299             Compatibility method: does nothing; returns true.
300              
301             =cut
302              
303 0     0 1   sub binary { 1; }
304              
305             =item quit
306              
307             Compatibility method: does nothing; returns true.
308              
309             =cut
310              
311 0     0 1   sub quit { 1; }
312              
313             =back
314              
315             =head1 FREQUENTLY ASKED QUESTIONS
316              
317             Q: How do you supply a password to connect with ssh within a perl script
318             using the Net::SSH module?
319              
320             A: You don't (at least not with this module). Use RSA or DSA keys. See the
321             quick help in the next section and the ssh-keygen(1) manpage.
322              
323             A #2: See L instead.
324              
325             Q: My script is "leaking" scp processes.
326              
327             A: See L, L,
328             L and L.
329              
330             =head1 GENERATING AND USING SSH KEYS
331              
332             =over 4
333              
334             =item 1 Generate keys
335              
336             Type:
337              
338             ssh-keygen -t rsa
339              
340             And do not enter a passphrase unless you wanted to be prompted for
341             one during file copying.
342              
343             Here is what you will see:
344              
345             $ ssh-keygen -t rsa
346             Generating public/private rsa key pair.
347             Enter file in which to save the key (/home/User/.ssh/id_rsa):
348             Enter passphrase (empty for no passphrase):
349              
350             Enter same passphrase again:
351              
352             Your identification has been saved in /home/User/.ssh/id_rsa.
353             Your public key has been saved in /home/User/.ssh/id_rsa.pub.
354             The key fingerprint is:
355             5a:cd:2b:0a:cd:d9:15:85:26:79:40:0c:55:2a:f4:23 User@JEFF-CPU
356              
357              
358             =item 2 Copy public to machines you want to upload to
359              
360             C is your public key. Copy it to C<~/.ssh> on target machine.
361              
362             Put a copy of the public key file on each machine you want to log into.
363             Name the copy C (some implementations name this file
364             C)
365              
366             Then type:
367              
368             chmod 600 authorized_keys
369              
370             Then make sure your home dir on the remote machine is not group or
371             world writeable.
372              
373             =back
374              
375             =head1 AUTHORS
376              
377             Could really use a maintainer with enough time to at least review and apply
378             patches more patches. Or the module should just be deprecated in favor of
379             Net::SFTP::Expect or Net::SFTP::Foreign and made into a simple compatiblity
380             wrapper.
381              
382             Ivan Kohler
383              
384             Major updates Anthony Deaver
385              
386             Thanks to Jon Gunnip for fixing a bug with size().
387              
388             Patch for the mkdir method by Anthony Awtrey .
389              
390             Thanks to terrence brannon for the documentation in
391             the GENERATING AND USING SSH KEYS section.
392              
393             =head1 COPYRIGHT
394              
395             Copyright (c) 2000 Ivan Kohler
396             Copyright (c) 2007 Freeside Internet Services, Inc.
397             All rights reserved.
398             This program is free software; you can redistribute it and/or modify it under
399             the same terms as Perl itself.
400              
401             =head1 BUGS
402              
403             Still has no-OO cruft.
404              
405             In order to work around some problems with commercial SSH2, if the source file
406             is on the local system, and is not a directory, the B<-r> flag is omitted.
407             It's probably better just to use OpenSSH which is
408             the de-facto standard these days anyway.
409              
410             The Net::FTP-style OO stuff is kinda lame. And incomplete.
411              
412             iscp doesnt expect you to be logging into the box that you are copying to
413             for the first time. so it's completely clueless about how to handle the
414             whole 'add this file to known hosts' message so it just hangs after the
415             user hits y. (Thanks to John L. Utz III). To avoid this, SSH to the box
416             once first.
417              
418             =head1 SEE ALSO
419              
420             For a perl implementation that does not require the system B command, see
421             L instead.
422              
423             For a wrapper version that allows you to use passwords, see L
424             instead.
425              
426             For a wrapper version of the newer SFTP protocol, see L
427             instead.
428              
429             L, L, L, L,
430             L
431              
432             scp(1), ssh(1), L, L, L
433              
434             =cut
435              
436             1;
437              
438