bug-gnulib@gnu.org mirror (unofficial)
 help / color / mirror / Atom feed
From: Bruno Haible <bruno@clisp.org>
To: bug-gnulib@gnu.org
Cc: Eli Zaretskii <eliz@gnu.org>
Subject: new modules execve, execvpe, execvp, execv, execl, execle, execlp
Date: Sat, 26 Dec 2020 14:53:36 +0100	[thread overview]
Message-ID: <19625603.TXvseGJZxX@omega> (raw)

[-- Attachment #1: Type: text/plain, Size: 3682 bytes --]

Eli Zaretskii wrote in
<https://lists.gnu.org/archive/html/bug-grep/2014-05/msg00118.html>:

  ... found that the implementation of the exec* family did
  the following: it started the process that runs the child program, and
  then immediately exited without waiting for the child to finish.
  ...
  The solution was to reimplement execvp in a way that didn't exit ...
  until the child program finished.

Indeed, that is a major problem with these exec* implementations: The
parent process cannot know the exit code if the exec'd process runs
asynchronously.

Another major problem is that the Windows _spawnv* and CreateProcess
functions split the arguments when they contain spaces or special
characters.

All of these problems are fixed with these new Gnulib modules.


2020-12-26  Bruno Haible  <bruno@clisp.org>

	execlp: Add tests.
	* tests/test-execlp-main.c: New file.
	* tests/test-execlp.sh: New file.
	* modules/execlp-tests: New file.

	execlp: New module.
	* lib/execlp.c: New file.
	* m4/execlp.m4: New file.
	* modules/execlp: New file.
	* doc/posix-functions/execlp.texi: Mention more Windows problems and the
	new module.

	execle: Add tests.
	* tests/test-execle-main.c: New file.
	* tests/test-execle.sh: New file.
	* modules/execle-tests: New file.

	execle: New module.
	* lib/execle.c: New file.
	* m4/execle.m4: New file.
	* modules/execle: New file.
	* doc/posix-functions/execle.texi: Mention more Windows problems and the
	new module.

	execl: Add tests.
	* tests/test-execl-main.c: New file.
	* tests/test-execl.sh: New file.
	* modules/execl-tests: New file.

	execl: New module.
	* lib/execl.c: New file.
	* m4/execl.m4: New file.
	* modules/execl: New file.
	* doc/posix-functions/execl.texi: Mention more Windows problems and the
	new module.

	execv: Add tests.
	* tests/test-execv-main.c: New file.
	* tests/test-execv.sh: New file.
	* modules/execv-tests: New file.

	execv: New module.
	* lib/execv.c: New file.
	* m4/execv.m4: New file.
	* modules/execv: New file.
	* doc/posix-functions/execv.texi: Mention more Windows problems and the
	new module.

	execvp: Add tests.
	* tests/test-execvp-main.c: New file.
	* tests/test-execvp.sh: New file.
	* modules/execvp-tests: New file.

	execvp: New module.
	* lib/execvp.c: New file.
	* m4/execvp.m4: New file.
	* modules/execvp: New file.
	* doc/posix-functions/execvp.texi: Mention more Windows problems and the
	new module.

	execvpe: Add tests.
	* tests/test-execvpe-main.c: New file.
	* tests/test-execvpe.sh: New file.
	* modules/execvpe-tests: New file.

	execvpe: New module.
	* lib/execvpe.c: New file.
	* m4/execvpe.m4: New file.
	* modules/execvpe: New file.
	* doc/glibc-functions/execvpe.texi: Mention the Windows problems and the
	new module.

	execve: Add tests.
	* tests/test-exec-child.c: New file.
	* tests/test-execve-main.c: New file.
	* tests/test-execve.sh: New file.
	* modules/execve-tests: New file.

	execve: New module.
	* lib/execve.c: New file.
	* m4/execve.m4: New file.
	* modules/execve: New file.
	* doc/posix-functions/execve.texi: Mention more Windows problems and the
	new module.

	execve, execvpe, execvp, execv, execl, execle, execlp: Prepare modules.
	* lib/unistd.in.h (execl, execle, execlp, execv, execve, execvp,
	execvpe): Add declarations for the new modules.
	* m4/unistd_h.m4 (gl_UNISTD_H): Test whether execl, execle, execlp,
	execv, execve, execvp, execvpe are declared.
	(gl_UNISTD_H_DEFAULTS): Initialize GNULIB_EXEC*, HAVE_EXECVPE,
	REPLACE_EXEC*.
	* modules/unistd (Makefile.am): Substitute GNULIB_EXEC*, HAVE_EXECVPE,
	REPLACE_EXEC*.
	* tests/test-unistd-c++.cc: Check the signature of execl, execle,
	execlp, execv, execve, execvp, execvpe.


[-- Attachment #2: 0001-execve-execvpe-execvp-execv-execl-execle-execlp-Prep.patch --]
[-- Type: text/x-patch, Size: 19294 bytes --]

From ba3aeabdd5317c3e21d1da54577235a054ce60f3 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Sat, 26 Dec 2020 14:09:29 +0100
Subject: [PATCH 01/15] execve, execvpe, execvp, execv, execl, execle, execlp:
 Prepare modules.

* lib/unistd.in.h (execl, execle, execlp, execv, execve, execvp,
execvpe): Add declarations for the new modules.
* m4/unistd_h.m4 (gl_UNISTD_H): Test whether execl, execle, execlp,
execv, execve, execvp, execvpe are declared.
(gl_UNISTD_H_DEFAULTS): Initialize GNULIB_EXEC*, HAVE_EXECVPE,
REPLACE_EXEC*.
* modules/unistd (Makefile.am): Substitute GNULIB_EXEC*, HAVE_EXECVPE,
REPLACE_EXEC*.
* tests/test-unistd-c++.cc: Check the signature of execl, execle,
execlp, execv, execve, execvp, execvpe.
---
 ChangeLog                |  14 ++++
 lib/unistd.in.h          | 195 +++++++++++++++++++++++++++++++++++++++++------
 m4/unistd_h.m4           |  18 ++++-
 modules/unistd           |  15 ++++
 tests/test-unistd-c++.cc |  35 +++++++++
 5 files changed, 253 insertions(+), 24 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 6752466..459df8e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,19 @@
 2020-12-26  Bruno Haible  <bruno@clisp.org>
 
+	execve, execvpe, execvp, execv, execl, execle, execlp: Prepare modules.
+	* lib/unistd.in.h (execl, execle, execlp, execv, execve, execvp,
+	execvpe): Add declarations for the new modules.
+	* m4/unistd_h.m4 (gl_UNISTD_H): Test whether execl, execle, execlp,
+	execv, execve, execvp, execvpe are declared.
+	(gl_UNISTD_H_DEFAULTS): Initialize GNULIB_EXEC*, HAVE_EXECVPE,
+	REPLACE_EXEC*.
+	* modules/unistd (Makefile.am): Substitute GNULIB_EXEC*, HAVE_EXECVPE,
+	REPLACE_EXEC*.
+	* tests/test-unistd-c++.cc: Check the signature of execl, execle,
+	execlp, execv, execve, execvp, execvpe.
+
+2020-12-26  Bruno Haible  <bruno@clisp.org>
+
 	stack: Fix typo in comments.
 	* lib/stack.h: Fix typo in comments.
 
diff --git a/lib/unistd.in.h b/lib/unistd.in.h
index 7517e3b..d43556a 100644
--- a/lib/unistd.in.h
+++ b/lib/unistd.in.h
@@ -615,7 +615,26 @@ _GL_WARN_ON_USE (euidaccess, "euidaccess is unportable - "
 #endif
 
 
-#if @GNULIB_MDA_EXECL@
+#if @GNULIB_EXECL@
+# if @REPLACE_EXECL@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef execl
+#   define execl rpl_execl
+#  endif
+_GL_FUNCDECL_RPL (execl, int, (const char *program, const char *arg, ...)
+                              _GL_ARG_NONNULL ((1)));
+_GL_CXXALIAS_RPL (execl, int, (const char *program, const char *arg, ...));
+# else
+_GL_CXXALIAS_SYS (execl, int, (const char *program, const char *arg, ...));
+# endif
+_GL_CXXALIASWARN (execl);
+#elif defined GNULIB_POSIXCHECK
+# undef execl
+# if HAVE_RAW_DECL_EXECL
+_GL_WARN_ON_USE (execl, "execl behaves very differently on mingw - "
+                 "use gnulib module execl for portability");
+# endif
+#elif @GNULIB_MDA_EXECL@
 /* On native Windows, map 'execl' to '_execl', so that -loldnames is not
    required.  In C++ with GNULIB_NAMESPACE, avoid differences between
    platforms by defining GNULIB_NAMESPACE::execl always.  */
@@ -631,7 +650,26 @@ _GL_CXXALIAS_SYS (execl, int, (const char *program, const char *arg, ...));
 _GL_CXXALIASWARN (execl);
 #endif
 
-#if @GNULIB_MDA_EXECLE@
+#if @GNULIB_EXECLE@
+# if @REPLACE_EXECLE@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef execle
+#   define execle rpl_execle
+#  endif
+_GL_FUNCDECL_RPL (execle, int, (const char *program, const char *arg, ...)
+                               _GL_ARG_NONNULL ((1)));
+_GL_CXXALIAS_RPL (execle, int, (const char *program, const char *arg, ...));
+# else
+_GL_CXXALIAS_SYS (execle, int, (const char *program, const char *arg, ...));
+# endif
+_GL_CXXALIASWARN (execle);
+#elif defined GNULIB_POSIXCHECK
+# undef execle
+# if HAVE_RAW_DECL_EXECLE
+_GL_WARN_ON_USE (execle, "execle behaves very differently on mingw - "
+                 "use gnulib module execle for portability");
+# endif
+#elif @GNULIB_MDA_EXECLE@
 /* On native Windows, map 'execle' to '_execle', so that -loldnames is not
    required.  In C++ with GNULIB_NAMESPACE, avoid differences between
    platforms by defining GNULIB_NAMESPACE::execle always.  */
@@ -640,14 +678,34 @@ _GL_CXXALIASWARN (execl);
 #   undef execle
 #   define execle _execle
 #  endif
-_GL_CXXALIAS_MDA (execle, intptr_t, (const char *program, const char *arg, ...));
+_GL_CXXALIAS_MDA (execle, intptr_t,
+                  (const char *program, const char *arg, ...));
 # else
 _GL_CXXALIAS_SYS (execle, int, (const char *program, const char *arg, ...));
 # endif
 _GL_CXXALIASWARN (execle);
 #endif
 
-#if @GNULIB_MDA_EXECLP@
+#if @GNULIB_EXECLP@
+# if @REPLACE_EXECLP@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef execlp
+#   define execlp rpl_execlp
+#  endif
+_GL_FUNCDECL_RPL (execlp, int, (const char *program, const char *arg, ...)
+                               _GL_ARG_NONNULL ((1)));
+_GL_CXXALIAS_RPL (execlp, int, (const char *program, const char *arg, ...));
+# else
+_GL_CXXALIAS_SYS (execlp, int, (const char *program, const char *arg, ...));
+# endif
+_GL_CXXALIASWARN (execlp);
+#elif defined GNULIB_POSIXCHECK
+# undef execlp
+# if HAVE_RAW_DECL_EXECLP
+_GL_WARN_ON_USE (execlp, "execlp behaves very differently on mingw - "
+                 "use gnulib module execlp for portability");
+# endif
+#elif @GNULIB_MDA_EXECLP@
 /* On native Windows, map 'execlp' to '_execlp', so that -loldnames is not
    required.  In C++ with GNULIB_NAMESPACE, avoid differences between
    platforms by defining GNULIB_NAMESPACE::execlp always.  */
@@ -656,7 +714,8 @@ _GL_CXXALIASWARN (execle);
 #   undef execlp
 #   define execlp _execlp
 #  endif
-_GL_CXXALIAS_MDA (execlp, intptr_t, (const char *program, const char *arg, ...));
+_GL_CXXALIAS_MDA (execlp, intptr_t,
+                  (const char *program, const char *arg, ...));
 # else
 _GL_CXXALIAS_SYS (execlp, int, (const char *program, const char *arg, ...));
 # endif
@@ -664,7 +723,26 @@ _GL_CXXALIASWARN (execlp);
 #endif
 
 
-#if @GNULIB_MDA_EXECV@
+#if @GNULIB_EXECV@
+# if @REPLACE_EXECV@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef execv
+#   define execv rpl_execv
+#  endif
+_GL_FUNCDECL_RPL (execv, int, (const char *program, char * const *argv)
+                              _GL_ARG_NONNULL ((1, 2)));
+_GL_CXXALIAS_RPL (execv, int, (const char *program, char * const *argv));
+# else
+_GL_CXXALIAS_SYS (execv, int, (const char *program, char * const *argv));
+# endif
+_GL_CXXALIASWARN (execv);
+#elif defined GNULIB_POSIXCHECK
+# undef execv
+# if HAVE_RAW_DECL_EXECV
+_GL_WARN_ON_USE (execv, "execv behaves very differently on mingw - "
+                 "use gnulib module execv for portability");
+# endif
+#elif @GNULIB_MDA_EXECV@
 /* On native Windows, map 'execv' to '_execv', so that -loldnames is not
    required.  In C++ with GNULIB_NAMESPACE, avoid differences between
    platforms by defining GNULIB_NAMESPACE::execv always.  */
@@ -673,15 +751,37 @@ _GL_CXXALIASWARN (execlp);
 #   undef execv
 #   define execv _execv
 #  endif
-_GL_CXXALIAS_MDA (execv, intptr_t,
-                  (const char *program, const char * const *argv));
+_GL_CXXALIAS_MDA_CAST (execv, intptr_t,
+                       (const char *program, char * const *argv));
 # else
 _GL_CXXALIAS_SYS (execv, int, (const char *program, char * const *argv));
 # endif
 _GL_CXXALIASWARN (execv);
 #endif
 
-#if @GNULIB_MDA_EXECVE@
+#if @GNULIB_EXECVE@
+# if @REPLACE_EXECVE@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef execve
+#   define execve rpl_execve
+#  endif
+_GL_FUNCDECL_RPL (execve, int,
+                  (const char *program, char * const *argv, char * const *env)
+                  _GL_ARG_NONNULL ((1, 2)));
+_GL_CXXALIAS_RPL (execve, int,
+                  (const char *program, char * const *argv, char * const *env));
+# else
+_GL_CXXALIAS_SYS (execve, int,
+                  (const char *program, char * const *argv, char * const *env));
+# endif
+_GL_CXXALIASWARN (execve);
+#elif defined GNULIB_POSIXCHECK
+# undef execve
+# if HAVE_RAW_DECL_EXECVE
+_GL_WARN_ON_USE (execve, "execve behaves very differently on mingw - "
+                 "use gnulib module execve for portability");
+# endif
+#elif @GNULIB_MDA_EXECVE@
 /* On native Windows, map 'execve' to '_execve', so that -loldnames is not
    required.  In C++ with GNULIB_NAMESPACE, avoid differences between
    platforms by defining GNULIB_NAMESPACE::execve always.  */
@@ -690,9 +790,9 @@ _GL_CXXALIASWARN (execv);
 #   undef execve
 #   define execve _execve
 #  endif
-_GL_CXXALIAS_MDA (execve, intptr_t,
-                  (const char *program, const char * const *argv,
-                   const char * const *env));
+_GL_CXXALIAS_MDA_CAST (execve, intptr_t,
+                       (const char *program, char * const *argv,
+                        char * const *env));
 # else
 _GL_CXXALIAS_SYS (execve, int,
                   (const char *program, char * const *argv, char * const *env));
@@ -700,7 +800,26 @@ _GL_CXXALIAS_SYS (execve, int,
 _GL_CXXALIASWARN (execve);
 #endif
 
-#if @GNULIB_MDA_EXECVP@
+#if @GNULIB_EXECVP@
+# if @REPLACE_EXECVP@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef execvp
+#   define execvp rpl_execvp
+#  endif
+_GL_FUNCDECL_RPL (execvp, int, (const char *program, char * const *argv)
+                               _GL_ARG_NONNULL ((1, 2)));
+_GL_CXXALIAS_RPL (execvp, int, (const char *program, char * const *argv));
+# else
+_GL_CXXALIAS_SYS (execvp, int, (const char *program, char * const *argv));
+# endif
+_GL_CXXALIASWARN (execvp);
+#elif defined GNULIB_POSIXCHECK
+# undef execvp
+# if HAVE_RAW_DECL_EXECVP
+_GL_WARN_ON_USE (execvp, "execvp behaves very differently on mingw - "
+                 "use gnulib module execvp for portability");
+# endif
+#elif @GNULIB_MDA_EXECVP@
 /* On native Windows, map 'execvp' to '_execvp', so that -loldnames is not
    required.  In C++ with GNULIB_NAMESPACE, avoid differences between
    platforms by defining GNULIB_NAMESPACE::execvp always.  */
@@ -709,15 +828,42 @@ _GL_CXXALIASWARN (execve);
 #   undef execvp
 #   define execvp _execvp
 #  endif
-_GL_CXXALIAS_MDA (execvp, intptr_t,
-                  (const char *program, const char * const *argv));
+_GL_CXXALIAS_MDA_CAST (execvp, intptr_t,
+                       (const char *program, char * const *argv));
 # else
 _GL_CXXALIAS_SYS (execvp, int, (const char *program, char * const *argv));
 # endif
 _GL_CXXALIASWARN (execvp);
 #endif
 
-#if @GNULIB_MDA_EXECVPE@
+#if @GNULIB_EXECVPE@
+# if @REPLACE_EXECVPE@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef execvpe
+#   define execvpe rpl_execvpe
+#  endif
+_GL_FUNCDECL_RPL (execvpe, int,
+                  (const char *program, char * const *argv, char * const *env)
+                  _GL_ARG_NONNULL ((1, 2)));
+_GL_CXXALIAS_RPL (execvpe, int,
+                  (const char *program, char * const *argv, char * const *env));
+# else
+#  if !@HAVE_DECL_EXECVPE@
+_GL_FUNCDECL_SYS (execvpe, int,
+                  (const char *program, char * const *argv, char * const *env)
+                  _GL_ARG_NONNULL ((1, 2)));
+#  endif
+_GL_CXXALIAS_SYS (execvpe, int,
+                  (const char *program, char * const *argv, char * const *env));
+# endif
+_GL_CXXALIASWARN (execvpe);
+#elif defined GNULIB_POSIXCHECK
+# undef execvpe
+# if HAVE_RAW_DECL_EXECVPE
+_GL_WARN_ON_USE (execvpe, "execvpe behaves very differently on mingw - "
+                 "use gnulib module execvpe for portability");
+# endif
+#elif @GNULIB_MDA_EXECVPE@
 /* On native Windows, map 'execvpe' to '_execvpe', so that -loldnames is not
    required.  In C++ with GNULIB_NAMESPACE, avoid differences between
    platforms by defining GNULIB_NAMESPACE::execvpe on all platforms that have
@@ -727,16 +873,19 @@ _GL_CXXALIASWARN (execvp);
 #   undef execvpe
 #   define execvpe _execvpe
 #  endif
-_GL_CXXALIAS_MDA (execvpe, intptr_t,
-                  (const char *program, const char * const *argv,
-                   const char * const *env));
-# else
-#  if @HAVE_DECL_EXECVPE@
+_GL_CXXALIAS_MDA_CAST (execvpe, intptr_t,
+                       (const char *program, char * const *argv,
+                        char * const *env));
+# elif @HAVE_EXECVPE@
+#  if !@HAVE_DECL_EXECVPE@
+_GL_FUNCDECL_SYS (execvpe, int,
+                  (const char *program, char * const *argv, char * const *env)
+                  _GL_ARG_NONNULL ((1, 2)));
+#  endif
 _GL_CXXALIAS_SYS (execvpe, int,
                   (const char *program, char * const *argv, char * const *env));
-#  endif
 # endif
-# if (defined _WIN32 && !defined __CYGWIN__) || @HAVE_DECL_EXECVPE@
+# if (defined _WIN32 && !defined __CYGWIN__) || @HAVE_EXECVPE@
 _GL_CXXALIASWARN (execvpe);
 # endif
 #endif
diff --git a/m4/unistd_h.m4 b/m4/unistd_h.m4
index db96e2b..f0db575 100644
--- a/m4/unistd_h.m4
+++ b/m4/unistd_h.m4
@@ -1,4 +1,4 @@
-# unistd_h.m4 serial 84
+# unistd_h.m4 serial 85
 dnl Copyright (C) 2006-2020 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -42,6 +42,7 @@ AC_DEFUN([gl_UNISTD_H],
 # endif
 #endif
     ]], [access chdir chown copy_file_range dup dup2 dup3 environ euidaccess
+    execl execle execlp execv execve execvp execvpe
     faccessat fchdir
     fchownat fdatasync fsync ftruncate getcwd getdomainname getdtablesize
     getentropy getgroups gethostname getlogin getlogin_r getpagesize getpass
@@ -79,6 +80,13 @@ AC_DEFUN([gl_UNISTD_H_DEFAULTS],
   GNULIB_DUP3=0;                 AC_SUBST([GNULIB_DUP3])
   GNULIB_ENVIRON=0;              AC_SUBST([GNULIB_ENVIRON])
   GNULIB_EUIDACCESS=0;           AC_SUBST([GNULIB_EUIDACCESS])
+  GNULIB_EXECL=0;                AC_SUBST([GNULIB_EXECL])
+  GNULIB_EXECLE=0;               AC_SUBST([GNULIB_EXECLE])
+  GNULIB_EXECLP=0;               AC_SUBST([GNULIB_EXECLP])
+  GNULIB_EXECV=0;                AC_SUBST([GNULIB_EXECV])
+  GNULIB_EXECVE=0;               AC_SUBST([GNULIB_EXECVE])
+  GNULIB_EXECVP=0;               AC_SUBST([GNULIB_EXECVP])
+  GNULIB_EXECVPE=0;              AC_SUBST([GNULIB_EXECVPE])
   GNULIB_FACCESSAT=0;            AC_SUBST([GNULIB_FACCESSAT])
   GNULIB_FCHDIR=0;               AC_SUBST([GNULIB_FCHDIR])
   GNULIB_FCHOWNAT=0;             AC_SUBST([GNULIB_FCHOWNAT])
@@ -150,6 +158,7 @@ AC_DEFUN([gl_UNISTD_H_DEFAULTS],
   HAVE_COPY_FILE_RANGE=1; AC_SUBST([HAVE_COPY_FILE_RANGE])
   HAVE_DUP3=1;            AC_SUBST([HAVE_DUP3])
   HAVE_EUIDACCESS=1;      AC_SUBST([HAVE_EUIDACCESS])
+  HAVE_EXECVPE=1;         AC_SUBST([HAVE_EXECVPE])
   HAVE_FACCESSAT=1;       AC_SUBST([HAVE_FACCESSAT])
   HAVE_FCHDIR=1;          AC_SUBST([HAVE_FCHDIR])
   HAVE_FCHOWNAT=1;        AC_SUBST([HAVE_FCHOWNAT])
@@ -198,6 +207,13 @@ AC_DEFUN([gl_UNISTD_H_DEFAULTS],
   REPLACE_CLOSE=0;        AC_SUBST([REPLACE_CLOSE])
   REPLACE_DUP=0;          AC_SUBST([REPLACE_DUP])
   REPLACE_DUP2=0;         AC_SUBST([REPLACE_DUP2])
+  REPLACE_EXECL=0;        AC_SUBST([REPLACE_EXECL])
+  REPLACE_EXECLE=0;       AC_SUBST([REPLACE_EXECLE])
+  REPLACE_EXECLP=0;       AC_SUBST([REPLACE_EXECLP])
+  REPLACE_EXECV=0;        AC_SUBST([REPLACE_EXECV])
+  REPLACE_EXECVE=0;       AC_SUBST([REPLACE_EXECVE])
+  REPLACE_EXECVP=0;       AC_SUBST([REPLACE_EXECVP])
+  REPLACE_EXECVPE=0;      AC_SUBST([REPLACE_EXECVPE])
   REPLACE_FACCESSAT=0;    AC_SUBST([REPLACE_FACCESSAT])
   REPLACE_FCHOWNAT=0;     AC_SUBST([REPLACE_FCHOWNAT])
   REPLACE_FTRUNCATE=0;    AC_SUBST([REPLACE_FTRUNCATE])
diff --git a/modules/unistd b/modules/unistd
index 27a4b67..442678b 100644
--- a/modules/unistd
+++ b/modules/unistd
@@ -47,6 +47,13 @@ unistd.h: unistd.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
 	      -e 's/@''GNULIB_DUP3''@/$(GNULIB_DUP3)/g' \
 	      -e 's/@''GNULIB_ENVIRON''@/$(GNULIB_ENVIRON)/g' \
 	      -e 's/@''GNULIB_EUIDACCESS''@/$(GNULIB_EUIDACCESS)/g' \
+	      -e 's/@''GNULIB_EXECL''@/$(GNULIB_EXECL)/g' \
+	      -e 's/@''GNULIB_EXECLE''@/$(GNULIB_EXECLE)/g' \
+	      -e 's/@''GNULIB_EXECLP''@/$(GNULIB_EXECLP)/g' \
+	      -e 's/@''GNULIB_EXECV''@/$(GNULIB_EXECV)/g' \
+	      -e 's/@''GNULIB_EXECVE''@/$(GNULIB_EXECVE)/g' \
+	      -e 's/@''GNULIB_EXECVP''@/$(GNULIB_EXECVP)/g' \
+	      -e 's/@''GNULIB_EXECVPE''@/$(GNULIB_EXECVPE)/g' \
 	      -e 's/@''GNULIB_FACCESSAT''@/$(GNULIB_FACCESSAT)/g' \
 	      -e 's/@''GNULIB_FCHDIR''@/$(GNULIB_FCHDIR)/g' \
 	      -e 's/@''GNULIB_FCHOWNAT''@/$(GNULIB_FCHOWNAT)/g' \
@@ -118,6 +125,7 @@ unistd.h: unistd.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
 	      -e 's|@''HAVE_COPY_FILE_RANGE''@|$(HAVE_COPY_FILE_RANGE)|g' \
 	      -e 's|@''HAVE_DUP3''@|$(HAVE_DUP3)|g' \
 	      -e 's|@''HAVE_EUIDACCESS''@|$(HAVE_EUIDACCESS)|g' \
+	      -e 's|@''HAVE_EXECVPE''@|$(HAVE_EXECVPE)|g' \
 	      -e 's|@''HAVE_FACCESSAT''@|$(HAVE_FACCESSAT)|g' \
 	      -e 's|@''HAVE_FCHDIR''@|$(HAVE_FCHDIR)|g' \
 	      -e 's|@''HAVE_FCHOWNAT''@|$(HAVE_FCHOWNAT)|g' \
@@ -166,6 +174,13 @@ unistd.h: unistd.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
 	      -e 's|@''REPLACE_CLOSE''@|$(REPLACE_CLOSE)|g' \
 	      -e 's|@''REPLACE_DUP''@|$(REPLACE_DUP)|g' \
 	      -e 's|@''REPLACE_DUP2''@|$(REPLACE_DUP2)|g' \
+	      -e 's|@''REPLACE_EXECL''@|$(REPLACE_EXECL)|g' \
+	      -e 's|@''REPLACE_EXECLE''@|$(REPLACE_EXECLE)|g' \
+	      -e 's|@''REPLACE_EXECLP''@|$(REPLACE_EXECLP)|g' \
+	      -e 's|@''REPLACE_EXECV''@|$(REPLACE_EXECV)|g' \
+	      -e 's|@''REPLACE_EXECVE''@|$(REPLACE_EXECVE)|g' \
+	      -e 's|@''REPLACE_EXECVP''@|$(REPLACE_EXECVP)|g' \
+	      -e 's|@''REPLACE_EXECVPE''@|$(REPLACE_EXECVPE)|g' \
 	      -e 's|@''REPLACE_FACCESSAT''@|$(REPLACE_FACCESSAT)|g' \
 	      -e 's|@''REPLACE_FCHOWNAT''@|$(REPLACE_FCHOWNAT)|g' \
 	      -e 's|@''REPLACE_FTRUNCATE''@|$(REPLACE_FTRUNCATE)|g' \
diff --git a/tests/test-unistd-c++.cc b/tests/test-unistd-c++.cc
index 6d4c8fb..d866091 100644
--- a/tests/test-unistd-c++.cc
+++ b/tests/test-unistd-c++.cc
@@ -52,6 +52,41 @@ SIGNATURE_CHECK (GNULIB_NAMESPACE::dup2, int, (int, int));
 SIGNATURE_CHECK (GNULIB_NAMESPACE::dup3, int, (int, int, int));
 #endif
 
+#if GNULIB_TEST_EXECL
+SIGNATURE_CHECK (GNULIB_NAMESPACE::execl, int,
+                 (const char *, const char *, ...));
+#endif
+
+#if GNULIB_TEST_EXECLE
+SIGNATURE_CHECK (GNULIB_NAMESPACE::execle, int,
+                 (const char *, const char *, ...));
+#endif
+
+#if GNULIB_TEST_EXECLP
+SIGNATURE_CHECK (GNULIB_NAMESPACE::execlp, int,
+                 (const char *, const char *, ...));
+#endif
+
+#if GNULIB_TEST_EXECV
+SIGNATURE_CHECK (GNULIB_NAMESPACE::execv, int,
+                 (const char *, char * const *));
+#endif
+
+#if GNULIB_TEST_EXECVE
+SIGNATURE_CHECK (GNULIB_NAMESPACE::execve, int,
+                 (const char *, char * const *, char * const *));
+#endif
+
+#if GNULIB_TEST_EXECVP
+SIGNATURE_CHECK (GNULIB_NAMESPACE::execvp, int,
+                 (const char *, char * const *));
+#endif
+
+#if GNULIB_TEST_EXECVPE
+SIGNATURE_CHECK (GNULIB_NAMESPACE::execvpe, int,
+                 (const char *, char * const *, char * const *));
+#endif
+
 #if GNULIB_TEST_EUIDACCESS
 SIGNATURE_CHECK (GNULIB_NAMESPACE::euidaccess, int, (const char *, int));
 #endif
-- 
2.7.4


[-- Attachment #3: 0002-execve-New-module.patch --]
[-- Type: text/x-patch, Size: 6795 bytes --]

From e8f57867dc5c05e7354576df19f1151ae9cb9fbb Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Sat, 26 Dec 2020 14:13:03 +0100
Subject: [PATCH 02/15] execve: New module.

* lib/execve.c: New file.
* m4/execve.m4: New file.
* modules/execve: New file.
* doc/posix-functions/execve.texi: Mention more Windows problems and the
new module.
---
 ChangeLog                       |  7 ++++
 doc/posix-functions/execve.texi | 21 ++++++++---
 lib/execve.c                    | 79 +++++++++++++++++++++++++++++++++++++++++
 m4/execve.m4                    | 15 ++++++++
 modules/execve                  | 31 ++++++++++++++++
 5 files changed, 148 insertions(+), 5 deletions(-)
 create mode 100644 lib/execve.c
 create mode 100644 m4/execve.m4
 create mode 100644 modules/execve

diff --git a/ChangeLog b/ChangeLog
index 459df8e..750f67b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2020-12-26  Bruno Haible  <bruno@clisp.org>
 
+	execve: New module.
+	* lib/execve.c: New file.
+	* m4/execve.m4: New file.
+	* modules/execve: New file.
+	* doc/posix-functions/execve.texi: Mention more Windows problems and the
+	new module.
+
 	execve, execvpe, execvp, execv, execl, execle, execlp: Prepare modules.
 	* lib/unistd.in.h (execl, execle, execlp, execv, execve, execvp,
 	execvpe): Add declarations for the new modules.
diff --git a/doc/posix-functions/execve.texi b/doc/posix-functions/execve.texi
index a07e3b5..9b4196c 100644
--- a/doc/posix-functions/execve.texi
+++ b/doc/posix-functions/execve.texi
@@ -4,19 +4,30 @@
 
 POSIX specification:@* @url{https://pubs.opengroup.org/onlinepubs/9699919799/functions/execve.html}
 
-Gnulib module: ---
+Gnulib module: execve
 
 Portability problems fixed by Gnulib:
 @itemize
+@item
+On Windows platforms (excluding Cygwin), this function does not pass
+command-line arguments correctly if they contain space, tab, backslash,
+or double-quote characters.
+@item
+On Windows platforms (excluding Cygwin), this function spawns an asynchronous
+child process and then exits the current process immediately.  As a
+consequence, the parent of the current process 1. may incorrectly proceed
+as if its child had exited, and 2. will never see the child's exit status.
+@item
+On Windows platforms (excluding Cygwin), the return type of this function is
+@code{intptr_t}, not @code{int}.
 @end itemize
 
+Note: The Gnulib replacement for this function is not async-safe, that is,
+it must not be invoked from a signal handler.
+
 Portability problems not fixed by Gnulib:
 @itemize
 @item
 On some platforms, a script without executable permission is still run:
 Cygwin 1.5.x.
-@item
-On Windows platforms (excluding Cygwin), this function operates by spawning
-and then by exiting the current process, which means the current
-process's parent may incorrectly proceed as if its child had exited.
 @end itemize
diff --git a/lib/execve.c b/lib/execve.c
new file mode 100644
index 0000000..d5987c9
--- /dev/null
+++ b/lib/execve.c
@@ -0,0 +1,79 @@
+/* execve() function: Execute a program, replacing the current process.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2020.  */
+
+/* Don't use __attribute__ __nonnull__ in this compilation unit.  Otherwise gcc
+   may optimize away the program == NULL and argv == NULL tests below.  */
+#define _GL_ARG_NONNULL(params)
+
+#include <config.h>
+
+/* Specification.  */
+#include <unistd.h>
+
+#if defined _WIN32 && !defined __CYGWIN__
+
+# include <errno.h>
+# include <stdio.h>
+# include <spawn.h>
+
+# include <sys/types.h>
+# include <sys/wait.h>
+
+int
+execve (const char *program, char * const *argv, char * const *env)
+{
+  if (program == NULL
+      || argv == NULL
+      /* The callee is not expecting a NULL argv[0].  */
+      || argv[0] == NULL
+      || env == NULL)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  pid_t child;
+  int err = posix_spawn (&child, program, NULL, NULL, argv, env);
+  if (err == 0)
+    {
+      /* Close all file descriptors, so that
+         - for opened files, the child may close and unlink() the file,
+         - for pipe handles, the pipe's reader or writer does not get stuck.
+         Ideally we would also suspend all other threads and close all other
+         HANDLEs (not associated with file descriptors) and SOCKETs, but we
+         can't do so since we have no way to enumerate them.  */
+      {
+        unsigned int fdmax = _getmaxstdio ();
+        unsigned int fd;
+        for (fd = 0; fd < fdmax; fd++)
+          close (fd);
+      }
+
+      /* Wait until the child process is terminated.  */
+      int status = 127;
+      waitpid (child, &status, 0);
+      int exitcode = status;
+
+      /* Pass its exit code to the parent process.  */
+      _exit (exitcode);
+    }
+  errno = err;
+  return -1;
+}
+
+#endif
diff --git a/m4/execve.m4 b/m4/execve.m4
new file mode 100644
index 0000000..9511da4
--- /dev/null
+++ b/m4/execve.m4
@@ -0,0 +1,15 @@
+# execve.m4 serial 1
+dnl Copyright (C) 2020 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_EXECVE],
+[
+  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+  AC_REQUIRE([AC_CANONICAL_HOST])
+
+  case "$host_os" in
+    mingw*) REPLACE_EXECVE=1 ;;
+  esac
+])
diff --git a/modules/execve b/modules/execve
new file mode 100644
index 0000000..ea381a2
--- /dev/null
+++ b/modules/execve
@@ -0,0 +1,31 @@
+Description:
+execve() function: Execute a program, replacing the current process.
+
+Files:
+lib/execve.c
+m4/execve.m4
+
+Depends-on:
+unistd
+posix_spawn     [test $REPLACE_EXECVE = 1]
+close           [test $REPLACE_EXECVE = 1]
+sys_wait        [test $REPLACE_EXECVE = 1]
+waitpid         [test $REPLACE_EXECVE = 1]
+
+configure.ac:
+gl_FUNC_EXECVE
+if test $REPLACE_EXECVE = 1; then
+  AC_LIBOBJ([execve])
+fi
+gl_UNISTD_MODULE_INDICATOR([execve])
+
+Makefile.am:
+
+Include:
+<unistd.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all
-- 
2.7.4


[-- Attachment #4: 0003-execve-Add-tests.patch --]
[-- Type: text/x-patch, Size: 6303 bytes --]

From c24b5cc4a8ff7e858ad7bc019a6e112a292fe468 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Sat, 26 Dec 2020 14:19:29 +0100
Subject: [PATCH 03/15] execve: Add tests.

* tests/test-exec-child.c: New file.
* tests/test-execve-main.c: New file.
* tests/test-execve.sh: New file.
* modules/execve-tests: New file.
---
 ChangeLog                |  6 ++++++
 modules/execve-tests     | 11 ++++++++++
 tests/test-exec-child.c  | 41 +++++++++++++++++++++++++++++++++++++
 tests/test-execve-main.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++
 tests/test-execve.sh     | 48 +++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 159 insertions(+)
 create mode 100644 modules/execve-tests
 create mode 100644 tests/test-exec-child.c
 create mode 100644 tests/test-execve-main.c
 create mode 100755 tests/test-execve.sh

diff --git a/ChangeLog b/ChangeLog
index 750f67b..f6795fb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2020-12-26  Bruno Haible  <bruno@clisp.org>
 
+	execve: Add tests.
+	* tests/test-exec-child.c: New file.
+	* tests/test-execve-main.c: New file.
+	* tests/test-execve.sh: New file.
+	* modules/execve-tests: New file.
+
 	execve: New module.
 	* lib/execve.c: New file.
 	* m4/execve.m4: New file.
diff --git a/modules/execve-tests b/modules/execve-tests
new file mode 100644
index 0000000..3077c5f
--- /dev/null
+++ b/modules/execve-tests
@@ -0,0 +1,11 @@
+Files:
+tests/test-execve.sh
+tests/test-execve-main.c
+tests/test-exec-child.c
+tests/signature.h
+
+Depends-on:
+
+Makefile.am:
+TESTS += test-execve.sh
+check_PROGRAMS += test-execve-main test-exec-child
diff --git a/tests/test-exec-child.c b/tests/test-exec-child.c
new file mode 100644
index 0000000..bbcf727
--- /dev/null
+++ b/tests/test-exec-child.c
@@ -0,0 +1,41 @@
+/* Callee program for the tests of the exec*() functions.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* Do not use any gnulib replacements, since this program should
+   link against as few libraries as possible.  */
+#undef printf
+
+int
+main (int argc, char* argv[])
+{
+  /* Print the arguments.  */
+  int i;
+  printf ("argc = %d\n", argc);
+  for (i = 1; i < argc; i++)
+    printf ("argv[%d] = |%s|\n", i, argv[i]);
+
+  /* Print a particular environment variable.  */
+  const char *var = "Hommingberg";
+  if (getenv (var) != NULL)
+    printf ("%s = |%s|\n", var, getenv (var));
+
+  return 49;
+}
diff --git a/tests/test-execve-main.c b/tests/test-execve-main.c
new file mode 100644
index 0000000..3667dd2
--- /dev/null
+++ b/tests/test-execve-main.c
@@ -0,0 +1,53 @@
+/* Test of execve().
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2020.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <unistd.h>
+
+#include "signature.h"
+SIGNATURE_CHECK (execve, int, (const char *, char * const *, char * const *));
+
+#include <stdio.h>
+
+int
+main ()
+{
+  const char *progname = "./test-exec-child";
+  const char *env[3] = { "PATH=.", "Hommingberg=Gepardenforelle", NULL };
+  const char *argv[12] =
+    {
+      progname,
+      "abc def",
+      "abc\"def\"ghi",
+      "xyz\"",
+      "abc\\def\\ghi",
+      "xyz\\",
+      "???",
+      "***",
+      "",
+      "foo",
+      "",
+      NULL
+    };
+  execve (progname, (char * const *) argv, (char * const *) env);
+
+  perror ("execve");
+  return 1;
+}
diff --git a/tests/test-execve.sh b/tests/test-execve.sh
new file mode 100755
index 0000000..3d7ac1c
--- /dev/null
+++ b/tests/test-execve.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+# Test of execve().
+#
+# Copyright (C) 2020 Free Software Foundation, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+#
+# Written by Bruno Haible <bruno@clisp.org>, 2020.
+
+${CHECKER} ./test-execve-main${EXEEXT} > test-execve.tmp
+result=$?
+test $result = 49 || exit 1
+LC_ALL=C tr -d '\r' < test-execve.tmp > test-execve.out || exit 1
+
+cat > test-execve.ok <<\EOF
+argc = 11
+argv[1] = |abc def|
+argv[2] = |abc"def"ghi|
+argv[3] = |xyz"|
+argv[4] = |abc\def\ghi|
+argv[5] = |xyz\|
+argv[6] = |???|
+argv[7] = |***|
+argv[8] = ||
+argv[9] = |foo|
+argv[10] = ||
+Hommingberg = |Gepardenforelle|
+EOF
+
+: ${DIFF=diff}
+${DIFF} test-execve.ok test-execve.out
+result=$?
+
+rm -f test-execve.tmp test-execve.out test-execve.ok
+
+exit $result
-- 
2.7.4


[-- Attachment #5: 0004-execvpe-New-module.patch --]
[-- Type: text/x-patch, Size: 6303 bytes --]

From a50484eb14bf2c2a8dc420ba2ad037fd85f9c739 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Sat, 26 Dec 2020 14:23:10 +0100
Subject: [PATCH 04/15] execvpe: New module.

* lib/execvpe.c: New file.
* m4/execvpe.m4: New file.
* modules/execvpe: New file.
* doc/glibc-functions/execvpe.texi: Mention the Windows problems and the
new module.
---
 ChangeLog                        |  7 +++++
 doc/glibc-functions/execvpe.texi | 22 ++++++++++----
 lib/execvpe.c                    | 62 ++++++++++++++++++++++++++++++++++++++++
 m4/execvpe.m4                    | 24 ++++++++++++++++
 modules/execvpe                  | 30 +++++++++++++++++++
 5 files changed, 140 insertions(+), 5 deletions(-)
 create mode 100644 lib/execvpe.c
 create mode 100644 m4/execvpe.m4
 create mode 100644 modules/execvpe

diff --git a/ChangeLog b/ChangeLog
index f6795fb..7a9e5fb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2020-12-26  Bruno Haible  <bruno@clisp.org>
 
+	execvpe: New module.
+	* lib/execvpe.c: New file.
+	* m4/execvpe.m4: New file.
+	* modules/execvpe: New file.
+	* doc/glibc-functions/execvpe.texi: Mention the Windows problems and the
+	new module.
+
 	execve: Add tests.
 	* tests/test-exec-child.c: New file.
 	* tests/test-execve-main.c: New file.
diff --git a/doc/glibc-functions/execvpe.texi b/doc/glibc-functions/execvpe.texi
index 814b160..04ac54a 100644
--- a/doc/glibc-functions/execvpe.texi
+++ b/doc/glibc-functions/execvpe.texi
@@ -4,18 +4,30 @@
 
 Documentation:@* @uref{https://www.kernel.org/doc/man-pages/online/pages/man3/execvpe.3.html,,man execvpe}
 
-Gnulib module: ---
+Gnulib module: execvpe
 
 Portability problems fixed by Gnulib:
 @itemize
-@end itemize
-
-Portability problems not fixed by Gnulib:
-@itemize
 @item
 This function is missing on many non-glibc platforms:
 glibc 2.10, Mac OS X 10.13, FreeBSD 6.0, NetBSD 7.1, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11, IRIX 6.5, Solaris 11.3, Cygwin 1.5.x, mingw, Android 4.4.
 @item
 This function is not declared on some platforms:
 AIX 7.1.
+@item
+On Windows platforms (excluding Cygwin), this function does not pass
+command-line arguments correctly if they contain space, tab, backslash,
+or double-quote characters.
+@item
+On Windows platforms (excluding Cygwin), this function spawns an asynchronous
+child process and then exits the current process immediately.  As a
+consequence, the parent of the current process 1. may incorrectly proceed
+as if its child had exited, and 2. will never see the child's exit status.
+@item
+On Windows platforms (excluding Cygwin), the return type of this function is
+@code{intptr_t}, not @code{int}.
+@end itemize
+
+Portability problems not fixed by Gnulib:
+@itemize
 @end itemize
diff --git a/lib/execvpe.c b/lib/execvpe.c
new file mode 100644
index 0000000..7bc369d
--- /dev/null
+++ b/lib/execvpe.c
@@ -0,0 +1,62 @@
+/* execvpe() function: Execute a program, replacing the current process.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2020.  */
+
+/* Don't use __attribute__ __nonnull__ in this compilation unit.  Otherwise gcc
+   may optimize away the program == NULL and argv == NULL tests below.  */
+#define _GL_ARG_NONNULL(params)
+
+#include <config.h>
+
+/* Specification.  */
+#include <unistd.h>
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include "findprog.h"
+
+int
+execvpe (const char *program, char * const *argv, char * const *env)
+{
+  if (program == NULL
+      || argv == NULL
+      /* The callee is not expecting a NULL argv[0].  */
+      || argv[0] == NULL
+      || env == NULL)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  const char *resolved_progname =
+    find_in_given_path (program, getenv ("PATH"), NULL, true);
+  if (resolved_progname == NULL)
+    return -1;
+
+  /* Invoke execve.  */
+  execve (resolved_progname, argv, env);
+
+  /* If execve returned, it must have failed.  */
+  if (resolved_progname != program)
+    {
+      int saved_errno = errno;
+      free ((char *) resolved_progname);
+      errno = saved_errno;
+    }
+  return -1;
+}
diff --git a/m4/execvpe.m4 b/m4/execvpe.m4
new file mode 100644
index 0000000..bfce909
--- /dev/null
+++ b/m4/execvpe.m4
@@ -0,0 +1,24 @@
+# execvpe.m4 serial 1
+dnl Copyright (C) 2020 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_EXECVPE],
+[
+  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+  AC_REQUIRE([AC_CANONICAL_HOST])
+
+  dnl Persuade glibc <unistd.h> to declare execvpe().
+  AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
+
+  case "$host_os" in
+    mingw*) REPLACE_EXECVPE=1 ;;
+    *)
+      AC_CHECK_FUNCS([execvpe])
+      if test $ac_cv_func_execvpe != yes; then
+        HAVE_EXECVPE=0
+      fi
+      ;;
+  esac
+])
diff --git a/modules/execvpe b/modules/execvpe
new file mode 100644
index 0000000..792a2c7
--- /dev/null
+++ b/modules/execvpe
@@ -0,0 +1,30 @@
+Description:
+execvpe() function: Execute a program, replacing the current process.
+
+Files:
+lib/execvpe.c
+m4/execvpe.m4
+
+Depends-on:
+unistd
+extensions
+findprog-in     [test $HAVE_EXECVPE = 0 || test $REPLACE_EXECVPE = 1]
+execve          [test $HAVE_EXECVPE = 0 || test $REPLACE_EXECVPE = 1]
+
+configure.ac:
+gl_FUNC_EXECVPE
+if test $HAVE_EXECVPE = 0 || test $REPLACE_EXECVPE = 1; then
+  AC_LIBOBJ([execvpe])
+fi
+gl_UNISTD_MODULE_INDICATOR([execvpe])
+
+Makefile.am:
+
+Include:
+<unistd.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all
-- 
2.7.4


[-- Attachment #6: 0005-execvpe-Add-tests.patch --]
[-- Type: text/x-patch, Size: 4844 bytes --]

From 7c170cbc17521f6eb0199e78fcd18d8dddbb12b4 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Sat, 26 Dec 2020 14:25:06 +0100
Subject: [PATCH 05/15] execvpe: Add tests.

* tests/test-execvpe-main.c: New file.
* tests/test-execvpe.sh: New file.
* modules/execvpe-tests: New file.
---
 ChangeLog                 |  5 +++++
 modules/execvpe-tests     | 11 ++++++++++
 tests/test-execvpe-main.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++
 tests/test-execvpe.sh     | 51 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 120 insertions(+)
 create mode 100644 modules/execvpe-tests
 create mode 100644 tests/test-execvpe-main.c
 create mode 100755 tests/test-execvpe.sh

diff --git a/ChangeLog b/ChangeLog
index 7a9e5fb..1f9acd2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2020-12-26  Bruno Haible  <bruno@clisp.org>
 
+	execvpe: Add tests.
+	* tests/test-execvpe-main.c: New file.
+	* tests/test-execvpe.sh: New file.
+	* modules/execvpe-tests: New file.
+
 	execvpe: New module.
 	* lib/execvpe.c: New file.
 	* m4/execvpe.m4: New file.
diff --git a/modules/execvpe-tests b/modules/execvpe-tests
new file mode 100644
index 0000000..911d1ca
--- /dev/null
+++ b/modules/execvpe-tests
@@ -0,0 +1,11 @@
+Files:
+tests/test-execvpe.sh
+tests/test-execvpe-main.c
+tests/test-exec-child.c
+tests/signature.h
+
+Depends-on:
+
+Makefile.am:
+TESTS += test-execvpe.sh
+check_PROGRAMS += test-execvpe-main test-exec-child
diff --git a/tests/test-execvpe-main.c b/tests/test-execvpe-main.c
new file mode 100644
index 0000000..0b7ebff
--- /dev/null
+++ b/tests/test-execvpe-main.c
@@ -0,0 +1,53 @@
+/* Test of execvpe().
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2020.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <unistd.h>
+
+#include "signature.h"
+SIGNATURE_CHECK (execvpe, int, (const char *, char * const *, char * const *));
+
+#include <stdio.h>
+
+int
+main ()
+{
+  const char *progname = "test-exec-child";
+  const char *env[3] = { "PATH=.", "Hommingberg=Gepardenforelle", NULL };
+  const char *argv[12] =
+    {
+      progname,
+      "abc def",
+      "abc\"def\"ghi",
+      "xyz\"",
+      "abc\\def\\ghi",
+      "xyz\\",
+      "???",
+      "***",
+      "",
+      "foo",
+      "",
+      NULL
+    };
+  execvpe (progname, (char * const *) argv, (char * const *) env);
+
+  perror ("execvpe");
+  return 1;
+}
diff --git a/tests/test-execvpe.sh b/tests/test-execvpe.sh
new file mode 100755
index 0000000..62fb258
--- /dev/null
+++ b/tests/test-execvpe.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+# Test of execvpe().
+#
+# Copyright (C) 2020 Free Software Foundation, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+#
+# Written by Bruno Haible <bruno@clisp.org>, 2020.
+
+rm -rf test-execvpe-subdir
+mkdir test-execvpe-subdir
+
+(cd test-execvpe-subdir && PATH="..:$PATH" ${CHECKER} ../test-execvpe-main${EXEEXT}) > test-execvpe.tmp
+result=$?
+test $result = 49 || { rm -rf test-execvpe-subdir; exit 1; }
+LC_ALL=C tr -d '\r' < test-execvpe.tmp > test-execvpe.out || { rm -rf test-execvpe-subdir; exit 1; }
+
+cat > test-execvpe.ok <<\EOF
+argc = 11
+argv[1] = |abc def|
+argv[2] = |abc"def"ghi|
+argv[3] = |xyz"|
+argv[4] = |abc\def\ghi|
+argv[5] = |xyz\|
+argv[6] = |???|
+argv[7] = |***|
+argv[8] = ||
+argv[9] = |foo|
+argv[10] = ||
+Hommingberg = |Gepardenforelle|
+EOF
+
+: ${DIFF=diff}
+${DIFF} test-execvpe.ok test-execvpe.out
+result=$?
+
+rm -rf test-execvpe-subdir test-execvpe.tmp test-execvpe.out test-execvpe.ok
+
+exit $result
-- 
2.7.4


[-- Attachment #7: 0006-execvp-New-module.patch --]
[-- Type: text/x-patch, Size: 5596 bytes --]

From 0e3778b00c4e4705cccec9261ef36c66c400e1fe Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Sat, 26 Dec 2020 14:28:16 +0100
Subject: [PATCH 06/15] execvp: New module.

* lib/execvp.c: New file.
* m4/execvp.m4: New file.
* modules/execvp: New file.
* doc/posix-functions/execvp.texi: Mention more Windows problems and the
new module.
---
 ChangeLog                       |  7 +++++++
 doc/posix-functions/execvp.texi | 18 +++++++++++++-----
 lib/execvp.c                    | 35 +++++++++++++++++++++++++++++++++++
 m4/execvp.m4                    | 15 +++++++++++++++
 modules/execvp                  | 29 +++++++++++++++++++++++++++++
 5 files changed, 99 insertions(+), 5 deletions(-)
 create mode 100644 lib/execvp.c
 create mode 100644 m4/execvp.m4
 create mode 100644 modules/execvp

diff --git a/ChangeLog b/ChangeLog
index 1f9acd2..5d20495 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2020-12-26  Bruno Haible  <bruno@clisp.org>
 
+	execvp: New module.
+	* lib/execvp.c: New file.
+	* m4/execvp.m4: New file.
+	* modules/execvp: New file.
+	* doc/posix-functions/execvp.texi: Mention more Windows problems and the
+	new module.
+
 	execvpe: Add tests.
 	* tests/test-execvpe-main.c: New file.
 	* tests/test-execvpe.sh: New file.
diff --git a/doc/posix-functions/execvp.texi b/doc/posix-functions/execvp.texi
index 24a3f06..0c242b2 100644
--- a/doc/posix-functions/execvp.texi
+++ b/doc/posix-functions/execvp.texi
@@ -4,10 +4,22 @@
 
 POSIX specification:@* @url{https://pubs.opengroup.org/onlinepubs/9699919799/functions/execvp.html}
 
-Gnulib module: ---
+Gnulib module: execvp
 
 Portability problems fixed by Gnulib:
 @itemize
+@item
+On Windows platforms (excluding Cygwin), this function does not pass
+command-line arguments correctly if they contain space, tab, backslash,
+or double-quote characters.
+@item
+On Windows platforms (excluding Cygwin), this function spawns an asynchronous
+child process and then exits the current process immediately.  As a
+consequence, the parent of the current process 1. may incorrectly proceed
+as if its child had exited, and 2. will never see the child's exit status.
+@item
+On Windows platforms (excluding Cygwin), the return type of this function is
+@code{intptr_t}, not @code{int}.
 @end itemize
 
 Portability problems not fixed by Gnulib:
@@ -15,8 +27,4 @@ Portability problems not fixed by Gnulib:
 @item
 On some platforms, a script without executable permission is still run:
 Cygwin 1.5.x.
-@item
-On Windows platforms (excluding Cygwin), this function operates by spawning
-and then by exiting the current process, which means the current
-process's parent may incorrectly proceed as if its child had exited.
 @end itemize
diff --git a/lib/execvp.c b/lib/execvp.c
new file mode 100644
index 0000000..db0fcb7
--- /dev/null
+++ b/lib/execvp.c
@@ -0,0 +1,35 @@
+/* execvp() function: Execute a program, replacing the current process.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2020.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <unistd.h>
+
+int
+execvp (const char *program, char * const *argv)
+{
+  /* Pass the environment explicitly.  This is needed if the program has
+     modified the environment using putenv() or [un]setenv().  On Windows,
+     processes have two environments, one in the "environment block" of the
+     process and managed through SetEnvironmentVariable(), and one inside the
+     process, in the location retrieved by the 'environ' macro.  If we were
+     to pass NULL, the child process would inherit a copy of the environment
+     block - ignoring the effects of putenv() and [un]setenv().  */
+  return execvpe (program, argv, environ);
+}
diff --git a/m4/execvp.m4 b/m4/execvp.m4
new file mode 100644
index 0000000..833b987
--- /dev/null
+++ b/m4/execvp.m4
@@ -0,0 +1,15 @@
+# execvp.m4 serial 1
+dnl Copyright (C) 2020 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_EXECVP],
+[
+  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+  AC_REQUIRE([AC_CANONICAL_HOST])
+
+  case "$host_os" in
+    mingw*) REPLACE_EXECVP=1 ;;
+  esac
+])
diff --git a/modules/execvp b/modules/execvp
new file mode 100644
index 0000000..df2d313
--- /dev/null
+++ b/modules/execvp
@@ -0,0 +1,29 @@
+Description:
+execvp() function: Execute a program, replacing the current process.
+
+Files:
+lib/execvp.c
+m4/execvp.m4
+
+Depends-on:
+unistd
+environ         [test $REPLACE_EXECVP = 1]
+execvpe         [test $REPLACE_EXECVP = 1]
+
+configure.ac:
+gl_FUNC_EXECVP
+if test $REPLACE_EXECVP = 1; then
+  AC_LIBOBJ([execvp])
+fi
+gl_UNISTD_MODULE_INDICATOR([execvp])
+
+Makefile.am:
+
+Include:
+<unistd.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all
-- 
2.7.4


[-- Attachment #8: 0007-execvp-Add-tests.patch --]
[-- Type: text/x-patch, Size: 4648 bytes --]

From b7f8be836643b720a0d9207fe0927889dd8b3b2b Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Sat, 26 Dec 2020 14:29:56 +0100
Subject: [PATCH 07/15] execvp: Add tests.

* tests/test-execvp-main.c: New file.
* tests/test-execvp.sh: New file.
* modules/execvp-tests: New file.
---
 ChangeLog                |  5 +++++
 modules/execvp-tests     | 11 ++++++++++
 tests/test-execvp-main.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++
 tests/test-execvp.sh     | 50 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 118 insertions(+)
 create mode 100644 modules/execvp-tests
 create mode 100644 tests/test-execvp-main.c
 create mode 100755 tests/test-execvp.sh

diff --git a/ChangeLog b/ChangeLog
index 5d20495..f7a0650 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2020-12-26  Bruno Haible  <bruno@clisp.org>
 
+	execvp: Add tests.
+	* tests/test-execvp-main.c: New file.
+	* tests/test-execvp.sh: New file.
+	* modules/execvp-tests: New file.
+
 	execvp: New module.
 	* lib/execvp.c: New file.
 	* m4/execvp.m4: New file.
diff --git a/modules/execvp-tests b/modules/execvp-tests
new file mode 100644
index 0000000..a1e050e
--- /dev/null
+++ b/modules/execvp-tests
@@ -0,0 +1,11 @@
+Files:
+tests/test-execvp.sh
+tests/test-execvp-main.c
+tests/test-exec-child.c
+tests/signature.h
+
+Depends-on:
+
+Makefile.am:
+TESTS += test-execvp.sh
+check_PROGRAMS += test-execvp-main test-exec-child
diff --git a/tests/test-execvp-main.c b/tests/test-execvp-main.c
new file mode 100644
index 0000000..9adc9b1
--- /dev/null
+++ b/tests/test-execvp-main.c
@@ -0,0 +1,52 @@
+/* Test of execvp().
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2020.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <unistd.h>
+
+#include "signature.h"
+SIGNATURE_CHECK (execvp, int, (const char *, char * const *));
+
+#include <stdio.h>
+
+int
+main ()
+{
+  const char *progname = "test-exec-child";
+  const char *argv[12] =
+    {
+      progname,
+      "abc def",
+      "abc\"def\"ghi",
+      "xyz\"",
+      "abc\\def\\ghi",
+      "xyz\\",
+      "???",
+      "***",
+      "",
+      "foo",
+      "",
+      NULL
+    };
+  execvp (progname, (char * const *) argv);
+
+  perror ("execvp");
+  return 1;
+}
diff --git a/tests/test-execvp.sh b/tests/test-execvp.sh
new file mode 100755
index 0000000..bf3b307
--- /dev/null
+++ b/tests/test-execvp.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+# Test of execvp().
+#
+# Copyright (C) 2020 Free Software Foundation, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+#
+# Written by Bruno Haible <bruno@clisp.org>, 2020.
+
+rm -rf test-execvp-subdir
+mkdir test-execvp-subdir
+
+(cd test-execvp-subdir && PATH="..:$PATH" ${CHECKER} ../test-execvp-main${EXEEXT}) > test-execvp.tmp
+result=$?
+test $result = 49 || { rm -rf test-execvp-subdir; exit 1; }
+LC_ALL=C tr -d '\r' < test-execvp.tmp > test-execvp.out || { rm -rf test-execvp-subdir; exit 1; }
+
+cat > test-execvp.ok <<\EOF
+argc = 11
+argv[1] = |abc def|
+argv[2] = |abc"def"ghi|
+argv[3] = |xyz"|
+argv[4] = |abc\def\ghi|
+argv[5] = |xyz\|
+argv[6] = |???|
+argv[7] = |***|
+argv[8] = ||
+argv[9] = |foo|
+argv[10] = ||
+EOF
+
+: ${DIFF=diff}
+${DIFF} test-execvp.ok test-execvp.out
+result=$?
+
+rm -rf test-execvp-subdir test-execvp.tmp test-execvp.out test-execvp.ok
+
+exit $result
-- 
2.7.4


[-- Attachment #9: 0008-execv-New-module.patch --]
[-- Type: text/x-patch, Size: 5624 bytes --]

From 58ef9c2d18f3c158ff42cd3b7297f9e9bbc74738 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Sat, 26 Dec 2020 14:31:50 +0100
Subject: [PATCH 08/15] execv: New module.

* lib/execv.c: New file.
* m4/execv.m4: New file.
* modules/execv: New file.
* doc/posix-functions/execv.texi: Mention more Windows problems and the
new module.
---
 ChangeLog                      |  7 +++++++
 doc/posix-functions/execv.texi | 21 ++++++++++++++++-----
 lib/execv.c                    | 35 +++++++++++++++++++++++++++++++++++
 m4/execv.m4                    | 15 +++++++++++++++
 modules/execv                  | 29 +++++++++++++++++++++++++++++
 5 files changed, 102 insertions(+), 5 deletions(-)
 create mode 100644 lib/execv.c
 create mode 100644 m4/execv.m4
 create mode 100644 modules/execv

diff --git a/ChangeLog b/ChangeLog
index f7a0650..836a115 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2020-12-26  Bruno Haible  <bruno@clisp.org>
 
+	execv: New module.
+	* lib/execv.c: New file.
+	* m4/execv.m4: New file.
+	* modules/execv: New file.
+	* doc/posix-functions/execv.texi: Mention more Windows problems and the
+	new module.
+
 	execvp: Add tests.
 	* tests/test-execvp-main.c: New file.
 	* tests/test-execvp.sh: New file.
diff --git a/doc/posix-functions/execv.texi b/doc/posix-functions/execv.texi
index c18fce4..9dbea90 100644
--- a/doc/posix-functions/execv.texi
+++ b/doc/posix-functions/execv.texi
@@ -4,19 +4,30 @@
 
 POSIX specification:@* @url{https://pubs.opengroup.org/onlinepubs/9699919799/functions/execv.html}
 
-Gnulib module: ---
+Gnulib module: execv
 
 Portability problems fixed by Gnulib:
 @itemize
+@item
+On Windows platforms (excluding Cygwin), this function does not pass
+command-line arguments correctly if they contain space, tab, backslash,
+or double-quote characters.
+@item
+On Windows platforms (excluding Cygwin), this function spawns an asynchronous
+child process and then exits the current process immediately.  As a
+consequence, the parent of the current process 1. may incorrectly proceed
+as if its child had exited, and 2. will never see the child's exit status.
+@item
+On Windows platforms (excluding Cygwin), the return type of this function is
+@code{intptr_t}, not @code{int}.
 @end itemize
 
+Note: The Gnulib replacement for this function is not async-safe, that is,
+it must not be invoked from a signal handler.
+
 Portability problems not fixed by Gnulib:
 @itemize
 @item
 On some platforms, a script without executable permission is still run:
 Cygwin 1.5.x.
-@item
-On Windows platforms (excluding Cygwin), this function operates by spawning
-and then by exiting the current process, which means the current
-process's parent may incorrectly proceed as if its child had exited.
 @end itemize
diff --git a/lib/execv.c b/lib/execv.c
new file mode 100644
index 0000000..d5c88a0
--- /dev/null
+++ b/lib/execv.c
@@ -0,0 +1,35 @@
+/* execv() function: Execute a program, replacing the current process.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2020.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <unistd.h>
+
+int
+execv (const char *program, char * const *argv)
+{
+  /* Pass the environment explicitly.  This is needed if the program has
+     modified the environment using putenv() or [un]setenv().  On Windows,
+     processes have two environments, one in the "environment block" of the
+     process and managed through SetEnvironmentVariable(), and one inside the
+     process, in the location retrieved by the 'environ' macro.  If we were
+     to pass NULL, the child process would inherit a copy of the environment
+     block - ignoring the effects of putenv() and [un]setenv().  */
+  return execve (program, argv, environ);
+}
diff --git a/m4/execv.m4 b/m4/execv.m4
new file mode 100644
index 0000000..8064482
--- /dev/null
+++ b/m4/execv.m4
@@ -0,0 +1,15 @@
+# execv.m4 serial 1
+dnl Copyright (C) 2020 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_EXECV],
+[
+  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+  AC_REQUIRE([AC_CANONICAL_HOST])
+
+  case "$host_os" in
+    mingw*) REPLACE_EXECV=1 ;;
+  esac
+])
diff --git a/modules/execv b/modules/execv
new file mode 100644
index 0000000..db64abb
--- /dev/null
+++ b/modules/execv
@@ -0,0 +1,29 @@
+Description:
+execv() function: Execute a program, replacing the current process.
+
+Files:
+lib/execv.c
+m4/execv.m4
+
+Depends-on:
+unistd
+environ         [test $REPLACE_EXECV = 1]
+execve          [test $REPLACE_EXECV = 1]
+
+configure.ac:
+gl_FUNC_EXECV
+if test $REPLACE_EXECV = 1; then
+  AC_LIBOBJ([execv])
+fi
+gl_UNISTD_MODULE_INDICATOR([execv])
+
+Makefile.am:
+
+Include:
+<unistd.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all
-- 
2.7.4


[-- Attachment #10: 0009-execv-Add-tests.patch --]
[-- Type: text/x-patch, Size: 4421 bytes --]

From 46c14c901d0a9b3aff27b9b3dde802e0a1c98bea Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Sat, 26 Dec 2020 14:33:33 +0100
Subject: [PATCH 09/15] execv: Add tests.

* tests/test-execv-main.c: New file.
* tests/test-execv.sh: New file.
* modules/execv-tests: New file.
---
 ChangeLog               |  5 +++++
 modules/execv-tests     | 11 +++++++++++
 tests/test-execv-main.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++
 tests/test-execv.sh     | 47 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 115 insertions(+)
 create mode 100644 modules/execv-tests
 create mode 100644 tests/test-execv-main.c
 create mode 100755 tests/test-execv.sh

diff --git a/ChangeLog b/ChangeLog
index 836a115..1af6b70 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2020-12-26  Bruno Haible  <bruno@clisp.org>
 
+	execv: Add tests.
+	* tests/test-execv-main.c: New file.
+	* tests/test-execv.sh: New file.
+	* modules/execv-tests: New file.
+
 	execv: New module.
 	* lib/execv.c: New file.
 	* m4/execv.m4: New file.
diff --git a/modules/execv-tests b/modules/execv-tests
new file mode 100644
index 0000000..99d63d9
--- /dev/null
+++ b/modules/execv-tests
@@ -0,0 +1,11 @@
+Files:
+tests/test-execv.sh
+tests/test-execv-main.c
+tests/test-exec-child.c
+tests/signature.h
+
+Depends-on:
+
+Makefile.am:
+TESTS += test-execv.sh
+check_PROGRAMS += test-execv-main test-exec-child
diff --git a/tests/test-execv-main.c b/tests/test-execv-main.c
new file mode 100644
index 0000000..fbe4d5c
--- /dev/null
+++ b/tests/test-execv-main.c
@@ -0,0 +1,52 @@
+/* Test of execv().
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2020.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <unistd.h>
+
+#include "signature.h"
+SIGNATURE_CHECK (execv, int, (const char *, char * const *));
+
+#include <stdio.h>
+
+int
+main ()
+{
+  const char *progname = "./test-exec-child";
+  const char *argv[12] =
+    {
+      progname,
+      "abc def",
+      "abc\"def\"ghi",
+      "xyz\"",
+      "abc\\def\\ghi",
+      "xyz\\",
+      "???",
+      "***",
+      "",
+      "foo",
+      "",
+      NULL
+    };
+  execv (progname, (char * const *) argv);
+
+  perror ("execv");
+  return 1;
+}
diff --git a/tests/test-execv.sh b/tests/test-execv.sh
new file mode 100755
index 0000000..cdea34f
--- /dev/null
+++ b/tests/test-execv.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+# Test of execv().
+#
+# Copyright (C) 2020 Free Software Foundation, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+#
+# Written by Bruno Haible <bruno@clisp.org>, 2020.
+
+${CHECKER} ./test-execv-main${EXEEXT} > test-execv.tmp
+result=$?
+test $result = 49 || exit 1
+LC_ALL=C tr -d '\r' < test-execv.tmp > test-execv.out || exit 1
+
+cat > test-execv.ok <<\EOF
+argc = 11
+argv[1] = |abc def|
+argv[2] = |abc"def"ghi|
+argv[3] = |xyz"|
+argv[4] = |abc\def\ghi|
+argv[5] = |xyz\|
+argv[6] = |???|
+argv[7] = |***|
+argv[8] = ||
+argv[9] = |foo|
+argv[10] = ||
+EOF
+
+: ${DIFF=diff}
+${DIFF} test-execv.ok test-execv.out
+result=$?
+
+rm -f test-execv.tmp test-execv.out test-execv.ok
+
+exit $result
-- 
2.7.4


[-- Attachment #11: 0010-execl-New-module.patch --]
[-- Type: text/x-patch, Size: 6278 bytes --]

From 7fbf62ebb9e7466a157b5f339d15ff1d11b18d45 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Sat, 26 Dec 2020 14:36:35 +0100
Subject: [PATCH 10/15] execl: New module.

* lib/execl.c: New file.
* m4/execl.m4: New file.
* modules/execl: New file.
* doc/posix-functions/execl.texi: Mention more Windows problems and the
new module.
---
 ChangeLog                      |  7 ++++
 doc/posix-functions/execl.texi | 21 ++++++++---
 lib/execl.c                    | 82 ++++++++++++++++++++++++++++++++++++++++++
 m4/execl.m4                    | 15 ++++++++
 modules/execl                  | 29 +++++++++++++++
 5 files changed, 149 insertions(+), 5 deletions(-)
 create mode 100644 lib/execl.c
 create mode 100644 m4/execl.m4
 create mode 100644 modules/execl

diff --git a/ChangeLog b/ChangeLog
index 1af6b70..5b8e553 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2020-12-26  Bruno Haible  <bruno@clisp.org>
 
+	execl: New module.
+	* lib/execl.c: New file.
+	* m4/execl.m4: New file.
+	* modules/execl: New file.
+	* doc/posix-functions/execl.texi: Mention more Windows problems and the
+	new module.
+
 	execv: Add tests.
 	* tests/test-execv-main.c: New file.
 	* tests/test-execv.sh: New file.
diff --git a/doc/posix-functions/execl.texi b/doc/posix-functions/execl.texi
index 70c9f8e..28460e2 100644
--- a/doc/posix-functions/execl.texi
+++ b/doc/posix-functions/execl.texi
@@ -4,19 +4,30 @@
 
 POSIX specification:@* @url{https://pubs.opengroup.org/onlinepubs/9699919799/functions/execl.html}
 
-Gnulib module: ---
+Gnulib module: execl
 
 Portability problems fixed by Gnulib:
 @itemize
+@item
+On Windows platforms (excluding Cygwin), this function does not pass
+command-line arguments correctly if they contain space, tab, backslash,
+or double-quote characters.
+@item
+On Windows platforms (excluding Cygwin), this function spawns an asynchronous
+child process and then exits the current process immediately.  As a
+consequence, the parent of the current process 1. may incorrectly proceed
+as if its child had exited, and 2. will never see the child's exit status.
+@item
+On Windows platforms (excluding Cygwin), the return type of this function is
+@code{intptr_t}, not @code{int}.
 @end itemize
 
+Note: The Gnulib replacement for this function is not async-safe, that is,
+it must not be invoked from a signal handler.
+
 Portability problems not fixed by Gnulib:
 @itemize
 @item
 On some platforms, a script without executable permission is still run:
 Cygwin 1.5.x.
-@item
-On Windows platforms (excluding Cygwin), this function operates by spawning
-and then by exiting the current process, which means the current
-process's parent may incorrectly proceed as if its child had exited.
 @end itemize
diff --git a/lib/execl.c b/lib/execl.c
new file mode 100644
index 0000000..d1df0c0
--- /dev/null
+++ b/lib/execl.c
@@ -0,0 +1,82 @@
+/* execl() function: Execute a program, replacing the current process.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2020.  */
+
+/* Don't use __attribute__ __nonnull__ in this compilation unit.  Otherwise gcc
+   may optimize away the arg0 == NULL test below.  */
+#define _GL_ARG_NONNULL(params)
+
+#include <config.h>
+
+/* Specification.  */
+#include <unistd.h>
+
+#include <errno.h>
+#include <stdarg.h>
+
+#include "malloca.h"
+
+int
+execl (const char *program, const char *arg0, ...)
+{
+  va_list args;
+
+  /* The callee is not expecting a NULL argv[0].  */
+  if (arg0 == NULL)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  /* Count the number of arguments (including arg0 and the trailing NULL).  */
+  size_t count = 1;
+  va_start (args, arg0);
+  for (;;)
+    {
+      count++;
+      if (va_arg (args, const char *) == NULL)
+        break;
+    }
+  va_end (args);
+
+  /* Allocate the argument vector.  */
+  const char **argv = (const char **) malloca (count * sizeof (const char *));
+  if (argv == NULL)
+    {
+      errno = ENOMEM;
+      return -1;
+    }
+
+  /* Copy the arguments into the argument vector.  */
+  {
+    size_t i = 0;
+    argv[i++] = arg0;
+    va_start (args, arg0);
+    for (; i < count;)
+      argv[i++] = va_arg (args, const char *);
+    va_end (args);
+  }
+
+  /* Invoke execv.  */
+  execv (program, argv);
+
+  /* If execv returned, it must have failed.  */
+  int saved_errno = errno;
+  freea (argv);
+  errno = saved_errno;
+  return -1;
+}
diff --git a/m4/execl.m4 b/m4/execl.m4
new file mode 100644
index 0000000..0f2c89c
--- /dev/null
+++ b/m4/execl.m4
@@ -0,0 +1,15 @@
+# execl.m4 serial 1
+dnl Copyright (C) 2020 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_EXECL],
+[
+  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+  AC_REQUIRE([AC_CANONICAL_HOST])
+
+  case "$host_os" in
+    mingw*) REPLACE_EXECL=1 ;;
+  esac
+])
diff --git a/modules/execl b/modules/execl
new file mode 100644
index 0000000..9d64c5c
--- /dev/null
+++ b/modules/execl
@@ -0,0 +1,29 @@
+Description:
+execl() function: Execute a program, replacing the current process.
+
+Files:
+lib/execl.c
+m4/execl.m4
+
+Depends-on:
+unistd
+execv           [test $REPLACE_EXECL = 1]
+malloca         [test $REPLACE_EXECL = 1]
+
+configure.ac:
+gl_FUNC_EXECL
+if test $REPLACE_EXECL = 1; then
+  AC_LIBOBJ([execl])
+fi
+gl_UNISTD_MODULE_INDICATOR([execl])
+
+Makefile.am:
+
+Include:
+<unistd.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all
-- 
2.7.4


[-- Attachment #12: 0011-execl-Add-tests.patch --]
[-- Type: text/x-patch, Size: 4400 bytes --]

From 614b2e6c98172bdcc96ca735f4e14056dc32e59c Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Sat, 26 Dec 2020 14:37:54 +0100
Subject: [PATCH 11/15] execl: Add tests.

* tests/test-execl-main.c: New file.
* tests/test-execl.sh: New file.
* modules/execl-tests: New file.
---
 ChangeLog               |  5 +++++
 modules/execl-tests     | 11 +++++++++++
 tests/test-execl-main.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
 tests/test-execl.sh     | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 112 insertions(+)
 create mode 100644 modules/execl-tests
 create mode 100644 tests/test-execl-main.c
 create mode 100755 tests/test-execl.sh

diff --git a/ChangeLog b/ChangeLog
index 5b8e553..7f5c99b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2020-12-26  Bruno Haible  <bruno@clisp.org>
 
+	execl: Add tests.
+	* tests/test-execl-main.c: New file.
+	* tests/test-execl.sh: New file.
+	* modules/execl-tests: New file.
+
 	execl: New module.
 	* lib/execl.c: New file.
 	* m4/execl.m4: New file.
diff --git a/modules/execl-tests b/modules/execl-tests
new file mode 100644
index 0000000..a7c56f5
--- /dev/null
+++ b/modules/execl-tests
@@ -0,0 +1,11 @@
+Files:
+tests/test-execl.sh
+tests/test-execl-main.c
+tests/test-exec-child.c
+tests/signature.h
+
+Depends-on:
+
+Makefile.am:
+TESTS += test-execl.sh
+check_PROGRAMS += test-execl-main test-exec-child
diff --git a/tests/test-execl-main.c b/tests/test-execl-main.c
new file mode 100644
index 0000000..a16cefa
--- /dev/null
+++ b/tests/test-execl-main.c
@@ -0,0 +1,49 @@
+/* Test of execl().
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2020.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <unistd.h>
+
+#include "signature.h"
+SIGNATURE_CHECK (execl, int, (const char *, const char *, ...));
+
+#include <stdio.h>
+
+int
+main ()
+{
+  const char *progname = "./test-exec-child";
+  execl (progname,
+         progname,
+         "abc def",
+         "abc\"def\"ghi",
+         "xyz\"",
+         "abc\\def\\ghi",
+         "xyz\\",
+         "???",
+         "***",
+         "",
+         "foo",
+         "",
+         NULL);
+
+  perror ("execl");
+  return 1;
+}
diff --git a/tests/test-execl.sh b/tests/test-execl.sh
new file mode 100755
index 0000000..285059d
--- /dev/null
+++ b/tests/test-execl.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+# Test of execl().
+#
+# Copyright (C) 2020 Free Software Foundation, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+#
+# Written by Bruno Haible <bruno@clisp.org>, 2020.
+
+${CHECKER} ./test-execl-main${EXEEXT} > test-execl.tmp
+result=$?
+test $result = 49 || exit 1
+LC_ALL=C tr -d '\r' < test-execl.tmp > test-execl.out || exit 1
+
+cat > test-execl.ok <<\EOF
+argc = 11
+argv[1] = |abc def|
+argv[2] = |abc"def"ghi|
+argv[3] = |xyz"|
+argv[4] = |abc\def\ghi|
+argv[5] = |xyz\|
+argv[6] = |???|
+argv[7] = |***|
+argv[8] = ||
+argv[9] = |foo|
+argv[10] = ||
+EOF
+
+: ${DIFF=diff}
+${DIFF} test-execl.ok test-execl.out
+result=$?
+
+rm -f test-execl.tmp test-execl.out test-execl.ok
+
+exit $result
-- 
2.7.4


[-- Attachment #13: 0012-execle-New-module.patch --]
[-- Type: text/x-patch, Size: 6383 bytes --]

From 6b1f82435bc2f900429b711d90e25857d817eafe Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Sat, 26 Dec 2020 14:39:39 +0100
Subject: [PATCH 12/15] execle: New module.

* lib/execle.c: New file.
* m4/execle.m4: New file.
* modules/execle: New file.
* doc/posix-functions/execle.texi: Mention more Windows problems and the
new module.
---
 ChangeLog                       |  7 ++++
 doc/posix-functions/execle.texi | 21 ++++++++---
 lib/execle.c                    | 83 +++++++++++++++++++++++++++++++++++++++++
 m4/execle.m4                    | 15 ++++++++
 modules/execle                  | 29 ++++++++++++++
 5 files changed, 150 insertions(+), 5 deletions(-)
 create mode 100644 lib/execle.c
 create mode 100644 m4/execle.m4
 create mode 100644 modules/execle

diff --git a/ChangeLog b/ChangeLog
index 7f5c99b..6a8939c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2020-12-26  Bruno Haible  <bruno@clisp.org>
 
+	execle: New module.
+	* lib/execle.c: New file.
+	* m4/execle.m4: New file.
+	* modules/execle: New file.
+	* doc/posix-functions/execle.texi: Mention more Windows problems and the
+	new module.
+
 	execl: Add tests.
 	* tests/test-execl-main.c: New file.
 	* tests/test-execl.sh: New file.
diff --git a/doc/posix-functions/execle.texi b/doc/posix-functions/execle.texi
index 04ef7c2..e556260 100644
--- a/doc/posix-functions/execle.texi
+++ b/doc/posix-functions/execle.texi
@@ -4,19 +4,30 @@
 
 POSIX specification:@* @url{https://pubs.opengroup.org/onlinepubs/9699919799/functions/execle.html}
 
-Gnulib module: ---
+Gnulib module: execle
 
 Portability problems fixed by Gnulib:
 @itemize
+@item
+On Windows platforms (excluding Cygwin), this function does not pass
+command-line arguments correctly if they contain space, tab, backslash,
+or double-quote characters.
+@item
+On Windows platforms (excluding Cygwin), this function spawns an asynchronous
+child process and then exits the current process immediately.  As a
+consequence, the parent of the current process 1. may incorrectly proceed
+as if its child had exited, and 2. will never see the child's exit status.
+@item
+On Windows platforms (excluding Cygwin), the return type of this function is
+@code{intptr_t}, not @code{int}.
 @end itemize
 
+Note: The Gnulib replacement for this function is not async-safe, that is,
+it must not be invoked from a signal handler.
+
 Portability problems not fixed by Gnulib:
 @itemize
 @item
 On some platforms, a script without executable permission is still run:
 Cygwin 1.5.x.
-@item
-On Windows platforms (excluding Cygwin), this function operates by spawning
-and then by exiting the current process, which means the current
-process's parent may incorrectly proceed as if its child had exited.
 @end itemize
diff --git a/lib/execle.c b/lib/execle.c
new file mode 100644
index 0000000..8e10d8a
--- /dev/null
+++ b/lib/execle.c
@@ -0,0 +1,83 @@
+/* execle() function: Execute a program, replacing the current process.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2020.  */
+
+/* Don't use __attribute__ __nonnull__ in this compilation unit.  Otherwise gcc
+   may optimize away the arg0 == NULL test below.  */
+#define _GL_ARG_NONNULL(params)
+
+#include <config.h>
+
+/* Specification.  */
+#include <unistd.h>
+
+#include <errno.h>
+#include <stdarg.h>
+
+#include "malloca.h"
+
+int
+execle (const char *program, const char *arg0, ...)
+{
+  va_list args;
+
+  /* The callee is not expecting a NULL argv[0].  */
+  if (arg0 == NULL)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  /* Count the number of arguments (including arg0 and the trailing NULL).  */
+  size_t count = 1;
+  va_start (args, arg0);
+  for (;;)
+    {
+      count++;
+      if (va_arg (args, const char *) == NULL)
+        break;
+    }
+  va_end (args);
+
+  /* Allocate the argument vector.  */
+  const char **argv = (const char **) malloca (count * sizeof (const char *));
+  if (argv == NULL)
+    {
+      errno = ENOMEM;
+      return -1;
+    }
+
+  /* Copy the arguments into the argument vector.  */
+  {
+    size_t i = 0;
+    argv[i++] = arg0;
+    va_start (args, arg0);
+    for (; i < count;)
+      argv[i++] = va_arg (args, const char *);
+  }
+  char * const *env = va_arg (args, char * const *);
+  va_end (args);
+
+  /* Invoke execve.  */
+  execve (program, argv, env);
+
+  /* If execve returned, it must have failed.  */
+  int saved_errno = errno;
+  freea (argv);
+  errno = saved_errno;
+  return -1;
+}
diff --git a/m4/execle.m4 b/m4/execle.m4
new file mode 100644
index 0000000..47b273b
--- /dev/null
+++ b/m4/execle.m4
@@ -0,0 +1,15 @@
+# execle.m4 serial 1
+dnl Copyright (C) 2020 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_EXECLE],
+[
+  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+  AC_REQUIRE([AC_CANONICAL_HOST])
+
+  case "$host_os" in
+    mingw*) REPLACE_EXECLE=1 ;;
+  esac
+])
diff --git a/modules/execle b/modules/execle
new file mode 100644
index 0000000..dd3c9ad
--- /dev/null
+++ b/modules/execle
@@ -0,0 +1,29 @@
+Description:
+execle() function: Execute a program, replacing the current process.
+
+Files:
+lib/execle.c
+m4/execle.m4
+
+Depends-on:
+unistd
+execve          [test $REPLACE_EXECLE = 1]
+malloca         [test $REPLACE_EXECLE = 1]
+
+configure.ac:
+gl_FUNC_EXECLE
+if test $REPLACE_EXECLE = 1; then
+  AC_LIBOBJ([execle])
+fi
+gl_UNISTD_MODULE_INDICATOR([execle])
+
+Makefile.am:
+
+Include:
+<unistd.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all
-- 
2.7.4


[-- Attachment #14: 0013-execle-Add-tests.patch --]
[-- Type: text/x-patch, Size: 4579 bytes --]

From b42620e8d20cfcb5d18f452a38aa05500d3ada35 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Sat, 26 Dec 2020 14:40:49 +0100
Subject: [PATCH 13/15] execle: Add tests.

* tests/test-execle-main.c: New file.
* tests/test-execle.sh: New file.
* modules/execle-tests: New file.
---
 ChangeLog                |  5 +++++
 modules/execle-tests     | 11 +++++++++++
 tests/test-execle-main.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++
 tests/test-execle.sh     | 48 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 115 insertions(+)
 create mode 100644 modules/execle-tests
 create mode 100644 tests/test-execle-main.c
 create mode 100755 tests/test-execle.sh

diff --git a/ChangeLog b/ChangeLog
index 6a8939c..e7a8228 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2020-12-26  Bruno Haible  <bruno@clisp.org>
 
+	execle: Add tests.
+	* tests/test-execle-main.c: New file.
+	* tests/test-execle.sh: New file.
+	* modules/execle-tests: New file.
+
 	execle: New module.
 	* lib/execle.c: New file.
 	* m4/execle.m4: New file.
diff --git a/modules/execle-tests b/modules/execle-tests
new file mode 100644
index 0000000..d752b2c
--- /dev/null
+++ b/modules/execle-tests
@@ -0,0 +1,11 @@
+Files:
+tests/test-execle.sh
+tests/test-execle-main.c
+tests/test-exec-child.c
+tests/signature.h
+
+Depends-on:
+
+Makefile.am:
+TESTS += test-execle.sh
+check_PROGRAMS += test-execle-main test-exec-child
diff --git a/tests/test-execle-main.c b/tests/test-execle-main.c
new file mode 100644
index 0000000..50d5899
--- /dev/null
+++ b/tests/test-execle-main.c
@@ -0,0 +1,51 @@
+/* Test of execle().
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2020.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <unistd.h>
+
+#include "signature.h"
+SIGNATURE_CHECK (execle, int, (const char *, const char *, ...));
+
+#include <stdio.h>
+
+int
+main ()
+{
+  const char *progname = "./test-exec-child";
+  const char *env[3] = { "PATH=.", "Hommingberg=Gepardenforelle", NULL };
+  execle (progname,
+          progname,
+          "abc def",
+          "abc\"def\"ghi",
+          "xyz\"",
+          "abc\\def\\ghi",
+          "xyz\\",
+          "???",
+          "***",
+          "",
+          "foo",
+          "",
+          NULL,
+          env);
+
+  perror ("execle");
+  return 1;
+}
diff --git a/tests/test-execle.sh b/tests/test-execle.sh
new file mode 100755
index 0000000..76469b7
--- /dev/null
+++ b/tests/test-execle.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+# Test of execle().
+#
+# Copyright (C) 2020 Free Software Foundation, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+#
+# Written by Bruno Haible <bruno@clisp.org>, 2020.
+
+${CHECKER} ./test-execle-main${EXEEXT} > test-execle.tmp
+result=$?
+test $result = 49 || exit 1
+LC_ALL=C tr -d '\r' < test-execle.tmp > test-execle.out || exit 1
+
+cat > test-execle.ok <<\EOF
+argc = 11
+argv[1] = |abc def|
+argv[2] = |abc"def"ghi|
+argv[3] = |xyz"|
+argv[4] = |abc\def\ghi|
+argv[5] = |xyz\|
+argv[6] = |???|
+argv[7] = |***|
+argv[8] = ||
+argv[9] = |foo|
+argv[10] = ||
+Hommingberg = |Gepardenforelle|
+EOF
+
+: ${DIFF=diff}
+${DIFF} test-execle.ok test-execle.out
+result=$?
+
+rm -f test-execle.tmp test-execle.out test-execle.ok
+
+exit $result
-- 
2.7.4


[-- Attachment #15: 0014-execlp-New-module.patch --]
[-- Type: text/x-patch, Size: 6253 bytes --]

From 761c7c948d36f58357e50913fd14b94a42e9ae14 Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Sat, 26 Dec 2020 14:42:38 +0100
Subject: [PATCH 14/15] execlp: New module.

* lib/execlp.c: New file.
* m4/execlp.m4: New file.
* modules/execlp: New file.
* doc/posix-functions/execlp.texi: Mention more Windows problems and the
new module.
---
 ChangeLog                       |  7 ++++
 doc/posix-functions/execlp.texi | 18 ++++++---
 lib/execlp.c                    | 82 +++++++++++++++++++++++++++++++++++++++++
 m4/execlp.m4                    | 15 ++++++++
 modules/execlp                  | 29 +++++++++++++++
 5 files changed, 146 insertions(+), 5 deletions(-)
 create mode 100644 lib/execlp.c
 create mode 100644 m4/execlp.m4
 create mode 100644 modules/execlp

diff --git a/ChangeLog b/ChangeLog
index e7a8228..0bda9d1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2020-12-26  Bruno Haible  <bruno@clisp.org>
 
+	execlp: New module.
+	* lib/execlp.c: New file.
+	* m4/execlp.m4: New file.
+	* modules/execlp: New file.
+	* doc/posix-functions/execlp.texi: Mention more Windows problems and the
+	new module.
+
 	execle: Add tests.
 	* tests/test-execle-main.c: New file.
 	* tests/test-execle.sh: New file.
diff --git a/doc/posix-functions/execlp.texi b/doc/posix-functions/execlp.texi
index 1314c75..8935119 100644
--- a/doc/posix-functions/execlp.texi
+++ b/doc/posix-functions/execlp.texi
@@ -4,10 +4,22 @@
 
 POSIX specification:@* @url{https://pubs.opengroup.org/onlinepubs/9699919799/functions/execlp.html}
 
-Gnulib module: ---
+Gnulib module: execlp
 
 Portability problems fixed by Gnulib:
 @itemize
+@item
+On Windows platforms (excluding Cygwin), this function does not pass
+command-line arguments correctly if they contain space, tab, backslash,
+or double-quote characters.
+@item
+On Windows platforms (excluding Cygwin), this function spawns an asynchronous
+child process and then exits the current process immediately.  As a
+consequence, the parent of the current process 1. may incorrectly proceed
+as if its child had exited, and 2. will never see the child's exit status.
+@item
+On Windows platforms (excluding Cygwin), the return type of this function is
+@code{intptr_t}, not @code{int}.
 @end itemize
 
 Portability problems not fixed by Gnulib:
@@ -15,8 +27,4 @@ Portability problems not fixed by Gnulib:
 @item
 On some platforms, a script without executable permission is still run:
 Cygwin 1.5.x.
-@item
-On Windows platforms (excluding Cygwin), this function operates by spawning
-and then by exiting the current process, which means the current
-process's parent may incorrectly proceed as if its child had exited.
 @end itemize
diff --git a/lib/execlp.c b/lib/execlp.c
new file mode 100644
index 0000000..cefa3ec
--- /dev/null
+++ b/lib/execlp.c
@@ -0,0 +1,82 @@
+/* execlp() function: Execute a program, replacing the current process.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2020.  */
+
+/* Don't use __attribute__ __nonnull__ in this compilation unit.  Otherwise gcc
+   may optimize away the arg0 == NULL test below.  */
+#define _GL_ARG_NONNULL(params)
+
+#include <config.h>
+
+/* Specification.  */
+#include <unistd.h>
+
+#include <errno.h>
+#include <stdarg.h>
+
+#include "malloca.h"
+
+int
+execlp (const char *program, const char *arg0, ...)
+{
+  va_list args;
+
+  /* The callee is not expecting a NULL argv[0].  */
+  if (arg0 == NULL)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  /* Count the number of arguments (including arg0 and the trailing NULL).  */
+  size_t count = 1;
+  va_start (args, arg0);
+  for (;;)
+    {
+      count++;
+      if (va_arg (args, const char *) == NULL)
+        break;
+    }
+  va_end (args);
+
+  /* Allocate the argument vector.  */
+  const char **argv = (const char **) malloca (count * sizeof (const char *));
+  if (argv == NULL)
+    {
+      errno = ENOMEM;
+      return -1;
+    }
+
+  /* Copy the arguments into the argument vector.  */
+  {
+    size_t i = 0;
+    argv[i++] = arg0;
+    va_start (args, arg0);
+    for (; i < count;)
+      argv[i++] = va_arg (args, const char *);
+    va_end (args);
+  }
+
+  /* Invoke execvp.  */
+  execvp (program, argv);
+
+  /* If execvp returned, it must have failed.  */
+  int saved_errno = errno;
+  freea (argv);
+  errno = saved_errno;
+  return -1;
+}
diff --git a/m4/execlp.m4 b/m4/execlp.m4
new file mode 100644
index 0000000..09df0c6
--- /dev/null
+++ b/m4/execlp.m4
@@ -0,0 +1,15 @@
+# execlp.m4 serial 1
+dnl Copyright (C) 2020 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_EXECLP],
+[
+  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+  AC_REQUIRE([AC_CANONICAL_HOST])
+
+  case "$host_os" in
+    mingw*) REPLACE_EXECLP=1 ;;
+  esac
+])
diff --git a/modules/execlp b/modules/execlp
new file mode 100644
index 0000000..b31191c
--- /dev/null
+++ b/modules/execlp
@@ -0,0 +1,29 @@
+Description:
+execlp() function: Execute a program, replacing the current process.
+
+Files:
+lib/execlp.c
+m4/execlp.m4
+
+Depends-on:
+unistd
+execvp          [test $REPLACE_EXECLP = 1]
+malloca         [test $REPLACE_EXECLP = 1]
+
+configure.ac:
+gl_FUNC_EXECLP
+if test $REPLACE_EXECLP = 1; then
+  AC_LIBOBJ([execlp])
+fi
+gl_UNISTD_MODULE_INDICATOR([execlp])
+
+Makefile.am:
+
+Include:
+<unistd.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all
-- 
2.7.4


[-- Attachment #16: 0015-execlp-Add-tests.patch --]
[-- Type: text/x-patch, Size: 4638 bytes --]

From 8e5c999bce06f3d09c27c40e82b1527592dfa41c Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Sat, 26 Dec 2020 14:43:58 +0100
Subject: [PATCH 15/15] execlp: Add tests.

* tests/test-execlp-main.c: New file.
* tests/test-execlp.sh: New file.
* modules/execlp-tests: New file.
---
 ChangeLog                |  5 +++++
 modules/execlp-tests     | 11 +++++++++++
 tests/test-execlp-main.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++
 tests/test-execlp.sh     | 50 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 115 insertions(+)
 create mode 100644 modules/execlp-tests
 create mode 100644 tests/test-execlp-main.c
 create mode 100755 tests/test-execlp.sh

diff --git a/ChangeLog b/ChangeLog
index 0bda9d1..309b5b8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2020-12-26  Bruno Haible  <bruno@clisp.org>
 
+	execlp: Add tests.
+	* tests/test-execlp-main.c: New file.
+	* tests/test-execlp.sh: New file.
+	* modules/execlp-tests: New file.
+
 	execlp: New module.
 	* lib/execlp.c: New file.
 	* m4/execlp.m4: New file.
diff --git a/modules/execlp-tests b/modules/execlp-tests
new file mode 100644
index 0000000..9ae80ab
--- /dev/null
+++ b/modules/execlp-tests
@@ -0,0 +1,11 @@
+Files:
+tests/test-execlp.sh
+tests/test-execlp-main.c
+tests/test-exec-child.c
+tests/signature.h
+
+Depends-on:
+
+Makefile.am:
+TESTS += test-execlp.sh
+check_PROGRAMS += test-execlp-main test-exec-child
diff --git a/tests/test-execlp-main.c b/tests/test-execlp-main.c
new file mode 100644
index 0000000..3b91ced
--- /dev/null
+++ b/tests/test-execlp-main.c
@@ -0,0 +1,49 @@
+/* Test of execlp().
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2020.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <unistd.h>
+
+#include "signature.h"
+SIGNATURE_CHECK (execlp, int, (const char *, const char *, ...));
+
+#include <stdio.h>
+
+int
+main ()
+{
+  const char *progname = "test-exec-child";
+  execlp (progname,
+          progname,
+          "abc def",
+          "abc\"def\"ghi",
+          "xyz\"",
+          "abc\\def\\ghi",
+          "xyz\\",
+          "???",
+          "***",
+          "",
+          "foo",
+          "",
+          NULL);
+
+  perror ("execlp");
+  return 1;
+}
diff --git a/tests/test-execlp.sh b/tests/test-execlp.sh
new file mode 100755
index 0000000..db68d54
--- /dev/null
+++ b/tests/test-execlp.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+# Test of execlp().
+#
+# Copyright (C) 2020 Free Software Foundation, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+#
+# Written by Bruno Haible <bruno@clisp.org>, 2020.
+
+rm -rf test-execlp-subdir
+mkdir test-execlp-subdir
+
+(cd test-execlp-subdir && PATH="..:$PATH" ${CHECKER} ../test-execlp-main${EXEEXT}) > test-execlp.tmp
+result=$?
+test $result = 49 || { rm -rf test-execlp-subdir; exit 1; }
+LC_ALL=C tr -d '\r' < test-execlp.tmp > test-execlp.out || { rm -rf test-execlp-subdir; exit 1; }
+
+cat > test-execlp.ok <<\EOF
+argc = 11
+argv[1] = |abc def|
+argv[2] = |abc"def"ghi|
+argv[3] = |xyz"|
+argv[4] = |abc\def\ghi|
+argv[5] = |xyz\|
+argv[6] = |???|
+argv[7] = |***|
+argv[8] = ||
+argv[9] = |foo|
+argv[10] = ||
+EOF
+
+: ${DIFF=diff}
+${DIFF} test-execlp.ok test-execlp.out
+result=$?
+
+rm -rf test-execlp-subdir test-execlp.tmp test-execlp.out test-execlp.ok
+
+exit $result
-- 
2.7.4


             reply	other threads:[~2020-12-26 13:53 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-26 13:53 Bruno Haible [this message]
2020-12-27 11:15 ` new modules execve, execvpe, execvp, execv, execl, execle, execlp Jeffrey Walton
2020-12-27 12:19   ` Apple embedded OSes Bruno Haible
2020-12-27 19:08     ` Jeffrey Walton

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://lists.gnu.org/mailman/listinfo/bug-gnulib

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=19625603.TXvseGJZxX@omega \
    --to=bruno@clisp.org \
    --cc=bug-gnulib@gnu.org \
    --cc=eliz@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).