PageRenderTime 21ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/ext/IPC-Open3/lib/IPC/Open3.pm

http://github.com/ggoossen/kurila
Perl | 379 lines | 240 code | 92 blank | 47 comment | 53 complexity | d04ef312b845a0d9df7b64e043e81cd4 MD5 | raw file
Possible License(s): AGPL-1.0
  1. package IPC::Open3
  2. our ($VERSION, @ISA, @EXPORT)
  3. require Exporter
  4. use Symbol < qw(gensym qualify)
  5. $VERSION = 1.02
  6. @ISA = qw(Exporter)
  7. @EXPORT = qw(open3)
  8. =head1 NAME
  9. IPC::Open3 - open a process for reading, writing, and error handling using open3()
  10. =head1 SYNOPSIS
  11. $pid = open3(\*CHLD_IN, \*CHLD_OUT, \*CHLD_ERR,
  12. 'some cmd and args', 'optarg', ...);
  13. my($wtr, $rdr, $err);
  14. use Symbol 'gensym'; $err = gensym;
  15. $pid = open3($wtr, $rdr, $err,
  16. 'some cmd and args', 'optarg', ...);
  17. waitpid( $pid, 0 );
  18. my $child_exit_status = $? >> 8;
  19. =head1 DESCRIPTION
  20. Extremely similar to open2(), open3() spawns the given $cmd and
  21. connects CHLD_OUT for reading from the child, CHLD_IN for writing to
  22. the child, and CHLD_ERR for errors. If CHLD_ERR is false, or the
  23. same file descriptor as CHLD_OUT, then STDOUT and STDERR of the child
  24. are on the same filehandle (this means that an autovivified lexical
  25. cannot be used for the STDERR filehandle, see SYNOPSIS). The CHLD_IN
  26. will have autoflush turned on.
  27. If CHLD_IN begins with C<< <& >>, then CHLD_IN will be closed in the
  28. parent, and the child will read from it directly. If CHLD_OUT or
  29. CHLD_ERR begins with C<< >& >>, then the child will send output
  30. directly to that filehandle. In both cases, there will be a dup(2)
  31. instead of a pipe(2) made.
  32. If either reader or writer is the null string, this will be replaced
  33. by an autogenerated filehandle. If so, you must pass a valid lvalue
  34. in the parameter slot so it can be overwritten in the caller, or
  35. an exception will be raised.
  36. The filehandles may also be integers, in which case they are understood
  37. as file descriptors.
  38. open3() returns the process ID of the child process. It doesn't return on
  39. failure: it just raises an exception matching C</^open3:/>. However,
  40. C<exec> failures in the child (such as no such file or permission denied),
  41. are just reported to CHLD_ERR, as it is not possible to trap them.
  42. If the child process dies for any reason, the next write to CHLD_IN is
  43. likely to generate a SIGPIPE in the parent, which is fatal by default.
  44. So you may wish to handle this signal.
  45. Note if you specify C<-> as the command, in an analogous fashion to
  46. C<open(FOO, "-|")> the child process will just be the forked Perl
  47. process rather than an external command. This feature isn't yet
  48. supported on Win32 platforms.
  49. open3() does not wait for and reap the child process after it exits.
  50. Except for short programs where it's acceptable to let the operating system
  51. take care of this, you need to do this yourself. This is normally as
  52. simple as calling C<waitpid $pid, 0> when you're done with the process.
  53. Failing to do this can result in an accumulation of defunct or "zombie"
  54. processes. See L<perlfunc/waitpid> for more information.
  55. If you try to read from the child's stdout writer and their stderr
  56. writer, you'll have problems with blocking, which means you'll want
  57. to use select() or the IO::Select, which means you'd best use
  58. sysread() instead of readline() for normal stuff.
  59. This is very dangerous, as you may block forever. It assumes it's
  60. going to talk to something like B<bc>, both writing to it and reading
  61. from it. This is presumably safe because you "know" that commands
  62. like B<bc> will read a line at a time and output a line at a time.
  63. Programs like B<sort> that read their entire input stream first,
  64. however, are quite apt to cause deadlock.
  65. The big problem with this approach is that if you don't have control
  66. over source code being run in the child process, you can't control
  67. what it does with pipe buffering. Thus you can't just open a pipe to
  68. C<cat -v> and continually read and write a line from it.
  69. =head1 See Also
  70. =over 4
  71. =item L<IPC::Open2>
  72. Like Open3 but without STDERR catpure.
  73. =item L<IPC::Run>
  74. This is a CPAN module that has better error handling and more facilities
  75. than Open3.
  76. =back
  77. =head1 WARNING
  78. The order of arguments differs from that of open2().
  79. =cut
  80. # &open3: Marc Horowitz <marc@mit.edu>
  81. # derived mostly from &open2 by tom christiansen, <tchrist@convex.com>
  82. # fixed for 5.001 by Ulrich Kunitz <kunitz@mai-koeln.com>
  83. # ported to Win32 by Ron Schmidt, Merrill Lynch almost ended my career
  84. # fixed for autovivving FHs, tchrist again
  85. # allow fd numbers to be used, by Frank Tobin
  86. # allow '-' as command (c.f. open "-|"), by Adam Spiers <perl@adamspiers.org>
  87. #
  88. # $Id: open3.pl,v 1.1 1993/11/23 06:26:15 marc Exp $
  89. #
  90. # usage: $pid = open3('wtr', 'rdr', 'err' 'some cmd and args', 'optarg', ...);
  91. #
  92. # spawn the given $cmd and connect rdr for
  93. # reading, wtr for writing, and err for errors.
  94. # if err is '', or the same as rdr, then stdout and
  95. # stderr of the child are on the same fh. returns pid
  96. # of child (or dies on failure).
  97. # if wtr begins with '<&', then wtr will be closed in the parent, and
  98. # the child will read from it directly. if rdr or err begins with
  99. # '>&', then the child will send output directly to that fd. In both
  100. # cases, there will be a dup() instead of a pipe() made.
  101. # WARNING: this is dangerous, as you may block forever
  102. # unless you are very careful.
  103. #
  104. # $wtr is left unbuffered.
  105. #
  106. # abort program if
  107. # rdr or wtr are null
  108. # a system call fails
  109. our $Me = 'open3 (bug)' # you should never see this, it's always localized
  110. # Fatal.pm needs to be fixed WRT prototypes.
  111. sub xfork
  112. my $pid = fork
  113. defined $pid or die: "$Me: fork failed: $^OS_ERROR"
  114. return $pid
  115. sub xpipe
  116. pipe: @_[0], @_[1] or die: "$Me: pipe(" . (Symbol::glob_name: @_[0]) . ", " . (Symbol::glob_name: @_[1]) . ") failed: $^OS_ERROR"
  117. # I tried using a * prototype character for the filehandle but it still
  118. # disallows a bearword while compiling under strict subs.
  119. sub xopen
  120. open: @_[0], @_[1], @_[2] or die: "$Me: open(...)" # . Symbol::glob_name($_[0]) . ", $_[1], " . Symbol::glob_name($_[2]) . ") failed: $!";
  121. sub xclose
  122. close @_[0] or die: "$Me: close(*" . (Symbol::glob_name: @_[0]->*) . ") failed: $^OS_ERROR"
  123. sub fh_is_fd
  124. return ref \@_[0] eq "SCALAR" && @_[0] =~ m/\A=?(\d+)\z/
  125. sub xfileno
  126. return $1 if ref \@_[0] eq "SCALAR" and @_[0] =~ m/\A=?(\d+)\z/ # deal with fh just being an fd
  127. return fileno @_[0]
  128. my $do_spawn = $^OS_NAME eq 'os2' || $^OS_NAME eq 'MSWin32'
  129. sub _open3
  130. local $Me = shift
  131. my(@: $package, $dad_wtr, $dad_rdr, $dad_err, @< @cmd) = @_
  132. my($dup_wtr, $dup_rdr, $dup_err, $kidpid)
  133. if ((nelems @cmd) +> 1 and @cmd[0] eq '-')
  134. die: "Arguments don't make sense when the command is '-'"
  135. # simulate autovivification of filehandles because
  136. # it's too ugly to use @_ throughout to make perl do it for us
  137. # tchrist 5-Mar-00
  138. unless (try {
  139. $dad_wtr = @_[1] = (gensym: )unless defined $dad_wtr;
  140. $dad_rdr = @_[2] = (gensym: )unless defined $dad_rdr;
  141. 1; })
  142. # must strip crud for die to add back, or looks ugly
  143. $^EVAL_ERROR =~ s/(?<=value attempted) at .*//s
  144. die: "$Me: $^EVAL_ERROR"
  145. $dad_err ||= $dad_rdr
  146. $dup_wtr = (ref \$dad_wtr eq "ARRAY" and $dad_wtr[0] =~ s/^[<>]&//)
  147. if ($dup_wtr)
  148. $dad_wtr = $dad_wtr[1]
  149. (ref::svtype: $dad_wtr) eq "PLAINVALUE" and die: "PLAINVALUE can not be used as a filehandle"
  150. $dup_rdr = (ref \$dad_rdr eq "ARRAY" and $dad_rdr[0] =~ s/^[<>]&//)
  151. if ($dup_rdr)
  152. $dad_rdr = $dad_rdr[1]
  153. (ref::svtype: $dad_rdr) eq "PLAINVALUE" and die: "PLAINVALUE can not be used as a filehandle"
  154. $dup_err = (ref \$dad_err eq "ARRAY" and $dad_err[0] =~ s/^[<>]&//)
  155. if ($dup_err)
  156. $dad_err = $dad_err[1]
  157. (ref::svtype: $dad_err) eq "PLAINVALUE" and die: "PLAINVALUE can not be used as a filehandle"
  158. # force unqualified filehandles into caller's package
  159. $dad_wtr = \(Symbol::fetch_glob: (qualify: $dad_wtr, $package))->* unless ref \$dad_wtr ne "SCALAR" or fh_is_fd: $dad_wtr
  160. $dad_rdr = \(Symbol::fetch_glob: (qualify: $dad_rdr, $package))->* unless ref \$dad_rdr ne "SCALAR" or fh_is_fd: $dad_rdr
  161. $dad_err = \(Symbol::fetch_glob: (qualify: $dad_err, $package))->* unless ref \$dad_err ne "SCALAR" or fh_is_fd: $dad_err
  162. my $kid_rdr = (gensym: )
  163. my $kid_wtr = (gensym: )
  164. my $kid_err = (gensym: )
  165. xpipe: $kid_rdr, $dad_wtr if !$dup_wtr
  166. xpipe: $dad_rdr, $kid_wtr if !$dup_rdr
  167. xpipe: $dad_err, $kid_err if !$dup_err && ($dad_err \!= $dad_rdr)
  168. $kidpid = $do_spawn ?? -1 !! (xfork: )
  169. if ($kidpid == 0) # Kid
  170. # If she wants to dup the kid's stderr onto her stdout I need to
  171. # save a copy of her stdout before I put something else there.
  172. if (($dad_rdr \!= $dad_err) && $dup_err
  173. && (xfileno: $dad_err) == (fileno: $^STDOUT))
  174. my $tmp = (gensym: )
  175. xopen: $tmp, ">&", $dad_err
  176. $dad_err = $tmp
  177. if ($dup_wtr)
  178. xopen: $^STDIN, "<&", $dad_wtr if (fileno: $^STDIN) != xfileno: $dad_wtr
  179. else
  180. xclose: $dad_wtr
  181. xopen: $^STDIN, "<&=", fileno $kid_rdr
  182. if ($dup_rdr)
  183. xopen: $^STDOUT, ">&", $dad_rdr if (fileno: $^STDOUT) != xfileno: $dad_rdr
  184. else
  185. xclose: $dad_rdr
  186. xopen: $^STDOUT, ">&=", $kid_wtr
  187. if ($dad_rdr \!= $dad_err)
  188. if ($dup_err)
  189. # I have to use a fileno here because in this one case
  190. # I'm doing a dup but the filehandle might be a reference
  191. # (from the special case above).
  192. xopen: $^STDERR, ">&", xfileno: $dad_err
  193. if (fileno: $^STDERR) != xfileno: $dad_err
  194. else
  195. xclose: $dad_err
  196. xopen: $^STDERR, ">&=", fileno $kid_err
  197. else
  198. xopen: $^STDERR, ">&", $^STDOUT if (fileno: $^STDERR) != fileno: $^STDOUT
  199. return 0 if (@cmd[0] eq '-')
  200. exec: < @cmd or do
  201. warn: "$Me: exec of $((join: ' ',@cmd)) failed"
  202. try { require POSIX; (POSIX::_exit: 255); }
  203. exit 255
  204. elsif ($do_spawn)
  205. # All the bookkeeping of coincidence between handles is
  206. # handled in spawn_with_handles.
  207. my @close
  208. if ($dup_wtr)
  209. $kid_rdr = \$dad_wtr->*
  210. push: @close, $kid_rdr
  211. else
  212. push: @close, \$dad_wtr->*, $kid_rdr
  213. if ($dup_rdr)
  214. $kid_wtr = \$dad_rdr->*
  215. push: @close, $kid_wtr
  216. else
  217. push: @close, \$dad_rdr->*, $kid_wtr
  218. if ($dad_rdr ne $dad_err)
  219. if ($dup_err)
  220. $kid_err = \$dad_err->*
  221. push: @close, $kid_err
  222. else
  223. push: @close, \$dad_err->*, $kid_err
  224. else
  225. $kid_err = $kid_wtr
  226. require IO::Pipe
  227. $kidpid = try {
  228. (spawn_with_handles: \(@: \ %: mode => 'r'
  229. open_as => $kid_rdr
  230. handle => $^STDIN
  231. \ %: mode => 'w'
  232. open_as => $kid_wtr
  233. handle => $^STDOUT
  234. \ %: mode => 'w'
  235. open_as => $kid_err
  236. handle => $^STDERR
  237. ), \@close, < @cmd);
  238. }
  239. die: "$Me: $^EVAL_ERROR" if $^EVAL_ERROR
  240. xclose: $kid_rdr if !$dup_wtr
  241. xclose: $kid_wtr if !$dup_rdr
  242. xclose: $kid_err if !$dup_err && $dad_rdr \!= $dad_err
  243. # If the write handle is a dup give it away entirely, close my copy
  244. # of it.
  245. xclose: $dad_wtr if $dup_wtr
  246. iohandle::output_autoflush: $dad_wtr, 1 # unbuffer pipe
  247. $kidpid
  248. sub open3
  249. if ((nelems @_) +< 4)
  250. die: "open3($((join: ', ',@_))): not enough arguments"
  251. return _open3: 'open3', scalar caller, < @_
  252. sub spawn_with_handles
  253. my $fds = shift # Fields: handle, mode, open_as
  254. my $close_in_child = shift
  255. my ($pid, @saved_fh, $saved, %saved, @errs)
  256. require Fcntl
  257. foreach my $fd ( $fds->@)
  258. $fd->{+tmp_copy} = IO::Handle->new_from_fd: $fd->{?handle}, $fd->{mode}
  259. %saved{+fileno $fd->{?handle}} = $fd->{?tmp_copy}
  260. foreach my $fd ( $fds->@)
  261. bless: $fd->{?handle}, 'IO::Handle'
  262. unless try { $fd->{?handle}->isa: 'IO::Handle' }
  263. # If some of handles to redirect-to coincide with handles to
  264. # redirect, we need to use saved variants:
  265. $fd->{?handle}->fdopen: %saved{?fileno $fd->{?open_as}} || $fd->{?open_as}
  266. $fd->{mode}
  267. unless ($^OS_NAME eq 'MSWin32')
  268. # Stderr may be redirected below, so we save the err text:
  269. foreach my $fd ( $close_in_child->@)
  270. fcntl: $fd, (Fcntl::F_SETFD: ), 1 or push: @errs, "fcntl $fd: $^OS_ERROR"
  271. unless %saved{?fileno $fd} # Do not close what we redirect!
  272. unless (nelems @errs)
  273. $pid = try { (system: 1, < @_) } # 1 == P_NOWAIT
  274. push: @errs, "IO::Pipe: Can't spawn-NOWAIT: $^OS_ERROR" if !$pid || $pid +< 0
  275. foreach my $fd ( $fds->@)
  276. $fd->{?handle}->fdopen: $fd->{?tmp_copy}, $fd->{mode}
  277. $fd->{tmp_copy}->close or die: "Can't close: $^OS_ERROR"
  278. die: (join: "\n", @errs) if (nelems @errs)
  279. return $pid
  280. 1 # so require is happy