File Coverage

blib/lib/IPC/PerlSSH/Library/Run.pm
Criterion Covered Total %
statement 9 9 100.0
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 12 12 100.0


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2009 -- leonerd@leonerd.org.uk
5              
6             package IPC::PerlSSH::Library::Run;
7              
8 1     1   4 use strict;
  1         1  
  1         27  
9 1     1   3 use warnings;
  1         1  
  1         25  
10              
11 1     1   3 use IPC::PerlSSH::Library;
  1         2  
  1         158  
12              
13             our $VERSION = '0.17';
14              
15             =head1 NAME
16              
17             C - a library of command running functions for
18             C
19              
20             =head1 SYNOPSIS
21              
22             use IPC::PerlSSH;
23              
24             my $ips = IPC::PerlSSH->new( Host => "over.there" );
25              
26             $ips->use_library( "Run", qw( system system_out system_in ) );
27              
28             my ( $result, $out ) = $ips->call( "system_out", qw( ip addr ls ) );
29             $out == 0 or die "ip failed\n";
30              
31             for (split m/\n/, $out ) {
32             # some processing here...
33             }
34              
35             my $result = $ips->call( "system", qw( ip addr add 1.2.3.4/28 dev eth0 ) );
36              
37             # To execute a shell command, send a single string
38             my $result = $ips->call( "system_in", "1",
39             "echo >/proc/sys/net/ipv4/ip_forward"
40             );
41              
42             =head1 DESCRIPTION
43              
44             This module provides a library of functions for executing processes on the
45             remote system. As well as a basic C-like wrapper, there are also
46             functions for passing data in to the executed process's STDIN stream, reading
47             from its STDOUT stream, or both simultaneously.
48              
49             Each of these functions will only return once the remote process has exited.
50             If interaction with the process is required while it is running, a remote pipe
51             open may be performed instead using functions in L.
52              
53             =cut
54              
55             # Have to protect the STDIN/STDOUT streams
56             # Don't capture the STDERR stream unless caller asked for it
57              
58             init q[
59             sub system_inouterr {
60             my ( $capture_stderr, $stdin, $path, @args ) = @_;
61              
62             pipe( my $rd0, my $wr0 ) or die "Cannot pipe() - $!";
63             pipe( my $rd1, my $wr1 ) or die "Cannot pipe() - $!";
64             pipe( my $rd2, my $wr2 ) or die "Cannot pipe() - $!" if $capture_stderr;
65              
66             defined( my $kid = fork ) or die "Cannot fork - ()\n";
67             if( $kid == 0 ) {
68             open STDIN, "<&=", $rd0; close $rd0; close $wr0;
69             open STDOUT, ">&=", $wr1; close $rd1; close $wr1;
70             if( $capture_stderr ) {
71             open STDERR, ">&=", $wr2; close $rd2; close $wr2;
72             }
73             exec $path, @args;
74             exit -1;
75             }
76              
77             close $rd0;
78             close $wr1;
79             close $wr2 if $capture_stderr;
80              
81             my $stdout = "";
82             my $stderr = "";
83             my $fn0 = fileno $wr0;
84             my $fn1 = fileno $rd1;
85             my $fn2 = fileno $rd2 if $capture_stderr;
86              
87             local $SIG{PIPE} = "IGNORE";
88              
89             while(1) {
90             undef $wr0 unless length $stdin;
91             last unless $wr0 or $rd1 or $rd2;
92             my ( $rv, $wv ) = ('') x 2;
93             vec( $wv, $fn0, 1 ) = 1 if $wr0;
94             vec( $rv, $fn1, 1 ) = 1 if $rd1;
95             vec( $rv, $fn2, 1 ) = 1 if $rd2;
96              
97             select $rv, $wv, undef, undef or die "Cannot select() - $!";
98              
99             if( vec( $wv, $fn0, 1 ) ) {
100             my $n = syswrite( $wr0, $stdin, 8192 ) or undef $wr0;
101             substr( $stdin, 0, $n ) = "" if $n;
102             }
103             if( vec( $rv, $fn1, 1 ) ) {
104             sysread( $rd1, $stdout, 8192, length $stdout ) or undef $rd1;
105             }
106             if( vec( $rv, $fn2, 1 ) ) {
107             sysread( $rd2, $stderr, 8192, length $stderr ) or undef $rd2;
108             }
109             }
110              
111             waitpid $kid, 0;
112             return $?, $stdout, $stderr if $capture_stderr;
113             return $?, $stdout;
114             }
115             ];
116              
117             =head1 FUNCTIONS
118              
119             The following four functions do not redirect the C stream of the
120             invoked program, allowing it to pass unhindered back through the F
121             connection to the local program.
122              
123             =cut
124              
125             =head2 system
126              
127             Execute a program with the given arguments, returning its exit status.
128              
129             my $exitstatus = $ips->call( "system", $path, @args );
130              
131             To obtain the exit value, use C from C.
132              
133             =cut
134              
135             func system => q{ ( system_inouterr( 0, "", @_ ) )[0] };
136              
137             =head2 system_in
138              
139             Execute a program with the given arguments, passing in a string to its STDIN,
140             and returning its exit status
141              
142             my $exitstatus = $ips->call( "system_in", $stdin, $path, @args );
143              
144             =cut
145              
146             func system_in => q{ ( system_inouterr( 0, @_ ) )[0] };
147              
148             =head2 system_out
149              
150             Execute a program with the given arguments, returning its exit status and what
151             it wrote on STDOUT.
152              
153             my ( $exitstatus, $stdout ) = $ips->call( "system_out", $path, @args );
154              
155             =cut
156              
157             func system_out => q{ system_inouterr( 0, "", @_ ) };
158              
159             =head2 system_inout
160              
161             Execute a program with the given arguments, passing in a string to its STDIN,
162             and returning its exit status and what it wrote on STDOUT.
163              
164             my ( $exitstatus, $stdout ) =
165             $ips->call( "system_inout", $stdin, $path, @args )
166              
167             =cut
168              
169             func system_inout => q{ system_inouterr( 0, @_ ) };
170              
171             =pod
172              
173             The following four functions capture the invoked program's C stream.
174              
175             =cut
176              
177             =head2 system_err
178              
179             Execute a program with the given arguments, returning its exit status and what
180             it wrote on STDERR.
181              
182             my ( $exitstatus, $stderr ) = $ips->call( "system_err", $path, @args );
183              
184             =cut
185              
186             func system_err => q{ ( system_inouterr( 1, "", @_ ) )[0,2] };
187              
188             =head2 system_inerr
189              
190             Execute a program with the given arguments, passing in a string to its STDIN,
191             and returning its exit status and what it wrote on STDERR.
192              
193             my ( $exitstatus, $stderr ) =
194             $ips->call( "system_inerr", $stdin, $path, @args );
195              
196             =cut
197              
198             func system_inerr => q{ ( system_inouterr( 1, @_ ) )[0,2] };
199              
200             =head2 system_outerr
201              
202             Execute a program with the given arguments, returning its exit status and what
203             it wrote on STDOUT and STDERR.
204              
205             my ( $exitstatus, $stdout, $stderr ) =
206             $ips->call( "system_outerr", $path, @args );
207              
208             =cut
209              
210             func system_outerr => q{ system_inouterr( 1, "", @_ ) };
211              
212             =head2 system_inouterr
213              
214             Execute a program with the given arguments, passing in a string to its STDIN,
215             and returning its exit status and what it wrote on STDOUT and STDERR.
216              
217             my ( $exitstatus, $stdout, $stderr ) =
218             $ips->call( "system_inouterr", $stdin, $path, @args )
219              
220             =cut
221              
222             func system_inouterr => q{ system_inouterr( 1, @_ ) };
223              
224             =head1 AUTHOR
225              
226             Paul Evans
227              
228             =cut
229              
230             0x55AA;