The OpenD Programming Language

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