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