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