Hi,

With the current m4 from git (branch-1.4), several tests fail on FreeBSD 13
and AIX 7.1 and 7.2, indicating that the syscmd built-in is completely
dysfunctional there:

$ gmake check
Checking ../../checks/001.preprocess
Checking ../../checks/002.debugging_
Checking ../../checks/003.command_li
Checking ../../checks/004.command_li
Checking ../../checks/005.command_li
@ ../doc/m4.texi:991: Origin of test
../../checks/005.command_li: stdout mismatch
--- m4-tmp.12976316/m4-xout     2022-09-22 11:14:37.000000000 -0700
+++ m4-tmp.12976316/m4-out      2022-09-22 11:14:37.000000000 -0700
@@ -1 +1 @@
- 1
+ 127
...
Failed checks were:
  ../../checks/005.command_li:out ../../checks/006.command_li:out 
../../checks/006.command_li:err ../../checks/007.command_li:out 
../../checks/007.command_li:err ../../checks/145.diversions:out 
../../checks/145.diversions:err ../../checks/194.syscmd:out 
../../checks/194.syscmd:err ../../checks/195.syscmd:err 
../../checks/196.esyscmd:out ../../checks/196.esyscmd:err 
../../checks/197.sysval:out ../../checks/197.sysval:err 
../../checks/199.mkstemp:out ../../checks/199.mkstemp:err 
../../checks/200.mkstemp:out ../../checks/200.mkstemp:err 
../../checks/201.mkstemp:out ../../checks/201.mkstemp:err 
../../checks/209.using_froz:out ../../checks/209.using_froz:err

The problem can be reproduced interactively:

$ src/m4
syscmd(`echo')
echo: --:  not found.
m4: syscmd subprocess failed

What happens, is that this invokes "sh -c -- echo". Which does not work. See:

$ sh -c -- echo
echo: --: not found
$ sh -c -- pwd
pwd: --: not found
$ sh -c -- foobar
foobar: --: not found

On Solaris 10, /bin/sh has the same problem, but the configuration of m4 sets
SYSCMD_SHELL = "/usr/xpg4/bin/sh", thus working around the problem in an elegant
way.

On FreeBSD, bash may or may not be installed as /usr/local/bin/bash (part of
the ports collection).
On AIX, bash may or may not be installed as /usr/bin/bash (part of the Bull
Freeware ports).

This is a regression, caused by the commit from 2021-11-19 with title
"syscmd: Allow commands with leading - or +".

Find attached a patch that limits the new behaviour to the commands that
actually start with - or +. With this, the set of failed tests shrinks to

Failed checks were:
  ../../checks/006.command_li:err ../../checks/196.esyscmd:out 
../../checks/196.esyscmd:err ../../checks/197.sysval:out 
../../checks/197.sysval:err ../../checks/198.sysval:out 
../../checks/198.sysval:err ../../checks/199.mkstemp:err

The added line
  prog_args[slot + 1] = NULL;
is currently technically a nop, but makes the code more future-proof
(in case more variation is needed in the prog_args array in the future).

Bruno
>From b331bbaf4eb0581fce24f078561283e3616398f8 Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Fri, 23 Sep 2022 02:36:48 +0200
Subject: [PATCH] syscmd: Make it work again for most commands on FreeBSD and
 AIX.

* src/builtin.c (m4_syscmd): Use "sh -c -- $cmd" only if $cmd starts with
'-' or '+'.
---
 src/builtin.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/src/builtin.c b/src/builtin.c
index 0715a332..0180d625 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -947,7 +947,7 @@ m4_syscmd (struct obstack *obs MAYBE_UNUSED, int argc, token_data **argv)
   const char *cmd = ARG (1);
   int status;
   int sig_status;
-  int slot = 3;
+  int slot;
   const char *prog_args[5] = { "sh", "-c", "--" };
   if (bad_argc (argv[0], argc, 2, 2) || !*cmd)
     {
@@ -964,8 +964,23 @@ m4_syscmd (struct obstack *obs MAYBE_UNUSED, int argc, token_data **argv)
       prog_args[1] = "/c";
       slot = 2;
     }
+  else
 #endif
+    {
+      if (cmd[0] == '-' || cmd[0] == '+')
+        /* If cmd starts with '-' or '+', "sh -c $cmd" is not guaranteed to
+           work.  In this case, use "sh -c -- $cmd".
+           Note: This requires a POSIX compliant SYSCMD_SHELL.  It does not
+           work with /bin/sh on FreeBSD 13 and AIX 7, and on these platforms
+           'bash' is not guaranteed to be installed.  */
+        slot = 3;
+      else
+        /* For most commands, the traditional "sh -c $cmd" works fine.
+           Including on FreeBSD 13 and AIX 7.  */
+        slot = 2;
+    }
   prog_args[slot] = cmd;
+  prog_args[slot + 1] = NULL;
   errno = 0;
   status = execute (ARG (0), SYSCMD_SHELL, prog_args, NULL, false,
                     false, false, false, true, false, &sig_status);
-- 
2.34.1

Reply via email to