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