# $Id: SafePipe.pm,v 1.1 2000-09-23 21:23:56-04 roderick Exp $ # # Copyright (c) 2000 Roderick Schertler. All rights reserved. This # program is free software; you can redistribute it and/or modify it # under the same terms as Perl itself. use strict; use 5.003_98; # piped close errno resetting =head1 NAME Proc::SafePipe - popen() and `` without calling the shell =head1 SYNOPSIS $fh = popen_noshell 'r', 'decrypt', $input; ($fh, $pid) = popen_noshell 'w', 'ssh', $host, "cat >$output"; $all_output = backtick_noshell 'decrypt', $input; @lines = backtick_noshell $cmd, @arg; =head1 DESCRIPTION These functions provide a simple way to read from or write to commands which are run without being interpreted by the shell. They croak if there's a system failure, such as a failed fork. =over 4 =cut package Proc::SafePipe; use Carp qw(croak); use Exporter (); use Symbol qw(gensym); use vars qw($VERSION @ISA @EXPORT); $VERSION = 0.01; @ISA = qw(Exporter); @EXPORT = qw(popen_noshell backtick_noshell); =item B I I [I]... This function is similar to popen() except that the I and its related Is are never interpreted by a shell, they are passed to exec() as-is. The I argument must be C<'r'> or C<'w'>. If called in an array context the return value is a list consisting of the filehandle and the PID of the child. In a scalar context only the filehandle is returned. =cut sub popen_noshell { @_ > 1 or croak 'Usage: popen_noshell {r|w} command [arg]...'; my ($type, @cmd) = @_; if ($type eq 'r') { $type = '-|' } elsif ($type eq 'w') { $type = '|-' } else { croak "Invalid popen mode `$type'" } my $fh = gensym; my $pid = open $fh, $type; defined $pid or croak "Can't fork: $!"; if (!$pid) { local $^W; # disable exec failure warning exec { $cmd[0] } @cmd or croak "Can't exec $cmd[0]: $!"; } wantarray ? ($fh, $pid) : $fh; } =item B I [I]... This function runs the given I with the given Is and returns the output, like C<``> does. The difference is that the arguments are not filtered through a shell, they are exec()ed directly. The return value is either all the output from the command (if in a scalar context) or a list of the lines gathered from the command (in an array context). The exit status of the command is in $?. =cut sub backtick_noshell { @_ >= 1 or croak 'Usage: backtick_noshell command [arg]...'; my @cmd = @_; my ($fh, @output); $fh = popen_noshell 'r', @cmd; @output = <$fh>; close $fh or !$! or croak "Error closing $fh: $!"; wantarray ? @output : join '', @output; } 1 __END__ =back =head1 AUTHOR Roderick Schertler > =cut