1 /* Auxiliary functions for the creation of subprocesses. Native Woe32 API.
2 Copyright (C) 2003, 2006-2009 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2003.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18 /* Get declarations of the Win32 API functions. */
19 #define WIN32_LEAN_AND_MEAN
22 /* Get _get_osfhandle() and _open_osfhandle(). */
31 /* Duplicates a file handle, making the copy uninheritable. */
33 dup_noinherit (int fd)
35 HANDLE curr_process = GetCurrentProcess ();
36 HANDLE old_handle = (HANDLE) _get_osfhandle (fd);
40 if (!DuplicateHandle (curr_process, /* SourceProcessHandle */
41 old_handle, /* SourceHandle */
42 curr_process, /* TargetProcessHandle */
43 (PHANDLE) &new_handle, /* TargetHandle */
44 (DWORD) 0, /* DesiredAccess */
45 FALSE, /* InheritHandle */
46 DUPLICATE_SAME_ACCESS)) /* Options */
47 error (EXIT_FAILURE, 0, _("DuplicateHandle failed with error code 0x%08x"),
48 (unsigned int) GetLastError ());
50 nfd = _open_osfhandle ((long) new_handle, O_BINARY);
52 error (EXIT_FAILURE, errno, _("_open_osfhandle failed"));
57 /* Prepares an argument vector before calling spawn().
58 Note that spawn() does not by itself call the command interpreter
59 (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
60 ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
62 v.dwPlatformId == VER_PLATFORM_WIN32_NT;
63 }) ? "cmd.exe" : "command.com").
64 Instead it simply concatenates the arguments, separated by ' ', and calls
65 CreateProcess(). We must quote the arguments since Win32 CreateProcess()
66 interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
68 - Space and tab are interpreted as delimiters. They are not treated as
69 delimiters if they are surrounded by double quotes: "...".
70 - Unescaped double quotes are removed from the input. Their only effect is
71 that within double quotes, space and tab are treated like normal
73 - Backslashes not followed by double quotes are not special.
74 - But 2*n+1 backslashes followed by a double quote become
75 n backslashes followed by a double quote (n >= 0):
80 #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"
81 #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"
83 prepare_spawn (char **argv)
89 /* Count number of arguments. */
90 for (argc = 0; argv[argc] != NULL; argc++)
93 /* Allocate new argument vector. */
94 new_argv = XNMALLOC (1 + argc + 1, char *);
96 /* Add an element upfront that can be used when argv[0] turns out to be a
97 script, not a program.
98 On Unix, this would be "/bin/sh". On native Windows, "sh" is actually
99 "sh.exe". We have to omit the directory part and rely on the search in
100 PATH, because the mingw "mount points" are not visible inside Win32
102 *new_argv++ = "sh.exe";
104 /* Put quoted arguments into the new argument vector. */
105 for (i = 0; i < argc; i++)
107 const char *string = argv[i];
109 if (string[0] == '\0')
110 new_argv[i] = xstrdup ("\"\"");
111 else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
113 bool quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
115 unsigned int backslashes;
124 for (s = string; *s != '\0'; s++)
128 length += backslashes + 1;
136 length += backslashes + 1;
138 quoted_string = (char *) xmalloc (length + 1);
144 for (s = string; *s != '\0'; s++)
150 for (j = backslashes + 1; j > 0; j--)
162 for (j = backslashes; j > 0; j--)
168 new_argv[i] = quoted_string;
171 new_argv[i] = (char *) string;
173 new_argv[argc] = NULL;