[debhelper-devel] [debhelper] 01/08: Dh_Lib: Fix shell bug and add stdout redirect

Niels Thykier nthykier at moszumanska.debian.org
Sat Jul 15 19:12:35 UTC 2017


This is an automated email from the git hooks/post-receive script.

nthykier pushed a commit to branch shell-out-less
in repository debhelper.

commit 6e8a58139d303d1252c8df8eabcb11bd7145032a
Author: Niels Thykier <niels at thykier.net>
Date:   Sat Jul 15 10:05:13 2017 +0000

    Dh_Lib: Fix shell bug and add stdout redirect
    
    Signed-off-by: Niels Thykier <niels at thykier.net>
---
 Debian/Debhelper/Dh_Lib.pm | 52 +++++++++++++++++++++++++++++++++-------------
 debhelper.pod              | 10 +++++++++
 debian/changelog           |  7 +++++++
 doc/PROGRAMMING            | 18 +++++++++++++---
 4 files changed, 70 insertions(+), 17 deletions(-)

diff --git a/Debian/Debhelper/Dh_Lib.pm b/Debian/Debhelper/Dh_Lib.pm
index 95b8f13..14bfcfe 100644
--- a/Debian/Debhelper/Dh_Lib.pm
+++ b/Debian/Debhelper/Dh_Lib.pm
@@ -286,33 +286,57 @@ sub escape_shell {
 # Note that this cannot handle complex commands, especially anything
 # involving redirection. Use complex_doit instead.
 sub doit {
-	doit_noerror(@_) || error_exitcode(join(" ", @_));
+	doit_noerror(@_) || error_exitcode(_format_cmdline(@_));
 }
 
 sub doit_noerror {
-	verbose_print(escape_shell(@_));
+	verbose_print(_format_cmdline(@_)) if $dh{VERBOSE};
 
-	if (! $dh{NO_ACT}) {
-		return (system(@_) == 0)
-	}
-	else {
-		return 1;
-	}
+	goto \&_doit;
 }
 
 sub print_and_doit {
-	print_and_doit_noerror(@_) || error_exitcode(join(" ", @_));
+	print_and_doit_noerror(@_) || error_exitcode(_format_cmdline(@_));
 }
 
 sub print_and_doit_noerror {
-	nonquiet_print(escape_shell(@_));
+	nonquiet_print(_format_cmdline(@_));
 
-	if (! $dh{NO_ACT}) {
-		return (system(@_) == 0)
+	goto \&_doit;
+}
+
+sub _doit {
+	my (@cmd) = @_;
+	my $options = ref($cmd[0]) ? shift(@cmd) : undef;
+	# In compat <= 10, we warn, compat 11 we detect and error, in
+	# compat 12 we assume peolpe know what they are doing.
+	if (not defined($options) and @cmd == 1 and not compat(11) and $cmd[0] =~ m/[\s<&>|;]/) {
+		deprecated_functionality('doit() + doit_*() calls will no longer spawn a shell in compat 11 for single string arguments (please use complex_doit instead)',
+								 11);
+		return 1 if $dh{NO_ACT};
+		return system(@cmd) == 0;
 	}
-	else {
-		return 1;
+	return 1 if $dh{NO_ACT};
+	my $pid = fork() // error("fork(): $!");
+	if (not $pid) {
+		if (defined($options)) {
+			if (defined(my $output = $options->{stdout})) {
+				open(STDOUT, '>', $output) or error("redirect STDOUT failed: $!");
+			}
+		}
+		exec(@cmd);
+	}
+	return waitpid($pid, 0) == $pid && $? == 0;
+}
+
+sub _format_cmdline {
+	my (@cmd) = @_;
+	my $options = ref($cmd[0]) ? shift(@cmd) : {};
+	my $cmd_line = escape_shell(@cmd);
+	if (defined(my $output = $options->{stdout})) {
+		$cmd_line .= ' > ' . escape_shell($output);
 	}
+	return $cmd_line;
 }
 
 # Run a command and display the command to stdout if verbose mode is on.
diff --git a/debhelper.pod b/debhelper.pod
index 036bde2..03fec65 100644
--- a/debhelper.pod
+++ b/debhelper.pod
@@ -679,6 +679,16 @@ to drop support for the B<PERL_USE_UNSAFE_INC> environment variable.
 When perl drops support for it, then this variable will be removed
 retroactively from existing compat levels as well.
 
+=item -
+
+There was a bug in the B<doit> (and similar) functions from
+L<Debian::Debhelper::Dh_Lib> that made them spawn a shell in one
+particular circumstance.  This bug is now removed and will cause
+helpers that rely on the bug to fail with an error.
+
+In compatibility 11, there is still a detection for this case.  This
+detection will be removed in compatibility level 12.
+
 =back
 
 =back
diff --git a/debian/changelog b/debian/changelog
index b381c5e..fac2d49 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,6 +1,13 @@
 debhelper (10.7) UNRELEASED; urgency=medium
 
   * dh_usrlocal: Fix call to doit to avoid making it fork a shell.
+  * Dh_Lib: Fix bug in doit + doit_* that made them fork a shell in
+    some cases.  For backwards compatibility, there is detection code
+    that should make warn for this case.  This can cause a weird
+    "Please specify the compatibility level in debian/compat" error if
+    the tools have chdir to a different directory.
+  * Dh_Lib: Support an optional hashref in doit + doit_* to enable some
+    trivial operations in the child process (e.g. redirect stdout).
 
  -- Niels Thykier <niels at thykier.net>  Sat, 15 Jul 2017 09:42:32 +0000
 
diff --git a/doc/PROGRAMMING b/doc/PROGRAMMING
index fa87fc5..f195e4a 100644
--- a/doc/PROGRAMMING
+++ b/doc/PROGRAMMING
@@ -155,12 +155,24 @@ Functions:
 
 Dh_Lib.pm also contains a number of functions you may find useful.
 
-doit(@command)
-	Pass this function an array that is a 
-	shell command. It will run the command (unless $dh{NO_ACT} is set), and
+doit([$options, ]@command)
+	Pass this function an array that is a command with arguments.
+	It will run the command (unless $dh{NO_ACT} is set), and
 	if $dh{VERBOSE} is set, it will also output the command to stdout. You
 	should use this function for almost all commands your program performs
 	that manipulate files in the package build directories.
+
+	The $options argument (if passed) must be a hashref (added in debhelper 10.7).
+	The following key-value pairs can be used:
+	  * stdout => A file name.  The child process will have its STDOUT redirected
+	    to that file.  [debhelper (>= 10.7)]
+
+	This will *not* invoke a shell, so meta characters will not have any special
+	meaning.  Use complex_doit for that.
+	NB: In compat 10 and below, there was a bug that would make doit fork a shell
+	in one special case.  This is deprecated and will be removed in compat 11.
+	The detection code for this can be disabled by passing an empty hashref for
+	as $options.  This will make doit unconditonally avoid forking a shell.
 print_and_doit(@command)
         Like doit but will print unless $dh{QUIET} is set. See "Standardization"
         above for when this is allowed to be called.

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debhelper/debhelper.git




More information about the debhelper-devel mailing list