dpkg (1.18.25) stretch; urgency=medium
[dpkg] / scripts / Dpkg / IPC.pm
CommitLineData
1479465f
GJ
1# Copyright © 2008-2009 Raphaël Hertzog <hertzog@debian.org>
2# Copyright © 2008 Frank Lichtenheld <djpig@debian.org>
3# Copyright © 2008-2010, 2012-2015 Guillem Jover <guillem@debian.org>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program. If not, see <https://www.gnu.org/licenses/>.
17
18package Dpkg::IPC;
19
20use strict;
21use warnings;
22
23our $VERSION = '1.02';
24our @EXPORT = qw(
25 spawn
26 wait_child
27);
28
29use Carp;
30use Exporter qw(import);
31
32use Dpkg::ErrorHandling;
33use Dpkg::Gettext;
34
35=encoding utf8
36
37=head1 NAME
38
39Dpkg::IPC - helper functions for IPC
40
41=head1 DESCRIPTION
42
43Dpkg::IPC offers helper functions to allow you to execute
44other programs in an easy, yet flexible way, while hiding
45all the gory details of IPC (Inter-Process Communication)
46from you.
47
48=head1 FUNCTIONS
49
50=over 4
51
52=item $pid = spawn(%opts)
53
54Creates a child process and executes another program in it.
55The arguments are interpreted as a hash of options, specifying
56how to handle the in and output of the program to execute.
57Returns the pid of the child process (unless the wait_child
58option was given).
59
60Any error will cause the function to exit with one of the
61Dpkg::ErrorHandling functions.
62
63Options:
64
65=over 4
66
67=item exec
68
69Can be either a scalar, i.e. the name of the program to be
70executed, or an array reference, i.e. the name of the program
71plus additional arguments. Note that the program will never be
72executed via the shell, so you can't specify additional arguments
73in the scalar string and you can't use any shell facilities like
74globbing.
75
76Mandatory Option.
77
78=item from_file, to_file, error_to_file
79
80Filename as scalar. Standard input/output/error of the
81child process will be redirected to the file specified.
82
83=item from_handle, to_handle, error_to_handle
84
85Filehandle. Standard input/output/error of the child process will be
86dup'ed from the handle.
87
88=item from_pipe, to_pipe, error_to_pipe
89
90Scalar reference or object based on IO::Handle. A pipe will be opened for
91each of the two options and either the reading (C<to_pipe> and
92C<error_to_pipe>) or the writing end (C<from_pipe>) will be returned in
93the referenced scalar. Standard input/output/error of the child process
94will be dup'ed to the other ends of the pipes.
95
96=item from_string, to_string, error_to_string
97
98Scalar reference. Standard input/output/error of the child
99process will be redirected to the string given as reference. Note
100that it wouldn't be strictly necessary to use a scalar reference
101for C<from_string>, as the string is not modified in any way. This was
102chosen only for reasons of symmetry with C<to_string> and
103C<error_to_string>. C<to_string> and C<error_to_string> imply the
104C<wait_child> option.
105
106=item wait_child
107
108Scalar. If containing a true value, wait_child() will be called before
109returning. The return value of spawn() will be a true value, not the pid.
110
111=item nocheck
112
113Scalar. Option of the wait_child() call.
114
115=item timeout
116
117Scalar. Option of the wait_child() call.
118
119=item chdir
120
121Scalar. The child process will chdir in the indicated directory before
122calling exec.
123
124=item env
125
126Hash reference. The child process will populate %ENV with the items of the
127hash before calling exec. This allows exporting environment variables.
128
129=item delete_env
130
131Array reference. The child process will remove all environment variables
132listed in the array before calling exec.
133
134=item sig
135
136Hash reference. The child process will populate %SIG with the items of the
137hash before calling exec. This allows setting signal dispositions.
138
139=item delete_sig
140
141Array reference. The child process will reset all signals listed in the
142array to their default dispositions before calling exec.
143
144=back
145
146=cut
147
148sub _sanity_check_opts {
149 my (%opts) = @_;
150
151 croak 'exec parameter is mandatory in spawn()'
152 unless $opts{exec};
153
154 my $to = my $error_to = my $from = 0;
155 foreach my $thing (qw(file handle string pipe)) {
156 $to++ if $opts{"to_$thing"};
157 $error_to++ if $opts{"error_to_$thing"};
158 $from++ if $opts{"from_$thing"};
159 }
160 croak 'not more than one of to_* parameters is allowed'
161 if $to > 1;
162 croak 'not more than one of error_to_* parameters is allowed'
163 if $error_to > 1;
164 croak 'not more than one of from_* parameters is allowed'
165 if $from > 1;
166
167 foreach my $param (qw(to_string error_to_string from_string)) {
168 if (exists $opts{$param} and
169 (not ref $opts{$param} or ref $opts{$param} ne 'SCALAR')) {
170 croak "parameter $param must be a scalar reference";
171 }
172 }
173
174 foreach my $param (qw(to_pipe error_to_pipe from_pipe)) {
175 if (exists $opts{$param} and
176 (not ref $opts{$param} or (ref $opts{$param} ne 'SCALAR' and
177 not $opts{$param}->isa('IO::Handle')))) {
178 croak "parameter $param must be a scalar reference or " .
179 'an IO::Handle object';
180 }
181 }
182
183 if (exists $opts{timeout} and defined($opts{timeout}) and
184 $opts{timeout} !~ /^\d+$/) {
185 croak 'parameter timeout must be an integer';
186 }
187
188 if (exists $opts{env} and ref($opts{env}) ne 'HASH') {
189 croak 'parameter env must be a hash reference';
190 }
191
192 if (exists $opts{delete_env} and ref($opts{delete_env}) ne 'ARRAY') {
193 croak 'parameter delete_env must be an array reference';
194 }
195
196 if (exists $opts{sig} and ref($opts{sig}) ne 'HASH') {
197 croak 'parameter sig must be a hash reference';
198 }
199
200 if (exists $opts{delete_sig} and ref($opts{delete_sig}) ne 'ARRAY') {
201 croak 'parameter delete_sig must be an array reference';
202 }
203
204 return %opts;
205}
206
207sub spawn {
208 my (%opts) = @_;
209 my @prog;
210
211 _sanity_check_opts(%opts);
212 $opts{close_in_child} //= [];
213 if (ref($opts{exec}) =~ /ARRAY/) {
214 push @prog, @{$opts{exec}};
215 } elsif (not ref($opts{exec})) {
216 push @prog, $opts{exec};
217 } else {
218 croak 'invalid exec parameter in spawn()';
219 }
220 my ($from_string_pipe, $to_string_pipe, $error_to_string_pipe);
221 if ($opts{to_string}) {
222 $opts{to_pipe} = \$to_string_pipe;
223 $opts{wait_child} = 1;
224 }
225 if ($opts{error_to_string}) {
226 $opts{error_to_pipe} = \$error_to_string_pipe;
227 $opts{wait_child} = 1;
228 }
229 if ($opts{from_string}) {
230 $opts{from_pipe} = \$from_string_pipe;
231 }
232 # Create pipes if needed
233 my ($input_pipe, $output_pipe, $error_pipe);
234 if ($opts{from_pipe}) {
235 pipe($opts{from_handle}, $input_pipe)
236 or syserr(g_('pipe for %s'), "@prog");
237 ${$opts{from_pipe}} = $input_pipe;
238 push @{$opts{close_in_child}}, $input_pipe;
239 }
240 if ($opts{to_pipe}) {
241 pipe($output_pipe, $opts{to_handle})
242 or syserr(g_('pipe for %s'), "@prog");
243 ${$opts{to_pipe}} = $output_pipe;
244 push @{$opts{close_in_child}}, $output_pipe;
245 }
246 if ($opts{error_to_pipe}) {
247 pipe($error_pipe, $opts{error_to_handle})
248 or syserr(g_('pipe for %s'), "@prog");
249 ${$opts{error_to_pipe}} = $error_pipe;
250 push @{$opts{close_in_child}}, $error_pipe;
251 }
252 # Fork and exec
253 my $pid = fork();
254 syserr(g_('cannot fork for %s'), "@prog") unless defined $pid;
255 if (not $pid) {
256 # Define environment variables
257 if ($opts{env}) {
258 foreach (keys %{$opts{env}}) {
259 $ENV{$_} = $opts{env}{$_};
260 }
261 }
262 if ($opts{delete_env}) {
263 delete $ENV{$_} foreach (@{$opts{delete_env}});
264 }
265 # Define signal dispositions.
266 if ($opts{sig}) {
267 foreach (keys %{$opts{sig}}) {
268 $SIG{$_} = $opts{sig}{$_};
269 }
270 }
271 if ($opts{delete_sig}) {
272 delete $SIG{$_} foreach (@{$opts{delete_sig}});
273 }
274 # Change the current directory
275 if ($opts{chdir}) {
276 chdir($opts{chdir}) or syserr(g_('chdir to %s'), $opts{chdir});
277 }
278 # Redirect STDIN if needed
279 if ($opts{from_file}) {
280 open(STDIN, '<', $opts{from_file})
281 or syserr(g_('cannot open %s'), $opts{from_file});
282 } elsif ($opts{from_handle}) {
283 open(STDIN, '<&', $opts{from_handle})
284 or syserr(g_('reopen stdin'));
285 # has been duped, can be closed
286 push @{$opts{close_in_child}}, $opts{from_handle};
287 }
288 # Redirect STDOUT if needed
289 if ($opts{to_file}) {
290 open(STDOUT, '>', $opts{to_file})
291 or syserr(g_('cannot write %s'), $opts{to_file});
292 } elsif ($opts{to_handle}) {
293 open(STDOUT, '>&', $opts{to_handle})
294 or syserr(g_('reopen stdout'));
295 # has been duped, can be closed
296 push @{$opts{close_in_child}}, $opts{to_handle};
297 }
298 # Redirect STDERR if needed
299 if ($opts{error_to_file}) {
300 open(STDERR, '>', $opts{error_to_file})
301 or syserr(g_('cannot write %s'), $opts{error_to_file});
302 } elsif ($opts{error_to_handle}) {
303 open(STDERR, '>&', $opts{error_to_handle})
304 or syserr(g_('reopen stdout'));
305 # has been duped, can be closed
306 push @{$opts{close_in_child}}, $opts{error_to_handle};
307 }
308 # Close some inherited filehandles
309 close($_) foreach (@{$opts{close_in_child}});
310 # Execute the program
311 exec({ $prog[0] } @prog) or syserr(g_('unable to execute %s'), "@prog");
312 }
313 # Close handle that we can't use any more
314 close($opts{from_handle}) if exists $opts{from_handle};
315 close($opts{to_handle}) if exists $opts{to_handle};
316 close($opts{error_to_handle}) if exists $opts{error_to_handle};
317
318 if ($opts{from_string}) {
319 print { $from_string_pipe } ${$opts{from_string}};
320 close($from_string_pipe);
321 }
322 if ($opts{to_string}) {
323 local $/ = undef;
324 ${$opts{to_string}} = readline($to_string_pipe);
325 }
326 if ($opts{error_to_string}) {
327 local $/ = undef;
328 ${$opts{error_to_string}} = readline($error_to_string_pipe);
329 }
330 if ($opts{wait_child}) {
331 my $cmdline = "@prog";
332 if ($opts{env}) {
333 foreach (keys %{$opts{env}}) {
334 $cmdline = "$_=\"" . $opts{env}{$_} . "\" $cmdline";
335 }
336 }
337 wait_child($pid, nocheck => $opts{nocheck},
338 timeout => $opts{timeout}, cmdline => $cmdline);
339 return 1;
340 }
341
342 return $pid;
343}
344
345
346=item wait_child($pid, %opts)
347
348Takes as first argument the pid of the process to wait for.
349Remaining arguments are taken as a hash of options. Returns
350nothing. Fails if the child has been ended by a signal or
351if it exited non-zero.
352
353Options:
354
355=over 4
356
357=item cmdline
358
359String to identify the child process in error messages.
360Defaults to "child process".
361
362=item nocheck
363
364If true do not check the return status of the child (and thus
365do not fail it has been killed or if it exited with a
366non-zero return code).
367
368=item timeout
369
370Set a maximum time to wait for the process, after that kill the process and
371fail with an error message.
372
373=back
374
375=cut
376
377sub wait_child {
378 my ($pid, %opts) = @_;
379 $opts{cmdline} //= g_('child process');
380 croak 'no PID set, cannot wait end of process' unless $pid;
381 eval {
382 local $SIG{ALRM} = sub { die "alarm\n" };
383 alarm($opts{timeout}) if defined($opts{timeout});
384 $pid == waitpid($pid, 0) or syserr(g_('wait for %s'), $opts{cmdline});
385 alarm(0) if defined($opts{timeout});
386 };
387 if ($@) {
388 die $@ unless $@ eq "alarm\n";
389 kill 'TERM', $pid;
390 error(P_("%s didn't complete in %d second",
391 "%s didn't complete in %d seconds",
392 $opts{timeout}),
393 $opts{cmdline}, $opts{timeout});
394 }
395 unless ($opts{nocheck}) {
396 subprocerr($opts{cmdline}) if $?;
397 }
398}
399
4001;
401__END__
402
403=back
404
405=head1 CHANGES
406
407=head2 Version 1.02 (dpkg 1.18.0)
408
409Change options: wait_child() now kills the process when reaching the 'timeout'.
410
411=head2 Version 1.01 (dpkg 1.17.11)
412
413New options: spawn() now accepts 'sig' and 'delete_sig'.
414
415=head2 Version 1.00 (dpkg 1.15.6)
416
417Mark the module as public.
418
419=head1 SEE ALSO
420
421Dpkg, Dpkg::ErrorHandling