Commit | Line | Data |
a0d0e21e |
1 | package IPC::Open3; |
2 | require 5.000; |
3 | require Exporter; |
4 | use Carp; |
5 | |
f06db76b |
6 | =head1 NAME |
7 | |
8 | IPC::Open3, open3 - open a process for reading, writing, and error handling |
9 | |
10 | =head1 SYNOPSIS |
11 | |
12 | $pid = open3('WTRFH', 'RDRFH', 'ERRFH' |
13 | 'some cmd and args', 'optarg', ...); |
14 | |
15 | =head1 DESCRIPTION |
16 | |
17 | Extremely similar to open2(), open3() spawns the given $cmd and |
18 | connects RDRFH for reading, WTRFH for writing, and ERRFH for errors. If |
19 | ERRFH is '', or the same as RDRFH, then STDOUT and STDERR of the child are |
20 | on the same file handle. |
21 | |
22 | If WTRFH begins with ">&", then WTRFH will be closed in the parent, and |
23 | the child will read from it directly. if RDRFH or ERRFH begins with |
24 | ">&", then the child will send output directly to that file handle. In both |
25 | cases, there will be a dup(2) instead of a pipe(2) made. |
26 | |
27 | All caveats from open2() continue to apply. See L<open2> for details. |
28 | |
29 | =cut |
30 | |
a0d0e21e |
31 | @ISA = qw(Exporter); |
32 | @EXPORT = qw(open3); |
33 | |
34 | # &open3: Marc Horowitz <marc@mit.edu> |
35 | # derived mostly from &open2 by tom christiansen, <tchrist@convex.com> |
36 | # |
37 | # $Id: open3.pl,v 1.1 1993/11/23 06:26:15 marc Exp $ |
38 | # |
39 | # usage: $pid = open3('wtr', 'rdr', 'err' 'some cmd and args', 'optarg', ...); |
40 | # |
41 | # spawn the given $cmd and connect rdr for |
42 | # reading, wtr for writing, and err for errors. |
43 | # if err is '', or the same as rdr, then stdout and |
44 | # stderr of the child are on the same fh. returns pid |
45 | # of child, or 0 on failure. |
46 | |
47 | |
48 | # if wtr begins with '>&', then wtr will be closed in the parent, and |
49 | # the child will read from it directly. if rdr or err begins with |
50 | # '>&', then the child will send output directly to that fd. In both |
51 | # cases, there will be a dup() instead of a pipe() made. |
52 | |
53 | |
54 | # WARNING: this is dangerous, as you may block forever |
55 | # unless you are very careful. |
56 | # |
57 | # $wtr is left unbuffered. |
58 | # |
59 | # abort program if |
60 | # rdr or wtr are null |
61 | # pipe or fork or exec fails |
62 | |
63 | $fh = 'FHOPEN000'; # package static in case called more than once |
64 | |
65 | sub open3 { |
66 | local($kidpid); |
67 | local($dad_wtr, $dad_rdr, $dad_err, @cmd) = @_; |
68 | local($dup_wtr, $dup_rdr, $dup_err); |
69 | |
70 | $dad_wtr || croak "open3: wtr should not be null"; |
71 | $dad_rdr || croak "open3: rdr should not be null"; |
72 | $dad_err = $dad_rdr if ($dad_err eq ''); |
73 | |
74 | $dup_wtr = ($dad_wtr =~ s/^\>\&//); |
75 | $dup_rdr = ($dad_rdr =~ s/^\>\&//); |
76 | $dup_err = ($dad_err =~ s/^\>\&//); |
77 | |
78 | # force unqualified filehandles into callers' package |
79 | local($package) = caller; |
80 | $dad_wtr =~ s/^[^']+$/$package'$&/; |
81 | $dad_rdr =~ s/^[^']+$/$package'$&/; |
82 | $dad_err =~ s/^[^']+$/$package'$&/; |
83 | |
84 | local($kid_rdr) = ++$fh; |
85 | local($kid_wtr) = ++$fh; |
86 | local($kid_err) = ++$fh; |
87 | |
88 | if (!$dup_wtr) { |
89 | pipe($kid_rdr, $dad_wtr) || croak "open3: pipe 1 (stdin) failed: $!"; |
90 | } |
91 | if (!$dup_rdr) { |
92 | pipe($dad_rdr, $kid_wtr) || croak "open3: pipe 2 (stdout) failed: $!"; |
93 | } |
94 | if ($dad_err ne $dad_rdr && !$dup_err) { |
95 | pipe($dad_err, $kid_err) || croak "open3: pipe 3 (stderr) failed: $!"; |
96 | } |
97 | |
98 | if (($kidpid = fork) < 0) { |
99 | croak "open2: fork failed: $!"; |
100 | } elsif ($kidpid == 0) { |
101 | if ($dup_wtr) { |
102 | open(STDIN, ">&$dad_wtr") if (fileno(STDIN) != fileno($dad_wtr)); |
103 | } else { |
104 | close($dad_wtr); |
105 | open(STDIN, ">&$kid_rdr"); |
106 | } |
107 | if ($dup_rdr) { |
108 | open(STDOUT, ">&$dad_rdr") if (fileno(STDOUT) != fileno($dad_rdr)); |
109 | } else { |
110 | close($dad_rdr); |
111 | open(STDOUT, ">&$kid_wtr"); |
112 | } |
113 | if ($dad_rdr ne $dad_err) { |
114 | if ($dup_err) { |
115 | open(STDERR, ">&$dad_err") |
116 | if (fileno(STDERR) != fileno($dad_err)); |
117 | } else { |
118 | close($dad_err); |
119 | open(STDERR, ">&$kid_err"); |
120 | } |
121 | } else { |
122 | open(STDERR, ">&STDOUT") if (fileno(STDERR) != fileno(STDOUT)); |
123 | } |
124 | local($")=(" "); |
125 | exec @cmd; |
126 | croak "open2: exec of @cmd failed"; |
127 | } |
128 | |
129 | close $kid_rdr; close $kid_wtr; close $kid_err; |
130 | if ($dup_wtr) { |
131 | close($dad_wtr); |
132 | } |
133 | |
134 | select((select($dad_wtr), $| = 1)[0]); # unbuffer pipe |
135 | $kidpid; |
136 | } |
137 | 1; # so require is happy |
138 | |