This source file includes following definitions.
- quoted_arg_length
- quoted_arg_string
- prepare_spawn
- compose_command
- compose_envblock
- init_inheritable_handles
- compose_handles_block
- free_inheritable_handles
- convert_CreateProcess_error
- spawnpvech
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 #include <config.h>
19
20
21 #include "windows-spawn.h"
22
23
24 #define WIN32_LEAN_AND_MEAN
25 #include <windows.h>
26
27 #include <stdbool.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32
33
34 #if GNULIB_MSVC_NOTHROW
35 # include "msvc-nothrow.h"
36 #else
37 # include <io.h>
38 #endif
39 #include <process.h>
40
41 #include "findprog.h"
42
43
44 #undef STARTUPINFO
45 #define STARTUPINFO STARTUPINFOA
46 #undef CreateProcess
47 #define CreateProcess CreateProcessA
48
49 #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*?"
50 #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"
51
52
53 static size_t
54 quoted_arg_length (const char *string)
55 {
56 bool quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
57 size_t length;
58 unsigned int backslashes;
59 const char *s;
60
61 length = 0;
62 backslashes = 0;
63 if (quote_around)
64 length++;
65 for (s = string; *s != '\0'; s++)
66 {
67 char c = *s;
68 if (c == '"')
69 length += backslashes + 1;
70 length++;
71 if (c == '\\')
72 backslashes++;
73 else
74 backslashes = 0;
75 }
76 if (quote_around)
77 length += backslashes + 1;
78
79 return length;
80 }
81
82
83
84
85
86 static char *
87 quoted_arg_string (const char *string, char *mem)
88 {
89 bool quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
90 char *p;
91 unsigned int backslashes;
92 const char *s;
93
94 p = mem;
95 backslashes = 0;
96 if (quote_around)
97 *p++ = '"';
98 for (s = string; *s != '\0'; s++)
99 {
100 char c = *s;
101 if (c == '"')
102 {
103 unsigned int j;
104 for (j = backslashes + 1; j > 0; j--)
105 *p++ = '\\';
106 }
107 *p++ = c;
108 if (c == '\\')
109 backslashes++;
110 else
111 backslashes = 0;
112 }
113 if (quote_around)
114 {
115 unsigned int j;
116 for (j = backslashes; j > 0; j--)
117 *p++ = '\\';
118 *p++ = '"';
119 }
120 *p++ = '\0';
121
122 return p;
123 }
124
125 const char **
126 prepare_spawn (const char * const *argv, char **mem_to_free)
127 {
128 size_t argc;
129 const char **new_argv;
130 size_t i;
131
132
133 for (argc = 0; argv[argc] != NULL; argc++)
134 ;
135
136
137 new_argv = (const char **) malloc ((1 + argc + 1) * sizeof (const char *));
138
139
140
141
142
143
144
145 new_argv[0] = "sh.exe";
146
147
148 size_t needed_size = 0;
149 for (i = 0; i < argc; i++)
150 {
151 const char *string = argv[i];
152 size_t length;
153
154 if (string[0] == '\0')
155 length = strlen ("\"\"");
156 else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
157 length = quoted_arg_length (string);
158 else
159 length = strlen (string);
160 needed_size += length + 1;
161 }
162
163 char *mem;
164 if (needed_size == 0)
165 mem = NULL;
166 else
167 {
168 mem = (char *) malloc (needed_size);
169 if (mem == NULL)
170 {
171
172 free (new_argv);
173 errno = ENOMEM;
174 return NULL;
175 }
176 }
177 *mem_to_free = mem;
178
179 for (i = 0; i < argc; i++)
180 {
181 const char *string = argv[i];
182
183 new_argv[1 + i] = mem;
184 if (string[0] == '\0')
185 {
186 size_t length = strlen ("\"\"");
187 memcpy (mem, "\"\"", length + 1);
188 mem += length + 1;
189 }
190 else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
191 {
192 mem = quoted_arg_string (string, mem);
193 }
194 else
195 {
196 size_t length = strlen (string);
197 memcpy (mem, string, length + 1);
198 mem += length + 1;
199 }
200 }
201 new_argv[1 + argc] = NULL;
202
203 return new_argv;
204 }
205
206 char *
207 compose_command (const char * const *argv)
208 {
209
210 char *command;
211
212
213 size_t total_size = 0;
214 const char * const *ap;
215 const char *p;
216 for (ap = argv; (p = *ap) != NULL; ap++)
217 total_size += strlen (p) + 1;
218 size_t command_size = (total_size > 0 ? total_size : 1);
219
220
221 command = (char *) malloc (command_size);
222 if (command == NULL)
223 {
224 errno = ENOMEM;
225 return NULL;
226 }
227
228
229 if (total_size > 0)
230 {
231 char *cp = command;
232 for (ap = argv; (p = *ap) != NULL; ap++)
233 {
234 size_t size = strlen (p) + 1;
235 memcpy (cp, p, size - 1);
236 cp += size;
237 cp[-1] = ' ';
238 }
239 cp[-1] = '\0';
240 }
241 else
242 *command = '\0';
243
244 return command;
245 }
246
247 char *
248 compose_envblock (const char * const *envp)
249 {
250
251
252
253
254 retry:
255 {
256
257
258 size_t total_size = 0;
259 const char * const *ep;
260 const char *p;
261 for (ep = envp; (p = *ep) != NULL; ep++)
262 total_size += strlen (p) + 1;
263 size_t envblock_size = total_size;
264
265
266 char *envblock = (char *) malloc (envblock_size + 1);
267 if (envblock == NULL)
268 {
269 errno = ENOMEM;
270 return NULL;
271 }
272 size_t envblock_used = 0;
273 for (ep = envp; (p = *ep) != NULL; ep++)
274 {
275 size_t size = strlen (p) + 1;
276 if (envblock_used + size > envblock_size)
277 {
278
279 envblock_size += envblock_size / 2;
280 if (envblock_used + size > envblock_size)
281 envblock_size = envblock_used + size;
282
283 char *new_envblock = (char *) realloc (envblock, envblock_size + 1);
284 if (new_envblock == NULL)
285 {
286 free (envblock);
287 errno = ENOMEM;
288 return NULL;
289 }
290 envblock = new_envblock;
291 }
292 memcpy (envblock + envblock_used, p, size);
293 envblock_used += size;
294 if (envblock[envblock_used - 1] != '\0')
295 {
296
297 free (envblock);
298 goto retry;
299 }
300 }
301 envblock[envblock_used] = '\0';
302 return envblock;
303 }
304 }
305
306 int
307 init_inheritable_handles (struct inheritable_handles *inh_handles,
308 bool duplicate)
309 {
310
311 size_t handles_count;
312 {
313
314
315
316 unsigned int fdmax = _getmaxstdio ();
317 if (fdmax < 3)
318 fdmax = 3;
319 for (; fdmax > 3; fdmax--)
320 {
321 unsigned int fd = fdmax - 1;
322
323
324 HANDLE handle = (HANDLE) _get_osfhandle (fd);
325 if (handle != INVALID_HANDLE_VALUE)
326 {
327 DWORD hflags;
328
329
330 if (GetHandleInformation (handle, &hflags))
331 {
332 if ((hflags & HANDLE_FLAG_INHERIT) != 0)
333
334 break;
335 }
336 }
337 }
338 handles_count = fdmax;
339 }
340
341
342
343 size_t handles_allocated = handles_count;
344 HANDLE *handles_array =
345 (HANDLE *) malloc (handles_allocated * sizeof (HANDLE));
346 if (handles_array == NULL)
347 {
348 errno = ENOMEM;
349 return -1;
350 }
351 unsigned char *flags_array =
352 (unsigned char *) malloc (handles_allocated * sizeof (unsigned char));
353 if (flags_array == NULL)
354 {
355 free (handles_array);
356 errno = ENOMEM;
357 return -1;
358 }
359
360
361 {
362 HANDLE curr_process = (duplicate ? GetCurrentProcess () : INVALID_HANDLE_VALUE);
363 unsigned int fd;
364 for (fd = 0; fd < handles_count; fd++)
365 {
366 handles_array[fd] = INVALID_HANDLE_VALUE;
367
368
369 HANDLE handle = (HANDLE) _get_osfhandle (fd);
370 if (handle != INVALID_HANDLE_VALUE)
371 {
372 DWORD hflags;
373
374
375 if (GetHandleInformation (handle, &hflags))
376 {
377 if ((hflags & HANDLE_FLAG_INHERIT) != 0)
378 {
379
380 if (duplicate)
381 {
382 if (!DuplicateHandle (curr_process, handle,
383 curr_process, &handles_array[fd],
384 0, TRUE, DUPLICATE_SAME_ACCESS))
385 {
386 unsigned int i;
387 for (i = 0; i < fd; i++)
388 if (handles_array[i] != INVALID_HANDLE_VALUE)
389 CloseHandle (handles_array[i]);
390 free (flags_array);
391 free (handles_array);
392 errno = EBADF;
393 return -1;
394 }
395 }
396 else
397 handles_array[fd] = handle;
398
399 flags_array[fd] = 0;
400 }
401 }
402 }
403 }
404 }
405
406
407 inh_handles->count = handles_count;
408 inh_handles->allocated = handles_allocated;
409 inh_handles->handles = handles_array;
410 inh_handles->flags = flags_array;
411 return 0;
412 }
413
414 int
415 compose_handles_block (const struct inheritable_handles *inh_handles,
416 STARTUPINFO *sinfo)
417 {
418
419
420 sinfo->dwFlags = STARTF_USESTDHANDLES;
421 sinfo->hStdInput = inh_handles->handles[0];
422 sinfo->hStdOutput = inh_handles->handles[1];
423 sinfo->hStdError = inh_handles->handles[2];
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446 size_t handles_count = inh_handles->count;
447
448 sinfo->cbReserved2 =
449 sizeof (unsigned int)
450 + handles_count * sizeof (unsigned char)
451 + handles_count * sizeof (HANDLE);
452
453
454 char *hblock = (char *) malloc (sinfo->cbReserved2 + (sizeof (HANDLE) - 1));
455 if (hblock == NULL)
456 {
457 errno = ENOMEM;
458 return -1;
459 }
460 unsigned char *flags = (unsigned char *) (hblock + sizeof (unsigned int));
461 char *handles = (char *) (flags + handles_count);
462 HANDLE *handles_aligned =
463 (HANDLE *) (((uintptr_t) handles + (sizeof (HANDLE) - 1))
464 & - (uintptr_t) sizeof (HANDLE));
465
466 * (unsigned int *) hblock = handles_count;
467 {
468 unsigned int fd;
469 for (fd = 0; fd < handles_count; fd++)
470 {
471 handles_aligned[fd] = INVALID_HANDLE_VALUE;
472 flags[fd] = 0;
473
474 HANDLE handle = inh_handles->handles[fd];
475 if (handle != INVALID_HANDLE_VALUE
476
477
478 && (fd >= 3 || inh_handles->flags[fd] != 0))
479 {
480 DWORD hflags;
481
482
483 if (GetHandleInformation (handle, &hflags))
484 {
485 if ((hflags & HANDLE_FLAG_INHERIT) != 0)
486 {
487
488 handles_aligned[fd] = handle;
489
490
491
492
493 flags[fd] = 1 | inh_handles->flags[fd];
494 switch (GetFileType (handle))
495 {
496 case FILE_TYPE_CHAR:
497 flags[fd] |= 64;
498 break;
499 case FILE_TYPE_PIPE:
500 flags[fd] |= 8;
501 break;
502 default:
503 break;
504 }
505 }
506 else
507
508
509 abort ();
510 }
511 }
512 }
513 }
514 if (handles != (char *) handles_aligned)
515 memmove (handles, (char *) handles_aligned, handles_count * sizeof (HANDLE));
516
517 sinfo->lpReserved2 = (BYTE *) hblock;
518
519 return 0;
520 }
521
522 void
523 free_inheritable_handles (struct inheritable_handles *inh_handles)
524 {
525 free (inh_handles->flags);
526 free (inh_handles->handles);
527 }
528
529 int
530 convert_CreateProcess_error (DWORD error)
531 {
532
533 switch (error)
534 {
535 case ERROR_FILE_NOT_FOUND:
536 case ERROR_PATH_NOT_FOUND:
537 case ERROR_BAD_PATHNAME:
538 case ERROR_BAD_NET_NAME:
539 case ERROR_INVALID_NAME:
540 case ERROR_DIRECTORY:
541 return ENOENT;
542 break;
543
544 case ERROR_ACCESS_DENIED:
545 case ERROR_SHARING_VIOLATION:
546 return EACCES;
547 break;
548
549 case ERROR_OUTOFMEMORY:
550 return ENOMEM;
551 break;
552
553 case ERROR_BUFFER_OVERFLOW:
554 case ERROR_FILENAME_EXCED_RANGE:
555 return ENAMETOOLONG;
556 break;
557
558 case ERROR_BAD_FORMAT:
559 case ERROR_BAD_EXE_FORMAT:
560 return ENOEXEC;
561 break;
562
563 default:
564 return EINVAL;
565 break;
566 }
567 }
568
569 intptr_t
570 spawnpvech (int mode,
571 const char *progname, const char * const *argv,
572 const char * const *envp,
573 const char *currdir,
574 HANDLE stdin_handle, HANDLE stdout_handle, HANDLE stderr_handle)
575 {
576
577 if (!(mode == P_WAIT
578 || mode == P_NOWAIT
579 || mode == P_DETACH
580 || mode == P_OVERLAY)
581 || progname == NULL || argv == NULL)
582 {
583 errno = EINVAL;
584 return -1;
585 }
586
587
588 const char *resolved_progname =
589 find_in_given_path (progname, getenv ("PATH"), NULL, false);
590 if (resolved_progname == NULL)
591 return -1;
592
593
594 char *command = compose_command (argv);
595 if (command == NULL)
596 goto out_of_memory_1;
597
598
599 char *envblock;
600 if (envp == NULL)
601 envblock = NULL;
602 else
603 {
604 envblock = compose_envblock (envp);
605 if (envblock == NULL)
606 goto out_of_memory_2;
607 }
608
609
610 struct inheritable_handles inh_handles;
611 if (init_inheritable_handles (&inh_handles, false) < 0)
612 {
613 int saved_errno = errno;
614 if (envblock != NULL)
615 free (envblock);
616 free (command);
617 if (resolved_progname != progname)
618 free ((char *) resolved_progname);
619 errno = saved_errno;
620 return -1;
621 }
622 inh_handles.handles[0] = stdin_handle; inh_handles.flags[0] = 0;
623 inh_handles.handles[1] = stdout_handle; inh_handles.flags[1] = 0;
624 inh_handles.handles[2] = stderr_handle; inh_handles.flags[2] = 0;
625
626
627
628
629 DWORD process_creation_flags = (mode == P_DETACH ? DETACHED_PROCESS : 0);
630
631
632 STARTUPINFO sinfo;
633 sinfo.cb = sizeof (STARTUPINFO);
634 sinfo.lpReserved = NULL;
635 sinfo.lpDesktop = NULL;
636 sinfo.lpTitle = NULL;
637 if (compose_handles_block (&inh_handles, &sinfo) < 0)
638 {
639 int saved_errno = errno;
640 free_inheritable_handles (&inh_handles);
641 if (envblock != NULL)
642 free (envblock);
643 free (command);
644 if (resolved_progname != progname)
645 free ((char *) resolved_progname);
646 errno = saved_errno;
647 return -1;
648 }
649
650 PROCESS_INFORMATION pinfo;
651 if (!CreateProcess (resolved_progname, command, NULL, NULL, TRUE,
652 process_creation_flags, envblock, currdir, &sinfo,
653 &pinfo))
654 {
655 DWORD error = GetLastError ();
656
657 free (sinfo.lpReserved2);
658 free_inheritable_handles (&inh_handles);
659 if (envblock != NULL)
660 free (envblock);
661 free (command);
662 if (resolved_progname != progname)
663 free ((char *) resolved_progname);
664
665 errno = convert_CreateProcess_error (error);
666 return -1;
667 }
668
669 if (pinfo.hThread)
670 CloseHandle (pinfo.hThread);
671 free (sinfo.lpReserved2);
672 free_inheritable_handles (&inh_handles);
673 if (envblock != NULL)
674 free (envblock);
675 free (command);
676 if (resolved_progname != progname)
677 free ((char *) resolved_progname);
678
679 switch (mode)
680 {
681 case P_WAIT:
682 {
683
684 switch (WaitForSingleObject (pinfo.hProcess, INFINITE))
685 {
686 case WAIT_OBJECT_0:
687 break;
688 case WAIT_FAILED:
689 errno = ECHILD;
690 return -1;
691 default:
692 abort ();
693 }
694
695 DWORD exit_code;
696 if (!GetExitCodeProcess (pinfo.hProcess, &exit_code))
697 {
698 errno = ECHILD;
699 return -1;
700 }
701 CloseHandle (pinfo.hProcess);
702 return exit_code;
703 }
704
705 case P_NOWAIT:
706
707 return (intptr_t) pinfo.hProcess;
708
709 case P_DETACH:
710 case P_OVERLAY:
711 CloseHandle (pinfo.hProcess);
712 return 0;
713
714 default:
715
716 abort ();
717 }
718
719
720 out_of_memory_2:
721 free (command);
722 out_of_memory_1:
723 if (resolved_progname != progname)
724 free ((char *) resolved_progname);
725 errno = ENOMEM;
726 return -1;
727 }