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>
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.
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.
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/>.
22 Dpkg::IPC - helper functions for IPC
26 Dpkg::IPC offers helper functions to allow you to execute
27 other programs in an easy, yet flexible way, while hiding
28 all the gory details of IPC (Inter-Process Communication)
33 package Dpkg
::IPC
1.02;
44 use Exporter
qw(import);
46 use Dpkg
::ErrorHandling
;
53 =item $pid = spawn(%opts)
55 Creates a child process and executes another program in it.
56 The arguments are interpreted as a hash of options, specifying
57 how to handle the in and output of the program to execute.
58 Returns the pid of the child process (unless the wait_child
61 Any error will cause the function to exit with one of the
62 Dpkg::ErrorHandling functions.
70 Can be either a scalar, i.e. the name of the program to be
71 executed, or an array reference, i.e. the name of the program
72 plus additional arguments. Note that the program will never be
73 executed via the shell, so you can't specify additional arguments
74 in the scalar string and you can't use any shell facilities like
79 =item from_file, to_file, error_to_file
81 Filename as scalar. Standard input/output/error of the
82 child process will be redirected to the file specified.
84 =item from_handle, to_handle, error_to_handle
86 Filehandle. Standard input/output/error of the child process will be
87 dup'ed from the handle.
89 =item from_pipe, to_pipe, error_to_pipe
91 Scalar reference or object based on IO::Handle. A pipe will be opened for
92 each of the two options and either the reading (C<to_pipe> and
93 C<error_to_pipe>) or the writing end (C<from_pipe>) will be returned in
94 the referenced scalar. Standard input/output/error of the child process
95 will be dup'ed to the other ends of the pipes.
97 =item from_string, to_string, error_to_string
99 Scalar reference. Standard input/output/error of the child
100 process will be redirected to the string given as reference. Note
101 that it wouldn't be strictly necessary to use a scalar reference
102 for C<from_string>, as the string is not modified in any way. This was
103 chosen only for reasons of symmetry with C<to_string> and
104 C<error_to_string>. C<to_string> and C<error_to_string> imply the
105 C<wait_child> option.
109 Scalar. If containing a true value, wait_child() will be called before
110 returning. The return value of spawn() will be a true value, not the pid.
114 Scalar. Option of the wait_child() call.
118 Scalar. Option of the wait_child() call.
122 Scalar. The child process will chdir in the indicated directory before
127 Hash reference. The child process will populate %ENV with the items of the
128 hash before calling exec. This allows exporting environment variables.
132 Array reference. The child process will remove all environment variables
133 listed in the array before calling exec.
137 Hash reference. The child process will populate %SIG with the items of the
138 hash before calling exec. This allows setting signal dispositions.
142 Array reference. The child process will reset all signals listed in the
143 array to their default dispositions before calling exec.
152 croak
'exec parameter is mandatory in spawn()'
155 my $to = my $error_to = my $from = 0;
156 foreach my $thing (qw(file handle string pipe)) {
157 $to++ if $opts{"to_$thing"};
158 $error_to++ if $opts{"error_to_$thing"};
159 $from++ if $opts{"from_$thing"};
161 croak
'not more than one of to_* parameters is allowed'
163 croak
'not more than one of error_to_* parameters is allowed'
165 croak
'not more than one of from_* parameters is allowed'
168 foreach my $param (qw(to_string error_to_string from_string)) {
169 if (exists $opts{$param} and
170 (not ref $opts{$param} or ref $opts{$param} ne 'SCALAR')) {
171 croak
"parameter $param must be a scalar reference";
175 foreach my $param (qw(to_pipe error_to_pipe from_pipe)) {
176 if (exists $opts{$param} and
177 (not ref $opts{$param} or (ref $opts{$param} ne 'SCALAR' and
178 not $opts{$param}->isa('IO::Handle')))) {
179 croak
"parameter $param must be a scalar reference or " .
180 'an IO::Handle object';
184 if (exists $opts{timeout
} and defined($opts{timeout
}) and
185 $opts{timeout
} !~ /^\d+$/) {
186 croak
'parameter timeout must be an integer';
189 if (exists $opts{env
} and ref($opts{env
}) ne 'HASH') {
190 croak
'parameter env must be a hash reference';
193 if (exists $opts{delete_env
} and ref($opts{delete_env
}) ne 'ARRAY') {
194 croak
'parameter delete_env must be an array reference';
197 if (exists $opts{sig
} and ref($opts{sig
}) ne 'HASH') {
198 croak
'parameter sig must be a hash reference';
201 if (exists $opts{delete_sig
} and ref($opts{delete_sig
}) ne 'ARRAY') {
202 croak
'parameter delete_sig must be an array reference';
213 $opts{close_in_child
} //= [];
214 if (ref($opts{exec}) =~ /ARRAY/) {
215 push @prog, @
{$opts{exec}};
216 } elsif (not ref($opts{exec})) {
217 push @prog, $opts{exec};
219 croak
'invalid exec parameter in spawn()';
221 my ($from_string_pipe, $to_string_pipe, $error_to_string_pipe);
222 if ($opts{to_string
}) {
223 $opts{to_pipe
} = \
$to_string_pipe;
224 $opts{wait_child
} = 1;
226 if ($opts{error_to_string
}) {
227 $opts{error_to_pipe
} = \
$error_to_string_pipe;
228 $opts{wait_child
} = 1;
230 if ($opts{from_string
}) {
231 $opts{from_pipe
} = \
$from_string_pipe;
233 # Create pipes if needed
234 my ($input_pipe, $output_pipe, $error_pipe);
235 if ($opts{from_pipe
}) {
236 pipe($opts{from_handle
}, $input_pipe)
237 or syserr
(g_
('pipe for %s'), "@prog");
238 ${$opts{from_pipe
}} = $input_pipe;
239 push @
{$opts{close_in_child
}}, $input_pipe;
241 if ($opts{to_pipe
}) {
242 pipe($output_pipe, $opts{to_handle
})
243 or syserr
(g_
('pipe for %s'), "@prog");
244 ${$opts{to_pipe
}} = $output_pipe;
245 push @
{$opts{close_in_child
}}, $output_pipe;
247 if ($opts{error_to_pipe
}) {
248 pipe($error_pipe, $opts{error_to_handle
})
249 or syserr
(g_
('pipe for %s'), "@prog");
250 ${$opts{error_to_pipe
}} = $error_pipe;
251 push @
{$opts{close_in_child
}}, $error_pipe;
255 syserr
(g_
('cannot fork for %s'), "@prog") unless defined $pid;
257 # Define environment variables
259 foreach (keys %{$opts{env
}}) {
260 $ENV{$_} = $opts{env
}{$_};
263 if ($opts{delete_env
}) {
264 delete $ENV{$_} foreach (@
{$opts{delete_env
}});
266 # Define signal dispositions.
268 foreach (keys %{$opts{sig
}}) {
269 $SIG{$_} = $opts{sig
}{$_};
272 if ($opts{delete_sig
}) {
273 delete $SIG{$_} foreach (@
{$opts{delete_sig
}});
275 # Change the current directory
277 chdir($opts{chdir}) or syserr
(g_
('chdir to %s'), $opts{chdir});
279 # Redirect STDIN if needed
280 if ($opts{from_file
}) {
281 open(STDIN
, '<', $opts{from_file
})
282 or syserr
(g_
('cannot open %s'), $opts{from_file
});
283 } elsif ($opts{from_handle
}) {
284 open(STDIN
, '<&', $opts{from_handle
})
285 or syserr
(g_
('reopen stdin'));
286 # has been duped, can be closed
287 push @
{$opts{close_in_child
}}, $opts{from_handle
};
289 # Redirect STDOUT if needed
290 if ($opts{to_file
}) {
291 open(STDOUT
, '>', $opts{to_file
})
292 or syserr
(g_
('cannot write %s'), $opts{to_file
});
293 } elsif ($opts{to_handle
}) {
294 open(STDOUT
, '>&', $opts{to_handle
})
295 or syserr
(g_
('reopen stdout'));
296 # has been duped, can be closed
297 push @
{$opts{close_in_child
}}, $opts{to_handle
};
299 # Redirect STDERR if needed
300 if ($opts{error_to_file
}) {
301 open(STDERR
, '>', $opts{error_to_file
})
302 or syserr
(g_
('cannot write %s'), $opts{error_to_file
});
303 } elsif ($opts{error_to_handle
}) {
304 open(STDERR
, '>&', $opts{error_to_handle
})
305 or syserr
(g_
('reopen stdout'));
306 # has been duped, can be closed
307 push @
{$opts{close_in_child
}}, $opts{error_to_handle
};
309 # Close some inherited filehandles
310 close($_) foreach (@
{$opts{close_in_child
}});
311 # Execute the program
312 exec({ $prog[0] } @prog) or syserr
(g_
('unable to execute %s'), "@prog");
314 # Close handle that we can't use any more
315 close($opts{from_handle
}) if exists $opts{from_handle
};
316 close($opts{to_handle
}) if exists $opts{to_handle
};
317 close($opts{error_to_handle
}) if exists $opts{error_to_handle
};
319 if ($opts{from_string
}) {
320 print { $from_string_pipe } ${$opts{from_string
}};
321 close($from_string_pipe);
323 if ($opts{to_string
}) {
325 ${$opts{to_string
}} = readline($to_string_pipe);
327 if ($opts{error_to_string
}) {
329 ${$opts{error_to_string
}} = readline($error_to_string_pipe);
331 if ($opts{wait_child
}) {
332 my $cmdline = "@prog";
334 foreach (keys %{$opts{env
}}) {
335 $cmdline = "$_=\"" . $opts{env
}{$_} . "\" $cmdline";
338 wait_child
($pid, nocheck
=> $opts{nocheck
},
339 timeout
=> $opts{timeout
}, cmdline
=> $cmdline);
347 =item wait_child($pid, %opts)
349 Takes as first argument the pid of the process to wait for.
350 Remaining arguments are taken as a hash of options. Returns
351 nothing. Fails if the child has been ended by a signal or
352 if it exited non-zero.
360 String to identify the child process in error messages.
361 Defaults to "child process".
365 If true do not check the return status of the child (and thus
366 do not fail it has been killed or if it exited with a
367 non-zero return code).
371 Set a maximum time to wait for the process, after that kill the process and
372 fail with an error message.
379 my ($pid, %opts) = @_;
380 $opts{cmdline
} //= g_
('child process');
381 croak
'no PID set, cannot wait end of process' unless $pid;
383 local $SIG{ALRM
} = sub { die "alarm\n" };
384 alarm($opts{timeout
}) if defined($opts{timeout
});
385 $pid == waitpid($pid, 0) or syserr
(g_
('wait for %s'), $opts{cmdline
});
386 alarm(0) if defined($opts{timeout
});
389 die $@
unless $@
eq "alarm\n";
391 error
(P_
("%s didn't complete in %d second",
392 "%s didn't complete in %d seconds",
394 $opts{cmdline
}, $opts{timeout
});
396 unless ($opts{nocheck
}) {
397 subprocerr
($opts{cmdline
}) if $?
;
407 =head2 Version 1.02 (dpkg 1.18.0)
409 Change options: wait_child() now kills the process when reaching the 'timeout'.
411 =head2 Version 1.01 (dpkg 1.17.11)
413 New options: spawn() now accepts 'sig' and 'delete_sig'.
415 =head2 Version 1.00 (dpkg 1.15.6)
417 Mark the module as public.
421 Dpkg, Dpkg::ErrorHandling