Package: moreutils
Version: 0.35
Severity: minor
Tags: patch
Hello, thanks alot for moreutils (and all the stuff you wrote that we
use on a daily basis...)
When mispipe executes its commands, with the the pipe duplicated as the
standard input (resp. output), the original file descriptor for it is
left open until after the command terminates.
This will cause the following commands to hang:
$ sudo mispipe '/etc/init.d/cron restart' 'logger -s'
logger: Restarting periodic command scheduler: cron.
*hangs*
$ sudo mispipe 'cat /dev/zero' '/etc/init.d/cron restart'
Restarting periodic command scheduler: cron.
*hangs*
What happens here is that the spawned cron daemon will inherit the pipe
as file descriptor 3 or 4 and keep it open, preventing 'cat /dev/null'
or 'logger -s' from terminating:
$ sudo lsof -n | egrep 687643
mispipe 4718 root 0r FIFO 0,6 0t0 687643 pipe
mispipe 4718 root 3r FIFO 0,6 0t0 687643 pipe
logger 4720 root 0r FIFO 0,6 0t0 687643 pipe
logger 4720 root 3r FIFO 0,6 0t0 687643 pipe
cron 4735 root 4w FIFO 0,6 0t0 687643 pipe
The attached patch makes mispipe close the original file descriptor
after it has been duplicated, but before the command is executed.
I could also use FD_CLOEXEC or a command-line switch if you think this
behaviour would cause problems in other circumstances.
Regards,
--
Jeremie Koenig <[email protected]>
http://jk.fr.eu.org
--- mispipe.c.orig 2009-06-17 17:23:17.000000000 +0200
+++ mispipe.c 2009-06-17 17:30:04.000000000 +0200
@@ -107,15 +107,15 @@
/* Make the reading end of the pipe the new standard input. */
if (dup2(filedes[0], 0) == -1)
error_with_errno("Failed (in child) redefining standard input");
+ /* Close the original file descriptor for it */
+ if (close(filedes[0]))
+ error_with_errno("Failed (in child) closing filedes[0]");
/* Close the other end of the pipe. */
if (close(filedes[1]))
error_with_errno("Failed (in child) closing filedes[1]");
/* Do the second command, and throw away the exit status. */
system(cmd);
- /* Close all the file descriptors. */
- if (close(filedes[0]))
- error_with_errno("Failed (in child) closing filedes[0]"
- " (while cleaning up)");
+ /* Close the standard input. */
if (close(0))
error_with_errno("Failed (in child) closing standard output "
" (while cleaning up)");
@@ -151,15 +151,15 @@
/* Make the writing end of the pipe the new standard output. */
if (dup2(filedes[1], 1) == -1)
error_with_errno("Failed redefining standard output");
+ /* Close the original file descriptor for it. */
+ if (close(filedes[1]))
+ error_with_errno("Failed closing filedes[1]");
/* Close the other end of the pipe. */
if (close(filedes[0]))
error_with_errno("Failed closing filedes[0]");
/* Do the first command, and (crucially) get the status. */
status_big = system(argv[1]);
- /* Close the pipe "standard output". */
- if (close(filedes[1]))
- error_with_errno("Failed closing filedes[1] (while cleaning up)");
/* Close standard output. */
if (close(1))
error_with_errno("Failed closing standard output (while cleaning up)");