From: Bruno Haible Date: Sat, 28 Nov 2020 09:46:23 +0000 (+0100) Subject: windows-spawn: New module. X-Git-Tag: v1.0~3464 X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=a27e759a67c21e62d539339140d4252ed176557a;p=gnulib.git windows-spawn: New module. * lib/windows-spawn.h: Renamed from lib/w32spawn.h. Remove implementations. * lib/windows-spawn.c: Renamed from lib/w32spawn.h. * modules/windows-spawn: New file. * lib/execute.c: Include "windows-spawn.h" instead of "w32spawn.h". * lib/spawn-pipe.c: Likewise. * modules/execute (Files): Remove lib/w32spawn.h. (Depends-on): Add windows-spawn. Remove cloexec, msvc-nothrow, strpbrk, xalloc. (Makefile.am): Remove w32spawn.h from lib_SOURCES. * modules/spawn-pipe (Files): Remove lib/w32spawn.h. (Depends-on): Add windows-spawn. Remove cloexec, msvc-nothrow, strpbrk, xalloc. (Makefile.am): Remove w32spawn.h from lib_SOURCES. --- diff --git a/ChangeLog b/ChangeLog index bf29984838..22a26e7e94 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2020-11-28 Bruno Haible + + windows-spawn: New module. + * lib/windows-spawn.h: Renamed from lib/w32spawn.h. Remove + implementations. + * lib/windows-spawn.c: Renamed from lib/w32spawn.h. + * modules/windows-spawn: New file. + * lib/execute.c: Include "windows-spawn.h" instead of "w32spawn.h". + * lib/spawn-pipe.c: Likewise. + * modules/execute (Files): Remove lib/w32spawn.h. + (Depends-on): Add windows-spawn. Remove cloexec, msvc-nothrow, strpbrk, + xalloc. + (Makefile.am): Remove w32spawn.h from lib_SOURCES. + * modules/spawn-pipe (Files): Remove lib/w32spawn.h. + (Depends-on): Add windows-spawn. Remove cloexec, msvc-nothrow, strpbrk, + xalloc. + (Makefile.am): Remove w32spawn.h from lib_SOURCES. + 2020-11-27 Bruno Haible ssfmalloc tests: Port to macOS 11. diff --git a/lib/execute.c b/lib/execute.c index 15d9ba98d2..41e1e9222c 100644 --- a/lib/execute.c +++ b/lib/execute.c @@ -39,7 +39,7 @@ /* Native Windows API. */ # include -# include "w32spawn.h" +# include "windows-spawn.h" #else diff --git a/lib/spawn-pipe.c b/lib/spawn-pipe.c index 947825ac8e..1a7a1e1662 100644 --- a/lib/spawn-pipe.c +++ b/lib/spawn-pipe.c @@ -44,7 +44,7 @@ /* Native Windows API. */ # include -# include "w32spawn.h" +# include "windows-spawn.h" #else diff --git a/lib/w32spawn.h b/lib/w32spawn.h deleted file mode 100644 index a4b3b1e500..0000000000 --- a/lib/w32spawn.h +++ /dev/null @@ -1,233 +0,0 @@ -/* Auxiliary functions for the creation of subprocesses. Native Windows API. - Copyright (C) 2001, 2003-2020 Free Software Foundation, Inc. - Written by Bruno Haible , 2003. - - 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 . */ - -#ifndef __KLIBC__ -/* Get declarations of the native Windows API functions. */ -# define WIN32_LEAN_AND_MEAN -# include -#endif - -/* Get _open_osfhandle(). */ -#include - -#include -#include -#include -#include - -/* Get _get_osfhandle(). */ -# if GNULIB_MSVC_NOTHROW -# include "msvc-nothrow.h" -# else -# include -# endif - -#include "cloexec.h" -#include "xalloc.h" - -/* Duplicates a file handle, making the copy uninheritable. - Returns -1 for a file handle that is equivalent to closed. */ -static int -dup_noinherit (int fd) -{ - fd = dup_cloexec (fd); - if (fd < 0 && errno == EMFILE) - error (EXIT_FAILURE, errno, _("_open_osfhandle failed")); - - return fd; -} - -/* Returns a file descriptor equivalent to FD, except that the resulting file - descriptor is none of STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO. - FD must be open and non-inheritable. The result will be non-inheritable as - well. - If FD < 0, FD itself is returned. */ -static int -fd_safer_noinherit (int fd) -{ - if (STDIN_FILENO <= fd && fd <= STDERR_FILENO) - { - /* The recursion depth is at most 3. */ - int nfd = fd_safer_noinherit (dup_noinherit (fd)); - int saved_errno = errno; - close (fd); - errno = saved_errno; - return nfd; - } - return fd; -} - -/* Duplicates a file handle, making the copy uninheritable and ensuring the - result is none of STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO. - Returns -1 for a file handle that is equivalent to closed. */ -static int -dup_safer_noinherit (int fd) -{ - return fd_safer_noinherit (dup_noinherit (fd)); -} - -/* Undoes the effect of TEMPFD = dup_safer_noinherit (ORIGFD); */ -static void -undup_safer_noinherit (int tempfd, int origfd) -{ - if (tempfd >= 0) - { - if (dup2 (tempfd, origfd) < 0) - error (EXIT_FAILURE, errno, _("cannot restore fd %d: dup2 failed"), - origfd); - close (tempfd); - } - else - { - /* origfd was closed or open to no handle at all. Set it to a closed - state. This is (nearly) equivalent to the original state. */ - close (origfd); - } -} - -/* Prepares an argument vector before calling spawn(). - Note that spawn() does not by itself call the command interpreter - (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : - ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&v); - v.dwPlatformId == VER_PLATFORM_WIN32_NT; - }) ? "cmd.exe" : "command.com"). - Instead it simply concatenates the arguments, separated by ' ', and calls - CreateProcess(). We must quote the arguments since Windows CreateProcess() - interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a - special way: - - Space and tab are interpreted as delimiters. They are not treated as - delimiters if they are surrounded by double quotes: "...". - - Unescaped double quotes are removed from the input. Their only effect is - that within double quotes, space and tab are treated like normal - characters. - - Backslashes not followed by double quotes are not special. - - But 2*n+1 backslashes followed by a double quote become - n backslashes followed by a double quote (n >= 0): - \" -> " - \\\" -> \" - \\\\\" -> \\" - - '*', '?' characters may get expanded through wildcard expansion in the - callee: By default, in the callee, the initialization code before main() - takes the result of GetCommandLine(), wildcard-expands it, and passes it - to main(). The exceptions to this rule are: - - programs that inspect GetCommandLine() and ignore argv, - - mingw programs that have a global variable 'int _CRT_glob = 0;', - - Cygwin programs, when invoked from a Cygwin program. - */ -#ifndef __KLIBC__ -# define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037*?" -# define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" -#else -# define SHELL_SPECIAL_CHARS "" -# define SHELL_SPACE_CHARS "" -#endif -static char ** -prepare_spawn (char **argv) -{ - size_t argc; - char **new_argv; - size_t i; - - /* Count number of arguments. */ - for (argc = 0; argv[argc] != NULL; argc++) - ; - - /* Allocate new argument vector. */ - new_argv = XNMALLOC (1 + argc + 1, char *); - - /* Add an element upfront that can be used when argv[0] turns out to be a - script, not a program. - On Unix, this would be "/bin/sh". On native Windows, "sh" is actually - "sh.exe". We have to omit the directory part and rely on the search in - PATH, because the mingw "mount points" are not visible inside Windows - CreateProcess(). */ - *new_argv++ = "sh.exe"; - - /* Put quoted arguments into the new argument vector. */ - for (i = 0; i < argc; i++) - { - const char *string = argv[i]; - - if (string[0] == '\0') - new_argv[i] = xstrdup ("\"\""); - else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) - { - bool quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); - size_t length; - unsigned int backslashes; - const char *s; - char *quoted_string; - char *p; - - length = 0; - backslashes = 0; - if (quote_around) - length++; - for (s = string; *s != '\0'; s++) - { - char c = *s; - if (c == '"') - length += backslashes + 1; - length++; - if (c == '\\') - backslashes++; - else - backslashes = 0; - } - if (quote_around) - length += backslashes + 1; - - quoted_string = (char *) xmalloc (length + 1); - - p = quoted_string; - backslashes = 0; - if (quote_around) - *p++ = '"'; - for (s = string; *s != '\0'; s++) - { - char c = *s; - if (c == '"') - { - unsigned int j; - for (j = backslashes + 1; j > 0; j--) - *p++ = '\\'; - } - *p++ = c; - if (c == '\\') - backslashes++; - else - backslashes = 0; - } - if (quote_around) - { - unsigned int j; - for (j = backslashes; j > 0; j--) - *p++ = '\\'; - *p++ = '"'; - } - *p = '\0'; - - new_argv[i] = quoted_string; - } - else - new_argv[i] = (char *) string; - } - new_argv[argc] = NULL; - - return new_argv; -} diff --git a/lib/windows-spawn.c b/lib/windows-spawn.c new file mode 100644 index 0000000000..eedb7e4c30 --- /dev/null +++ b/lib/windows-spawn.c @@ -0,0 +1,210 @@ +/* Auxiliary functions for the creation of subprocesses. Native Windows API. + Copyright (C) 2001, 2003-2020 Free Software Foundation, Inc. + Written by Bruno Haible , 2003. + + 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 . */ + +#include + +/* Specification. */ +#include "windows-spawn.h" + +#ifndef __KLIBC__ +/* Get declarations of the native Windows API functions. */ +# define WIN32_LEAN_AND_MEAN +# include +#endif + +/* Get _open_osfhandle(). */ +#include + +#include +#include +#include +#include +#include + +/* Get _get_osfhandle(). */ +#if GNULIB_MSVC_NOTHROW +# include "msvc-nothrow.h" +#else +# include +#endif + +#include "cloexec.h" +#include "error.h" +#include "xalloc.h" +#include "gettext.h" + +#define _(str) gettext (str) + + +/* Duplicates a file handle, making the copy uninheritable. + Returns -1 for a file handle that is equivalent to closed. */ +static int +dup_noinherit (int fd) +{ + fd = dup_cloexec (fd); + if (fd < 0 && errno == EMFILE) + error (EXIT_FAILURE, errno, _("_open_osfhandle failed")); + + return fd; +} + +/* Returns a file descriptor equivalent to FD, except that the resulting file + descriptor is none of STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO. + FD must be open and non-inheritable. The result will be non-inheritable as + well. + If FD < 0, FD itself is returned. */ +static int +fd_safer_noinherit (int fd) +{ + if (STDIN_FILENO <= fd && fd <= STDERR_FILENO) + { + /* The recursion depth is at most 3. */ + int nfd = fd_safer_noinherit (dup_noinherit (fd)); + int saved_errno = errno; + close (fd); + errno = saved_errno; + return nfd; + } + return fd; +} + +int +dup_safer_noinherit (int fd) +{ + return fd_safer_noinherit (dup_noinherit (fd)); +} + +void +undup_safer_noinherit (int tempfd, int origfd) +{ + if (tempfd >= 0) + { + if (dup2 (tempfd, origfd) < 0) + error (EXIT_FAILURE, errno, _("cannot restore fd %d: dup2 failed"), + origfd); + close (tempfd); + } + else + { + /* origfd was closed or open to no handle at all. Set it to a closed + state. This is (nearly) equivalent to the original state. */ + close (origfd); + } +} + +#ifndef __KLIBC__ +# define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037*?" +# define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +#else +# define SHELL_SPECIAL_CHARS "" +# define SHELL_SPACE_CHARS "" +#endif +char ** +prepare_spawn (char **argv) +{ + size_t argc; + char **new_argv; + size_t i; + + /* Count number of arguments. */ + for (argc = 0; argv[argc] != NULL; argc++) + ; + + /* Allocate new argument vector. */ + new_argv = XNMALLOC (1 + argc + 1, char *); + + /* Add an element upfront that can be used when argv[0] turns out to be a + script, not a program. + On Unix, this would be "/bin/sh". On native Windows, "sh" is actually + "sh.exe". We have to omit the directory part and rely on the search in + PATH, because the mingw "mount points" are not visible inside Windows + CreateProcess(). */ + *new_argv++ = "sh.exe"; + + /* Put quoted arguments into the new argument vector. */ + for (i = 0; i < argc; i++) + { + const char *string = argv[i]; + + if (string[0] == '\0') + new_argv[i] = xstrdup ("\"\""); + else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) + { + bool quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); + size_t length; + unsigned int backslashes; + const char *s; + char *quoted_string; + char *p; + + length = 0; + backslashes = 0; + if (quote_around) + length++; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + length += backslashes + 1; + length++; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + length += backslashes + 1; + + quoted_string = (char *) xmalloc (length + 1); + + p = quoted_string; + backslashes = 0; + if (quote_around) + *p++ = '"'; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + { + unsigned int j; + for (j = backslashes + 1; j > 0; j--) + *p++ = '\\'; + } + *p++ = c; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + { + unsigned int j; + for (j = backslashes; j > 0; j--) + *p++ = '\\'; + *p++ = '"'; + } + *p = '\0'; + + new_argv[i] = quoted_string; + } + else + new_argv[i] = (char *) string; + } + new_argv[argc] = NULL; + + return new_argv; +} diff --git a/lib/windows-spawn.h b/lib/windows-spawn.h new file mode 100644 index 0000000000..200f321b5a --- /dev/null +++ b/lib/windows-spawn.h @@ -0,0 +1,61 @@ +/* Auxiliary functions for the creation of subprocesses. Native Windows API. + Copyright (C) 2001, 2003-2020 Free Software Foundation, Inc. + Written by Bruno Haible , 2003. + + 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 . */ + +#ifndef _WINDOWS_SPAWN_H +#define _WINDOWS_SPAWN_H + +/* Duplicates a file handle, making the copy uninheritable and ensuring the + result is none of STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO. + Returns -1 for a file handle that is equivalent to closed. */ +extern int dup_safer_noinherit (int fd); + +/* Undoes the effect of TEMPFD = dup_safer_noinherit (ORIGFD); */ +extern void undup_safer_noinherit (int tempfd, int origfd); + +/* Prepares an argument vector before calling spawn(). + Note that spawn() does not by itself call the command interpreter + (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : + ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&v); + v.dwPlatformId == VER_PLATFORM_WIN32_NT; + }) ? "cmd.exe" : "command.com"). + Instead it simply concatenates the arguments, separated by ' ', and calls + CreateProcess(). We must quote the arguments since Windows CreateProcess() + interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a + special way: + - Space and tab are interpreted as delimiters. They are not treated as + delimiters if they are surrounded by double quotes: "...". + - Unescaped double quotes are removed from the input. Their only effect is + that within double quotes, space and tab are treated like normal + characters. + - Backslashes not followed by double quotes are not special. + - But 2*n+1 backslashes followed by a double quote become + n backslashes followed by a double quote (n >= 0): + \" -> " + \\\" -> \" + \\\\\" -> \\" + - '*', '?' characters may get expanded through wildcard expansion in the + callee: By default, in the callee, the initialization code before main() + takes the result of GetCommandLine(), wildcard-expands it, and passes it + to main(). The exceptions to this rule are: + - programs that inspect GetCommandLine() and ignore argv, + - mingw programs that have a global variable 'int _CRT_glob = 0;', + - Cygwin programs, when invoked from a Cygwin program. + */ +extern char ** prepare_spawn (char **argv); + +#endif /* _WINDOWS_SPAWN_H */ diff --git a/modules/execute b/modules/execute index a438fbfd7b..4a7f845961 100644 --- a/modules/execute +++ b/modules/execute @@ -4,17 +4,14 @@ Creation of autonomous subprocesses. Files: lib/execute.h lib/execute.c -lib/w32spawn.h m4/execute.m4 Depends-on: -cloexec dup2 error fatal-signal wait-process gettext-h -msvc-nothrow spawn posix_spawnp posix_spawn_file_actions_init @@ -26,16 +23,15 @@ posix_spawnattr_setflags posix_spawnattr_destroy stdbool stdlib -strpbrk unistd environ -xalloc +windows-spawn configure.ac: gl_EXECUTE Makefile.am: -lib_SOURCES += execute.h execute.c w32spawn.h +lib_SOURCES += execute.h execute.c Include: "execute.h" diff --git a/modules/spawn-pipe b/modules/spawn-pipe index dd07fef303..2c62586e27 100644 --- a/modules/spawn-pipe +++ b/modules/spawn-pipe @@ -4,17 +4,14 @@ Creation of subprocesses, communicating via pipes. Files: lib/spawn-pipe.h lib/spawn-pipe.c -lib/w32spawn.h m4/spawn-pipe.m4 Depends-on: -cloexec dup2 environ error fatal-signal gettext-h -msvc-nothrow open pipe2 pipe2-safer @@ -31,17 +28,16 @@ posix_spawnattr_setflags posix_spawnattr_destroy stdbool stdlib -strpbrk unistd unistd-safer wait-process -xalloc +windows-spawn configure.ac: gl_SPAWN_PIPE Makefile.am: -lib_SOURCES += spawn-pipe.h spawn-pipe.c w32spawn.h +lib_SOURCES += spawn-pipe.h spawn-pipe.c Include: "spawn-pipe.h" diff --git a/modules/windows-spawn b/modules/windows-spawn new file mode 100644 index 0000000000..747f8bb8a7 --- /dev/null +++ b/modules/windows-spawn @@ -0,0 +1,37 @@ +Description: +Auxiliary functions for the creation of subprocesses on native Windows. + +Files: +lib/windows-spawn.h +lib/windows-spawn.c + +Depends-on: +cloexec +dup2 +error +gettext-h +msvc-nothrow +stdbool +stdlib +strpbrk +unistd +xalloc + +configure.ac: +AC_REQUIRE([AC_CANONICAL_HOST]) +case "$host_os" in + mingw*) + AC_LIBOBJ([windows-spawn]) + ;; +esac + +Makefile.am: + +Include: +"windows-spawn.h" + +License: +GPL + +Maintainer: +all