1 // Written in the D programming language.
2 
3 /**
4 Functions for starting and interacting with other processes, and for
5 working with the current process' execution environment.
6 
7 Process_handling:
8 $(UL $(LI
9     $(LREF spawnProcess) spawns a new process, optionally assigning it an
10     arbitrary set of standard input, output, and error streams.
11     The function returns immediately, leaving the child process to execute
12     in parallel with its parent.  All other functions in this module that
13     spawn processes are built around `spawnProcess`.)
14 $(LI
15     $(LREF wait) makes the parent process wait for a child process to
16     terminate.  In general one should always do this, to avoid
17     child processes becoming "zombies" when the parent process exits.
18     Scope guards are perfect for this – see the $(LREF spawnProcess)
19     documentation for examples.  $(LREF tryWait) is similar to `wait`,
20     but does not block if the process has not yet terminated.)
21 $(LI
22     $(LREF pipeProcess) also spawns a child process which runs
23     in parallel with its parent.  However, instead of taking
24     arbitrary streams, it automatically creates a set of
25     pipes that allow the parent to communicate with the child
26     through the child's standard input, output, and/or error streams.
27     This function corresponds roughly to C's `popen` function.)
28 $(LI
29     $(LREF execute) starts a new process and waits for it
30     to complete before returning.  Additionally, it captures
31     the process' standard output and error streams and returns
32     the output of these as a string.)
33 $(LI
34     $(LREF spawnShell), $(LREF pipeShell) and $(LREF executeShell) work like
35     `spawnProcess`, `pipeProcess` and `execute`, respectively,
36     except that they take a single command string and run it through
37     the current user's default command interpreter.
38     `executeShell` corresponds roughly to C's `system` function.)
39 $(LI
40     $(LREF kill) attempts to terminate a running process.)
41 )
42 
43 The following table compactly summarises the different process creation
44 functions and how they relate to each other:
45 $(BOOKTABLE,
46     $(TR $(TH )
47          $(TH Runs program directly)
48          $(TH Runs shell command))
49     $(TR $(TD Low-level process creation)
50          $(TD $(LREF spawnProcess))
51          $(TD $(LREF spawnShell)))
52     $(TR $(TD Automatic input/output redirection using pipes)
53          $(TD $(LREF pipeProcess))
54          $(TD $(LREF pipeShell)))
55     $(TR $(TD Execute and wait for completion, collect output)
56          $(TD $(LREF execute))
57          $(TD $(LREF executeShell)))
58 )
59 
60 Other_functionality:
61 $(UL
62 $(LI
63     $(LREF pipe) is used to create unidirectional pipes.)
64 $(LI
65     $(LREF environment) is an interface through which the current process'
66     environment variables can be read and manipulated.)
67 $(LI
68     $(LREF escapeShellCommand) and $(LREF escapeShellFileName) are useful
69     for constructing shell command lines in a portable way.)
70 )
71 
72 Authors:
73     $(LINK2 https://github.com/kyllingstad, Lars Tandle Kyllingstad),
74     $(LINK2 https://github.com/schveiguy, Steven Schveighoffer),
75     $(HTTP thecybershadow.net, Vladimir Panteleev)
76 Copyright:
77     Copyright (c) 2013, the authors. All rights reserved.
78 License:
79    $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
80 Source:
81     $(PHOBOSSRC std/process.d)
82 Macros:
83     OBJECTREF=$(REF1 $0, object)
84 
85 Note:
86 Most of the functionality in this module is not available on iOS, tvOS
87 and watchOS. The only functions available on those platforms are:
88 $(LREF environment), $(LREF thisProcessID) and $(LREF thisThreadID).
89 */
90 module std.process;
91 
92 import core.thread : ThreadID;
93 
94 version (Posix)
95 {
96     import core.sys.posix.sys.wait;
97     import core.sys.posix.unistd;
98 }
99 version (Windows)
100 {
101     import core.stdc.stdio;
102     import core.sys.windows.winbase;
103     import core.sys.windows.winnt;
104     import std.utf;
105     import std.windows.syserror;
106 }
107 
108 import std.internal.cstring;
109 import std.range;
110 import std.stdio;
111 
112 version (OSX)
113     version = Darwin;
114 else version (iOS)
115 {
116     version = Darwin;
117     version = iOSDerived;
118 }
119 else version (TVOS)
120 {
121     version = Darwin;
122     version = iOSDerived;
123 }
124 else version (WatchOS)
125 {
126     version = Darwin;
127     version = iOSDerived;
128 }
129 
130 
131 // Some of the following should be moved to druntime.
132 private
133 {
134     // Microsoft Visual C Runtime (MSVCRT) declarations.
135     version (CRuntime_Microsoft)
136     {
137         import core.stdc.stdint;
138         enum
139         {
140             STDIN_FILENO  = 0,
141             STDOUT_FILENO = 1,
142             STDERR_FILENO = 2,
143         }
144     }
145 
146     // POSIX API declarations.
147     version (Posix)
148     {
149         import core.sys.posix.unistd : getEnvironPtr = environ;
150 
151         @system unittest
152         {
153             import core.thread : Thread;
154             new Thread({assert(getEnvironPtr !is null);}).start();
155         }
156     }
157 } // private
158 
159 // =============================================================================
160 // Environment variable manipulation.
161 // =============================================================================
162 
163 /**
164 Manipulates _environment variables using an associative-array-like
165 interface.
166 
167 This class contains only static methods, and cannot be instantiated.
168 See below for examples of use.
169 */
170 abstract final class environment
171 {
172     static import core.sys.posix.stdlib;
173     import core.stdc.errno : errno, EINVAL;
174 
175 static:
176     /**
177     Retrieves the value of the environment variable with the given `name`.
178     ---
179     auto path = environment["PATH"];
180     ---
181 
182     Throws:
183     $(OBJECTREF Exception) if the environment variable does not exist,
184     or $(REF UTFException, std,utf) if the variable contains invalid UTF-16
185     characters (Windows only).
186 
187     See_also:
188     $(LREF environment.get), which doesn't throw on failure.
189     */
190     string opIndex(scope const(char)[] name) @safe
191     {
192         import std.exception : enforce;
193         return get(name, null).enforce("Environment variable not found: "~name);
194     }
195 
196     /**
197     Retrieves the value of the environment variable with the given `name`,
198     or a default value if the variable doesn't exist.
199 
200     Unlike $(LREF environment.opIndex), this function never throws on Posix.
201     ---
202     auto sh = environment.get("SHELL", "/bin/sh");
203     ---
204     This function is also useful in checking for the existence of an
205     environment variable.
206     ---
207     auto myVar = environment.get("MYVAR");
208     if (myVar is null)
209     {
210         // Environment variable doesn't exist.
211         // Note that we have to use 'is' for the comparison, since
212         // myVar == null is also true if the variable exists but is
213         // empty.
214     }
215     ---
216     Params:
217         name = name of the environment variable to retrieve
218         defaultValue = default value to return if the environment variable doesn't exist.
219 
220     Returns:
221         the value of the environment variable if found, otherwise
222         `null` if the environment doesn't exist.
223 
224     Throws:
225     $(REF UTFException, std,utf) if the variable contains invalid UTF-16
226     characters (Windows only).
227     */
228     string get(scope const(char)[] name, string defaultValue = null) @safe
229     {
230         string value;
231         getImpl(name, (result) { value = result ? cachedToString(result) : defaultValue; });
232         return value;
233     }
234 
235     /**
236     Assigns the given `value` to the environment variable with the given
237     `name`.
238     If `value` is null the variable is removed from environment.
239 
240     If the variable does not exist, it will be created. If it already exists,
241     it will be overwritten.
242     ---
243     environment["foo"] = "bar";
244     ---
245 
246     Throws:
247     $(OBJECTREF Exception) if the environment variable could not be added
248         (e.g. if the name is invalid).
249 
250     Note:
251     On some platforms, modifying environment variables may not be allowed in
252     multi-threaded programs. See e.g.
253     $(LINK2 https://www.gnu.org/software/libc/manual/html_node/Environment-Access.html#Environment-Access, glibc).
254     */
255     inout(char)[] opIndexAssign(return scope inout char[] value, scope const(char)[] name) @trusted
256     {
257         version (Posix)
258         {
259             import std.exception : enforce, errnoEnforce;
260             if (value is null)
261             {
262                 remove(name);
263                 return value;
264             }
265             if (core.sys.posix.stdlib.setenv(name.tempCString(), value.tempCString(), 1) != -1)
266             {
267                 return value;
268             }
269             // The default errno error message is very uninformative
270             // in the most common case, so we handle it manually.
271             enforce(errno != EINVAL,
272                 "Invalid environment variable name: '"~name~"'");
273             errnoEnforce(false,
274                 "Failed to add environment variable");
275             assert(0);
276         }
277         else version (Windows)
278         {
279             import std.windows.syserror : wenforce;
280             wenforce(
281                 SetEnvironmentVariableW(name.tempCStringW(), value.tempCStringW()),
282             );
283             return value;
284         }
285         else static assert(0);
286     }
287 
288     /**
289     Removes the environment variable with the given `name`.
290 
291     If the variable isn't in the environment, this function returns
292     successfully without doing anything.
293 
294     Note:
295     On some platforms, modifying environment variables may not be allowed in
296     multi-threaded programs. See e.g.
297     $(LINK2 https://www.gnu.org/software/libc/manual/html_node/Environment-Access.html#Environment-Access, glibc).
298     */
299     void remove(scope const(char)[] name) @trusted nothrow @nogc
300     {
301         version (Windows)    SetEnvironmentVariableW(name.tempCStringW(), null);
302         else version (Posix) core.sys.posix.stdlib.unsetenv(name.tempCString());
303         else static assert(0);
304     }
305 
306     /**
307     Identify whether a variable is defined in the environment.
308 
309     Because it doesn't return the value, this function is cheaper than `get`.
310     However, if you do need the value as well, you should just check the
311     return of `get` for `null` instead of using this function first.
312 
313     Example:
314     -------------
315     // good usage
316     if ("MY_ENV_FLAG" in environment)
317         doSomething();
318 
319     // bad usage
320     if ("MY_ENV_VAR" in environment)
321         doSomething(environment["MY_ENV_VAR"]);
322 
323     // do this instead
324     if (auto var = environment.get("MY_ENV_VAR"))
325         doSomething(var);
326     -------------
327     */
328     bool opBinaryRight(string op : "in")(scope const(char)[] name) @trusted
329     {
330         if (name is null)
331             return false;
332         version (Posix)
333             return core.sys.posix.stdlib.getenv(name.tempCString()) !is null;
334         else version (Windows)
335         {
336             SetLastError(NO_ERROR);
337             if (GetEnvironmentVariableW(name.tempCStringW, null, 0) > 0)
338                 return true;
339             immutable err = GetLastError();
340             if (err == NO_ERROR)
341                 return true; // zero-length environment variable on Wine / XP
342             if (err == ERROR_ENVVAR_NOT_FOUND)
343                 return false;
344             // Some other Windows error, throw.
345             throw new WindowsException(err);
346         }
347         else static assert(0);
348     }
349 
350     /**
351     Copies all environment variables into an associative array.
352 
353     Windows_specific:
354     While Windows environment variable names are case insensitive, D's
355     built-in associative arrays are not.  This function will store all
356     variable names in uppercase (e.g. `PATH`).
357 
358     Throws:
359     $(OBJECTREF Exception) if the environment variables could not
360         be retrieved (Windows only).
361     */
362     string[string] toAA() @trusted
363     {
364         import std.conv : to;
365         string[string] aa;
366         version (Posix)
367         {
368             auto environ = getEnvironPtr;
369             for (int i=0; environ[i] != null; ++i)
370             {
371                 import std.string : indexOf;
372 
373                 immutable varDef = to!string(environ[i]);
374                 immutable eq = indexOf(varDef, '=');
375                 assert(eq >= 0);
376 
377                 immutable name = varDef[0 .. eq];
378                 immutable value = varDef[eq+1 .. $];
379 
380                 // In POSIX, environment variables may be defined more
381                 // than once.  This is a security issue, which we avoid
382                 // by checking whether the key already exists in the array.
383                 // For more info:
384                 // http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/environment-variables.html
385                 if (name !in aa)  aa[name] = value;
386             }
387         }
388         else version (Windows)
389         {
390             import std.exception : enforce;
391             import std.uni : toUpper;
392             auto envBlock = GetEnvironmentStringsW();
393             enforce(envBlock, "Failed to retrieve environment variables.");
394             scope(exit) FreeEnvironmentStringsW(envBlock);
395 
396             for (int i=0; envBlock[i] != '\0'; ++i)
397             {
398                 auto start = i;
399                 while (envBlock[i] != '=') ++i;
400                 immutable name = toUTF8(toUpper(envBlock[start .. i]));
401 
402                 start = i+1;
403                 while (envBlock[i] != '\0') ++i;
404 
405                 // Ignore variables with empty names. These are used internally
406                 // by Windows to keep track of each drive's individual current
407                 // directory.
408                 if (!name.length)
409                     continue;
410 
411                 // Just like in POSIX systems, environment variables may be
412                 // defined more than once in an environment block on Windows,
413                 // and it is just as much of a security issue there.  Moreso,
414                 // in fact, due to the case insensensitivity of variable names,
415                 // which is not handled correctly by all programs.
416                 auto val = toUTF8(envBlock[start .. i]);
417                 if (name !in aa) aa[name] = val is null ? "" : val;
418             }
419         }
420         else static assert(0);
421         return aa;
422     }
423 
424 private:
425     version (Windows) alias OSChar = WCHAR;
426     else version (Posix) alias OSChar = char;
427 
428     // Retrieves the environment variable. Calls `sink` with a
429     // temporary buffer of OS characters, or `null` if the variable
430     // doesn't exist.
431     void getImpl(scope const(char)[] name, scope void delegate(const(OSChar)[]) @safe sink) @trusted
432     {
433         // fix issue https://issues.dlang.org/show_bug.cgi?id=24549
434         if (name is null)
435             return sink(null);
436 
437         version (Windows)
438         {
439             // first we ask windows how long the environment variable is,
440             // then we try to read it in to a buffer of that length. Lots
441             // of error conditions because the windows API is nasty.
442 
443             import std.conv : to;
444             const namezTmp = name.tempCStringW();
445             WCHAR[] buf;
446 
447             // clear error because GetEnvironmentVariable only says it sets it
448             // if the environment variable is missing, not on other errors.
449             SetLastError(NO_ERROR);
450             // len includes terminating null
451             immutable len = GetEnvironmentVariableW(namezTmp, null, 0);
452             if (len == 0)
453             {
454                 immutable err = GetLastError();
455                 if (err == ERROR_ENVVAR_NOT_FOUND)
456                     return sink(null);
457                 if (err != NO_ERROR) // Some other Windows error, throw.
458                     throw new WindowsException(err);
459             }
460             if (len <= 1)
461                 return sink("");
462             buf.length = len;
463 
464             while (true)
465             {
466                 // lenRead is either the number of bytes read w/o null - if buf was long enough - or
467                 // the number of bytes necessary *including* null if buf wasn't long enough
468                 immutable lenRead = GetEnvironmentVariableW(namezTmp, buf.ptr, to!DWORD(buf.length));
469                 if (lenRead == 0)
470                 {
471                     immutable err = GetLastError();
472                     if (err == NO_ERROR) // sucessfully read a 0-length variable
473                         return sink("");
474                     if (err == ERROR_ENVVAR_NOT_FOUND) // variable didn't exist
475                         return sink(null);
476                     // some other windows error
477                     throw new WindowsException(err);
478                 }
479                 assert(lenRead != buf.length, "impossible according to msft docs");
480                 if (lenRead < buf.length) // the buffer was long enough
481                     return sink(buf[0 .. lenRead]);
482                 // resize and go around again, because the environment variable grew
483                 buf.length = lenRead;
484             }
485         }
486         else version (Posix)
487         {
488             import core.stdc.string : strlen;
489 
490             const vz = core.sys.posix.stdlib.getenv(name.tempCString());
491             if (vz == null) return sink(null);
492             return sink(vz[0 .. strlen(vz)]);
493        }
494         else static assert(0);
495     }
496 
497     string cachedToString(C)(scope const(C)[] v) @safe
498     {
499         import std.algorithm.comparison : equal;
500 
501         // Cache the last call's result.
502         static string lastResult;
503         if (v.empty)
504         {
505             // Return non-null array for blank result to distinguish from
506             // not-present result.
507             lastResult = "";
508         }
509         else if (!v.equal(lastResult))
510         {
511             import std.conv : to;
512             lastResult = v.to!string;
513         }
514         return lastResult;
515     }
516 }
517 
518 @safe unittest
519 {
520     import std.exception : assertThrown;
521     // New variable
522     environment["std_process"] = "foo";
523     assert(environment["std_process"] == "foo");
524     assert("std_process" in environment);
525 
526     // Set variable again (also tests length 1 case)
527     environment["std_process"] = "b";
528     assert(environment["std_process"] == "b");
529     assert("std_process" in environment);
530 
531     // Remove variable
532     environment.remove("std_process");
533     assert("std_process" !in environment);
534 
535     // Remove again, should succeed
536     environment.remove("std_process");
537     assert("std_process" !in environment);
538 
539     // Throw on not found.
540     assertThrown(environment["std_process"]);
541 
542     // get() without default value
543     assert(environment.get("std_process") is null);
544 
545     // get() with default value
546     assert(environment.get("std_process", "baz") == "baz");
547 
548     // get() on an empty (but present) value
549     environment["std_process"] = "";
550     auto res = environment.get("std_process");
551     assert(res !is null);
552     assert(res == "");
553     assert("std_process" in environment);
554 
555     // Important to do the following round-trip after the previous test
556     // because it tests toAA with an empty var
557 
558     // Convert to associative array
559     auto aa = environment.toAA();
560     assert(aa.length > 0);
561     foreach (n, v; aa)
562     {
563         // Wine has some bugs related to environment variables:
564         //  - Wine allows the existence of an env. variable with the name
565         //    "\0", but GetEnvironmentVariable refuses to retrieve it.
566         //    As of 2.067 we filter these out anyway (see comment in toAA).
567 
568         assert(v == environment[n]);
569     }
570 
571     // ... and back again.
572     foreach (n, v; aa)
573         environment[n] = v;
574 
575     // Complete the roundtrip
576     auto aa2 = environment.toAA();
577     import std.conv : text;
578     assert(aa == aa2, text(aa, " != ", aa2));
579     assert("std_process" in environment);
580 
581     // Setting null must have the same effect as remove
582     environment["std_process"] = null;
583     assert("std_process" !in environment);
584 }
585 
586 // https://issues.dlang.org/show_bug.cgi?id=24549
587 @safe unittest
588 {
589     import std.exception : assertThrown;
590     assert(environment.get(null) is null);
591     assertThrown(environment[null]);
592     assert(!(null in environment));
593 }
594 
595 // =============================================================================
596 // Functions and classes for process management.
597 // =============================================================================
598 
599 /**
600  * Returns the process ID of the current process,
601  * which is guaranteed to be unique on the system.
602  *
603  * Example:
604  * ---
605  * writefln("Current process ID: %d", thisProcessID);
606  * ---
607  */
608 @property int thisProcessID() @trusted nothrow @nogc //TODO: @safe
609 {
610     version (Windows)    return GetCurrentProcessId();
611     else version (Posix) return core.sys.posix.unistd.getpid();
612 }
613 
614 
615 /**
616  * Returns the process ID of the current thread,
617  * which is guaranteed to be unique within the current process.
618  *
619  * Returns:
620  * A $(REF ThreadID, core,thread) value for the calling thread.
621  *
622  * Example:
623  * ---
624  * writefln("Current thread ID: %s", thisThreadID);
625  * ---
626  */
627 @property ThreadID thisThreadID() @trusted nothrow @nogc //TODO: @safe
628 {
629     version (Windows)
630         return GetCurrentThreadId();
631     else
632     version (Posix)
633     {
634         import core.sys.posix.pthread : pthread_self;
635         return pthread_self();
636     }
637 }
638 
639 
640 @system unittest
641 {
642     int pidA, pidB;
643     ThreadID tidA, tidB;
644     pidA = thisProcessID;
645     tidA = thisThreadID;
646 
647     import core.thread;
648     auto t = new Thread({
649         pidB = thisProcessID;
650         tidB = thisThreadID;
651     });
652     t.start();
653     t.join();
654 
655     assert(pidA == pidB);
656     assert(tidA != tidB);
657 }
658 
659 
660 package(std) string uniqueTempPath() @safe
661 {
662     import std.file : tempDir;
663     import std.path : buildPath;
664     import std.uuid : randomUUID;
665     // Path should contain spaces to test escaping whitespace
666     return buildPath(tempDir(), "std.process temporary file " ~
667         randomUUID().toString());
668 }
669 
670 
671 version (iOSDerived) {}
672 else:
673 
674 /**
675 Spawns a new process, optionally assigning it an arbitrary set of standard
676 input, output, and error streams.
677 
678 The function returns immediately, leaving the child process to execute
679 in parallel with its parent.  It is recommended to always call $(LREF wait)
680 on the returned $(LREF Pid) unless the process was spawned with
681 `Config.detached` flag, as detailed in the documentation for `wait`.
682 
683 Command_line:
684 There are four overloads of this function.  The first two take an array
685 of strings, `args`, which should contain the program name as the
686 zeroth element and any command-line arguments in subsequent elements.
687 The third and fourth versions are included for convenience, and may be
688 used when there are no command-line arguments.  They take a single string,
689 `program`, which specifies the program name.
690 
691 Unless a directory is specified in `args[0]` or `program`,
692 `spawnProcess` will search for the program in a platform-dependent
693 manner.  On POSIX systems, it will look for the executable in the
694 directories listed in the PATH environment variable, in the order
695 they are listed.  On Windows, it will search for the executable in
696 the following sequence:
697 $(OL
698     $(LI The directory from which the application loaded.)
699     $(LI The current directory for the parent process.)
700     $(LI The 32-bit Windows system directory.)
701     $(LI The 16-bit Windows system directory.)
702     $(LI The Windows directory.)
703     $(LI The directories listed in the PATH environment variable.)
704 )
705 ---
706 // Run an executable called "prog" located in the current working
707 // directory:
708 auto pid = spawnProcess("./prog");
709 scope(exit) wait(pid);
710 // We can do something else while the program runs.  The scope guard
711 // ensures that the process is waited for at the end of the scope.
712 ...
713 
714 // Run DMD on the file "myprog.d", specifying a few compiler switches:
715 auto dmdPid = spawnProcess(["dmd", "-O", "-release", "-inline", "myprog.d" ]);
716 if (wait(dmdPid) != 0)
717     writeln("Compilation failed!");
718 ---
719 
720 Environment_variables:
721 By default, the child process inherits the environment of the parent
722 process, along with any additional variables specified in the `env`
723 parameter.  If the same variable exists in both the parent's environment
724 and in `env`, the latter takes precedence.
725 
726 If the $(LREF Config.newEnv) flag is set in `config`, the child
727 process will $(I not) inherit the parent's environment.  Its entire
728 environment will then be determined by `env`.
729 ---
730 wait(spawnProcess("myapp", ["foo" : "bar"], Config.newEnv));
731 ---
732 
733 Standard_streams:
734 The optional arguments `stdin`, `stdout` and `stderr` may
735 be used to assign arbitrary $(REF File, std,stdio) objects as the standard
736 input, output and error streams, respectively, of the child process.  The
737 former must be opened for reading, while the latter two must be opened for
738 writing.  The default is for the child process to inherit the standard
739 streams of its parent.
740 ---
741 // Run DMD on the file myprog.d, logging any error messages to a
742 // file named errors.log.
743 auto logFile = File("errors.log", "w");
744 auto pid = spawnProcess(["dmd", "myprog.d"],
745                         std.stdio.stdin,
746                         std.stdio.stdout,
747                         logFile);
748 if (wait(pid) != 0)
749     writeln("Compilation failed. See errors.log for details.");
750 ---
751 
752 Note that if you pass a `File` object that is $(I not)
753 one of the standard input/output/error streams of the parent process,
754 that stream will by default be $(I closed) in the parent process when
755 this function returns.  See the $(LREF Config) documentation below for
756 information about how to disable this behaviour.
757 
758 Beware of buffering issues when passing `File` objects to
759 `spawnProcess`.  The child process will inherit the low-level raw
760 read/write offset associated with the underlying file descriptor, but
761 it will not be aware of any buffered data.  In cases where this matters
762 (e.g. when a file should be aligned before being passed on to the
763 child process), it may be a good idea to use unbuffered streams, or at
764 least ensure all relevant buffers are flushed.
765 
766 Params:
767 args    = An array which contains the program name as the zeroth element
768           and any command-line arguments in the following elements.
769 stdin   = The standard input stream of the child process.
770           This can be any $(REF File, std,stdio) that is opened for reading.
771           By default the child process inherits the parent's input
772           stream.
773 stdout  = The standard output stream of the child process.
774           This can be any $(REF File, std,stdio) that is opened for writing.
775           By default the child process inherits the parent's output stream.
776 stderr  = The standard error stream of the child process.
777           This can be any $(REF File, std,stdio) that is opened for writing.
778           By default the child process inherits the parent's error stream.
779 env     = Additional environment variables for the child process.
780 config  = Flags that control process creation. See $(LREF Config)
781           for an overview of available flags.
782 workDir = The working directory for the new process.
783           By default the child process inherits the parent's working
784           directory.
785 
786 Returns:
787 A $(LREF Pid) object that corresponds to the spawned process.
788 
789 Throws:
790 $(LREF ProcessException) on failure to start the process.$(BR)
791 $(REF StdioException, std,stdio) on failure to pass one of the streams
792     to the child process (Windows only).$(BR)
793 $(REF RangeError, core,exception) if `args` is empty.
794 */
795 Pid spawnProcess(scope const(char[])[] args,
796                  File stdin = std.stdio.stdin,
797                  File stdout = std.stdio.stdout,
798                  File stderr = std.stdio.stderr,
799                  const string[string] env = null,
800                  Config config = Config.none,
801                  scope const char[] workDir = null)
802     @safe
803 {
804     version (Windows)
805     {
806         const commandLine = escapeShellArguments(args);
807         const program = args.length ? args[0] : null;
808         return spawnProcessWin(commandLine, program, stdin, stdout, stderr, env, config, workDir);
809     }
810     else version (Posix)
811     {
812         return spawnProcessPosix(args, stdin, stdout, stderr, env, config, workDir);
813     }
814     else
815         static assert(0);
816 }
817 
818 /// ditto
819 Pid spawnProcess(scope const(char[])[] args,
820                  const string[string] env,
821                  Config config = Config.none,
822                  scope const(char)[] workDir = null)
823     @trusted // TODO: Should be @safe
824 {
825     return spawnProcess(args,
826                         std.stdio.stdin,
827                         std.stdio.stdout,
828                         std.stdio.stderr,
829                         env,
830                         config,
831                         workDir);
832 }
833 
834 /// ditto
835 Pid spawnProcess(scope const(char)[] program,
836                  File stdin = std.stdio.stdin,
837                  File stdout = std.stdio.stdout,
838                  File stderr = std.stdio.stderr,
839                  const string[string] env = null,
840                  Config config = Config.none,
841                  scope const(char)[] workDir = null)
842     @trusted
843 {
844     return spawnProcess((&program)[0 .. 1],
845                         stdin, stdout, stderr, env, config, workDir);
846 }
847 
848 /// ditto
849 Pid spawnProcess(scope const(char)[] program,
850                  const string[string] env,
851                  Config config = Config.none,
852                  scope const(char)[] workDir = null)
853     @trusted
854 {
855     return spawnProcess((&program)[0 .. 1], env, config, workDir);
856 }
857 
858 version (Posix) private enum InternalError : ubyte
859 {
860     noerror,
861     exec,
862     chdir,
863     getrlimit,
864     doubleFork,
865     malloc,
866     preExec,
867     closefds_dup2,
868 }
869 
870 /*
871 Implementation of spawnProcess() for POSIX.
872 
873 envz should be a zero-terminated array of zero-terminated strings
874 on the form "var=value".
875 */
876 version (Posix)
877 private Pid spawnProcessPosix(scope const(char[])[] args,
878                               File stdin,
879                               File stdout,
880                               File stderr,
881                               scope const string[string] env,
882                               Config config,
883                               scope const(char)[] workDir)
884     @trusted // TODO: Should be @safe
885 {
886     import core.exception : RangeError;
887     import std.algorithm.searching : any;
888     import std.conv : text;
889     import std.path : isDirSeparator;
890     import std.string : toStringz;
891 
892     if (args.empty) throw new RangeError();
893     const(char)[] name = args[0];
894     if (!any!isDirSeparator(name))
895     {
896         name = searchPathFor(name);
897         if (name is null)
898             throw new ProcessException(text("Executable file not found: ", args[0]));
899     }
900 
901     // Convert program name and arguments to C-style strings.
902     auto argz = new const(char)*[args.length+1];
903     argz[0] = toStringz(name);
904     foreach (i; 1 .. args.length) argz[i] = toStringz(args[i]);
905     argz[$-1] = null;
906 
907     // Prepare environment.
908     auto envz = createEnv(env, !(config.flags & Config.Flags.newEnv));
909 
910     // Open the working directory.
911     // We use open in the parent and fchdir in the child
912     // so that most errors (directory doesn't exist, not a directory)
913     // can be propagated as exceptions before forking.
914     int workDirFD = -1;
915     scope(exit) if (workDirFD >= 0) close(workDirFD);
916     if (workDir.length)
917     {
918         import core.sys.posix.fcntl : open, O_RDONLY, stat_t, fstat, S_ISDIR;
919         workDirFD = open(workDir.tempCString(), O_RDONLY);
920         if (workDirFD < 0)
921             throw ProcessException.newFromErrno("Failed to open working directory");
922         stat_t s;
923         if (fstat(workDirFD, &s) < 0)
924             throw ProcessException.newFromErrno("Failed to stat working directory");
925         if (!S_ISDIR(s.st_mode))
926             throw new ProcessException("Not a directory: " ~ cast(string) workDir);
927     }
928 
929     static int getFD(ref File f) { return core.stdc.stdio.fileno(f.getFP()); }
930 
931     // Get the file descriptors of the streams.
932     // These could potentially be invalid, but that is OK.  If so, later calls
933     // to dup2() and close() will just silently fail without causing any harm.
934     auto stdinFD  = getFD(stdin);
935     auto stdoutFD = getFD(stdout);
936     auto stderrFD = getFD(stderr);
937 
938     // We don't have direct access to the errors that may happen in a child process.
939     // So we use this pipe to deliver them.
940     int[2] forkPipe;
941     if (core.sys.posix.unistd.pipe(forkPipe) == 0)
942         setCLOEXEC(forkPipe[1], true);
943     else
944         throw ProcessException.newFromErrno("Could not create pipe to check startup of child");
945     scope(exit) close(forkPipe[0]);
946 
947     /*
948     To create detached process, we use double fork technique
949     but we don't have a direct access to the second fork pid from the caller side thus use a pipe.
950     We also can't reuse forkPipe for that purpose
951     because we can't predict the order in which pid and possible error will be written
952     since the first and the second forks will run in parallel.
953     */
954     int[2] pidPipe;
955     if (config.flags & Config.Flags.detached)
956     {
957         if (core.sys.posix.unistd.pipe(pidPipe) != 0)
958             throw ProcessException.newFromErrno("Could not create pipe to get process pid");
959         setCLOEXEC(pidPipe[1], true);
960     }
961     scope(exit) if (config.flags & Config.Flags.detached) close(pidPipe[0]);
962 
963     static void abortOnError(int forkPipeOut, InternalError errorType, int error) nothrow
964     {
965         core.sys.posix.unistd.write(forkPipeOut, &errorType, errorType.sizeof);
966         core.sys.posix.unistd.write(forkPipeOut, &error, error.sizeof);
967         close(forkPipeOut);
968         core.sys.posix.unistd._exit(1);
969         assert(0);
970     }
971 
972     void closePipeWriteEnds()
973     {
974         close(forkPipe[1]);
975         if (config.flags & Config.Flags.detached)
976             close(pidPipe[1]);
977     }
978 
979     auto id = core.sys.posix.unistd.fork();
980     if (id < 0)
981     {
982         closePipeWriteEnds();
983         throw ProcessException.newFromErrno("Failed to spawn new process");
984     }
985 
986     void forkChild() nothrow @nogc
987     {
988         static import core.sys.posix.stdio;
989 
990         // Child process
991 
992         // no need for the read end of pipe on child side
993         if (config.flags & Config.Flags.detached)
994             close(pidPipe[0]);
995         close(forkPipe[0]);
996         auto forkPipeOut = forkPipe[1];
997         immutable pidPipeOut = pidPipe[1];
998 
999         // Set the working directory.
1000         if (workDirFD >= 0)
1001         {
1002             if (fchdir(workDirFD) < 0)
1003             {
1004                 // Fail. It is dangerous to run a program
1005                 // in an unexpected working directory.
1006                 abortOnError(forkPipeOut, InternalError.chdir, .errno);
1007             }
1008             close(workDirFD);
1009         }
1010 
1011         void execProcess()
1012         {
1013             // Redirect streams and close the old file descriptors.
1014             // In the case that stderr is redirected to stdout, we need
1015             // to backup the file descriptor since stdout may be redirected
1016             // as well.
1017             if (stderrFD == STDOUT_FILENO) stderrFD = dup(stderrFD);
1018             dup2(stdinFD,  STDIN_FILENO);
1019             dup2(stdoutFD, STDOUT_FILENO);
1020             dup2(stderrFD, STDERR_FILENO);
1021 
1022             // Ensure that the standard streams aren't closed on execute, and
1023             // optionally close all other file descriptors.
1024             setCLOEXEC(STDIN_FILENO, false);
1025             setCLOEXEC(STDOUT_FILENO, false);
1026             setCLOEXEC(STDERR_FILENO, false);
1027 
1028             if (!(config.flags & Config.Flags.inheritFDs))
1029             {
1030                 version (FreeBSD)
1031                     import core.sys.freebsd.unistd : closefrom;
1032                 else version (OpenBSD)
1033                     import core.sys.openbsd.unistd : closefrom;
1034 
1035                 static if (!__traits(compiles, closefrom))
1036                 {
1037                     void fallback (int lowfd)
1038                     {
1039                         import core.sys.posix.dirent : dirent, opendir, readdir, closedir, DIR;
1040                         import core.sys.posix.unistd : close;
1041                         import core.sys.posix.stdlib : atoi, malloc, free;
1042                         import core.sys.posix.sys.resource : rlimit, getrlimit, RLIMIT_NOFILE;
1043 
1044                         // Get the maximum number of file descriptors that could be open.
1045                         rlimit r;
1046                         if (getrlimit(RLIMIT_NOFILE, &r) != 0)
1047                             abortOnError(forkPipeOut, InternalError.getrlimit, .errno);
1048 
1049                         immutable maxDescriptors = cast(int) r.rlim_cur;
1050 
1051                         // Missing druntime declaration
1052                         pragma(mangle, "dirfd")
1053                         extern(C) nothrow @nogc int dirfd(DIR* dir);
1054 
1055                         DIR* dir = null;
1056 
1057                         // We read from /dev/fd or /proc/self/fd only if the limit is high enough
1058                         if (maxDescriptors > 128*1024)
1059                         {
1060                             // Try to open the directory /dev/fd or /proc/self/fd
1061                             dir = opendir("/dev/fd");
1062                             if (dir is null) dir = opendir("/proc/self/fd");
1063                         }
1064 
1065                         // If we have a directory, close all file descriptors except stdin, stdout, and stderr
1066                         if (dir)
1067                         {
1068                             scope(exit) closedir(dir);
1069 
1070                             int opendirfd = dirfd(dir);
1071 
1072                             // Iterate over all file descriptors
1073                             while (true)
1074                             {
1075                                 dirent* entry = readdir(dir);
1076 
1077                                 if (entry is null) break;
1078                                 if (entry.d_name[0] == '.') continue;
1079 
1080                                 int fd = atoi(cast(char*) entry.d_name);
1081 
1082                                 // Don't close stdin, stdout, stderr, or the directory file descriptor
1083                                 if (fd < lowfd || fd == opendirfd) continue;
1084 
1085                                 close(fd);
1086                             }
1087                         }
1088                         else
1089                         {
1090                             // This is going to allocate 8 bytes for each possible file descriptor from lowfd to r.rlim_cur
1091                             if (maxDescriptors <= 128*1024)
1092                             {
1093                                 // NOTE: malloc() and getrlimit() are not on the POSIX async
1094                                 // signal safe functions list, but practically this should
1095                                 // not be a problem. Java VM and CPython also use malloc()
1096                                 // in its own implementation via opendir().
1097                                 import core.stdc.stdlib : malloc;
1098                                 import core.sys.posix.poll : pollfd, poll, POLLNVAL;
1099 
1100                                 immutable maxToClose = maxDescriptors - lowfd;
1101 
1102                                 // Call poll() to see which ones are actually open:
1103                                 auto pfds = cast(pollfd*) malloc(pollfd.sizeof * maxToClose);
1104                                 if (pfds is null)
1105                                 {
1106                                     abortOnError(forkPipeOut, InternalError.malloc, .errno);
1107                                 }
1108 
1109                                 foreach (i; 0 .. maxToClose)
1110                                 {
1111                                     pfds[i].fd = i + lowfd;
1112                                     pfds[i].events = 0;
1113                                     pfds[i].revents = 0;
1114                                 }
1115 
1116                                 if (poll(pfds, maxToClose, 0) < 0)
1117                                     // couldn't use poll, use the slow path.
1118                                     goto LslowClose;
1119 
1120                                 foreach (i; 0 .. maxToClose)
1121                                 {
1122                                     // POLLNVAL will be set if the file descriptor is invalid.
1123                                     if (!(pfds[i].revents & POLLNVAL)) close(pfds[i].fd);
1124                                 }
1125                             }
1126                             else
1127                             {
1128                             LslowClose:
1129                                 // Fall back to closing everything.
1130                                 foreach (i; lowfd .. maxDescriptors)
1131                                 {
1132                                     close(i);
1133                                 }
1134                             }
1135                         }
1136                     }
1137 
1138                     // closefrom may not be available on the version of glibc we build against.
1139                     // Until we find a way to perform this check we will try to use dlsym to
1140                     // check for the function. See: https://github.com/dlang/phobos/pull/9048
1141                     version (CRuntime_Glibc)
1142                     {
1143                         void closefrom (int lowfd) {
1144                             static bool tryGlibcClosefrom (int lowfd) {
1145                                 import core.sys.posix.dlfcn : dlopen, dlclose, dlsym, dlerror, RTLD_LAZY;
1146 
1147                                 void *handle = dlopen("libc.so.6", RTLD_LAZY);
1148                                 if (!handle)
1149                                     return false;
1150                                 scope(exit) dlclose(handle);
1151 
1152                                 // Clear errors
1153                                 dlerror();
1154                                 alias closefromT = extern(C) void function(int) @nogc @system nothrow;
1155                                 auto closefrom = cast(closefromT) dlsym(handle, "closefrom");
1156                                 if (dlerror())
1157                                     return false;
1158 
1159                                 closefrom(lowfd);
1160                                 return true;
1161                             }
1162 
1163                             if (!tryGlibcClosefrom(lowfd))
1164                                 fallback(lowfd);
1165                         }
1166                     }
1167                     else
1168                         alias closefrom = fallback;
1169                 }
1170 
1171                 // We need to close all open file descriptors excluding std{in,out,err}
1172                 // and forkPipeOut because we still need it.
1173                 // Since the various libc's provide us with `closefrom` move forkPipeOut
1174                 // to position 3, right after STDERR_FILENO, and close all FDs following that.
1175                 if (dup2(forkPipeOut, 3) == -1)
1176                     abortOnError(forkPipeOut, InternalError.closefds_dup2, .errno);
1177                 forkPipeOut = 3;
1178                 // forkPipeOut needs to be closed after we call `exec`.
1179                 setCLOEXEC(forkPipeOut, true);
1180                 closefrom(forkPipeOut + 1);
1181             }
1182             else // This is already done if we don't inherit descriptors.
1183             {
1184                 // Close the old file descriptors, unless they are
1185                 // either of the standard streams.
1186                 if (stdinFD  > STDERR_FILENO)  close(stdinFD);
1187                 if (stdoutFD > STDERR_FILENO)  close(stdoutFD);
1188                 if (stderrFD > STDERR_FILENO)  close(stderrFD);
1189             }
1190 
1191             if (config.preExecFunction !is null)
1192             {
1193                 if (config.preExecFunction() != true)
1194                 {
1195                     abortOnError(forkPipeOut, InternalError.preExec, .errno);
1196                 }
1197             }
1198 
1199             if (config.preExecDelegate !is null)
1200             {
1201                 if (config.preExecDelegate() != true)
1202                 {
1203                     abortOnError(forkPipeOut, InternalError.preExec, .errno);
1204                 }
1205             }
1206 
1207             // Execute program.
1208             core.sys.posix.unistd.execve(argz[0], argz.ptr, envz is null ? getEnvironPtr : envz);
1209 
1210             // If execution fails, exit as quickly as possible.
1211             abortOnError(forkPipeOut, InternalError.exec, .errno);
1212         }
1213 
1214         if (config.flags & Config.Flags.detached)
1215         {
1216             auto secondFork = core.sys.posix.unistd.fork();
1217             if (secondFork == 0)
1218             {
1219                 close(pidPipeOut);
1220                 execProcess();
1221             }
1222             else if (secondFork == -1)
1223             {
1224                 auto secondForkErrno = .errno;
1225                 close(pidPipeOut);
1226                 abortOnError(forkPipeOut, InternalError.doubleFork, secondForkErrno);
1227             }
1228             else
1229             {
1230                 core.sys.posix.unistd.write(pidPipeOut, &secondFork, pid_t.sizeof);
1231                 close(pidPipeOut);
1232                 close(forkPipeOut);
1233                 _exit(0);
1234             }
1235         }
1236         else
1237         {
1238             execProcess();
1239         }
1240     }
1241 
1242     if (id == 0)
1243     {
1244         forkChild();
1245         assert(0);
1246     }
1247     else
1248     {
1249         closePipeWriteEnds();
1250 
1251         T retryInterrupted(T)(scope T delegate() syscall)
1252         {
1253             import core.stdc.errno : errno, EINTR;
1254             T result;
1255             do
1256                 result = syscall();
1257             while (result == -1 && .errno == EINTR);
1258             return result;
1259         }
1260 
1261         auto status = InternalError.noerror;
1262         auto readExecResult = retryInterrupted(() => core.sys.posix.unistd.read(forkPipe[0], &status, status.sizeof));
1263         // Save error number just in case if subsequent "waitpid" fails and overrides errno
1264         immutable lastError = .errno;
1265 
1266         if (config.flags & Config.Flags.detached)
1267         {
1268             // Forked child exits right after creating second fork. So it should be safe to wait here.
1269             import core.sys.posix.sys.wait : waitpid;
1270             int waitResult;
1271             retryInterrupted(() => waitpid(id, &waitResult, 0));
1272         }
1273 
1274         if (readExecResult == -1)
1275             throw ProcessException.newFromErrno(lastError, "Could not read from pipe to get child status");
1276 
1277         bool owned = true;
1278         if (status != InternalError.noerror)
1279         {
1280             int error;
1281             readExecResult = retryInterrupted(() => read(forkPipe[0], &error, error.sizeof));
1282             string errorMsg;
1283             final switch (status)
1284             {
1285                 case InternalError.chdir:
1286                     errorMsg = "Failed to set working directory";
1287                     break;
1288                 case InternalError.getrlimit:
1289                     errorMsg = "getrlimit failed";
1290                     break;
1291                 case InternalError.exec:
1292                     errorMsg = "Failed to execute '" ~ cast(string) name ~ "'";
1293                     break;
1294                 case InternalError.doubleFork:
1295                     // Can happen only when starting detached process
1296                     assert(config.flags & Config.Flags.detached);
1297                     errorMsg = "Failed to fork twice";
1298                     break;
1299                 case InternalError.malloc:
1300                     errorMsg = "Failed to allocate memory";
1301                     break;
1302                 case InternalError.preExec:
1303                     errorMsg = "Failed to execute preExecFunction or preExecDelegate";
1304                     break;
1305                 case InternalError.closefds_dup2:
1306                     assert(!(config.flags & Config.Flags.inheritFDs));
1307                     errorMsg = "Failed to close inherited file descriptors";
1308                     break;
1309                 case InternalError.noerror:
1310                     assert(false);
1311             }
1312             if (readExecResult == error.sizeof)
1313                 throw ProcessException.newFromErrno(error, errorMsg);
1314             throw new ProcessException(errorMsg);
1315         }
1316         else if (config.flags & Config.Flags.detached)
1317         {
1318             owned = false;
1319             if (read(pidPipe[0], &id, id.sizeof) != id.sizeof)
1320                 throw ProcessException.newFromErrno("Could not read from pipe to get detached process id");
1321         }
1322 
1323         // Parent process:  Close streams and return.
1324         if (!(config.flags & Config.Flags.retainStdin ) && stdinFD  > STDERR_FILENO
1325                                             && stdinFD  != getFD(std.stdio.stdin ))
1326             stdin.close();
1327         if (!(config.flags & Config.Flags.retainStdout) && stdoutFD > STDERR_FILENO
1328                                             && stdoutFD != getFD(std.stdio.stdout))
1329             stdout.close();
1330         if (!(config.flags & Config.Flags.retainStderr) && stderrFD > STDERR_FILENO
1331                                             && stderrFD != getFD(std.stdio.stderr))
1332             stderr.close();
1333         return new Pid(id, owned);
1334     }
1335 }
1336 
1337 version (Posix)
1338 @system unittest
1339 {
1340     import std.concurrency : ownerTid, receiveTimeout, send, spawn;
1341     import std.datetime : seconds;
1342 
1343     sigset_t ss;
1344     sigemptyset(&ss);
1345     sigaddset(&ss, SIGINT);
1346     pthread_sigmask(SIG_BLOCK, &ss, null);
1347 
1348     Config config = {
1349         preExecFunction: () @trusted @nogc nothrow {
1350             // Reset signal handlers
1351             sigset_t ss;
1352             if (sigfillset(&ss) != 0)
1353             {
1354                 return false;
1355             }
1356             if (sigprocmask(SIG_UNBLOCK, &ss, null) != 0)
1357             {
1358                 return false;
1359             }
1360             return true;
1361         },
1362     };
1363 
1364     auto pid = spawnProcess(["sleep", "10000"],
1365                             std.stdio.stdin,
1366                             std.stdio.stdout,
1367                             std.stdio.stderr,
1368                             null,
1369                             config,
1370                             null);
1371     scope(failure)
1372     {
1373         kill(pid, SIGKILL);
1374         wait(pid);
1375     }
1376 
1377     // kill the spawned process with SIGINT
1378     // and send its return code
1379     spawn((shared Pid pid) {
1380         auto p = cast() pid;
1381         kill(p, SIGINT);
1382         auto code = wait(p);
1383         assert(code < 0);
1384         send(ownerTid, code);
1385     }, cast(shared) pid);
1386 
1387     auto received = receiveTimeout(3.seconds, (int) {});
1388     assert(received);
1389 }
1390 
1391 version (Posix)
1392 @system unittest
1393 {
1394     __gshared int j;
1395     foreach (i; 0 .. 3)
1396     {
1397         auto config = Config(
1398             preExecFunction: function() @trusted {
1399                 j = 1;
1400                 return true;
1401             },
1402             preExecDelegate: delegate() @trusted {
1403                 // j should now be 1, as preExecFunction is called before
1404                 // preExecDelegate is.
1405                 _Exit(i + j);
1406                 return true;
1407             },
1408         );
1409         auto pid = spawnProcess(["false"], config: config);
1410         assert(wait(pid) == i + 1);
1411     }
1412 }
1413 
1414 /*
1415 Implementation of spawnProcess() for Windows.
1416 
1417 commandLine must contain the entire command line, properly
1418 quoted/escaped as required by CreateProcessW().
1419 
1420 envz must be a pointer to a block of UTF-16 characters on the form
1421 "var1=value1\0var2=value2\0...varN=valueN\0\0".
1422 */
1423 version (Windows)
1424 private Pid spawnProcessWin(scope const(char)[] commandLine,
1425                             scope const(char)[] program,
1426                             File stdin,
1427                             File stdout,
1428                             File stderr,
1429                             scope const string[string] env,
1430                             Config config,
1431                             scope const(char)[] workDir)
1432     @trusted
1433 {
1434     import core.exception : RangeError;
1435     import std.conv : text;
1436 
1437     if (commandLine.empty) throw new RangeError("Command line is empty");
1438 
1439     // Prepare environment.
1440     auto envz = createEnv(env, !(config.flags & Config.Flags.newEnv));
1441 
1442     // Startup info for CreateProcessW().
1443     STARTUPINFO_W startinfo;
1444     startinfo.cb = startinfo.sizeof;
1445     static int getFD(ref File f) { return f.isOpen ? f.fileno : -1; }
1446 
1447     // Extract file descriptors and HANDLEs from the streams and make the
1448     // handles inheritable.
1449     static void prepareStream(ref File file, DWORD stdHandle, string which,
1450                               out int fileDescriptor, out HANDLE handle)
1451     {
1452         enum _NO_CONSOLE_FILENO = cast(HANDLE)-2;
1453         fileDescriptor = getFD(file);
1454         handle = null;
1455         if (fileDescriptor >= 0)
1456             handle = file.windowsHandle;
1457         // Windows GUI applications have a fd but not a valid Windows HANDLE.
1458         if (handle is null || handle == INVALID_HANDLE_VALUE || handle == _NO_CONSOLE_FILENO)
1459             handle = GetStdHandle(stdHandle);
1460 
1461         DWORD dwFlags;
1462         if (GetHandleInformation(handle, &dwFlags))
1463         {
1464             if (!(dwFlags & HANDLE_FLAG_INHERIT))
1465             {
1466                 if (!SetHandleInformation(handle,
1467                                           HANDLE_FLAG_INHERIT,
1468                                           HANDLE_FLAG_INHERIT))
1469                 {
1470                     throw new StdioException(
1471                         "Failed to make "~which~" stream inheritable by child process ("
1472                         ~generateSysErrorMsg() ~ ')',
1473                         0);
1474                 }
1475             }
1476         }
1477     }
1478     int stdinFD = -1, stdoutFD = -1, stderrFD = -1;
1479     prepareStream(stdin,  STD_INPUT_HANDLE,  "stdin" , stdinFD,  startinfo.hStdInput );
1480     prepareStream(stdout, STD_OUTPUT_HANDLE, "stdout", stdoutFD, startinfo.hStdOutput);
1481     prepareStream(stderr, STD_ERROR_HANDLE,  "stderr", stderrFD, startinfo.hStdError );
1482 
1483     if ((startinfo.hStdInput  != null && startinfo.hStdInput  != INVALID_HANDLE_VALUE)
1484      || (startinfo.hStdOutput != null && startinfo.hStdOutput != INVALID_HANDLE_VALUE)
1485      || (startinfo.hStdError  != null && startinfo.hStdError  != INVALID_HANDLE_VALUE))
1486         startinfo.dwFlags = STARTF_USESTDHANDLES;
1487 
1488     // Create process.
1489     PROCESS_INFORMATION pi;
1490     DWORD dwCreationFlags =
1491         CREATE_UNICODE_ENVIRONMENT |
1492         ((config.flags & Config.Flags.suppressConsole) ? CREATE_NO_WINDOW : 0);
1493     // workaround until https://issues.dlang.org/show_bug.cgi?id=14696 is fixed
1494     auto pworkDir = workDir.tempCStringW();
1495     if (!CreateProcessW(null, commandLine.tempCStringW().buffPtr,
1496                         null, null, true, dwCreationFlags,
1497                         envz, workDir.length ? pworkDir : null, &startinfo, &pi))
1498         throw ProcessException.newFromLastError("Failed to spawn process \"" ~ cast(string) program ~ '"');
1499 
1500     // figure out if we should close any of the streams
1501     if (!(config.flags & Config.Flags.retainStdin ) && stdinFD  > STDERR_FILENO
1502                                         && stdinFD  != getFD(std.stdio.stdin ))
1503         stdin.close();
1504     if (!(config.flags & Config.Flags.retainStdout) && stdoutFD > STDERR_FILENO
1505                                         && stdoutFD != getFD(std.stdio.stdout))
1506         stdout.close();
1507     if (!(config.flags & Config.Flags.retainStderr) && stderrFD > STDERR_FILENO
1508                                         && stderrFD != getFD(std.stdio.stderr))
1509         stderr.close();
1510 
1511     // close the thread handle in the process info structure
1512     CloseHandle(pi.hThread);
1513     if (config.flags & Config.Flags.detached)
1514     {
1515         CloseHandle(pi.hProcess);
1516         return new Pid(pi.dwProcessId);
1517     }
1518     return new Pid(pi.dwProcessId, pi.hProcess);
1519 }
1520 
1521 // Converts childEnv to a zero-terminated array of zero-terminated strings
1522 // on the form "name=value", optionally adding those of the current process'
1523 // environment strings that are not present in childEnv.  If the parent's
1524 // environment should be inherited without modification, this function
1525 // returns null.
1526 version (Posix)
1527 private const(char*)* createEnv(const string[string] childEnv,
1528                                 bool mergeWithParentEnv)
1529 {
1530     // Determine the number of strings in the parent's environment.
1531     int parentEnvLength = 0;
1532     auto environ = getEnvironPtr;
1533     if (mergeWithParentEnv)
1534     {
1535         if (childEnv.length == 0) return null;
1536         while (environ[parentEnvLength] != null) ++parentEnvLength;
1537     }
1538 
1539     // Convert the "new" variables to C-style strings.
1540     auto envz = new const(char)*[parentEnvLength + childEnv.length + 1];
1541     int pos = 0;
1542     foreach (var, val; childEnv)
1543         envz[pos++] = (var~'='~val~'\0').ptr;
1544 
1545     // Add the parent's environment.
1546     foreach (environStr; environ[0 .. parentEnvLength])
1547     {
1548         int eqPos = 0;
1549         while (environStr[eqPos] != '=' && environStr[eqPos] != '\0') ++eqPos;
1550         if (environStr[eqPos] != '=') continue;
1551         auto var = environStr[0 .. eqPos];
1552         if (var in childEnv) continue;
1553         envz[pos++] = environStr;
1554     }
1555     envz[pos] = null;
1556     return envz.ptr;
1557 }
1558 
1559 version (Posix) @system unittest
1560 {
1561     auto e1 = createEnv(null, false);
1562     assert(e1 != null && *e1 == null);
1563 
1564     auto e2 = createEnv(null, true);
1565     assert(e2 == null);
1566 
1567     auto e3 = createEnv(["foo" : "bar", "hello" : "world"], false);
1568     assert(e3 != null && e3[0] != null && e3[1] != null && e3[2] == null);
1569     assert((e3[0][0 .. 8] == "foo=bar\0" && e3[1][0 .. 12] == "hello=world\0")
1570          || (e3[0][0 .. 12] == "hello=world\0" && e3[1][0 .. 8] == "foo=bar\0"));
1571 }
1572 
1573 
1574 // Converts childEnv to a Windows environment block, which is on the form
1575 // "name1=value1\0name2=value2\0...nameN=valueN\0\0", optionally adding
1576 // those of the current process' environment strings that are not present
1577 // in childEnv.  Returns null if the parent's environment should be
1578 // inherited without modification, as this is what is expected by
1579 // CreateProcess().
1580 version (Windows)
1581 private LPVOID createEnv(const string[string] childEnv,
1582                          bool mergeWithParentEnv)
1583 {
1584     if (mergeWithParentEnv && childEnv.length == 0) return null;
1585     import std.array : appender;
1586     import std.uni : toUpper;
1587     auto envz = appender!(wchar[])();
1588     void put(string var, string val)
1589     {
1590         envz.put(var);
1591         envz.put('=');
1592         envz.put(val);
1593         envz.put(cast(wchar) '\0');
1594     }
1595 
1596     // Add the variables in childEnv, removing them from parentEnv
1597     // if they exist there too.
1598     auto parentEnv = mergeWithParentEnv ? environment.toAA() : null;
1599     foreach (k, v; childEnv)
1600     {
1601         auto uk = toUpper(k);
1602         put(uk, v);
1603         if (uk in parentEnv) parentEnv.remove(uk);
1604     }
1605 
1606     // Add remaining parent environment variables.
1607     foreach (k, v; parentEnv) put(k, v);
1608 
1609     // Two final zeros are needed in case there aren't any environment vars,
1610     // and the last one does no harm when there are.
1611     envz.put("\0\0"w);
1612     return envz.data.ptr;
1613 }
1614 
1615 version (Windows) @system unittest
1616 {
1617     assert(createEnv(null, true) == null);
1618     assert((cast(wchar*) createEnv(null, false))[0 .. 2] == "\0\0"w);
1619     auto e1 = (cast(wchar*) createEnv(["foo":"bar", "ab":"c"], false))[0 .. 14];
1620     assert(e1 == "FOO=bar\0AB=c\0\0"w || e1 == "AB=c\0FOO=bar\0\0"w);
1621 }
1622 
1623 // Searches the PATH variable for the given executable file,
1624 // (checking that it is in fact executable).
1625 version (Posix)
1626 package(std) string searchPathFor(scope const(char)[] executable)
1627     @safe
1628 {
1629     import std.algorithm.iteration : splitter;
1630     import std.conv : to;
1631     import std.path : chainPath;
1632 
1633     typeof(return) result;
1634 
1635     environment.getImpl("PATH",
1636         (scope const(char)[] path)
1637         {
1638             if (!path)
1639                 return;
1640 
1641             foreach (dir; splitter(path, ":"))
1642             {
1643                 auto execPath = chainPath(dir, executable);
1644                 if (isExecutable(execPath))
1645                 {
1646                     result = execPath.to!(typeof(result));
1647                     return;
1648                 }
1649             }
1650         });
1651 
1652     return result;
1653 }
1654 
1655 // Checks whether the file exists and can be executed by the
1656 // current user.
1657 version (Posix)
1658 private bool isExecutable(R)(R path) @trusted nothrow @nogc
1659 if (isSomeFiniteCharInputRange!R)
1660 {
1661     return (access(path.tempCString(), X_OK) == 0);
1662 }
1663 
1664 version (Posix) @safe unittest
1665 {
1666     import std.algorithm;
1667     auto lsPath = searchPathFor("ls");
1668     assert(!lsPath.empty);
1669     assert(lsPath[0] == '/');
1670     assert(lsPath.endsWith("ls"));
1671     auto unlikely = searchPathFor("lkmqwpoialhggyaofijadsohufoiqezm");
1672     assert(unlikely is null, "Are you kidding me?");
1673 }
1674 
1675 // Sets or unsets the FD_CLOEXEC flag on the given file descriptor.
1676 version (Posix)
1677 private void setCLOEXEC(int fd, bool on) nothrow @nogc
1678 {
1679     import core.sys.posix.fcntl : fcntl, F_GETFD, FD_CLOEXEC, F_SETFD;
1680     auto flags = fcntl(fd, F_GETFD);
1681     if (flags >= 0)
1682     {
1683         if (on) flags |= FD_CLOEXEC;
1684         else    flags &= ~(cast(typeof(flags)) FD_CLOEXEC);
1685         flags = fcntl(fd, F_SETFD, flags);
1686     }
1687     assert(flags != -1 || .errno == EBADF);
1688 }
1689 
1690 @system unittest // Command line arguments in spawnProcess().
1691 {
1692     version (Windows) TestScript prog =
1693        "if not [%~1]==[foo] ( exit 1 )
1694         if not [%~2]==[bar] ( exit 2 )
1695         exit 0";
1696     else version (Posix) TestScript prog =
1697        `if test "$1" != "foo"; then exit 1; fi
1698         if test "$2" != "bar"; then exit 2; fi
1699         exit 0`;
1700     assert(wait(spawnProcess(prog.path)) == 1);
1701     assert(wait(spawnProcess([prog.path])) == 1);
1702     assert(wait(spawnProcess([prog.path, "foo"])) == 2);
1703     assert(wait(spawnProcess([prog.path, "foo", "baz"])) == 2);
1704     assert(wait(spawnProcess([prog.path, "foo", "bar"])) == 0);
1705 }
1706 
1707 // test that file descriptors are correctly closed / left open.
1708 // ideally this would be done by the child process making libc
1709 // calls, but we make do...
1710 version (Posix) @system unittest
1711 {
1712     import core.stdc.errno : errno;
1713     import core.sys.posix.fcntl : open, O_RDONLY;
1714     import core.sys.posix.unistd : close;
1715     import std.algorithm.searching : canFind, findSplitBefore;
1716     import std.array : split;
1717     import std.conv : to;
1718     static import std.file;
1719     import std.functional : reverseArgs;
1720     import std.path : buildPath;
1721 
1722     auto directory = uniqueTempPath();
1723     std.file.mkdir(directory);
1724     scope(exit) std.file.rmdirRecurse(directory);
1725     auto path = buildPath(directory, "tmp");
1726     std.file.write(path, null);
1727     errno = 0;
1728     auto fd = open(path.tempCString, O_RDONLY);
1729     if (fd == -1)
1730     {
1731         import core.stdc.string : strerror;
1732         import std.stdio : stderr;
1733         import std.string : fromStringz;
1734 
1735         // For the CI logs
1736         stderr.writefln("%s: could not open '%s': %s",
1737             __FUNCTION__, path, strerror(errno).fromStringz);
1738         // TODO: should we retry here instead?
1739         return;
1740     }
1741     scope(exit) close(fd);
1742 
1743     // command >&2 (or any other number) checks whethether that number
1744     // file descriptor is open.
1745     // Can't use this for arbitrary descriptors as many shells only support
1746     // single digit fds.
1747     TestScript testDefaults = `command >&0 && command >&1 && command >&2`;
1748     assert(execute(testDefaults.path).status == 0);
1749     assert(execute(testDefaults.path, null, Config.inheritFDs).status == 0);
1750 
1751     // Try a few different methods to check whether there are any
1752     // incorrectly-open files.
1753     void testFDs()
1754     {
1755         // try /proc/<pid>/fd/ on linux
1756         version (linux)
1757         {
1758             TestScript proc = "ls /proc/$$/fd";
1759             auto procRes = execute(proc.path, null);
1760             if (procRes.status == 0)
1761             {
1762                 auto fdStr = fd.to!string;
1763                 assert(!procRes.output.split.canFind(fdStr));
1764                 assert(execute(proc.path, null, Config.inheritFDs)
1765                         .output.split.canFind(fdStr));
1766                 return;
1767             }
1768         }
1769 
1770         // try fuser (might sometimes need permissions)
1771         TestScript fuser = "echo $$ && fuser -f " ~ path;
1772         auto fuserRes = execute(fuser.path, null);
1773         if (fuserRes.status == 0)
1774         {
1775             assert(!reverseArgs!canFind(fuserRes
1776                         .output.findSplitBefore("\n").expand));
1777             assert(reverseArgs!canFind(execute(fuser.path, null, Config.inheritFDs)
1778                         .output.findSplitBefore("\n").expand));
1779             return;
1780         }
1781 
1782         // last resort, try lsof (not available on all Posix)
1783         TestScript lsof = "lsof -p$$";
1784         auto lsofRes = execute(lsof.path, null);
1785         if (lsofRes.status == 0)
1786         {
1787             assert(!lsofRes.output.canFind(path));
1788             auto lsofOut = execute(lsof.path, null, Config.inheritFDs).output;
1789             if (!lsofOut.canFind(path))
1790             {
1791                 std.stdio.stderr.writeln(__FILE__, ':', __LINE__,
1792                     ": Warning: unexpected lsof output:", lsofOut);
1793             }
1794             return;
1795         }
1796 
1797         std.stdio.stderr.writeln(__FILE__, ':', __LINE__,
1798                 ": Warning: Couldn't find any way to check open files");
1799     }
1800     testFDs();
1801 }
1802 
1803 @system unittest // Environment variables in spawnProcess().
1804 {
1805     // We really should use set /a on Windows, but Wine doesn't support it.
1806     version (Windows) TestScript envProg =
1807        `if [%STD_PROCESS_UNITTEST1%] == [1] (
1808             if [%STD_PROCESS_UNITTEST2%] == [2] (exit 3)
1809             exit 1
1810         )
1811         if [%STD_PROCESS_UNITTEST1%] == [4] (
1812             if [%STD_PROCESS_UNITTEST2%] == [2] (exit 6)
1813             exit 4
1814         )
1815         if [%STD_PROCESS_UNITTEST2%] == [2] (exit 2)
1816         exit 0`;
1817     version (Posix) TestScript envProg =
1818        `if test "$std_process_unittest1" = ""; then
1819             std_process_unittest1=0
1820         fi
1821         if test "$std_process_unittest2" = ""; then
1822             std_process_unittest2=0
1823         fi
1824         exit $(($std_process_unittest1+$std_process_unittest2))`;
1825 
1826     environment.remove("std_process_unittest1"); // Just in case.
1827     environment.remove("std_process_unittest2");
1828     assert(wait(spawnProcess(envProg.path)) == 0);
1829     assert(wait(spawnProcess(envProg.path, null, Config.newEnv)) == 0);
1830 
1831     environment["std_process_unittest1"] = "1";
1832     assert(wait(spawnProcess(envProg.path)) == 1);
1833     assert(wait(spawnProcess(envProg.path, null, Config.newEnv)) == 0);
1834 
1835     auto env = ["std_process_unittest2" : "2"];
1836     assert(wait(spawnProcess(envProg.path, env)) == 3);
1837     assert(wait(spawnProcess(envProg.path, env, Config.newEnv)) == 2);
1838 
1839     env["std_process_unittest1"] = "4";
1840     assert(wait(spawnProcess(envProg.path, env)) == 6);
1841     assert(wait(spawnProcess(envProg.path, env, Config.newEnv)) == 6);
1842 
1843     environment.remove("std_process_unittest1");
1844     assert(wait(spawnProcess(envProg.path, env)) == 6);
1845     assert(wait(spawnProcess(envProg.path, env, Config.newEnv)) == 6);
1846 }
1847 
1848 @system unittest // Stream redirection in spawnProcess().
1849 {
1850     import std.path : buildPath;
1851     import std.string;
1852     version (Windows) TestScript prog =
1853        "set /p INPUT=
1854         echo %INPUT% output %~1
1855         echo %INPUT% error %~2 1>&2
1856         echo done > %3";
1857     else version (Posix) TestScript prog =
1858        "read INPUT
1859         echo $INPUT output $1
1860         echo $INPUT error $2 >&2
1861         echo done > \"$3\"";
1862 
1863     // Pipes
1864     void testPipes(Config config)
1865     {
1866         import std.file : tempDir, exists, remove;
1867         import std.uuid : randomUUID;
1868         import std.exception : collectException;
1869         auto pipei = pipe();
1870         auto pipeo = pipe();
1871         auto pipee = pipe();
1872         auto done = buildPath(tempDir(), randomUUID().toString());
1873         auto pid = spawnProcess([prog.path, "foo", "bar", done],
1874                                     pipei.readEnd, pipeo.writeEnd, pipee.writeEnd, null, config);
1875         pipei.writeEnd.writeln("input");
1876         pipei.writeEnd.flush();
1877         assert(pipeo.readEnd.readln().chomp() == "input output foo");
1878         assert(pipee.readEnd.readln().chomp().stripRight() == "input error bar");
1879         if (config.flags & Config.Flags.detached)
1880             while (!done.exists) Thread.sleep(10.msecs);
1881         else
1882             wait(pid);
1883         while (remove(done).collectException) Thread.sleep(10.msecs);
1884     }
1885 
1886     // Files
1887     void testFiles(Config config)
1888     {
1889         import std.ascii : newline;
1890         import std.file : tempDir, exists, remove, readText, write;
1891         import std.uuid : randomUUID;
1892         import std.exception : collectException;
1893         auto pathi = buildPath(tempDir(), randomUUID().toString());
1894         auto patho = buildPath(tempDir(), randomUUID().toString());
1895         auto pathe = buildPath(tempDir(), randomUUID().toString());
1896         write(pathi, "INPUT" ~ newline);
1897         auto filei = File(pathi, "r");
1898         auto fileo = File(patho, "w");
1899         auto filee = File(pathe, "w");
1900         auto done = buildPath(tempDir(), randomUUID().toString());
1901         auto pid = spawnProcess([prog.path, "bar", "baz", done], filei, fileo, filee, null, config);
1902         if (config.flags & Config.Flags.detached)
1903             while (!done.exists) Thread.sleep(10.msecs);
1904         else
1905             wait(pid);
1906         assert(readText(patho).chomp() == "INPUT output bar");
1907         assert(readText(pathe).chomp().stripRight() == "INPUT error baz");
1908         while (remove(pathi).collectException) Thread.sleep(10.msecs);
1909         while (remove(patho).collectException) Thread.sleep(10.msecs);
1910         while (remove(pathe).collectException) Thread.sleep(10.msecs);
1911         while (remove(done).collectException) Thread.sleep(10.msecs);
1912     }
1913 
1914     testPipes(Config.none);
1915     testFiles(Config.none);
1916     testPipes(Config.detached);
1917     testFiles(Config.detached);
1918 }
1919 
1920 @system unittest // Error handling in spawnProcess()
1921 {
1922     import std.algorithm.searching : canFind;
1923     import std.exception : assertThrown, collectExceptionMsg;
1924 
1925     static void testNotFoundException(string program)
1926     {
1927         assert(collectExceptionMsg!ProcessException(spawnProcess(program)).canFind(program));
1928         assert(collectExceptionMsg!ProcessException(spawnProcess(program, null, Config.detached)).canFind(program));
1929     }
1930     testNotFoundException("ewrgiuhrifuheiohnmnvqweoijwf");
1931     testNotFoundException("./rgiuhrifuheiohnmnvqweoijwf");
1932 
1933     // can't execute malformed file with executable permissions
1934     version (Posix)
1935     {
1936         import std.path : buildPath;
1937         import std.file : remove, write, setAttributes, tempDir;
1938         import core.sys.posix.sys.stat : S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IXGRP, S_IROTH, S_IXOTH;
1939         import std.conv : to;
1940         string deleteme = buildPath(tempDir(), "deleteme.std.process.unittest.pid") ~ to!string(thisProcessID);
1941         write(deleteme, "");
1942         scope(exit) remove(deleteme);
1943         setAttributes(deleteme, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
1944         assertThrown!ProcessException(spawnProcess(deleteme));
1945         assertThrown!ProcessException(spawnProcess(deleteme, null, Config.detached));
1946     }
1947 }
1948 
1949 @system unittest // Specifying a working directory.
1950 {
1951     import std.path;
1952     import std.file;
1953     TestScript prog = "echo foo>bar";
1954 
1955     auto directory = uniqueTempPath();
1956     mkdir(directory);
1957     scope(exit) rmdirRecurse(directory);
1958 
1959     auto pid = spawnProcess([prog.path], null, Config.none, directory);
1960     wait(pid);
1961     assert(exists(buildPath(directory, "bar")));
1962 }
1963 
1964 @system unittest // Specifying a bad working directory.
1965 {
1966     import std.exception : assertThrown;
1967     import std.file;
1968     TestScript prog = "echo";
1969 
1970     auto directory = uniqueTempPath();
1971     assertThrown!ProcessException(spawnProcess([prog.path], null, Config.none, directory));
1972     assertThrown!ProcessException(spawnProcess([prog.path], null, Config.detached, directory));
1973 
1974     std.file.write(directory, "foo");
1975     scope(exit) remove(directory);
1976     assertThrown!ProcessException(spawnProcess([prog.path], null, Config.none, directory));
1977     assertThrown!ProcessException(spawnProcess([prog.path], null, Config.detached, directory));
1978 
1979     // can't run in directory if user does not have search permission on this directory
1980     version (Posix)
1981     {
1982         if (core.sys.posix.unistd.getuid() != 0)
1983         {
1984             import core.sys.posix.sys.stat : S_IRUSR;
1985             auto directoryNoSearch = uniqueTempPath();
1986             mkdir(directoryNoSearch);
1987             scope(exit) rmdirRecurse(directoryNoSearch);
1988             setAttributes(directoryNoSearch, S_IRUSR);
1989             assertThrown!ProcessException(spawnProcess(prog.path, null, Config.none, directoryNoSearch));
1990             assertThrown!ProcessException(spawnProcess(prog.path, null, Config.detached, directoryNoSearch));
1991         }
1992     }
1993 }
1994 
1995 @system unittest // Specifying empty working directory.
1996 {
1997     TestScript prog = "";
1998 
1999     string directory = "";
2000     assert(directory.ptr && !directory.length);
2001     spawnProcess([prog.path], null, Config.none, directory).wait();
2002 }
2003 
2004 // Reopening the standard streams (https://issues.dlang.org/show_bug.cgi?id=13258)
2005 @system unittest
2006 {
2007     import std.string;
2008     import std.file;
2009     void fun()
2010     {
2011         spawnShell("echo foo").wait();
2012         spawnShell("echo bar").wait();
2013     }
2014 
2015     auto tmpFile = uniqueTempPath();
2016     scope(exit) if (exists(tmpFile)) remove(tmpFile);
2017 
2018     {
2019         auto oldOut = std.stdio.stdout;
2020         scope(exit) std.stdio.stdout = oldOut;
2021 
2022         std.stdio.stdout = File(tmpFile, "w");
2023         fun();
2024         std.stdio.stdout.close();
2025     }
2026 
2027     auto lines = readText(tmpFile).splitLines();
2028     assert(lines == ["foo", "bar"]);
2029 }
2030 
2031 // MSVCRT workaround (https://issues.dlang.org/show_bug.cgi?id=14422)
2032 version (Windows)
2033 @system unittest
2034 {
2035     auto fn = uniqueTempPath();
2036     scope(exit) if (exists(fn)) remove(fn);
2037     std.file.write(fn, "AAAAAAAAAA");
2038 
2039     auto f = File(fn, "a");
2040     spawnProcess(["cmd", "/c", "echo BBBBB"], std.stdio.stdin, f).wait();
2041 
2042     auto data = readText(fn);
2043     assert(data == "AAAAAAAAAABBBBB\r\n", data);
2044 }
2045 
2046 // https://issues.dlang.org/show_bug.cgi?id=20765
2047 // Test that running processes with relative path works in conjunction
2048 // with indicating a workDir.
2049 version (Posix) @system unittest
2050 {
2051     import std.file : mkdir, write, setAttributes, rmdirRecurse;
2052     import std.conv : octal;
2053 
2054     auto dir = uniqueTempPath();
2055     mkdir(dir);
2056     scope(exit) rmdirRecurse(dir);
2057     write(dir ~ "/program", "#!/bin/sh\necho Hello");
2058     setAttributes(dir ~ "/program", octal!700);
2059 
2060     assert(execute(["./program"], null, Config.none, size_t.max, dir).output == "Hello\n");
2061 }
2062 
2063 /**
2064 A variation on $(LREF spawnProcess) that runs the given _command through
2065 the current user's preferred _command interpreter (aka. shell).
2066 
2067 The string `command` is passed verbatim to the shell, and is therefore
2068 subject to its rules about _command structure, argument/filename quoting
2069 and escaping of special characters.
2070 The path to the shell executable defaults to $(LREF nativeShell).
2071 
2072 In all other respects this function works just like `spawnProcess`.
2073 Please refer to the $(LREF spawnProcess) documentation for descriptions
2074 of the other function parameters, the return value and any exceptions
2075 that may be thrown.
2076 ---
2077 // Run the command/program "foo" on the file named "my file.txt", and
2078 // redirect its output into foo.log.
2079 auto pid = spawnShell(`foo "my file.txt" > foo.log`);
2080 wait(pid);
2081 ---
2082 
2083 See_also:
2084 $(LREF escapeShellCommand), which may be helpful in constructing a
2085 properly quoted and escaped shell _command line for the current platform.
2086 */
2087 Pid spawnShell(scope const(char)[] command,
2088                File stdin = std.stdio.stdin,
2089                File stdout = std.stdio.stdout,
2090                File stderr = std.stdio.stderr,
2091                scope const string[string] env = null,
2092                Config config = Config.none,
2093                scope const(char)[] workDir = null,
2094                scope string shellPath = nativeShell)
2095     @trusted // See reason below
2096 {
2097     version (Windows)
2098     {
2099         // CMD does not parse its arguments like other programs.
2100         // It does not use CommandLineToArgvW.
2101         // Instead, it treats the first and last quote specially.
2102         // See CMD.EXE /? for details.
2103         const commandLine = escapeShellFileName(shellPath)
2104                             ~ ` ` ~ shellSwitch ~ ` "` ~ command ~ `"`;
2105         return spawnProcessWin(commandLine, shellPath, stdin, stdout, stderr, env, config, workDir);
2106     }
2107     else version (Posix)
2108     {
2109         const(char)[][3] args;
2110         args[0] = shellPath;
2111         args[1] = shellSwitch;
2112         args[2] = command;
2113         /* The passing of args converts the static array, which is initialized with `scope` pointers,
2114          * to a dynamic array, which is also a scope parameter. So, it is a scope pointer to a
2115          * scope pointer, which although is safely used here, D doesn't allow transitive scope.
2116          * See https://github.com/dlang/dmd/pull/10951
2117          */
2118         return spawnProcessPosix(args, stdin, stdout, stderr, env, config, workDir);
2119     }
2120     else
2121         static assert(0);
2122 }
2123 
2124 /// ditto
2125 Pid spawnShell(scope const(char)[] command,
2126                scope const string[string] env,
2127                Config config = Config.none,
2128                scope const(char)[] workDir = null,
2129                scope string shellPath = nativeShell)
2130     @trusted // TODO: Should be @safe
2131 {
2132     return spawnShell(command,
2133                       std.stdio.stdin,
2134                       std.stdio.stdout,
2135                       std.stdio.stderr,
2136                       env,
2137                       config,
2138                       workDir,
2139                       shellPath);
2140 }
2141 
2142 @system unittest
2143 {
2144     version (Windows)
2145         auto cmd = "echo %FOO%";
2146     else version (Posix)
2147         auto cmd = "echo $foo";
2148     import std.file;
2149     auto tmpFile = uniqueTempPath();
2150     scope(exit) if (exists(tmpFile)) remove(tmpFile);
2151     auto redir = "> \""~tmpFile~'"';
2152     auto env = ["foo" : "bar"];
2153     assert(wait(spawnShell(cmd~redir, env)) == 0);
2154     auto f = File(tmpFile, "a");
2155     version (CRuntime_Microsoft) f.seek(0, SEEK_END); // MSVCRT probably seeks to the end when writing, not before
2156     assert(wait(spawnShell(cmd, std.stdio.stdin, f, std.stdio.stderr, env)) == 0);
2157     f.close();
2158     auto output = std.file.readText(tmpFile);
2159     assert(output == "bar\nbar\n" || output == "bar\r\nbar\r\n");
2160 }
2161 
2162 version (Windows)
2163 @system unittest
2164 {
2165     import std.string;
2166     import std.conv : text;
2167     TestScript prog = "echo %0 %*";
2168     auto outputFn = uniqueTempPath();
2169     scope(exit) if (exists(outputFn)) remove(outputFn);
2170     auto args = [`a b c`, `a\b\c\`, `a"b"c"`];
2171     auto result = executeShell(
2172         escapeShellCommand([prog.path] ~ args)
2173         ~ " > " ~
2174         escapeShellFileName(outputFn));
2175     assert(result.status == 0);
2176     auto args2 = outputFn.readText().strip().parseCommandLine()[1..$];
2177     assert(args == args2, text(args2));
2178 }
2179 
2180 
2181 /**
2182 Options that control the behaviour of process creation functions in this
2183 module. Most options only apply to $(LREF spawnProcess) and
2184 $(LREF spawnShell).
2185 
2186 Example:
2187 ---
2188 auto logFile = File("myapp_error.log", "w");
2189 
2190 // Start program, suppressing the console window (Windows only),
2191 // redirect its error stream to logFile, and leave logFile open
2192 // in the parent process as well.
2193 auto pid = spawnProcess("myapp", stdin, stdout, logFile,
2194                         Config.retainStderr | Config.suppressConsole);
2195 scope(exit)
2196 {
2197     auto exitCode = wait(pid);
2198     logFile.writeln("myapp exited with code ", exitCode);
2199     logFile.close();
2200 }
2201 ---
2202 */
2203 struct Config
2204 {
2205     /**
2206        Flag options.
2207        Use bitwise OR to combine flags.
2208     **/
2209     enum Flags
2210     {
2211         none = 0,
2212 
2213         /**
2214         By default, the child process inherits the parent's environment,
2215         and any environment variables passed to $(LREF spawnProcess) will
2216         be added to it.  If this flag is set, the only variables in the
2217         child process' environment will be those given to spawnProcess.
2218         */
2219         newEnv = 1,
2220 
2221         /**
2222         Unless the child process inherits the standard input/output/error
2223         streams of its parent, one almost always wants the streams closed
2224         in the parent when $(LREF spawnProcess) returns.  Therefore, by
2225         default, this is done.  If this is not desirable, pass any of these
2226         options to spawnProcess.
2227         */
2228         retainStdin  = 2,
2229         retainStdout = 4,                                  /// ditto
2230         retainStderr = 8,                                  /// ditto
2231 
2232         /**
2233         On Windows, if the child process is a console application, this
2234         flag will prevent the creation of a console window.  Otherwise,
2235         it will be ignored. On POSIX, `suppressConsole` has no effect.
2236         */
2237         suppressConsole = 16,
2238 
2239         /**
2240         On POSIX, open $(LINK2 http://en.wikipedia.org/wiki/File_descriptor,file descriptors)
2241         are by default inherited by the child process.  As this may lead
2242         to subtle bugs when pipes or multiple threads are involved,
2243         $(LREF spawnProcess) ensures that all file descriptors except the
2244         ones that correspond to standard input/output/error are closed
2245         in the child process when it starts.  Use `inheritFDs` to prevent
2246         this.
2247 
2248         On Windows, this option has no effect, and any handles which have been
2249         explicitly marked as inheritable will always be inherited by the child
2250         process.
2251         */
2252         inheritFDs = 32,
2253 
2254         /**
2255         Spawn process in detached state. This removes the need in calling
2256         $(LREF wait) to clean up the process resources.
2257 
2258         Note:
2259         Calling $(LREF wait) or $(LREF kill) with the resulting `Pid` is invalid.
2260         */
2261         detached = 64,
2262 
2263         /**
2264         By default, the $(LREF execute) and $(LREF executeShell) functions
2265         will capture child processes' both stdout and stderr. This can be
2266         undesirable if the standard output is to be processed or otherwise
2267         used by the invoking program, as `execute`'s result would then
2268         contain a mix of output and warning/error messages.
2269 
2270         Specify this flag when calling `execute` or `executeShell` to
2271         cause invoked processes' stderr stream to be sent to $(REF stderr,
2272         std,stdio), and only capture and return standard output.
2273 
2274         This flag has no effect on $(LREF spawnProcess) or $(LREF spawnShell).
2275         */
2276         stderrPassThrough = 128,
2277     }
2278     Flags flags; /// ditto
2279 
2280     /**
2281        For backwards compatibility, and cases when only flags need to
2282        be specified in the `Config`, these allow building `Config`
2283        instances using flag names only.
2284     */
2285     enum Config none = Config.init;
2286     enum Config newEnv = Config(Flags.newEnv); /// ditto
2287     enum Config retainStdin = Config(Flags.retainStdin); /// ditto
2288     enum Config retainStdout = Config(Flags.retainStdout); /// ditto
2289     enum Config retainStderr = Config(Flags.retainStderr); /// ditto
2290     enum Config suppressConsole = Config(Flags.suppressConsole); /// ditto
2291     enum Config inheritFDs = Config(Flags.inheritFDs); /// ditto
2292     enum Config detached = Config(Flags.detached); /// ditto
2293     enum Config stderrPassThrough = Config(Flags.stderrPassThrough); /// ditto
2294     Config opUnary(string op)()
2295     if (is(typeof(mixin(op ~ q{flags}))))
2296     {
2297         return Config(mixin(op ~ q{flags}));
2298     } /// ditto
2299     Config opBinary(string op)(Config other)
2300     if (is(typeof(mixin(q{flags} ~ op ~ q{other.flags}))))
2301     {
2302         return Config(mixin(q{flags} ~ op ~ q{other.flags}));
2303     } /// ditto
2304     Config opOpAssign(string op)(Config other)
2305     if (is(typeof(mixin(q{flags} ~ op ~ q{=other.flags}))))
2306     {
2307         return Config(mixin(q{flags} ~ op ~ q{=other.flags}));
2308     } /// ditto
2309 
2310     version (StdDdoc)
2311     {
2312         /**
2313         A function that is called before `exec` in $(LREF spawnProcess).
2314         It returns `true` if succeeded and otherwise returns `false`.
2315 
2316         $(RED Warning:
2317             Please note that the code in this function must only use
2318             async-signal-safe functions.)
2319 
2320         If $(LREF preExecDelegate) is also set, it is called last.
2321 
2322         On Windows, this member is not available.
2323         */
2324         bool function() nothrow @nogc @safe preExecFunction;
2325 
2326         /**
2327         A delegate that is called before `exec` in $(LREF spawnProcess).
2328         It returns `true` if succeeded and otherwise returns `false`.
2329 
2330         $(RED Warning:
2331             Please note that the code in this function must only use
2332             async-signal-safe functions.)
2333 
2334         If $(LREF preExecFunction) is also set, it is called first.
2335 
2336         On Windows, this member is not available.
2337         */
2338         bool delegate() nothrow @nogc @safe preExecDelegate;
2339     }
2340     else version (Posix)
2341     {
2342         bool function() nothrow @nogc @safe preExecFunction;
2343         bool delegate() nothrow @nogc @safe preExecDelegate;
2344     }
2345 }
2346 
2347 // https://issues.dlang.org/show_bug.cgi?id=22125
2348 @safe unittest
2349 {
2350     Config c = Config.retainStdin;
2351     c |= Config.retainStdout;
2352     c |= Config.retainStderr;
2353     c &= ~Config.retainStderr;
2354     assert(c == (Config.retainStdin | Config.retainStdout));
2355 }
2356 
2357 /// A handle that corresponds to a spawned process.
2358 final class Pid
2359 {
2360     /**
2361     The process ID number.
2362 
2363     This is a number that uniquely identifies the process on the operating
2364     system, for at least as long as the process is running.  Once $(LREF wait)
2365     has been called on the $(LREF Pid), this method will return an
2366     invalid (negative) process ID.
2367     */
2368     @property int processID() const @safe pure nothrow
2369     {
2370         return _processID;
2371     }
2372 
2373     /**
2374     An operating system handle to the process.
2375 
2376     This handle is used to specify the process in OS-specific APIs.
2377     On POSIX, this function returns a `core.sys.posix.sys.types.pid_t`
2378     with the same value as $(LREF Pid.processID), while on Windows it returns
2379     a `core.sys.windows.windows.HANDLE`.
2380 
2381     Once $(LREF wait) has been called on the $(LREF Pid), this method
2382     will return an invalid handle.
2383     */
2384     // Note: Since HANDLE is a reference, this function cannot be const.
2385     version (Windows)
2386     @property HANDLE osHandle() @nogc @safe pure nothrow
2387     {
2388         return _handle;
2389     }
2390     else version (Posix)
2391     @property pid_t osHandle() @nogc @safe pure nothrow
2392     {
2393         return _processID;
2394     }
2395 
2396 private:
2397     /*
2398     Pid.performWait() does the dirty work for wait() and nonBlockingWait().
2399 
2400     If block == true, this function blocks until the process terminates,
2401     sets _processID to terminated, and returns the exit code or terminating
2402     signal as described in the wait() documentation.
2403 
2404     If block == false, this function returns immediately, regardless
2405     of the status of the process.  If the process has terminated, the
2406     function has the exact same effect as the blocking version.  If not,
2407     it returns 0 and does not modify _processID.
2408     */
2409     version (Posix)
2410     int performWait(bool block) @trusted
2411     {
2412         import std.exception : enforce;
2413         enforce!ProcessException(owned, "Can't wait on a detached process");
2414         if (_processID == terminated) return _exitCode;
2415         int exitCode;
2416         while (true)
2417         {
2418             int status;
2419             auto check = waitpid(_processID, &status, block ? 0 : WNOHANG);
2420             if (check == -1)
2421             {
2422                 if (errno == ECHILD)
2423                 {
2424                     throw new ProcessException(
2425                         "Process does not exist or is not a child process.");
2426                 }
2427                 else
2428                 {
2429                     // waitpid() was interrupted by a signal.  We simply
2430                     // restart it.
2431                     assert(errno == EINTR);
2432                     continue;
2433                 }
2434             }
2435             if (!block && check == 0) return 0;
2436             if (WIFEXITED(status))
2437             {
2438                 exitCode = WEXITSTATUS(status);
2439                 break;
2440             }
2441             else if (WIFSIGNALED(status))
2442             {
2443                 exitCode = -WTERMSIG(status);
2444                 break;
2445             }
2446             // We check again whether the call should be blocking,
2447             // since we don't care about other status changes besides
2448             // "exited" and "terminated by signal".
2449             if (!block) return 0;
2450 
2451             // Process has stopped, but not terminated, so we continue waiting.
2452         }
2453         // Mark Pid as terminated, and cache and return exit code.
2454         _processID = terminated;
2455         _exitCode = exitCode;
2456         return exitCode;
2457     }
2458     else version (Windows)
2459     {
2460         int performWait(const bool block, const DWORD timeout = INFINITE) @trusted
2461         {
2462             import std.exception : enforce;
2463             enforce!ProcessException(owned, "Can't wait on a detached process");
2464             if (_processID == terminated) return _exitCode;
2465             assert(_handle != INVALID_HANDLE_VALUE);
2466             if (block)
2467             {
2468                 auto result = WaitForSingleObject(_handle, timeout);
2469                 if (result != WAIT_OBJECT_0)
2470                 {
2471                     // Wait time exceeded `timeout` milliseconds?
2472                     if (result == WAIT_TIMEOUT && timeout != INFINITE)
2473                         return 0;
2474 
2475                     throw ProcessException.newFromLastError("Wait failed.");
2476                 }
2477             }
2478             if (!GetExitCodeProcess(_handle, cast(LPDWORD)&_exitCode))
2479                 throw ProcessException.newFromLastError();
2480             if (!block && _exitCode == STILL_ACTIVE) return 0;
2481             CloseHandle(_handle);
2482             _handle = INVALID_HANDLE_VALUE;
2483             _processID = terminated;
2484             return _exitCode;
2485         }
2486 
2487         int performWait(Duration timeout) @safe
2488         {
2489             import std.exception : enforce;
2490             const msecs = timeout.total!"msecs";
2491 
2492             // Limit this implementation the maximum wait time offered by
2493             // WaitForSingleObject. One could theoretically break up larger
2494             // durations into multiple waits but (DWORD.max - 1).msecs
2495             // (> 7 weeks, 17 hours) should be enough for the usual case.
2496             // DWORD.max is reserved for INFINITE
2497             enforce!ProcessException(msecs < DWORD.max, "Timeout exceeds maximum wait time!");
2498             return performWait(true, cast(DWORD) msecs);
2499         }
2500 
2501         ~this()
2502         {
2503             if (_handle != INVALID_HANDLE_VALUE)
2504             {
2505                 CloseHandle(_handle);
2506                 _handle = INVALID_HANDLE_VALUE;
2507             }
2508         }
2509     }
2510 
2511     // Special values for _processID.
2512     enum invalid = -1, terminated = -2;
2513 
2514     // OS process ID number.  Only nonnegative IDs correspond to
2515     // running processes.
2516     int _processID = invalid;
2517 
2518     // Exit code cached by wait().  This is only expected to hold a
2519     // sensible value if _processID == terminated.
2520     int _exitCode;
2521 
2522     // Whether the process can be waited for by wait() for or killed by kill().
2523     // False if process was started as detached. True otherwise.
2524     bool owned;
2525 
2526     // Pids are only meant to be constructed inside this module, so
2527     // we make the constructor private.
2528     version (Windows)
2529     {
2530         HANDLE _handle = INVALID_HANDLE_VALUE;
2531         this(int pid, HANDLE handle) @safe pure nothrow
2532         {
2533             _processID = pid;
2534             _handle = handle;
2535             this.owned = true;
2536         }
2537         this(int pid) @safe pure nothrow
2538         {
2539             _processID = pid;
2540             this.owned = false;
2541         }
2542     }
2543     else
2544     {
2545         this(int id, bool owned) @safe pure nothrow
2546         {
2547             _processID = id;
2548             this.owned = owned;
2549         }
2550     }
2551 }
2552 
2553 
2554 /**
2555 Waits for the process associated with `pid` to terminate, and returns
2556 its exit status.
2557 
2558 In general one should always _wait for child processes to terminate
2559 before exiting the parent process unless the process was spawned as detached
2560 (that was spawned with `Config.detached` flag).
2561 Otherwise, they may become "$(HTTP en.wikipedia.org/wiki/Zombie_process,zombies)"
2562 – processes that are defunct, yet still occupy a slot in the OS process table.
2563 You should not and must not wait for detached processes, since you don't own them.
2564 
2565 If the process has already terminated, this function returns directly.
2566 The exit code is cached, so that if wait() is called multiple times on
2567 the same $(LREF Pid) it will always return the same value.
2568 
2569 POSIX_specific:
2570 If the process is terminated by a signal, this function returns a
2571 negative number whose absolute value is the signal number.
2572 Since POSIX restricts normal exit codes to the range 0-255, a
2573 negative return value will always indicate termination by signal.
2574 Signal codes are defined in the `core.sys.posix.signal` module
2575 (which corresponds to the `signal.h` POSIX header).
2576 
2577 Throws:
2578 $(LREF ProcessException) on failure or on attempt to wait for detached process.
2579 
2580 Example:
2581 See the $(LREF spawnProcess) documentation.
2582 
2583 See_also:
2584 $(LREF tryWait), for a non-blocking function.
2585 */
2586 int wait(Pid pid) @safe
2587 {
2588     assert(pid !is null, "Called wait on a null Pid.");
2589     return pid.performWait(true);
2590 }
2591 
2592 
2593 @system unittest // Pid and wait()
2594 {
2595     version (Windows)    TestScript prog = "exit %~1";
2596     else version (Posix) TestScript prog = "exit $1";
2597     assert(wait(spawnProcess([prog.path, "0"])) == 0);
2598     assert(wait(spawnProcess([prog.path, "123"])) == 123);
2599     auto pid = spawnProcess([prog.path, "10"]);
2600     assert(pid.processID > 0);
2601     version (Windows)    assert(pid.osHandle != INVALID_HANDLE_VALUE);
2602     else version (Posix) assert(pid.osHandle == pid.processID);
2603     assert(wait(pid) == 10);
2604     assert(wait(pid) == 10); // cached exit code
2605     assert(pid.processID < 0);
2606     version (Windows)    assert(pid.osHandle == INVALID_HANDLE_VALUE);
2607     else version (Posix) assert(pid.osHandle < 0);
2608 }
2609 
2610 private import std.typecons : Tuple;
2611 
2612 /**
2613 Waits until either the process associated with `pid` terminates or the
2614 elapsed time exceeds the given timeout.
2615 
2616 If the process terminates within the given duration it behaves exactly like
2617 `wait`, except that it returns a tuple `(true, exit code)`.
2618 
2619 If the process does not terminate within the given duration it will stop
2620 waiting and return `(false, 0).`
2621 
2622 The timeout may not exceed `(uint.max - 1).msecs` (~ 7 weeks, 17 hours).
2623 
2624 $(BLUE This function is Windows-Only.)
2625 
2626 Returns:
2627 An $(D std.typecons.Tuple!(bool, "terminated", int, "status")).
2628 
2629 Throws:
2630 $(LREF ProcessException) on failure or on attempt to wait for detached process.
2631 
2632 Example:
2633 See the $(LREF spawnProcess) documentation.
2634 
2635 See_also:
2636 $(LREF wait), for a blocking function without timeout.
2637 $(LREF tryWait), for a non-blocking function without timeout.
2638 */
2639 version (StdDdoc)
2640 Tuple!(bool, "terminated", int, "status") waitTimeout(Pid pid, Duration timeout) @safe;
2641 
2642 else version (Windows)
2643 Tuple!(bool, "terminated", int, "status") waitTimeout(Pid pid, Duration timeout) @safe
2644 {
2645     assert(pid !is null, "Called wait on a null Pid.");
2646     auto code = pid.performWait(timeout);
2647     return typeof(return)(pid._processID == Pid.terminated, code);
2648 }
2649 
2650 version (Windows)
2651 @system unittest // Pid and waitTimeout()
2652 {
2653     import std.exception : collectException;
2654     import std.typecons : tuple;
2655 
2656     TestScript prog = ":Loop\r\n" ~ "goto Loop";
2657     auto pid = spawnProcess(prog.path);
2658 
2659     // Doesn't block longer than one second
2660     assert(waitTimeout(pid, 1.seconds) == tuple(false, 0));
2661 
2662     kill(pid);
2663     assert(waitTimeout(pid, 1.seconds) == tuple(true, 1)); // exit 1 because the process is killed
2664 
2665     // Rejects timeouts exceeding the Windows API capabilities
2666     const dur = DWORD.max.msecs;
2667     const ex = collectException!ProcessException(waitTimeout(pid, dur));
2668     assert(ex);
2669     assert(ex.msg == "Timeout exceeds maximum wait time!");
2670 }
2671 
2672 /**
2673 A non-blocking version of $(LREF wait).
2674 
2675 If the process associated with `pid` has already terminated,
2676 `tryWait` has the exact same effect as `wait`.
2677 In this case, it returns a tuple where the `terminated` field
2678 is set to `true` and the `status` field has the same
2679 interpretation as the return value of `wait`.
2680 
2681 If the process has $(I not) yet terminated, this function differs
2682 from `wait` in that does not wait for this to happen, but instead
2683 returns immediately.  The `terminated` field of the returned
2684 tuple will then be set to `false`, while the `status` field
2685 will always be 0 (zero).  `wait` or `tryWait` should then be
2686 called again on the same `Pid` at some later time; not only to
2687 get the exit code, but also to avoid the process becoming a "zombie"
2688 when it finally terminates.  (See $(LREF wait) for details).
2689 
2690 Returns:
2691 An $(D std.typecons.Tuple!(bool, "terminated", int, "status")).
2692 
2693 Throws:
2694 $(LREF ProcessException) on failure or on attempt to wait for detached process.
2695 
2696 Example:
2697 ---
2698 auto pid = spawnProcess("dmd myapp.d");
2699 scope(exit) wait(pid);
2700 ...
2701 auto dmd = tryWait(pid);
2702 if (dmd.terminated)
2703 {
2704     if (dmd.status == 0) writeln("Compilation succeeded!");
2705     else writeln("Compilation failed");
2706 }
2707 else writeln("Still compiling...");
2708 ...
2709 ---
2710 Note that in this example, the first `wait` call will have no
2711 effect if the process has already terminated by the time `tryWait`
2712 is called.  In the opposite case, however, the `scope` statement
2713 ensures that we always wait for the process if it hasn't terminated
2714 by the time we reach the end of the scope.
2715 */
2716 auto tryWait(Pid pid) @safe
2717 {
2718     import std.typecons : Tuple;
2719     assert(pid !is null, "Called tryWait on a null Pid.");
2720     auto code = pid.performWait(false);
2721     return Tuple!(bool, "terminated", int, "status")(pid._processID == Pid.terminated, code);
2722 }
2723 // unittest: This function is tested together with kill() below.
2724 
2725 
2726 /**
2727 Attempts to terminate the process associated with `pid`.
2728 
2729 The effect of this function, as well as the meaning of `codeOrSignal`,
2730 is highly platform dependent.  Details are given below.  Common to all
2731 platforms is that this function only $(I initiates) termination of the process,
2732 and returns immediately.  It does not wait for the process to end,
2733 nor does it guarantee that the process does in fact get terminated.
2734 
2735 Always call $(LREF wait) to wait for a process to complete, even if `kill`
2736 has been called on it.
2737 
2738 Windows_specific:
2739 The process will be
2740 $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/ms686714%28v=vs.100%29.aspx,
2741 forcefully and abruptly terminated).  If `codeOrSignal` is specified, it
2742 must be a nonnegative number which will be used as the exit code of the process.
2743 If not, the process wil exit with code 1.  Do not use $(D codeOrSignal = 259),
2744 as this is a special value (aka. $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/ms683189.aspx,STILL_ACTIVE))
2745 used by Windows to signal that a process has in fact $(I not) terminated yet.
2746 ---
2747 auto pid = spawnProcess("some_app");
2748 kill(pid, 10);
2749 assert(wait(pid) == 10);
2750 ---
2751 
2752 POSIX_specific:
2753 A $(LINK2 http://en.wikipedia.org/wiki/Unix_signal,signal) will be sent to
2754 the process, whose value is given by `codeOrSignal`.  Depending on the
2755 signal sent, this may or may not terminate the process.  Symbolic constants
2756 for various $(LINK2 http://en.wikipedia.org/wiki/Unix_signal#POSIX_signals,
2757 POSIX signals) are defined in `core.sys.posix.signal`, which corresponds to the
2758 $(LINK2 http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html,
2759 `signal.h` POSIX header).  If `codeOrSignal` is omitted, the
2760 `SIGTERM` signal will be sent.  (This matches the behaviour of the
2761 $(LINK2 http://pubs.opengroup.org/onlinepubs/9699919799/utilities/kill.html,
2762 `_kill`) shell command.)
2763 ---
2764 import core.sys.posix.signal : SIGKILL;
2765 auto pid = spawnProcess("some_app");
2766 kill(pid, SIGKILL);
2767 assert(wait(pid) == -SIGKILL); // Negative return value on POSIX!
2768 ---
2769 
2770 Throws:
2771 $(LREF ProcessException) on error (e.g. if codeOrSignal is invalid).
2772     or on attempt to kill detached process.
2773     Note that failure to terminate the process is considered a "normal"
2774     outcome, not an error.$(BR)
2775 */
2776 void kill(Pid pid)
2777 {
2778     version (Windows) kill(pid, 1);
2779     else version (Posix)
2780     {
2781         import core.sys.posix.signal : SIGTERM;
2782         kill(pid, SIGTERM);
2783     }
2784 }
2785 
2786 /// ditto
2787 void kill(Pid pid, int codeOrSignal)
2788 {
2789     import std.exception : enforce;
2790     enforce!ProcessException(pid.owned, "Can't kill detached process");
2791     version (Windows)
2792     {
2793         if (codeOrSignal < 0) throw new ProcessException("Invalid exit code");
2794         // On Windows, TerminateProcess() appears to terminate the
2795         // *current* process if it is passed an invalid handle...
2796         if (pid.osHandle == INVALID_HANDLE_VALUE)
2797             throw new ProcessException("Invalid process handle");
2798         if (!TerminateProcess(pid.osHandle, codeOrSignal))
2799             throw ProcessException.newFromLastError();
2800     }
2801     else version (Posix)
2802     {
2803         import core.sys.posix.signal : kill;
2804         if (pid.osHandle == Pid.invalid)
2805             throw new ProcessException("Pid is invalid");
2806         if (pid.osHandle == Pid.terminated)
2807             throw new ProcessException("Pid is already terminated");
2808         if (kill(pid.osHandle, codeOrSignal) == -1)
2809             throw ProcessException.newFromErrno();
2810     }
2811 }
2812 
2813 @system unittest // tryWait() and kill()
2814 {
2815     import core.thread;
2816     import std.exception : assertThrown;
2817     // The test script goes into an infinite loop.
2818     version (Windows)
2819     {
2820         TestScript prog = ":loop
2821                            goto loop";
2822     }
2823     else version (Posix)
2824     {
2825         import core.sys.posix.signal : SIGTERM, SIGKILL;
2826         TestScript prog = "while true; do sleep 1; done";
2827     }
2828     auto pid = spawnProcess(prog.path);
2829     // Android appears to automatically kill sleeping processes very quickly,
2830     // so shorten the wait before killing here.
2831     version (Android)
2832         Thread.sleep(dur!"msecs"(5));
2833     else
2834         Thread.sleep(dur!"msecs"(500));
2835     kill(pid);
2836     version (Windows)    assert(wait(pid) == 1);
2837     else version (Posix) assert(wait(pid) == -SIGTERM);
2838 
2839     pid = spawnProcess(prog.path);
2840     Thread.sleep(dur!"msecs"(500));
2841     auto s = tryWait(pid);
2842     assert(!s.terminated && s.status == 0);
2843     assertThrown!ProcessException(kill(pid, -123)); // Negative code not allowed.
2844     version (Windows)    kill(pid, 123);
2845     else version (Posix) kill(pid, SIGKILL);
2846     do { s = tryWait(pid); } while (!s.terminated);
2847     version (Windows)    assert(s.status == 123);
2848     else version (Posix) assert(s.status == -SIGKILL);
2849     assertThrown!ProcessException(kill(pid)); // Already terminated
2850 }
2851 
2852 @system unittest // wait() and kill() detached process
2853 {
2854     import core.thread;
2855     import std.exception : assertThrown;
2856     TestScript prog = "exit 0";
2857     auto pid = spawnProcess([prog.path], null, Config.detached);
2858     /*
2859     This sleep is needed because we can't wait() for detached process to end
2860     and therefore TestScript destructor may run at the same time as /bin/sh tries to start the script.
2861     This leads to the annoying message like "/bin/sh: 0: Can't open /tmp/std.process temporary file" to appear when running tests.
2862     It does not happen in unittests with non-detached processes because we always wait() for them to finish.
2863     */
2864     Thread.sleep(500.msecs);
2865     assert(!pid.owned);
2866     version (Windows) assert(pid.osHandle == INVALID_HANDLE_VALUE);
2867     assertThrown!ProcessException(wait(pid));
2868     assertThrown!ProcessException(kill(pid));
2869 }
2870 
2871 
2872 /**
2873 Creates a unidirectional _pipe.
2874 
2875 Data is written to one end of the _pipe and read from the other.
2876 ---
2877 auto p = pipe();
2878 p.writeEnd.writeln("Hello World");
2879 p.writeEnd.flush();
2880 assert(p.readEnd.readln().chomp() == "Hello World");
2881 ---
2882 Pipes can, for example, be used for interprocess communication
2883 by spawning a new process and passing one end of the _pipe to
2884 the child, while the parent uses the other end.
2885 (See also $(LREF pipeProcess) and $(LREF pipeShell) for an easier
2886 way of doing this.)
2887 ---
2888 // Use cURL to download the dlang.org front page, pipe its
2889 // output to grep to extract a list of links to ZIP files,
2890 // and write the list to the file "D downloads.txt":
2891 auto p = pipe();
2892 auto outFile = File("D downloads.txt", "w");
2893 auto cpid = spawnProcess(["curl", "http://dlang.org/download.html"],
2894                          std.stdio.stdin, p.writeEnd);
2895 scope(exit) wait(cpid);
2896 auto gpid = spawnProcess(["grep", "-o", `http://\S*\.zip`],
2897                          p.readEnd, outFile);
2898 scope(exit) wait(gpid);
2899 ---
2900 
2901 Returns:
2902 A $(LREF Pipe) object that corresponds to the created _pipe.
2903 
2904 Throws:
2905 $(REF StdioException, std,stdio) on failure.
2906 */
2907 version (Posix)
2908 Pipe pipe() @trusted //TODO: @safe
2909 {
2910     import core.sys.posix.stdio : fdopen;
2911     int[2] fds;
2912     if (core.sys.posix.unistd.pipe(fds) != 0)
2913         throw new StdioException("Unable to create pipe");
2914     Pipe p;
2915     auto readFP = fdopen(fds[0], "r");
2916     if (readFP == null)
2917         throw new StdioException("Cannot open read end of pipe");
2918     p._read = File(readFP, null);
2919     auto writeFP = fdopen(fds[1], "w");
2920     if (writeFP == null)
2921         throw new StdioException("Cannot open write end of pipe");
2922     p._write = File(writeFP, null);
2923     return p;
2924 }
2925 else version (Windows)
2926 Pipe pipe() @trusted //TODO: @safe
2927 {
2928     // use CreatePipe to create an anonymous pipe
2929     HANDLE readHandle;
2930     HANDLE writeHandle;
2931     if (!CreatePipe(&readHandle, &writeHandle, null, 0))
2932     {
2933         throw new StdioException(
2934             "Error creating pipe (" ~ generateSysErrorMsg() ~ ')',
2935             0);
2936     }
2937 
2938     scope(failure)
2939     {
2940         CloseHandle(readHandle);
2941         CloseHandle(writeHandle);
2942     }
2943 
2944     try
2945     {
2946         Pipe p;
2947         p._read .windowsHandleOpen(readHandle , "r");
2948         p._write.windowsHandleOpen(writeHandle, "a");
2949         return p;
2950     }
2951     catch (Exception e)
2952     {
2953         throw new StdioException("Error attaching pipe (" ~ e.msg ~ ")",
2954             0);
2955     }
2956 }
2957 
2958 
2959 /// An interface to a pipe created by the $(LREF pipe) function.
2960 struct Pipe
2961 {
2962     /// The read end of the pipe.
2963     @property File readEnd() @safe nothrow { return _read; }
2964 
2965 
2966     /// The write end of the pipe.
2967     @property File writeEnd() @safe nothrow { return _write; }
2968 
2969 
2970     /**
2971     Closes both ends of the pipe.
2972 
2973     Normally it is not necessary to do this manually, as $(REF File, std,stdio)
2974     objects are automatically closed when there are no more references
2975     to them.
2976 
2977     Note that if either end of the pipe has been passed to a child process,
2978     it will only be closed in the parent process.  (What happens in the
2979     child process is platform dependent.)
2980 
2981     Throws:
2982     $(REF ErrnoException, std,exception) if an error occurs.
2983     */
2984     void close() @safe
2985     {
2986         _read.close();
2987         _write.close();
2988     }
2989 
2990 private:
2991     File _read, _write;
2992 }
2993 
2994 @system unittest
2995 {
2996     import std.string;
2997     auto p = pipe();
2998     p.writeEnd.writeln("Hello World");
2999     p.writeEnd.flush();
3000     assert(p.readEnd.readln().chomp() == "Hello World");
3001     p.close();
3002     assert(!p.readEnd.isOpen);
3003     assert(!p.writeEnd.isOpen);
3004 }
3005 
3006 
3007 /**
3008 Starts a new process, creating pipes to redirect its standard
3009 input, output and/or error streams.
3010 
3011 `pipeProcess` and `pipeShell` are convenient wrappers around
3012 $(LREF spawnProcess) and $(LREF spawnShell), respectively, and
3013 automate the task of redirecting one or more of the child process'
3014 standard streams through pipes.  Like the functions they wrap,
3015 these functions return immediately, leaving the child process to
3016 execute in parallel with the invoking process.  It is recommended
3017 to always call $(LREF wait) on the returned $(LREF ProcessPipes.pid),
3018 as detailed in the documentation for `wait`.
3019 
3020 The `args`/`program`/`command`, `env` and `config`
3021 parameters are forwarded straight to the underlying spawn functions,
3022 and we refer to their documentation for details.
3023 
3024 Params:
3025 args      = An array which contains the program name as the zeroth element
3026             and any command-line arguments in the following elements.
3027             (See $(LREF spawnProcess) for details.)
3028 program   = The program name, $(I without) command-line arguments.
3029             (See $(LREF spawnProcess) for details.)
3030 command   = A shell command which is passed verbatim to the command
3031             interpreter.  (See $(LREF spawnShell) for details.)
3032 redirect  = Flags that determine which streams are redirected, and
3033             how.  See $(LREF Redirect) for an overview of available
3034             flags.
3035 env       = Additional environment variables for the child process.
3036             (See $(LREF spawnProcess) for details.)
3037 config    = Flags that control process creation. See $(LREF Config)
3038             for an overview of available flags, and note that the
3039             `retainStd...` flags have no effect in this function.
3040 workDir   = The working directory for the new process.
3041             By default the child process inherits the parent's working
3042             directory.
3043 shellPath = The path to the shell to use to run the specified program.
3044             By default this is $(LREF nativeShell).
3045 
3046 Returns:
3047 A $(LREF ProcessPipes) object which contains $(REF File, std,stdio)
3048 handles that communicate with the redirected streams of the child
3049 process, along with a $(LREF Pid) object that corresponds to the
3050 spawned process.
3051 
3052 Throws:
3053 $(LREF ProcessException) on failure to start the process.$(BR)
3054 $(REF StdioException, std,stdio) on failure to redirect any of the streams.$(BR)
3055 
3056 Example:
3057 ---
3058 // my_application writes to stdout and might write to stderr
3059 auto pipes = pipeProcess("my_application", Redirect.stdout | Redirect.stderr);
3060 scope(exit) wait(pipes.pid);
3061 
3062 // Store lines of output.
3063 string[] output;
3064 foreach (line; pipes.stdout.byLine) output ~= line.idup;
3065 
3066 // Store lines of errors.
3067 string[] errors;
3068 foreach (line; pipes.stderr.byLine) errors ~= line.idup;
3069 
3070 
3071 // sendmail expects to read from stdin
3072 pipes = pipeProcess(["/usr/bin/sendmail", "-t"], Redirect.stdin);
3073 pipes.stdin.writeln("To: you");
3074 pipes.stdin.writeln("From: me");
3075 pipes.stdin.writeln("Subject: dlang");
3076 pipes.stdin.writeln("");
3077 pipes.stdin.writeln(message);
3078 
3079 // a single period tells sendmail we are finished
3080 pipes.stdin.writeln(".");
3081 
3082 // but at this point sendmail might not see it, we need to flush
3083 pipes.stdin.flush();
3084 
3085 // sendmail happens to exit on ".", but some you have to close the file:
3086 pipes.stdin.close();
3087 
3088 // otherwise this wait will wait forever
3089 wait(pipes.pid);
3090 
3091 ---
3092 */
3093 ProcessPipes pipeProcess(scope const(char[])[] args,
3094                          Redirect redirect = Redirect.all,
3095                          const string[string] env = null,
3096                          Config config = Config.none,
3097                          scope const(char)[] workDir = null)
3098     @safe
3099 {
3100     return pipeProcessImpl!spawnProcess(args, redirect, env, config, workDir);
3101 }
3102 
3103 /// ditto
3104 ProcessPipes pipeProcess(scope const(char)[] program,
3105                          Redirect redirect = Redirect.all,
3106                          const string[string] env = null,
3107                          Config config = Config.none,
3108                          scope const(char)[] workDir = null)
3109     @safe
3110 {
3111     return pipeProcessImpl!spawnProcess(program, redirect, env, config, workDir);
3112 }
3113 
3114 /// ditto
3115 ProcessPipes pipeShell(scope const(char)[] command,
3116                        Redirect redirect = Redirect.all,
3117                        const string[string] env = null,
3118                        Config config = Config.none,
3119                        scope const(char)[] workDir = null,
3120                        string shellPath = nativeShell)
3121     @safe
3122 {
3123     return pipeProcessImpl!spawnShell(command,
3124                                       redirect,
3125                                       env,
3126                                       config,
3127                                       workDir,
3128                                       shellPath);
3129 }
3130 
3131 // Implementation of the pipeProcess() family of functions.
3132 private ProcessPipes pipeProcessImpl(alias spawnFunc, Cmd, ExtraSpawnFuncArgs...)
3133                                     (scope Cmd command,
3134                                      Redirect redirectFlags,
3135                                      const string[string] env = null,
3136                                      Config config = Config.none,
3137                                      scope const(char)[] workDir = null,
3138                                      ExtraSpawnFuncArgs extraArgs = ExtraSpawnFuncArgs.init)
3139     @trusted //TODO: @safe
3140 {
3141     File childStdin, childStdout, childStderr;
3142     ProcessPipes pipes;
3143     pipes._redirectFlags = redirectFlags;
3144 
3145     if (redirectFlags & Redirect.stdin)
3146     {
3147         auto p = pipe();
3148         childStdin = p.readEnd;
3149         pipes._stdin = p.writeEnd;
3150     }
3151     else
3152     {
3153         childStdin = std.stdio.stdin;
3154     }
3155 
3156     if (redirectFlags & Redirect.stdout)
3157     {
3158         if ((redirectFlags & Redirect.stdoutToStderr) != 0)
3159             throw new StdioException("Cannot create pipe for stdout AND "
3160                                      ~"redirect it to stderr", 0);
3161         auto p = pipe();
3162         childStdout = p.writeEnd;
3163         pipes._stdout = p.readEnd;
3164     }
3165     else
3166     {
3167         childStdout = std.stdio.stdout;
3168     }
3169 
3170     if (redirectFlags & Redirect.stderr)
3171     {
3172         if ((redirectFlags & Redirect.stderrToStdout) != 0)
3173             throw new StdioException("Cannot create pipe for stderr AND "
3174                                      ~"redirect it to stdout", 0);
3175         auto p = pipe();
3176         childStderr = p.writeEnd;
3177         pipes._stderr = p.readEnd;
3178     }
3179     else
3180     {
3181         childStderr = std.stdio.stderr;
3182     }
3183 
3184     if (redirectFlags & Redirect.stdoutToStderr)
3185     {
3186         if (redirectFlags & Redirect.stderrToStdout)
3187         {
3188             // We know that neither of the other options have been
3189             // set, so we assign the std.stdio.std* streams directly.
3190             childStdout = std.stdio.stderr;
3191             childStderr = std.stdio.stdout;
3192         }
3193         else
3194         {
3195             childStdout = childStderr;
3196         }
3197     }
3198     else if (redirectFlags & Redirect.stderrToStdout)
3199     {
3200         childStderr = childStdout;
3201     }
3202 
3203     config.flags &= ~(Config.Flags.retainStdin | Config.Flags.retainStdout | Config.Flags.retainStderr);
3204     pipes._pid = spawnFunc(command, childStdin, childStdout, childStderr,
3205                            env, config, workDir, extraArgs);
3206     return pipes;
3207 }
3208 
3209 
3210 /**
3211 Flags that can be passed to $(LREF pipeProcess) and $(LREF pipeShell)
3212 to specify which of the child process' standard streams are redirected.
3213 Use bitwise OR to combine flags.
3214 */
3215 enum Redirect
3216 {
3217     /// Redirect the standard input, output or error streams, respectively.
3218     stdin = 1,
3219     stdout = 2,                             /// ditto
3220     stderr = 4,                             /// ditto
3221 
3222     /**
3223     Redirect _all three streams.  This is equivalent to
3224     $(D Redirect.stdin | Redirect.stdout | Redirect.stderr).
3225     */
3226     all = stdin | stdout | stderr,
3227 
3228     /**
3229     Redirect the standard error stream into the standard output stream.
3230     This can not be combined with `Redirect.stderr`.
3231     */
3232     stderrToStdout = 8,
3233 
3234     /**
3235     Redirect the standard output stream into the standard error stream.
3236     This can not be combined with `Redirect.stdout`.
3237     */
3238     stdoutToStderr = 16,
3239 }
3240 
3241 @system unittest
3242 {
3243     import std.string;
3244     version (Windows) TestScript prog =
3245        "call :sub %~1 %~2 0
3246         call :sub %~1 %~2 1
3247         call :sub %~1 %~2 2
3248         call :sub %~1 %~2 3
3249         exit 3
3250 
3251         :sub
3252         set /p INPUT=
3253         if -%INPUT%-==-stop- ( exit %~3 )
3254         echo %INPUT% %~1
3255         echo %INPUT% %~2 1>&2";
3256     else version (Posix) TestScript prog =
3257        `for EXITCODE in 0 1 2 3; do
3258             read INPUT
3259             if test "$INPUT" = stop; then break; fi
3260             echo "$INPUT $1"
3261             echo "$INPUT $2" >&2
3262         done
3263         exit $EXITCODE`;
3264     auto pp = pipeProcess([prog.path, "bar", "baz"]);
3265     pp.stdin.writeln("foo");
3266     pp.stdin.flush();
3267     assert(pp.stdout.readln().chomp() == "foo bar");
3268     assert(pp.stderr.readln().chomp().stripRight() == "foo baz");
3269     pp.stdin.writeln("1234567890");
3270     pp.stdin.flush();
3271     assert(pp.stdout.readln().chomp() == "1234567890 bar");
3272     assert(pp.stderr.readln().chomp().stripRight() == "1234567890 baz");
3273     pp.stdin.writeln("stop");
3274     pp.stdin.flush();
3275     assert(wait(pp.pid) == 2);
3276 
3277     pp = pipeProcess([prog.path, "12345", "67890"],
3278                      Redirect.stdin | Redirect.stdout | Redirect.stderrToStdout);
3279     pp.stdin.writeln("xyz");
3280     pp.stdin.flush();
3281     assert(pp.stdout.readln().chomp() == "xyz 12345");
3282     assert(pp.stdout.readln().chomp().stripRight() == "xyz 67890");
3283     pp.stdin.writeln("stop");
3284     pp.stdin.flush();
3285     assert(wait(pp.pid) == 1);
3286 
3287     pp = pipeShell(escapeShellCommand(prog.path, "AAAAA", "BBB"),
3288                    Redirect.stdin | Redirect.stdoutToStderr | Redirect.stderr);
3289     pp.stdin.writeln("ab");
3290     pp.stdin.flush();
3291     assert(pp.stderr.readln().chomp() == "ab AAAAA");
3292     assert(pp.stderr.readln().chomp().stripRight() == "ab BBB");
3293     pp.stdin.writeln("stop");
3294     pp.stdin.flush();
3295     assert(wait(pp.pid) == 1);
3296 }
3297 
3298 @system unittest
3299 {
3300     import std.exception : assertThrown;
3301     TestScript prog = "exit 0";
3302     assertThrown!StdioException(pipeProcess(
3303         prog.path,
3304         Redirect.stdout | Redirect.stdoutToStderr));
3305     assertThrown!StdioException(pipeProcess(
3306         prog.path,
3307         Redirect.stderr | Redirect.stderrToStdout));
3308     auto p = pipeProcess(prog.path, Redirect.stdin);
3309     assertThrown!Error(p.stdout);
3310     assertThrown!Error(p.stderr);
3311     wait(p.pid);
3312     p = pipeProcess(prog.path, Redirect.stderr);
3313     assertThrown!Error(p.stdin);
3314     assertThrown!Error(p.stdout);
3315     wait(p.pid);
3316 }
3317 
3318 /**
3319 Object which contains $(REF File, std,stdio) handles that allow communication
3320 with a child process through its standard streams.
3321 */
3322 struct ProcessPipes
3323 {
3324     /// The $(LREF Pid) of the child process.
3325     @property Pid pid() @safe nothrow
3326     {
3327         return _pid;
3328     }
3329 
3330     /**
3331     An $(REF File, std,stdio) that allows writing to the child process'
3332     standard input stream.
3333 
3334     Throws:
3335     $(OBJECTREF Error) if the child process' standard input stream hasn't
3336     been redirected.
3337     */
3338     @property File stdin() @safe nothrow
3339     {
3340         if ((_redirectFlags & Redirect.stdin) == 0)
3341             throw new Error("Child process' standard input stream hasn't "
3342                             ~"been redirected.");
3343         return _stdin;
3344     }
3345 
3346     /**
3347     An $(REF File, std,stdio) that allows reading from the child process'
3348     standard output stream.
3349 
3350     Throws:
3351     $(OBJECTREF Error) if the child process' standard output stream hasn't
3352     been redirected.
3353     */
3354     @property File stdout() @safe nothrow
3355     {
3356         if ((_redirectFlags & Redirect.stdout) == 0)
3357             throw new Error("Child process' standard output stream hasn't "
3358                             ~"been redirected.");
3359         return _stdout;
3360     }
3361 
3362     /**
3363     An $(REF File, std,stdio) that allows reading from the child process'
3364     standard error stream.
3365 
3366     Throws:
3367     $(OBJECTREF Error) if the child process' standard error stream hasn't
3368     been redirected.
3369     */
3370     @property File stderr() @safe nothrow
3371     {
3372         if ((_redirectFlags & Redirect.stderr) == 0)
3373             throw new Error("Child process' standard error stream hasn't "
3374                             ~"been redirected.");
3375         return _stderr;
3376     }
3377 
3378 private:
3379     Redirect _redirectFlags;
3380     Pid _pid;
3381     File _stdin, _stdout, _stderr;
3382 }
3383 
3384 
3385 
3386 /**
3387 Executes the given program or shell command and returns its exit
3388 code and output.
3389 
3390 `execute` and `executeShell` start a new process using
3391 $(LREF spawnProcess) and $(LREF spawnShell), respectively, and wait
3392 for the process to complete before returning.  The functions capture
3393 what the child process prints to both its standard output and
3394 standard error streams, and return this together with its exit code.
3395 ---
3396 auto dmd = execute(["dmd", "myapp.d"]);
3397 if (dmd.status != 0) writeln("Compilation failed:\n", dmd.output);
3398 
3399 auto ls = executeShell("ls -l");
3400 if (ls.status != 0) writeln("Failed to retrieve file listing");
3401 else writeln(ls.output);
3402 ---
3403 
3404 The `args`/`program`/`command`, `env` and `config`
3405 parameters are forwarded straight to the underlying spawn functions,
3406 and we refer to their documentation for details.
3407 
3408 Params:
3409 args      = An array which contains the program name as the zeroth element
3410             and any command-line arguments in the following elements.
3411             (See $(LREF spawnProcess) for details.)
3412 program   = The program name, $(I without) command-line arguments.
3413             (See $(LREF spawnProcess) for details.)
3414 command   = A shell command which is passed verbatim to the command
3415             interpreter.  (See $(LREF spawnShell) for details.)
3416 env       = Additional environment variables for the child process.
3417             (See $(LREF spawnProcess) for details.)
3418 config    = Flags that control process creation. See $(LREF Config)
3419             for an overview of available flags, and note that the
3420             `retainStd...` flags have no effect in this function.
3421 maxOutput = The maximum number of bytes of output that should be
3422             captured.
3423 workDir   = The working directory for the new process.
3424             By default the child process inherits the parent's working
3425             directory.
3426 shellPath = The path to the shell to use to run the specified program.
3427             By default this is $(LREF nativeShell).
3428 
3429 
3430 Returns:
3431 An $(D std.typecons.Tuple!(int, "status", string, "output")).
3432 
3433 POSIX_specific:
3434 If the process is terminated by a signal, the `status` field of
3435 the return value will contain a negative number whose absolute
3436 value is the signal number.  (See $(LREF wait) for details.)
3437 
3438 Throws:
3439 $(LREF ProcessException) on failure to start the process.$(BR)
3440 $(REF StdioException, std,stdio) on failure to capture output.
3441 */
3442 auto execute(scope const(char[])[] args,
3443              const string[string] env = null,
3444              Config config = Config.none,
3445              size_t maxOutput = size_t.max,
3446              scope const(char)[] workDir = null)
3447     @safe
3448 {
3449     return executeImpl!pipeProcess(args, env, config, maxOutput, workDir);
3450 }
3451 
3452 /// ditto
3453 auto execute(scope const(char)[] program,
3454              const string[string] env = null,
3455              Config config = Config.none,
3456              size_t maxOutput = size_t.max,
3457              scope const(char)[] workDir = null)
3458     @safe
3459 {
3460     return executeImpl!pipeProcess(program, env, config, maxOutput, workDir);
3461 }
3462 
3463 /// ditto
3464 auto executeShell(scope const(char)[] command,
3465                   const string[string] env = null,
3466                   Config config = Config.none,
3467                   size_t maxOutput = size_t.max,
3468                   scope const(char)[] workDir = null,
3469                   string shellPath = nativeShell)
3470     @safe
3471 {
3472     return executeImpl!pipeShell(command,
3473                                  env,
3474                                  config,
3475                                  maxOutput,
3476                                  workDir,
3477                                  shellPath);
3478 }
3479 
3480 // Does the actual work for execute() and executeShell().
3481 private auto executeImpl(alias pipeFunc, Cmd, ExtraPipeFuncArgs...)(
3482     Cmd commandLine,
3483     const string[string] env = null,
3484     Config config = Config.none,
3485     size_t maxOutput = size_t.max,
3486     scope const(char)[] workDir = null,
3487     ExtraPipeFuncArgs extraArgs = ExtraPipeFuncArgs.init)
3488     @trusted //TODO: @safe
3489 {
3490     import std.algorithm.comparison : min;
3491     import std.array : appender;
3492     import std.typecons : Tuple;
3493 
3494     auto redirect = (config.flags & Config.Flags.stderrPassThrough)
3495         ? Redirect.stdout
3496         : Redirect.stdout | Redirect.stderrToStdout;
3497 
3498     auto p = pipeFunc(commandLine, redirect,
3499                       env, config, workDir, extraArgs);
3500 
3501     auto a = appender!string;
3502     enum size_t defaultChunkSize = 4096;
3503     immutable chunkSize = min(maxOutput, defaultChunkSize);
3504 
3505     // Store up to maxOutput bytes in a.
3506     foreach (ubyte[] chunk; p.stdout.byChunk(chunkSize))
3507     {
3508         immutable size_t remain = maxOutput - a.data.length;
3509 
3510         if (chunk.length < remain) a.put(chunk);
3511         else
3512         {
3513             a.put(chunk[0 .. remain]);
3514             break;
3515         }
3516     }
3517     // Exhaust the stream, if necessary.
3518     foreach (ubyte[] chunk; p.stdout.byChunk(defaultChunkSize)) { }
3519 
3520     return Tuple!(int, "status", string, "output")(wait(p.pid), a.data);
3521 }
3522 
3523 @system unittest
3524 {
3525     import std.string;
3526     // To avoid printing the newline characters, we use the echo|set trick on
3527     // Windows, and printf on POSIX (neither echo -n nor echo \c are portable).
3528     version (Windows) TestScript prog =
3529        "echo|set /p=%~1
3530         echo|set /p=%~2 1>&2
3531         exit 123";
3532     else version (Android) TestScript prog =
3533        `echo -n $1
3534         echo -n $2 >&2
3535         exit 123`;
3536     else version (Posix) TestScript prog =
3537        `printf '%s' $1
3538         printf '%s' $2 >&2
3539         exit 123`;
3540     auto r = execute([prog.path, "foo", "bar"]);
3541     assert(r.status == 123);
3542     assert(r.output.stripRight() == "foobar");
3543     auto s = execute([prog.path, "Hello", "World"]);
3544     assert(s.status == 123);
3545     assert(s.output.stripRight() == "HelloWorld");
3546 }
3547 
3548 @safe unittest
3549 {
3550     import std.string;
3551     auto r1 = executeShell("echo foo");
3552     assert(r1.status == 0);
3553     assert(r1.output.chomp() == "foo");
3554     auto r2 = executeShell("echo bar 1>&2");
3555     assert(r2.status == 0);
3556     assert(r2.output.chomp().stripRight() == "bar");
3557     auto r3 = executeShell("exit 123");
3558     assert(r3.status == 123);
3559     assert(r3.output.empty);
3560 }
3561 
3562 @system unittest
3563 {
3564     // Temporarily disable output to stderr so as to not spam the build log.
3565     import std.stdio : stderr;
3566     import std.typecons : Tuple;
3567     import std.file : readText, exists, remove;
3568     import std.traits : ReturnType;
3569 
3570     ReturnType!executeShell r;
3571     auto tmpname = uniqueTempPath;
3572     scope(exit) if (exists(tmpname)) remove(tmpname);
3573     auto t = stderr;
3574     // Open a new scope to minimize code ran with stderr redirected.
3575     {
3576         stderr.open(tmpname, "w");
3577         scope(exit) stderr = t;
3578         r = executeShell("echo D rox>&2", null, Config.stderrPassThrough);
3579     }
3580     assert(r.status == 0);
3581     assert(r.output.empty);
3582     auto witness = readText(tmpname);
3583     import std.ascii : newline;
3584     assert(witness == "D rox" ~ newline, "'" ~ witness ~ "'");
3585 }
3586 
3587 @safe unittest
3588 {
3589     import std.typecons : Tuple;
3590     void foo() //Just test the compilation
3591     {
3592         auto ret1 = execute(["dummy", "arg"]);
3593         auto ret2 = executeShell("dummy arg");
3594         static assert(is(typeof(ret1) == typeof(ret2)));
3595 
3596         Tuple!(int, string) ret3 = execute(["dummy", "arg"]);
3597     }
3598 }
3599 
3600 /// An exception that signals a problem with starting or waiting for a process.
3601 class ProcessException : Exception
3602 {
3603     import std.exception : basicExceptionCtors;
3604     mixin basicExceptionCtors;
3605 
3606     // Creates a new ProcessException based on errno.
3607     static ProcessException newFromErrno(string customMsg = null,
3608                                          string file = __FILE__,
3609                                          size_t line = __LINE__)
3610     {
3611         import core.stdc.errno : errno;
3612         return newFromErrno(errno, customMsg, file, line);
3613     }
3614 
3615     // ditto, but error number is provided by caller
3616     static ProcessException newFromErrno(int error,
3617                                          string customMsg = null,
3618                                          string file = __FILE__,
3619                                          size_t line = __LINE__)
3620     {
3621         import std.exception : errnoString;
3622         auto errnoMsg = errnoString(error);
3623         auto msg = customMsg.empty ? errnoMsg
3624                                    : customMsg ~ " (" ~ errnoMsg ~ ')';
3625         return new ProcessException(msg, file, line);
3626     }
3627 
3628     // Creates a new ProcessException based on GetLastError() (Windows only).
3629     version (Windows)
3630     static ProcessException newFromLastError(string customMsg = null,
3631                                              string file = __FILE__,
3632                                              size_t line = __LINE__)
3633     {
3634         auto lastMsg = generateSysErrorMsg();
3635         auto msg = customMsg.empty ? lastMsg
3636                                    : customMsg ~ " (" ~ lastMsg ~ ')';
3637         return new ProcessException(msg, file, line);
3638     }
3639 }
3640 
3641 
3642 /**
3643 Determines the path to the current user's preferred command interpreter.
3644 
3645 On Windows, this function returns the contents of the COMSPEC environment
3646 variable, if it exists.  Otherwise, it returns the result of $(LREF nativeShell).
3647 
3648 On POSIX, `userShell` returns the contents of the SHELL environment
3649 variable, if it exists and is non-empty.  Otherwise, it returns the result of
3650 $(LREF nativeShell).
3651 */
3652 @property string userShell() @safe
3653 {
3654     version (Windows)      return environment.get("COMSPEC", nativeShell);
3655     else version (Posix)   return environment.get("SHELL", nativeShell);
3656 }
3657 
3658 /**
3659 The platform-specific native shell path.
3660 
3661 This function returns `"cmd.exe"` on Windows, `"/bin/sh"` on POSIX, and
3662 `"/system/bin/sh"` on Android.
3663 */
3664 @property string nativeShell() @safe @nogc pure nothrow
3665 {
3666     version (Windows)      return "cmd.exe";
3667     else version (Android) return "/system/bin/sh";
3668     else version (Posix)   return "/bin/sh";
3669 }
3670 
3671 // A command-line switch that indicates to the shell that it should
3672 // interpret the following argument as a command to be executed.
3673 version (Posix)   private immutable string shellSwitch = "-c";
3674 version (Windows) private immutable string shellSwitch = "/C";
3675 
3676 // Unittest support code:  TestScript takes a string that contains a
3677 // shell script for the current platform, and writes it to a temporary
3678 // file. On Windows the file name gets a .cmd extension, while on
3679 // POSIX its executable permission bit is set.  The file is
3680 // automatically deleted when the object goes out of scope.
3681 version (StdUnittest)
3682 private struct TestScript
3683 {
3684     this(string code) @system
3685     {
3686         // @system due to chmod
3687         import std.ascii : newline;
3688         import std.file : write;
3689         version (Windows)
3690         {
3691             auto ext = ".cmd";
3692             auto firstLine = "@echo off";
3693         }
3694         else version (Posix)
3695         {
3696             auto ext = "";
3697             auto firstLine = "#!" ~ nativeShell;
3698         }
3699         path = uniqueTempPath()~ext;
3700         write(path, firstLine ~ newline ~ code ~ newline);
3701         version (Posix)
3702         {
3703             import core.sys.posix.sys.stat : chmod;
3704             import std.conv : octal;
3705             chmod(path.tempCString(), octal!777);
3706         }
3707     }
3708 
3709     ~this()
3710     {
3711         import std.file : remove, exists;
3712         if (!path.empty && exists(path))
3713         {
3714             try { remove(path); }
3715             catch (Exception e)
3716             {
3717                 debug std.stdio.stderr.writeln(e.msg);
3718             }
3719         }
3720     }
3721 
3722     string path;
3723 }
3724 
3725 
3726 // =============================================================================
3727 // Functions for shell command quoting/escaping.
3728 // =============================================================================
3729 
3730 
3731 /*
3732     Command line arguments exist in three forms:
3733     1) string or char* array, as received by main.
3734        Also used internally on POSIX systems.
3735     2) Command line string, as used in Windows'
3736        CreateProcess and CommandLineToArgvW functions.
3737        A specific quoting and escaping algorithm is used
3738        to distinguish individual arguments.
3739     3) Shell command string, as written at a shell prompt
3740        or passed to cmd /C - this one may contain shell
3741        control characters, e.g. > or | for redirection /
3742        piping - thus, yet another layer of escaping is
3743        used to distinguish them from program arguments.
3744 
3745     Except for escapeWindowsArgument, the intermediary
3746     format (2) is hidden away from the user in this module.
3747 */
3748 
3749 /**
3750 Escapes an argv-style argument array to be used with $(LREF spawnShell),
3751 $(LREF pipeShell) or $(LREF executeShell).
3752 ---
3753 string url = "http://dlang.org/";
3754 executeShell(escapeShellCommand("wget", url, "-O", "dlang-index.html"));
3755 ---
3756 
3757 Concatenate multiple `escapeShellCommand` and
3758 $(LREF escapeShellFileName) results to use shell redirection or
3759 piping operators.
3760 ---
3761 executeShell(
3762     escapeShellCommand("curl", "http://dlang.org/download.html") ~
3763     "|" ~
3764     escapeShellCommand("grep", "-o", `http://\S*\.zip`) ~
3765     ">" ~
3766     escapeShellFileName("D download links.txt"));
3767 ---
3768 
3769 Throws:
3770 $(OBJECTREF Exception) if any part of the command line contains unescapable
3771 characters (NUL on all platforms, as well as CR and LF on Windows).
3772 */
3773 string escapeShellCommand(scope const(char[])[] args...) @safe pure
3774 {
3775     if (args.empty)
3776         return null;
3777     version (Windows)
3778     {
3779         // Do not ^-escape the first argument (the program path),
3780         // as the shell parses it differently from parameters.
3781         // ^-escaping a program path that contains spaces will fail.
3782         string result = escapeShellFileName(args[0]);
3783         if (args.length > 1)
3784         {
3785             result ~= " " ~ escapeShellCommandString(
3786                 escapeShellArguments(args[1..$]));
3787         }
3788         return result;
3789     }
3790     version (Posix)
3791     {
3792         return escapeShellCommandString(escapeShellArguments(args));
3793     }
3794 }
3795 
3796 @safe unittest
3797 {
3798     // This is a simple unit test without any special requirements,
3799     // in addition to the unittest_burnin one below which requires
3800     // special preparation.
3801 
3802     struct TestVector { string[] args; string windows, posix; }
3803     TestVector[] tests =
3804     [
3805         {
3806             args    : ["foo bar"],
3807             windows : `"foo bar"`,
3808             posix   : `'foo bar'`
3809         },
3810         {
3811             args    : ["foo bar", "hello"],
3812             windows : `"foo bar" hello`,
3813             posix   : `'foo bar' hello`
3814         },
3815         {
3816             args    : ["foo bar", "hello world"],
3817             windows : `"foo bar" ^"hello world^"`,
3818             posix   : `'foo bar' 'hello world'`
3819         },
3820         {
3821             args    : ["foo bar", "hello", "world"],
3822             windows : `"foo bar" hello world`,
3823             posix   : `'foo bar' hello world`
3824         },
3825         {
3826             args    : ["foo bar", `'"^\`],
3827             windows : `"foo bar" ^"'\^"^^\\^"`,
3828             posix   : `'foo bar' ''\''"^\'`
3829         },
3830         {
3831             args    : ["foo bar", ""],
3832             windows : `"foo bar" ^"^"`,
3833             posix   : `'foo bar' ''`
3834         },
3835         {
3836             args    : ["foo bar", "2"],
3837             windows : `"foo bar" ^"2^"`,
3838             posix   : `'foo bar' '2'`
3839         },
3840     ];
3841 
3842     foreach (test; tests)
3843     {
3844         auto actual = escapeShellCommand(test.args);
3845         version (Windows)
3846             string expected = test.windows;
3847         else
3848             string expected = test.posix;
3849         assert(actual == expected, "\nExpected: " ~ expected ~ "\nGot: " ~ actual);
3850     }
3851 }
3852 
3853 private string escapeShellCommandString(return scope string command) @safe pure
3854 {
3855     version (Windows)
3856         return escapeWindowsShellCommand(command);
3857     else
3858         return command;
3859 }
3860 
3861 private string escapeWindowsShellCommand(scope const(char)[] command) @safe pure
3862 {
3863     import std.array : appender;
3864     auto result = appender!string();
3865     result.reserve(command.length);
3866 
3867     foreach (c; command)
3868         switch (c)
3869         {
3870             case '\0':
3871                 throw new Exception("Cannot put NUL in command line");
3872             case '\r':
3873             case '\n':
3874                 throw new Exception("CR/LF are not escapable");
3875             case '\x01': .. case '\x09':
3876             case '\x0B': .. case '\x0C':
3877             case '\x0E': .. case '\x1F':
3878             case '"':
3879             case '^':
3880             case '&':
3881             case '<':
3882             case '>':
3883             case '|':
3884                 result.put('^');
3885                 goto default;
3886             default:
3887                 result.put(c);
3888         }
3889     return result.data;
3890 }
3891 
3892 private string escapeShellArguments(scope const(char[])[] args...)
3893     @trusted pure nothrow
3894 {
3895     import std.exception : assumeUnique;
3896     char[] buf;
3897 
3898     @safe nothrow
3899     char[] allocator(size_t size)
3900     {
3901         if (buf.length == 0)
3902             return buf = new char[size];
3903         else
3904         {
3905             auto p = buf.length;
3906             buf.length = buf.length + 1 + size;
3907             buf[p++] = ' ';
3908             return buf[p .. p+size];
3909         }
3910     }
3911 
3912     foreach (arg; args)
3913         escapeShellArgument!allocator(arg);
3914     return assumeUnique(buf);
3915 }
3916 
3917 private auto escapeShellArgument(alias allocator)(scope const(char)[] arg) @safe nothrow
3918 {
3919     // The unittest for this function requires special
3920     // preparation - see below.
3921 
3922     version (Windows)
3923         return escapeWindowsArgumentImpl!allocator(arg);
3924     else
3925         return escapePosixArgumentImpl!allocator(arg);
3926 }
3927 
3928 /**
3929 Quotes a command-line argument in a manner conforming to the behavior of
3930 $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx,
3931 CommandLineToArgvW).
3932 */
3933 string escapeWindowsArgument(scope const(char)[] arg) @trusted pure nothrow
3934 {
3935     // Rationale for leaving this function as public:
3936     // this algorithm of escaping paths is also used in other software,
3937     // e.g. DMD's response files.
3938     import std.exception : assumeUnique;
3939     auto buf = escapeWindowsArgumentImpl!charAllocator(arg);
3940     return assumeUnique(buf);
3941 }
3942 
3943 
3944 private char[] charAllocator(size_t size) @safe pure nothrow
3945 {
3946     return new char[size];
3947 }
3948 
3949 
3950 private char[] escapeWindowsArgumentImpl(alias allocator)(scope const(char)[] arg)
3951     @safe nothrow
3952 if (is(typeof(allocator(size_t.init)[0] = char.init)))
3953 {
3954     // References:
3955     // * http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx
3956     // * http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx
3957 
3958     // Check if the string needs to be escaped,
3959     // and calculate the total string size.
3960 
3961     // Trailing backslashes must be escaped
3962     bool escaping = true;
3963     bool needEscape = false;
3964     // Result size = input size + 2 for surrounding quotes + 1 for the
3965     // backslash for each escaped character.
3966     size_t size = 1 + arg.length + 1;
3967 
3968     foreach_reverse (char c; arg)
3969     {
3970         if (c == '"')
3971         {
3972             needEscape = true;
3973             escaping = true;
3974             size++;
3975         }
3976         else
3977         if (c == '\\')
3978         {
3979             if (escaping)
3980                 size++;
3981         }
3982         else
3983         {
3984             if (c == ' ' || c == '\t')
3985                 needEscape = true;
3986             escaping = false;
3987         }
3988     }
3989 
3990     import std.ascii : isDigit;
3991     // Empty arguments need to be specified as ""
3992     if (!arg.length)
3993         needEscape = true;
3994     else
3995     // Arguments ending with digits need to be escaped,
3996     // to disambiguate with 1>file redirection syntax
3997     if (isDigit(arg[$-1]))
3998         needEscape = true;
3999 
4000     if (!needEscape)
4001         return allocator(arg.length)[] = arg;
4002 
4003     // Construct result string.
4004 
4005     auto buf = allocator(size);
4006     size_t p = size;
4007     buf[--p] = '"';
4008     escaping = true;
4009     foreach_reverse (char c; arg)
4010     {
4011         if (c == '"')
4012             escaping = true;
4013         else
4014         if (c != '\\')
4015             escaping = false;
4016 
4017         buf[--p] = c;
4018         if (escaping)
4019             buf[--p] = '\\';
4020     }
4021     buf[--p] = '"';
4022     assert(p == 0);
4023 
4024     return buf;
4025 }
4026 
4027 version (Windows) version (StdUnittest)
4028 {
4029 private:
4030     import core.stdc.stddef;
4031     import core.stdc.wchar_ : wcslen;
4032     import core.sys.windows.shellapi : CommandLineToArgvW;
4033     import core.sys.windows.winbase;
4034     import core.sys.windows.winnt;
4035     import std.array;
4036 
4037     string[] parseCommandLine(string line)
4038     {
4039         import std.algorithm.iteration : map;
4040         import std.array : array;
4041         import std.conv : to;
4042         auto lpCommandLine = (to!(WCHAR[])(line) ~ '\0').ptr;
4043         int numArgs;
4044         auto args = CommandLineToArgvW(lpCommandLine, &numArgs);
4045         scope(exit) LocalFree(args);
4046         return args[0 .. numArgs]
4047             .map!(arg => to!string(arg[0 .. wcslen(arg)]))
4048             .array();
4049     }
4050 
4051     @system unittest
4052     {
4053         import std.conv : text;
4054         string[] testStrings = [
4055             `Hello`,
4056             `Hello, world`,
4057             `Hello, "world"`,
4058             `C:\`,
4059             `C:\dmd`,
4060             `C:\Program Files\`,
4061         ];
4062 
4063         enum CHARS = `_x\" *&^` ~ "\t"; // _ is placeholder for nothing
4064         foreach (c1; CHARS)
4065         foreach (c2; CHARS)
4066         foreach (c3; CHARS)
4067         foreach (c4; CHARS)
4068             testStrings ~= [c1, c2, c3, c4].replace("_", "");
4069 
4070         foreach (s; testStrings)
4071         {
4072             auto q = escapeWindowsArgument(s);
4073             auto args = parseCommandLine("Dummy.exe " ~ q);
4074             assert(args.length == 2, s ~ " => " ~ q ~ " #" ~ text(args.length-1));
4075             assert(args[1] == s, s ~ " => " ~ q ~ " => " ~ args[1]);
4076         }
4077     }
4078 }
4079 
4080 private string escapePosixArgument(scope const(char)[] arg) @trusted pure nothrow
4081 {
4082     import std.exception : assumeUnique;
4083     auto buf = escapePosixArgumentImpl!charAllocator(arg);
4084     return assumeUnique(buf);
4085 }
4086 
4087 private char[] escapePosixArgumentImpl(alias allocator)(scope const(char)[] arg)
4088     @safe nothrow
4089 if (is(typeof(allocator(size_t.init)[0] = char.init)))
4090 {
4091     bool needQuoting = {
4092         import std.ascii : isAlphaNum, isDigit;
4093         import std.algorithm.comparison : among;
4094 
4095         // Empty arguments need to be specified as ''
4096         if (arg.length == 0)
4097             return true;
4098         // Arguments ending with digits need to be escaped,
4099         // to disambiguate with 1>file redirection syntax
4100         if (isDigit(arg[$-1]))
4101             return true;
4102 
4103         // Obtained using:
4104         // for n in $(seq 1 255) ; do
4105         //     c=$(printf \\$(printf "%o" $n))
4106         //     q=$(/bin/printf '%q' "$c")
4107         //     if [[ "$q" == "$c" ]] ; then printf "%s, " "'$c'" ; fi
4108         // done
4109         // printf '\n'
4110         foreach (char c; arg)
4111             if (!isAlphaNum(c) && !c.among('%', '+', ',', '-', '.', '/', ':', '@', ']', '_'))
4112                 return true;
4113         return false;
4114     }();
4115     if (!needQuoting)
4116     {
4117         auto buf = allocator(arg.length);
4118         buf[] = arg;
4119         return buf;
4120     }
4121 
4122     // '\'' means: close quoted part of argument, append an escaped
4123     // single quote, and reopen quotes
4124 
4125     // Below code is equivalent to:
4126     // return `'` ~ std.array.replace(arg, `'`, `'\''`) ~ `'`;
4127 
4128     size_t size = 1 + arg.length + 1;
4129     foreach (char c; arg)
4130         if (c == '\'')
4131             size += 3;
4132 
4133     auto buf = allocator(size);
4134     size_t p = 0;
4135     buf[p++] = '\'';
4136     foreach (char c; arg)
4137         if (c == '\'')
4138         {
4139             buf[p .. p+4] = `'\''`;
4140             p += 4;
4141         }
4142         else
4143             buf[p++] = c;
4144     buf[p++] = '\'';
4145     assert(p == size);
4146 
4147     return buf;
4148 }
4149 
4150 /**
4151 Escapes a filename to be used for shell redirection with $(LREF spawnShell),
4152 $(LREF pipeShell) or $(LREF executeShell).
4153 */
4154 string escapeShellFileName(scope const(char)[] fileName) @trusted pure nothrow
4155 {
4156     // The unittest for this function requires special
4157     // preparation - see below.
4158 
4159     version (Windows)
4160     {
4161         // If a file starts with &, it can cause cmd.exe to misinterpret
4162         // the file name as the stream redirection syntax:
4163         //     command > "&foo.txt"
4164         // gets interpreted as
4165         //     command >&foo.txt
4166         // Prepend .\ to disambiguate.
4167 
4168         if (fileName.length && fileName[0] == '&')
4169             return cast(string)(`".\` ~ fileName ~ '"');
4170 
4171         return cast(string)('"' ~ fileName ~ '"');
4172     }
4173     else
4174         return escapePosixArgument(fileName);
4175 }
4176 
4177 // Loop generating strings with random characters
4178 //version = unittest_burnin;
4179 
4180 version (unittest_burnin)
4181 @system unittest
4182 {
4183     // There are no readily-available commands on all platforms suitable
4184     // for properly testing command escaping. The behavior of CMD's "echo"
4185     // built-in differs from the POSIX program, and Windows ports of POSIX
4186     // environments (Cygwin, msys, gnuwin32) may interfere with their own
4187     // "echo" ports.
4188 
4189     // To run this unit test, create std_process_unittest_helper.d with the
4190     // following content and compile it:
4191     // import std.stdio, std.array; void main(string[] args) { write(args.join("\0")); }
4192     // Then, test this module with:
4193     // rdmd --main -unittest -version=unittest_burnin process.d
4194 
4195     import std.file : readText, remove;
4196     import std.format : format;
4197     import std.path : absolutePath;
4198     import std.random : uniform;
4199 
4200     auto helper = absolutePath("std_process_unittest_helper");
4201     assert(executeShell(helper ~ " hello").output.split("\0")[1..$] == ["hello"], "Helper malfunction");
4202 
4203     void test(string[] s, string fn)
4204     {
4205         string e;
4206         string[] g;
4207 
4208         e = escapeShellCommand(helper ~ s);
4209         {
4210             scope(failure) writefln("executeShell() failed.\nExpected:\t%s\nEncoded:\t%s", s, [e]);
4211             auto result = executeShell(e);
4212             assert(result.status == 0, "std_process_unittest_helper failed");
4213             g = result.output.split("\0")[1..$];
4214         }
4215         assert(s == g, format("executeShell() test failed.\nExpected:\t%s\nGot:\t\t%s\nEncoded:\t%s", s, g, [e]));
4216 
4217         e = escapeShellCommand(helper ~ s) ~ ">" ~ escapeShellFileName(fn);
4218         {
4219             scope(failure) writefln(
4220                 "executeShell() with redirect failed.\nExpected:\t%s\nFilename:\t%s\nEncoded:\t%s", s, [fn], [e]);
4221             auto result = executeShell(e);
4222             assert(result.status == 0, "std_process_unittest_helper failed");
4223             assert(!result.output.length, "No output expected, got:\n" ~ result.output);
4224             g = readText(fn).split("\0")[1..$];
4225         }
4226         remove(fn);
4227         assert(s == g,
4228             format("executeShell() with redirect test failed.\nExpected:\t%s\nGot:\t\t%s\nEncoded:\t%s", s, g, [e]));
4229     }
4230 
4231     while (true)
4232     {
4233         string[] args;
4234         foreach (n; 0 .. uniform(1, 4))
4235         {
4236             string arg;
4237             foreach (l; 0 .. uniform(0, 10))
4238             {
4239                 dchar c;
4240                 while (true)
4241                 {
4242                     version (Windows)
4243                     {
4244                         // As long as DMD's system() uses CreateProcessA,
4245                         // we can't reliably pass Unicode
4246                         c = uniform(0, 128);
4247                     }
4248                     else
4249                         c = uniform!ubyte();
4250 
4251                     if (c == 0)
4252                         continue; // argv-strings are zero-terminated
4253                     version (Windows)
4254                         if (c == '\r' || c == '\n')
4255                             continue; // newlines are unescapable on Windows
4256                     break;
4257                 }
4258                 arg ~= c;
4259             }
4260             args ~= arg;
4261         }
4262 
4263         // generate filename
4264         string fn;
4265         foreach (l; 0 .. uniform(1, 10))
4266         {
4267             dchar c;
4268             while (true)
4269             {
4270                 version (Windows)
4271                     c = uniform(0, 128); // as above
4272                 else
4273                     c = uniform!ubyte();
4274 
4275                 if (c == 0 || c == '/')
4276                     continue; // NUL and / are the only characters
4277                               // forbidden in POSIX filenames
4278                 version (Windows)
4279                     if (c < '\x20' || c == '<' || c == '>' || c == ':' ||
4280                         c == '"' || c == '\\' || c == '|' || c == '?' || c == '*')
4281                         continue; // http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx
4282                 break;
4283             }
4284 
4285             fn ~= c;
4286         }
4287         fn = fn[0..$/2] ~ "_testfile_" ~ fn[$/2..$];
4288 
4289         test(args, fn);
4290     }
4291 }
4292 
4293 // =============================================================================
4294 // Everything below this line was part of the old std.process, and most of
4295 // it will be deprecated and removed.
4296 // =============================================================================
4297 
4298 
4299 /*
4300 Copyright: Copyright The D Language Foundation 2007 - 2009.
4301 License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
4302 Authors:   $(HTTP digitalmars.com, Walter Bright),
4303            $(HTTP erdani.org, Andrei Alexandrescu),
4304            $(HTTP thecybershadow.net, Vladimir Panteleev)
4305 Source:    $(PHOBOSSRC std/_process.d)
4306 */
4307 /*
4308          Copyright The D Language Foundation 2007 - 2009.
4309 Distributed under the Boost Software License, Version 1.0.
4310    (See accompanying file LICENSE_1_0.txt or copy at
4311          http://www.boost.org/LICENSE_1_0.txt)
4312 */
4313 
4314 
4315 import core.stdc.errno;
4316 import core.stdc.stdlib;
4317 import core.stdc.string;
4318 import core.thread;
4319 
4320 version (Windows)
4321 {
4322     import std.file, std.format, std.random;
4323 }
4324 version (Posix)
4325 {
4326     import core.sys.posix.stdlib;
4327 }
4328 
4329 private const(char)** toAStringz(in string[] a)
4330 {
4331     import std.string : toStringz;
4332     auto p = (new const(char)*[1 + a.length]).ptr;
4333     foreach (i, string s; a)
4334         p[i] = toStringz(s);
4335     p[a.length] = null;
4336     return p;
4337 }
4338 
4339 
4340 /* ========================================================== */
4341 
4342 //version (Windows)
4343 //{
4344 //    int spawnvp(int mode, string pathname, string[] argv)
4345 //    {
4346 //      char** argv_ = cast(char**) core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length));
4347 //      scope(exit) core.stdc.stdlib.free(argv_);
4348 //
4349 //      toAStringz(argv, argv_);
4350 //
4351 //      return spawnvp(mode, pathname.tempCString(), argv_);
4352 //    }
4353 //}
4354 
4355 // Incorporating idea (for spawnvp() on Posix) from Dave Fladebo
4356 
4357 enum { _P_WAIT, _P_NOWAIT, _P_OVERLAY }
4358 version (Windows) extern(C) int spawnvp(int, scope const(char) *, scope const(char*)*);
4359 alias P_WAIT = _P_WAIT;
4360 alias P_NOWAIT = _P_NOWAIT;
4361 
4362 /* ========================================================== */
4363 
4364 version (StdDdoc)
4365 {
4366     /**
4367     Replaces the current process by executing a command, `pathname`, with
4368     the arguments in `argv`.
4369 
4370     $(BLUE This function is Posix-Only.)
4371 
4372     Typically, the first element of `argv` is
4373     the command being executed, i.e. $(D argv[0] == pathname). The 'p'
4374     versions of `exec` search the PATH environment variable for $(D
4375     pathname). The 'e' versions additionally take the new process'
4376     environment variables as an array of strings of the form key=value.
4377 
4378     Does not return on success (the current process will have been
4379     replaced). Returns -1 on failure with no indication of the
4380     underlying error.
4381 
4382     Windows_specific:
4383     These functions are only supported on POSIX platforms, as the Windows
4384     operating systems do not provide the ability to overwrite the current
4385     process image with another. In single-threaded programs it is possible
4386     to approximate the effect of `execv*` by using $(LREF spawnProcess)
4387     and terminating the current process once the child process has returned.
4388     For example:
4389     ---
4390     auto commandLine = [ "program", "arg1", "arg2" ];
4391     version (Posix)
4392     {
4393         execv(commandLine[0], commandLine);
4394         throw new Exception("Failed to execute program");
4395     }
4396     else version (Windows)
4397     {
4398         import core.stdc.stdlib : _Exit;
4399         _Exit(wait(spawnProcess(commandLine)));
4400     }
4401     ---
4402     This is, however, NOT equivalent to POSIX' `execv*`.  For one thing, the
4403     executed program is started as a separate process, with all this entails.
4404     Secondly, in a multithreaded program, other threads will continue to do
4405     work while the current thread is waiting for the child process to complete.
4406 
4407     A better option may sometimes be to terminate the current program immediately
4408     after spawning the child process.  This is the behaviour exhibited by the
4409     $(LINK2 http://msdn.microsoft.com/en-us/library/431x4c1w.aspx,`__exec`)
4410     functions in Microsoft's C runtime library, and it is how D's now-deprecated
4411     Windows `execv*` functions work. Example:
4412     ---
4413     auto commandLine = [ "program", "arg1", "arg2" ];
4414     version (Posix)
4415     {
4416         execv(commandLine[0], commandLine);
4417         throw new Exception("Failed to execute program");
4418     }
4419     else version (Windows)
4420     {
4421         spawnProcess(commandLine);
4422         import core.stdc.stdlib : _exit;
4423         _exit(0);
4424     }
4425     ---
4426     */
4427     int execv(in string pathname, in string[] argv);
4428     ///ditto
4429     int execve(in string pathname, in string[] argv, in string[] envp);
4430     /// ditto
4431     int execvp(in string pathname, in string[] argv);
4432     /// ditto
4433     int execvpe(in string pathname, in string[] argv, in string[] envp);
4434 }
4435 else version (Posix)
4436 {
4437     int execv(in string pathname, in string[] argv)
4438     {
4439         return execv_(pathname, argv);
4440     }
4441     int execve(in string pathname, in string[] argv, in string[] envp)
4442     {
4443         return execve_(pathname, argv, envp);
4444     }
4445     int execvp(in string pathname, in string[] argv)
4446     {
4447         return execvp_(pathname, argv);
4448     }
4449     int execvpe(in string pathname, in string[] argv, in string[] envp)
4450     {
4451         return execvpe_(pathname, argv, envp);
4452     }
4453 }
4454 
4455 // Move these C declarations to druntime if we decide to keep the D wrappers
4456 extern(C)
4457 {
4458     int execv(scope const(char) *, scope const(char *)*);
4459     int execve(scope const(char)*, scope const(char*)*, scope const(char*)*);
4460     int execvp(scope const(char)*, scope const(char*)*);
4461     version (Windows) int execvpe(scope const(char)*, scope const(char*)*, scope const(char*)*);
4462 }
4463 
4464 private int execv_(in string pathname, in string[] argv)
4465 {
4466     return execv(pathname.tempCString(), toAStringz(argv));
4467 }
4468 
4469 private int execve_(in string pathname, in string[] argv, in string[] envp)
4470 {
4471     return execve(pathname.tempCString(), toAStringz(argv), toAStringz(envp));
4472 }
4473 
4474 private int execvp_(in string pathname, in string[] argv)
4475 {
4476     return execvp(pathname.tempCString(), toAStringz(argv));
4477 }
4478 
4479 private int execvpe_(in string pathname, in string[] argv, in string[] envp)
4480 {
4481 version (Posix)
4482 {
4483     import std.array : split;
4484     import std.conv : to;
4485     // Is pathname rooted?
4486     if (pathname[0] == '/')
4487     {
4488         // Yes, so just call execve()
4489         return execve(pathname, argv, envp);
4490     }
4491     else
4492     {
4493         // No, so must traverse PATHs, looking for first match
4494         string[]    envPaths    =   split(
4495             to!string(core.stdc.stdlib.getenv("PATH")), ":");
4496         int         iRet        =   0;
4497 
4498         // Note: if any call to execve() succeeds, this process will cease
4499         // execution, so there's no need to check the execve() result through
4500         // the loop.
4501 
4502         foreach (string pathDir; envPaths)
4503         {
4504             string  composite   =  cast(string) (pathDir ~ "/" ~ pathname);
4505 
4506             iRet = execve(composite, argv, envp);
4507         }
4508         if (0 != iRet)
4509         {
4510             iRet = execve(pathname, argv, envp);
4511         }
4512 
4513         return iRet;
4514     }
4515 }
4516 else version (Windows)
4517 {
4518     return execvpe(pathname.tempCString(), toAStringz(argv), toAStringz(envp));
4519 }
4520 else
4521 {
4522     static assert(0);
4523 } // version
4524 }
4525 
4526 version (StdDdoc)
4527 {
4528     /****************************************
4529      * Start up the browser and set it to viewing the page at url.
4530      */
4531     void browse(scope const(char)[] url);
4532 }
4533 else
4534 version (Windows)
4535 {
4536     import core.sys.windows.shellapi, core.sys.windows.winuser;
4537 
4538     pragma(lib,"shell32.lib");
4539 
4540     void browse(scope const(char)[] url) nothrow @nogc @trusted
4541     {
4542         ShellExecuteW(null, "open", url.tempCStringW(), null, null, SW_SHOWNORMAL);
4543     }
4544 }
4545 else version (Posix)
4546 {
4547     import core.stdc.stdio;
4548     import core.stdc.string;
4549     import core.sys.posix.unistd;
4550 
4551     void browse(scope const(char)[] url) nothrow @nogc @safe
4552     {
4553         const buffer = url.tempCString(); // Retain buffer until end of scope
4554         const(char)*[3] args;
4555 
4556         // Trusted because it's called with a zero-terminated literal
4557         const(char)* browser = (() @trusted => core.stdc.stdlib.getenv("BROWSER"))();
4558         if (browser)
4559         {
4560             // String already zero-terminated
4561             browser = (() @trusted => strdup(browser))();
4562             args[0] = browser;
4563         }
4564         else
4565         {
4566             version (OSX)
4567             {
4568                 args[0] = "open";
4569             }
4570             else
4571             {
4572                 //args[0] = "x-www-browser";  // doesn't work on some systems
4573                 args[0] = "xdg-open";
4574             }
4575         }
4576 
4577         args[1] = buffer;
4578         args[2] = null;
4579 
4580         auto childpid = core.sys.posix.unistd.fork();
4581         if (childpid == 0)
4582         {
4583             // Trusted because args and all entries are always zero-terminated
4584             (() @trusted {
4585                 core.sys.posix.unistd.execvp(args[0], &args[0]);
4586                 perror(args[0]);
4587                 core.sys.posix.unistd._exit(1);
4588             })();
4589             assert(0, "Child failed to exec");
4590         }
4591         if (browser)
4592             // Trusted because it's allocated via strdup above
4593             (() @trusted => free(cast(void*) browser))();
4594 
4595         version (StdUnittest)
4596         {
4597             // Verify that the test script actually suceeds
4598             int status;
4599             const check = (() @trusted => waitpid(childpid, &status, 0))();
4600             assert(check != -1);
4601             assert(status == 0);
4602         }
4603     }
4604 }
4605 else
4606     static assert(0, "os not supported");
4607 
4608 // Verify attributes are consistent between all implementations
4609 @safe @nogc nothrow unittest
4610 {
4611     if (false)
4612         browse("");
4613 }
4614 
4615 version (Windows) { /* Doesn't use BROWSER */ }
4616 else
4617 @system unittest
4618 {
4619     import std.conv : text;
4620     import std.range : repeat;
4621     immutable string url = text("http://", repeat('x', 249));
4622 
4623     TestScript prog = `if [ "$1" != "` ~ url ~ `" ]; then exit 1; fi`;
4624     environment["BROWSER"] = prog.path;
4625     browse(url);
4626 }