1 /* Auxiliary functions for the creation of subprocesses. Native Woe32 API. 2 Copyright (C) 2003 Free Software Foundation, Inc. 3 Written by Bruno Haible <bruno@clisp.org>, 2003. 4 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 2, or (at your option) 8 any later version. 9 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. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software Foundation, 17 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ 18 19 /* Get declarations of the Win32 API functions. */ 20 #define WIN32_LEAN_AND_MEAN 21 #include <windows.h> 22 23 /* Get _get_osfhandle() and _open_osfhandle(). */ 24 #include <io.h> 25 26 #include <stdbool.h> 27 #include <errno.h> 28 29 #include "strpbrk.h" 30 #include "xalloc.h" 31 32 /* Duplicates a file handle, making the copy uninheritable. */ 33 static int 34 dup_noinherit (int fd) 35 { 36 HANDLE curr_process = GetCurrentProcess (); 37 HANDLE old_handle = (HANDLE) _get_osfhandle (fd); 38 HANDLE new_handle; 39 int nfd; 40 41 if (!DuplicateHandle (curr_process, /* SourceProcessHandle */ 42 old_handle, /* SourceHandle */ 43 curr_process, /* TargetProcessHandle */ 44 (PHANDLE) &new_handle, /* TargetHandle */ 45 (DWORD) 0, /* DesiredAccess */ 46 FALSE, /* InheritHandle */ 47 DUPLICATE_SAME_ACCESS)) /* Options */ 48 error (EXIT_FAILURE, 0, _("DuplicateHandle failed with error code 0x%08x"), 49 GetLastError ()); 50 51 nfd = _open_osfhandle ((long) new_handle, O_BINARY); 52 if (nfd < 0) 53 error (EXIT_FAILURE, errno, _("_open_osfhandle failed")); 54 55 return nfd; 56 } 57 58 /* Prepares an argument vector before calling spawn(). 59 Note that spawn() does not by itself call the command interpreter 60 (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : 61 ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); 62 GetVersionEx(&v); 63 v.dwPlatformId == VER_PLATFORM_WIN32_NT; 64 }) ? "cmd.exe" : "command.com"). 65 Instead it simply concatenates the arguments, separated by ' ', and calls 66 CreateProcess(). We must quote the arguments since Win32 CreateProcess() 67 interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a 68 special way: 69 - Space and tab are interpreted as delimiters. They are not treated as 70 delimiters if they are surrounded by double quotes: "...". 71 - Unescaped double quotes are removed from the input. Their only effect is 72 that within double quotes, space and tab are treated like normal 73 characters. 74 - Backslashes not followed by double quotes are not special. 75 - But 2*n+1 backslashes followed by a double quote become 76 n backslashes followed by a double quote (n >= 0): 77 \" -> " 78 \\\" -> \" 79 \\\\\" -> \\" 80 */ 81 #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" 82 #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 static char ** 84 prepare_spawn (char **argv) 85 { 86 size_t argc; 87 char **new_argv; 88 size_t i; 89 90 /* Count number of arguments. */ 91 for (argc = 0; argv[argc] != NULL; argc++) 92 ; 93 94 /* Allocate new argument vector. */ 95 new_argv = (char **) xmalloc ((argc + 1) * sizeof (char *)); 96 97 /* Put quoted arguments into the new argument vector. */ 98 for (i = 0; i < argc; i++) 99 { 100 const char *string = argv[i]; 101 102 if (string[0] == '\0') 103 new_argv[i] = xstrdup ("\"\""); 104 else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) 105 { 106 bool quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); 107 size_t length; 108 unsigned int backslashes; 109 const char *s; 110 char *quoted_string; 111 char *p; 112 113 length = 0; 114 backslashes = 0; 115 if (quote_around) 116 length++; 117 for (s = string; *s != '\0'; s++) 118 { 119 char c = *s; 120 if (c == '"') 121 length += backslashes + 1; 122 length++; 123 if (c == '\\') 124 backslashes++; 125 else 126 backslashes = 0; 127 } 128 if (quote_around) 129 length += backslashes + 1; 130 131 quoted_string = (char *) xmalloc (length + 1); 132 133 p = quoted_string; 134 backslashes = 0; 135 if (quote_around) 136 *p++ = '"'; 137 for (s = string; *s != '\0'; s++) 138 { 139 char c = *s; 140 if (c == '"') 141 { 142 unsigned int j; 143 for (j = backslashes + 1; j > 0; j--) 144 *p++ = '\\'; 145 } 146 *p++ = c; 147 if (c == '\\') 148 backslashes++; 149 else 150 backslashes = 0; 151 } 152 if (quote_around) 153 { 154 unsigned int j; 155 for (j = backslashes; j > 0; j--) 156 *p++ = '\\'; 157 *p++ = '"'; 158 } 159 *p = '\0'; 160 161 new_argv[i] = quoted_string; 162 } 163 else 164 new_argv[i] = (char *) string; 165 } 166 new_argv[argc] = NULL; 167 168 return new_argv; 169 } 170