1 // Written in the D programming language.
4 Functions for starting and interacting with other processes, and for
5 working with the current _process' execution environment.
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).)
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.)
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.)
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.)
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.)
40 $(LREF kill) attempts to terminate a running _process.)
43 The following table compactly summarises the different _process creation
44 functions and how they relate to each other:
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)
57 $(TD $(LREF executeShell)))
63 $(LREF pipe) is used to create unidirectional pipes.)
65 $(LREF environment) is an interface through which the current _process'
66 environment variables can be read and manipulated.)
68 $(LREF escapeShellCommand) and $(LREF escapeShellFileName) are useful
69 for constructing shell command lines in a portable way.)
73 $(LINK2 https://github.com/kyllingstad, Lars Tandle Kyllingstad),
74 $(LINK2 https://github.com/schveiguy, Steven Schveighoffer),
75 $(HTTP thecybershadow.net, Vladimir Panteleev)
77 Copyright (c) 2013, the authors. All rights reserved.
79 $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
81 $(PHOBOSSRC std/_process.d)
83 OBJECTREF=$(D $(LINK2 object.html#$0,$0))
84 LREF=$(D $(LINK2 #.$0,$0))
90 import core.sys.posix.sys.wait;
91 import core.sys.posix.unistd;
95 import core.stdc.stdio;
96 import core.sys.windows.windows;
98 import std.windows.syserror;
101 import std.internal.cstring;
102 import std.range.primitives;
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;
111 // Some of the following should be moved to druntime.
114 // Microsoft Visual C Runtime (MSVCRT) declarations.
117 version (DMC_RUNTIME) { } else
119 import core.stdc.stdint;
129 // POSIX API declarations.
134 extern(C) char*** _NSGetEnviron() nothrow;
135 const(char**) getEnvironPtr() @trusted
137 return *_NSGetEnviron;
142 // Made available by the C runtime:
143 extern(C) extern __gshared const char** environ;
144 const(char**) getEnvironPtr() @trusted
152 new Thread({assert(getEnvironPtr !is null);}).start();
158 // =============================================================================
159 // Functions and classes for process management.
160 // =============================================================================
164 Spawns a new _process, optionally assigning it an arbitrary set of standard
165 input, output, and error streams.
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).
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.
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:
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.)
195 // Run an executable called "prog" located in the current working
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.
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!");
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.
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).
219 wait(spawnProcess("myapp", ["foo" : "bar"], Config.newEnv));
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.
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"],
238 writeln("Compilation failed. See errors.log for details.");
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.
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.
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
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
276 A $(LREF Pid) object that corresponds to the spawned process.
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.
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
293 version (Windows) auto args2 = escapeShellArguments(args);
294 else version (Posix) alias args2 = args;
295 return spawnProcessImpl(args2, stdin, stdout, stderr, env, config, workDir);
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
305 return spawnProcess(args,
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)
324 return spawnProcess((&program)[0 .. 1],
325 stdin, stdout, stderr, env, config, workDir);
329 Pid spawnProcess(in char[] program,
330 const string[string] env,
331 Config config = Config.none,
332 in char[] workDir = null)
335 return spawnProcess((&program)[0 .. 1], env, config, workDir);
338 version (Posix) private enum InternalError : ubyte
348 Implementation of spawnProcess() for POSIX.
350 envz should be a zero-terminated array of zero-terminated strings
351 on the form "var=value".
354 private Pid spawnProcessImpl(in char[][] args,
358 const string[string] env,
361 @trusted // TODO: Should be @safe
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;
369 if (args.empty) throw new RangeError();
370 const(char)[] name = args[0];
371 if (any!isDirSeparator(name))
373 if (!isExecutable(name))
374 throw new ProcessException(text("Not an executable file: ", name));
378 name = searchPathFor(name);
380 throw new ProcessException(text("Executable file not found: ", args[0]));
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]);
389 // Prepare environment.
390 auto envz = createEnv(env, !(config & Config.newEnv));
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.
397 scope(exit) if (workDirFD >= 0) close(workDirFD);
400 import core.sys.posix.fcntl : open, O_RDONLY, stat_t, fstat, S_ISDIR;
401 workDirFD = open(workDir.tempCString(), O_RDONLY);
403 throw ProcessException.newFromErrno("Failed to open working directory");
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);
411 static int getFD(ref File f) { return core.stdc.stdio.fileno(f.getFP()); }
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);
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.
423 if (core.sys.posix.unistd.pipe(forkPipe) == 0)
424 setCLOEXEC(forkPipe[1], true);
426 throw ProcessException.newFromErrno("Could not create pipe to check startup of child");
427 scope(exit) close(forkPipe[0]);
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.
437 if (config & Config.detached)
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);
443 scope(exit) if (config & Config.detached) close(pidPipe[0]);
445 static void abortOnError(int forkPipeOut, InternalError errorType, int error) nothrow
447 core.sys.posix.unistd.write(forkPipeOut, &errorType, errorType.sizeof);
448 core.sys.posix.unistd.write(forkPipeOut, &error, error.sizeof);
450 core.sys.posix.unistd._exit(1);
454 void closePipeWriteEnds()
457 if (config & Config.detached)
461 auto id = core.sys.posix.unistd.fork();
464 closePipeWriteEnds();
465 throw ProcessException.newFromErrno("Failed to spawn new process");
468 void forkChild() nothrow @nogc
470 static import core.sys.posix.stdio;
471 pragma(inline, true);
475 // no need for the read end of pipe on child side
476 if (config & Config.detached)
479 immutable forkPipeOut = forkPipe[1];
480 immutable pidPipeOut = pidPipe[1];
482 // Set the working directory.
485 if (fchdir(workDirFD) < 0)
487 // Fail. It is dangerous to run a program
488 // in an unexpected working directory.
489 abortOnError(forkPipeOut, InternalError.chdir, .errno);
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
500 if (stderrFD == STDOUT_FILENO) stderrFD = dup(stderrFD);
501 dup2(stdinFD, STDIN_FILENO);
502 dup2(stdoutFD, STDOUT_FILENO);
503 dup2(stderrFD, STDERR_FILENO);
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);
511 if (!(config & Config.inheritFDs))
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;
517 // Get the maximum number of file descriptors that could be open.
519 if (getrlimit(RLIMIT_NOFILE, &r) != 0)
521 abortOnError(forkPipeOut, InternalError.getrlimit, .errno);
523 immutable maxDescriptors = cast(int) r.rlim_cur;
525 // The above, less stdin, stdout, and stderr
526 immutable maxToClose = maxDescriptors - 3;
528 // Call poll() to see which ones are actually open:
529 auto pfds = cast(pollfd*) malloc(pollfd.sizeof * maxToClose);
530 foreach (i; 0 .. maxToClose)
536 if (poll(pfds, maxToClose, 0) >= 0)
538 foreach (i; 0 .. maxToClose)
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);
548 // Fall back to closing everything.
549 foreach (i; 3 .. maxDescriptors)
551 if (i == forkPipeOut) continue;
556 else // This is already done if we don't inherit descriptors.
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);
566 core.sys.posix.unistd.execve(argz[0], argz.ptr, envz);
568 // If execution fails, exit as quickly as possible.
569 abortOnError(forkPipeOut, InternalError.exec, .errno);
572 if (config & Config.detached)
574 auto secondFork = core.sys.posix.unistd.fork();
580 else if (secondFork == -1)
582 auto secondForkErrno = .errno;
584 abortOnError(forkPipeOut, InternalError.doubleFork, secondForkErrno);
588 core.sys.posix.unistd.write(pidPipeOut, &secondFork, pid_t.sizeof);
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;
613 if (config & Config.detached)
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;
618 waitpid(id, &waitResult, 0);
621 if (readExecResult == -1)
622 throw ProcessException.newFromErrno(lastError, "Could not read from pipe to get child status");
625 if (status != InternalError.noerror)
628 readExecResult = read(forkPipe[0], &error, error.sizeof);
630 final switch (status)
632 case InternalError.chdir:
633 errorMsg = "Failed to set working directory";
635 case InternalError.getrlimit:
636 errorMsg = "getrlimit failed";
638 case InternalError.exec:
639 errorMsg = "Failed to execute program";
641 case InternalError.doubleFork:
642 // Can happen only when starting detached process
643 assert(config & Config.detached);
644 errorMsg = "Failed to fork twice";
646 case InternalError.noerror:
649 if (readExecResult == error.sizeof)
650 throw ProcessException.newFromErrno(error, errorMsg);
651 throw new ProcessException(errorMsg);
653 else if (config & Config.detached)
656 if (read(pidPipe[0], &id, id.sizeof) != id.sizeof)
657 throw ProcessException.newFromErrno("Could not read from pipe to get detached process id");
660 // Parent process: Close streams and return.
661 if (!(config & Config.retainStdin ) && stdinFD > STDERR_FILENO
662 && stdinFD != getFD(std.stdio.stdin ))
664 if (!(config & Config.retainStdout) && stdoutFD > STDERR_FILENO
665 && stdoutFD != getFD(std.stdio.stdout))
667 if (!(config & Config.retainStderr) && stderrFD > STDERR_FILENO
668 && stderrFD != getFD(std.stdio.stderr))
670 return new Pid(id, owned);
675 Implementation of spawnProcess() for Windows.
677 commandLine must contain the entire command line, properly
678 quoted/escaped as required by CreateProcessW().
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".
684 private Pid spawnProcessImpl(in char[] commandLine,
688 const string[string] env,
693 import core.exception : RangeError;
695 if (commandLine.empty) throw new RangeError("Command line is empty");
697 // Prepare environment.
698 auto envz = createEnv(env, !(config & Config.newEnv));
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; }
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)
710 fileDescriptor = getFD(file);
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);
719 if (GetHandleInformation(handle, &dwFlags))
721 if (!(dwFlags & HANDLE_FLAG_INHERIT))
723 if (!SetHandleInformation(handle,
725 HANDLE_FLAG_INHERIT))
727 throw new StdioException(
728 "Failed to make "~which~" stream inheritable by child process ("
729 ~sysErrorString(GetLastError()) ~ ')',
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 );
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;
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");
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 ))
759 if (!(config & Config.retainStdout) && stdoutFD > STDERR_FILENO
760 && stdoutFD != getFD(std.stdio.stdout))
762 if (!(config & Config.retainStderr) && stderrFD > STDERR_FILENO
763 && stderrFD != getFD(std.stdio.stderr))
766 // close the thread handle in the process info structure
767 CloseHandle(pi.hThread);
768 if (config & Config.detached)
770 CloseHandle(pi.hProcess);
771 return new Pid(pi.dwProcessId);
773 return new Pid(pi.dwProcessId, pi.hProcess);
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.
782 private const(char*)* createEnv(const string[string] childEnv,
783 bool mergeWithParentEnv)
785 // Determine the number of strings in the parent's environment.
786 int parentEnvLength = 0;
787 auto environ = getEnvironPtr;
788 if (mergeWithParentEnv)
790 if (childEnv.length == 0) return environ;
791 while (environ[parentEnvLength] != null) ++parentEnvLength;
794 // Convert the "new" variables to C-style strings.
795 auto envz = new const(char)*[parentEnvLength + childEnv.length + 1];
797 foreach (var, val; childEnv)
798 envz[pos++] = (var~'='~val~'\0').ptr;
800 // Add the parent's environment.
801 foreach (environStr; environ[0 .. parentEnvLength])
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;
814 version (Posix) @system unittest
816 auto e1 = createEnv(null, false);
817 assert(e1 != null && *e1 == null);
819 auto e2 = createEnv(null, true);
822 auto environ = getEnvironPtr;
823 for (; environ[i] != null; ++i)
825 assert(e2[i] != null);
826 import core.stdc.string;
827 assert(strcmp(e2[i], environ[i]) == 0);
829 assert(e2[i] == null);
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"));
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
845 private LPVOID createEnv(const string[string] childEnv,
846 bool mergeWithParentEnv)
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)
857 envz.put(cast(wchar) '\0');
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)
865 auto uk = toUpper(k);
867 if (uk in parentEnv) parentEnv.remove(uk);
870 // Add remaining parent environment variables.
871 foreach (k, v; parentEnv) put(k, v);
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.
876 return envz.data.ptr;
879 version (Windows) @system unittest
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);
887 // Searches the PATH variable for the given executable file,
888 // (checking that it is in fact executable).
890 private string searchPathFor(in char[] executable)
891 @trusted //TODO: @safe nothrow
893 import std.algorithm.iteration : splitter;
894 import std.conv : to;
895 import std.path : buildPath;
897 auto pathz = core.stdc.stdlib.getenv("PATH");
898 if (pathz == null) return null;
900 foreach (dir; splitter(to!string(pathz), ':'))
902 auto execPath = buildPath(dir, executable);
903 if (isExecutable(execPath)) return execPath;
909 // Checks whether the file exists and can be executed by the
912 private bool isExecutable(in char[] path) @trusted nothrow @nogc //TODO: @safe
914 return (access(path.tempCString(), X_OK) == 0);
917 version (Posix) @safe unittest
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?");
928 // Sets or unsets the FD_CLOEXEC flag on the given file descriptor.
930 private void setCLOEXEC(int fd, bool on) nothrow @nogc
932 import core.sys.posix.fcntl : fcntl, F_GETFD, FD_CLOEXEC, F_SETFD;
933 auto flags = fcntl(fd, F_GETFD);
936 if (on) flags |= FD_CLOEXEC;
937 else flags &= ~(cast(typeof(flags)) FD_CLOEXEC);
938 flags = fcntl(fd, F_SETFD, flags);
940 assert(flags != -1 || .errno == EBADF);
943 @system unittest // Command line arguments in spawnProcess().
945 version (Windows) TestScript prog =
946 "if not [%~1]==[foo] ( exit 1 )
947 if not [%~2]==[bar] ( exit 2 )
949 else version (Posix) TestScript prog =
950 `if test "$1" != "foo"; then exit 1; fi
951 if test "$2" != "bar"; then exit 2; fi
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);
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
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;
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);
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
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);
990 // try /proc/<pid>/fd/ on linux
993 TestScript proc = "ls /proc/$$/fd";
994 auto procRes = execute(proc.path, null);
995 if (procRes.status == 0)
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));
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)
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));
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)
1022 assert(!lsofRes.output.canFind(path));
1023 assert(execute(lsof.path, null, Config.inheritFDs).output.canFind(path));
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
1033 @system unittest // Environment variables in spawnProcess().
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)
1041 if [%STD_PROCESS_UNITTEST1%] == [4] (
1042 if [%STD_PROCESS_UNITTEST2%] == [2] (exit 6)
1045 if [%STD_PROCESS_UNITTEST2%] == [2] (exit 2)
1047 version (Posix) TestScript envProg =
1048 `if test "$std_process_unittest1" = ""; then
1049 std_process_unittest1=0
1051 if test "$std_process_unittest2" = ""; then
1052 std_process_unittest2=0
1054 exit $(($std_process_unittest1+$std_process_unittest2))`;
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);
1061 environment["std_process_unittest1"] = "1";
1062 assert(wait(spawnProcess(envProg.path)) == 1);
1063 assert(wait(spawnProcess(envProg.path, null, Config.newEnv)) == 0);
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);
1069 env["std_process_unittest1"] = "4";
1070 assert(wait(spawnProcess(envProg.path, env)) == 6);
1071 assert(wait(spawnProcess(envProg.path, env, Config.newEnv)) == 6);
1073 environment.remove("std_process_unittest1");
1074 assert(wait(spawnProcess(envProg.path, env)) == 6);
1075 assert(wait(spawnProcess(envProg.path, env, Config.newEnv)) == 6);
1078 @system unittest // Stream redirection in spawnProcess().
1080 import std.path : buildPath;
1082 version (Windows) TestScript prog =
1084 echo %INPUT% output %~1
1085 echo %INPUT% error %~2 1>&2";
1086 else version (Posix) TestScript prog =
1088 echo $INPUT output $1
1089 echo $INPUT error $2 >&2";
1092 void testPipes(Config config)
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))
1108 void testFiles(Config config)
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))
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");
1131 testPipes(Config.none);
1132 testFiles(Config.none);
1133 testPipes(Config.detached);
1134 testFiles(Config.detached);
1137 @system unittest // Error handling in spawnProcess()
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));
1145 // can't execute malformed file with executable permissions
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));
1160 @system unittest // Specifying a working directory.
1163 TestScript prog = "echo foo>bar";
1165 auto directory = uniqueTempPath();
1167 scope(exit) rmdirRecurse(directory);
1169 auto pid = spawnProcess([prog.path], null, Config.none, directory);
1171 assert(exists(buildPath(directory, "bar")));
1174 @system unittest // Specifying a bad working directory.
1176 import std.exception : assertThrown;
1177 TestScript prog = "echo";
1179 auto directory = uniqueTempPath();
1180 assertThrown!ProcessException(spawnProcess([prog.path], null, Config.none, directory));
1181 assertThrown!ProcessException(spawnProcess([prog.path], null, Config.detached, directory));
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));
1188 // can't run in directory if user does not have search permission on this directory
1191 import core.sys.posix.sys.stat : S_IRUSR;
1192 auto directoryNoSearch = uniqueTempPath();
1193 mkdir(directoryNoSearch);
1194 scope(exit) rmdirRecurse(directoryNoSearch);
1195 setAttributes(directoryNoSearch, S_IRUSR);
1196 assertThrown!ProcessException(spawnProcess(prog.path, null, Config.none, directoryNoSearch));
1197 assertThrown!ProcessException(spawnProcess(prog.path, null, Config.detached, directoryNoSearch));
1201 @system unittest // Specifying empty working directory.
1203 TestScript prog = "";
1205 string directory = "";
1206 assert(directory.ptr && !directory.length);
1207 spawnProcess([prog.path], null, Config.none, directory).wait();
1210 @system unittest // Reopening the standard streams (issue 13258)
1215 spawnShell("echo foo").wait();
1216 spawnShell("echo bar").wait();
1219 auto tmpFile = uniqueTempPath();
1220 scope(exit) if (exists(tmpFile)) remove(tmpFile);
1223 auto oldOut = std.stdio.stdout;
1224 scope(exit) std.stdio.stdout = oldOut;
1226 std.stdio.stdout = File(tmpFile, "w");
1228 std.stdio.stdout.close();
1231 auto lines = readText(tmpFile).splitLines();
1232 assert(lines == ["foo", "bar"]);
1236 @system unittest // MSVCRT workaround (issue 14422)
1238 auto fn = uniqueTempPath();
1239 std.file.write(fn, "AAAAAAAAAA");
1241 auto f = File(fn, "a");
1242 spawnProcess(["cmd", "/c", "echo BBBBB"], std.stdio.stdin, f).wait();
1244 auto data = readText(fn);
1245 assert(data == "AAAAAAAAAABBBBB\r\n", data);
1249 A variation on $(LREF spawnProcess) that runs the given _command through
1250 the current user's preferred _command interpreter (aka. shell).
1252 The string $(D command) is passed verbatim to the shell, and is therefore
1253 subject to its rules about _command structure, argument/filename quoting
1254 and escaping of special characters.
1255 The path to the shell executable defaults to $(LREF nativeShell).
1257 In all other respects this function works just like $(D spawnProcess).
1258 Please refer to the $(LREF spawnProcess) documentation for descriptions
1259 of the other function parameters, the return value and any exceptions
1262 // Run the command/program "foo" on the file named "my file.txt", and
1263 // redirect its output into foo.log.
1264 auto pid = spawnShell(`foo "my file.txt" > foo.log`);
1269 $(LREF escapeShellCommand), which may be helpful in constructing a
1270 properly quoted and escaped shell _command line for the current platform.
1272 Pid spawnShell(in char[] command,
1273 File stdin = std.stdio.stdin,
1274 File stdout = std.stdio.stdout,
1275 File stderr = std.stdio.stderr,
1276 const string[string] env = null,
1277 Config config = Config.none,
1278 in char[] workDir = null,
1279 string shellPath = nativeShell)
1280 @trusted // TODO: Should be @safe
1284 // CMD does not parse its arguments like other programs.
1285 // It does not use CommandLineToArgvW.
1286 // Instead, it treats the first and last quote specially.
1287 // See CMD.EXE /? for details.
1288 auto args = escapeShellFileName(shellPath)
1289 ~ ` ` ~ shellSwitch ~ ` "` ~ command ~ `"`;
1291 else version (Posix)
1293 const(char)[][3] args;
1294 args[0] = shellPath;
1295 args[1] = shellSwitch;
1298 return spawnProcessImpl(args, stdin, stdout, stderr, env, config, workDir);
1302 Pid spawnShell(in char[] command,
1303 const string[string] env,
1304 Config config = Config.none,
1305 in char[] workDir = null,
1306 string shellPath = nativeShell)
1307 @trusted // TODO: Should be @safe
1309 return spawnShell(command,
1322 auto cmd = "echo %FOO%";
1323 else version (Posix)
1324 auto cmd = "echo $foo";
1326 auto tmpFile = uniqueTempPath();
1327 scope(exit) if (exists(tmpFile)) remove(tmpFile);
1328 auto redir = "> \""~tmpFile~'"';
1329 auto env = ["foo" : "bar"];
1330 assert(wait(spawnShell(cmd~redir, env)) == 0);
1331 auto f = File(tmpFile, "a");
1332 version (CRuntime_Microsoft) f.seek(0, SEEK_END); // MSVCRT probably seeks to the end when writing, not before
1333 assert(wait(spawnShell(cmd, std.stdio.stdin, f, std.stdio.stderr, env)) == 0);
1335 auto output = std.file.readText(tmpFile);
1336 assert(output == "bar\nbar\n" || output == "bar\r\nbar\r\n");
1343 TestScript prog = "echo %0 %*";
1344 auto outputFn = uniqueTempPath();
1345 scope(exit) if (exists(outputFn)) remove(outputFn);
1346 auto args = [`a b c`, `a\b\c\`, `a"b"c"`];
1347 auto result = executeShell(
1348 escapeShellCommand([prog.path] ~ args)
1350 escapeShellFileName(outputFn));
1351 assert(result.status == 0);
1352 auto args2 = outputFn.readText().strip().parseCommandLine()[1..$];
1353 assert(args == args2, text(args2));
1358 Flags that control the behaviour of $(LREF spawnProcess) and
1361 Use bitwise OR to combine flags.
1365 auto logFile = File("myapp_error.log", "w");
1367 // Start program, suppressing the console window (Windows only),
1368 // redirect its error stream to logFile, and leave logFile open
1369 // in the parent process as well.
1370 auto pid = spawnProcess("myapp", stdin, stdout, logFile,
1371 Config.retainStderr | Config.suppressConsole);
1374 auto exitCode = wait(pid);
1375 logFile.writeln("myapp exited with code ", exitCode);
1385 By default, the child process inherits the parent's environment,
1386 and any environment variables passed to $(LREF spawnProcess) will
1387 be added to it. If this flag is set, the only variables in the
1388 child process' environment will be those given to spawnProcess.
1393 Unless the child process inherits the standard input/output/error
1394 streams of its parent, one almost always wants the streams closed
1395 in the parent when $(LREF spawnProcess) returns. Therefore, by
1396 default, this is done. If this is not desirable, pass any of these
1397 options to spawnProcess.
1400 retainStdout = 4, /// ditto
1401 retainStderr = 8, /// ditto
1404 On Windows, if the child process is a console application, this
1405 flag will prevent the creation of a console window. Otherwise,
1406 it will be ignored. On POSIX, $(D suppressConsole) has no effect.
1408 suppressConsole = 16,
1411 On POSIX, open $(LINK2 http://en.wikipedia.org/wiki/File_descriptor,file descriptors)
1412 are by default inherited by the child process. As this may lead
1413 to subtle bugs when pipes or multiple threads are involved,
1414 $(LREF spawnProcess) ensures that all file descriptors except the
1415 ones that correspond to standard input/output/error are closed
1416 in the child process when it starts. Use $(D inheritFDs) to prevent
1419 On Windows, this option has no effect, and any handles which have been
1420 explicitly marked as inheritable will always be inherited by the child
1426 Spawn process in detached state. This removes the need in calling
1427 $(LREF wait) to clean up the process resources.
1430 Calling $(LREF wait) or $(LREF kill) with the resulting $(D Pid) is invalid.
1436 /// A handle that corresponds to a spawned process.
1440 The process ID number.
1442 This is a number that uniquely identifies the process on the operating
1443 system, for at least as long as the process is running. Once $(LREF wait)
1444 has been called on the $(LREF Pid), this method will return an
1445 invalid (negative) process ID.
1447 @property int processID() const @safe pure nothrow
1453 An operating system handle to the process.
1455 This handle is used to specify the process in OS-specific APIs.
1456 On POSIX, this function returns a $(D core.sys.posix.sys.types.pid_t)
1457 with the same value as $(LREF Pid.processID), while on Windows it returns
1458 a $(D core.sys.windows.windows.HANDLE).
1460 Once $(LREF wait) has been called on the $(LREF Pid), this method
1461 will return an invalid handle.
1463 // Note: Since HANDLE is a reference, this function cannot be const.
1465 @property HANDLE osHandle() @safe pure nothrow
1469 else version (Posix)
1470 @property pid_t osHandle() @safe pure nothrow
1477 Pid.performWait() does the dirty work for wait() and nonBlockingWait().
1479 If block == true, this function blocks until the process terminates,
1480 sets _processID to terminated, and returns the exit code or terminating
1481 signal as described in the wait() documentation.
1483 If block == false, this function returns immediately, regardless
1484 of the status of the process. If the process has terminated, the
1485 function has the exact same effect as the blocking version. If not,
1486 it returns 0 and does not modify _processID.
1489 int performWait(bool block) @trusted
1491 import std.exception : enforceEx;
1492 enforceEx!ProcessException(owned, "Can't wait on a detached process");
1493 if (_processID == terminated) return _exitCode;
1498 auto check = waitpid(_processID, &status, block ? 0 : WNOHANG);
1501 if (errno == ECHILD)
1503 throw new ProcessException(
1504 "Process does not exist or is not a child process.");
1508 // waitpid() was interrupted by a signal. We simply
1510 assert(errno == EINTR);
1514 if (!block && check == 0) return 0;
1515 if (WIFEXITED(status))
1517 exitCode = WEXITSTATUS(status);
1520 else if (WIFSIGNALED(status))
1522 exitCode = -WTERMSIG(status);
1525 // We check again whether the call should be blocking,
1526 // since we don't care about other status changes besides
1527 // "exited" and "terminated by signal".
1528 if (!block) return 0;
1530 // Process has stopped, but not terminated, so we continue waiting.
1532 // Mark Pid as terminated, and cache and return exit code.
1533 _processID = terminated;
1534 _exitCode = exitCode;
1537 else version (Windows)
1539 int performWait(bool block) @trusted
1541 import std.exception : enforceEx;
1542 enforceEx!ProcessException(owned, "Can't wait on a detached process");
1543 if (_processID == terminated) return _exitCode;
1544 assert(_handle != INVALID_HANDLE_VALUE);
1547 auto result = WaitForSingleObject(_handle, INFINITE);
1548 if (result != WAIT_OBJECT_0)
1549 throw ProcessException.newFromLastError("Wait failed.");
1551 if (!GetExitCodeProcess(_handle, cast(LPDWORD)&_exitCode))
1552 throw ProcessException.newFromLastError();
1553 if (!block && _exitCode == STILL_ACTIVE) return 0;
1554 CloseHandle(_handle);
1555 _handle = INVALID_HANDLE_VALUE;
1556 _processID = terminated;
1562 if (_handle != INVALID_HANDLE_VALUE)
1564 CloseHandle(_handle);
1565 _handle = INVALID_HANDLE_VALUE;
1570 // Special values for _processID.
1571 enum invalid = -1, terminated = -2;
1573 // OS process ID number. Only nonnegative IDs correspond to
1574 // running processes.
1575 int _processID = invalid;
1577 // Exit code cached by wait(). This is only expected to hold a
1578 // sensible value if _processID == terminated.
1581 // Whether the process can be waited for by wait() for or killed by kill().
1582 // False if process was started as detached. True otherwise.
1585 // Pids are only meant to be constructed inside this module, so
1586 // we make the constructor private.
1589 HANDLE _handle = INVALID_HANDLE_VALUE;
1590 this(int pid, HANDLE handle) @safe pure nothrow
1596 this(int pid) @safe pure nothrow
1604 this(int id, bool owned) @safe pure nothrow
1614 Waits for the process associated with $(D pid) to terminate, and returns
1617 In general one should always _wait for child processes to terminate
1618 before exiting the parent process unless the process was spawned as detached
1619 (that was spawned with $(D Config.detached) flag).
1620 Otherwise, they may become "$(HTTP en.wikipedia.org/wiki/Zombie_process,zombies)"
1621 – processes that are defunct, yet still occupy a slot in the OS process table.
1622 You should not and must not wait for detached processes, since you don't own them.
1624 If the process has already terminated, this function returns directly.
1625 The exit code is cached, so that if wait() is called multiple times on
1626 the same $(LREF Pid) it will always return the same value.
1629 If the process is terminated by a signal, this function returns a
1630 negative number whose absolute value is the signal number.
1631 Since POSIX restricts normal exit codes to the range 0-255, a
1632 negative return value will always indicate termination by signal.
1633 Signal codes are defined in the $(D core.sys.posix.signal) module
1634 (which corresponds to the $(D signal.h) POSIX header).
1637 $(LREF ProcessException) on failure or on attempt to wait for detached process.
1640 See the $(LREF spawnProcess) documentation.
1643 $(LREF tryWait), for a non-blocking function.
1645 int wait(Pid pid) @safe
1647 assert(pid !is null, "Called wait on a null Pid.");
1648 return pid.performWait(true);
1652 @system unittest // Pid and wait()
1654 version (Windows) TestScript prog = "exit %~1";
1655 else version (Posix) TestScript prog = "exit $1";
1656 assert(wait(spawnProcess([prog.path, "0"])) == 0);
1657 assert(wait(spawnProcess([prog.path, "123"])) == 123);
1658 auto pid = spawnProcess([prog.path, "10"]);
1659 assert(pid.processID > 0);
1660 version (Windows) assert(pid.osHandle != INVALID_HANDLE_VALUE);
1661 else version (Posix) assert(pid.osHandle == pid.processID);
1662 assert(wait(pid) == 10);
1663 assert(wait(pid) == 10); // cached exit code
1664 assert(pid.processID < 0);
1665 version (Windows) assert(pid.osHandle == INVALID_HANDLE_VALUE);
1666 else version (Posix) assert(pid.osHandle < 0);
1671 A non-blocking version of $(LREF wait).
1673 If the process associated with $(D pid) has already terminated,
1674 $(D tryWait) has the exact same effect as $(D wait).
1675 In this case, it returns a tuple where the $(D terminated) field
1676 is set to $(D true) and the $(D status) field has the same
1677 interpretation as the return value of $(D wait).
1679 If the process has $(I not) yet terminated, this function differs
1680 from $(D wait) in that does not wait for this to happen, but instead
1681 returns immediately. The $(D terminated) field of the returned
1682 tuple will then be set to $(D false), while the $(D status) field
1683 will always be 0 (zero). $(D wait) or $(D tryWait) should then be
1684 called again on the same $(D Pid) at some later time; not only to
1685 get the exit code, but also to avoid the process becoming a "zombie"
1686 when it finally terminates. (See $(LREF wait) for details).
1689 An $(D std.typecons.Tuple!(bool, "terminated", int, "status")).
1692 $(LREF ProcessException) on failure or on attempt to wait for detached process.
1696 auto pid = spawnProcess("dmd myapp.d");
1697 scope(exit) wait(pid);
1699 auto dmd = tryWait(pid);
1702 if (dmd.status == 0) writeln("Compilation succeeded!");
1703 else writeln("Compilation failed");
1705 else writeln("Still compiling...");
1708 Note that in this example, the first $(D wait) call will have no
1709 effect if the process has already terminated by the time $(D tryWait)
1710 is called. In the opposite case, however, the $(D scope) statement
1711 ensures that we always wait for the process if it hasn't terminated
1712 by the time we reach the end of the scope.
1714 auto tryWait(Pid pid) @safe
1716 import std.typecons : Tuple;
1717 assert(pid !is null, "Called tryWait on a null Pid.");
1718 auto code = pid.performWait(false);
1719 return Tuple!(bool, "terminated", int, "status")(pid._processID == Pid.terminated, code);
1721 // unittest: This function is tested together with kill() below.
1725 Attempts to terminate the process associated with $(D pid).
1727 The effect of this function, as well as the meaning of $(D codeOrSignal),
1728 is highly platform dependent. Details are given below. Common to all
1729 platforms is that this function only $(I initiates) termination of the process,
1730 and returns immediately. It does not wait for the process to end,
1731 nor does it guarantee that the process does in fact get terminated.
1733 Always call $(LREF wait) to wait for a process to complete, even if $(D kill)
1734 has been called on it.
1738 $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/ms686714%28v=vs.100%29.aspx,
1739 forcefully and abruptly terminated). If $(D codeOrSignal) is specified, it
1740 must be a nonnegative number which will be used as the exit code of the process.
1741 If not, the process wil exit with code 1. Do not use $(D codeOrSignal = 259),
1742 as this is a special value (aka. $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/ms683189.aspx,STILL_ACTIVE))
1743 used by Windows to signal that a process has in fact $(I not) terminated yet.
1745 auto pid = spawnProcess("some_app");
1747 assert(wait(pid) == 10);
1751 A $(LINK2 http://en.wikipedia.org/wiki/Unix_signal,signal) will be sent to
1752 the process, whose value is given by $(D codeOrSignal). Depending on the
1753 signal sent, this may or may not terminate the process. Symbolic constants
1754 for various $(LINK2 http://en.wikipedia.org/wiki/Unix_signal#POSIX_signals,
1755 POSIX signals) are defined in $(D core.sys.posix.signal), which corresponds to the
1756 $(LINK2 http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html,
1757 $(D signal.h) POSIX header). If $(D codeOrSignal) is omitted, the
1758 $(D SIGTERM) signal will be sent. (This matches the behaviour of the
1759 $(LINK2 http://pubs.opengroup.org/onlinepubs/9699919799/utilities/kill.html,
1760 $(D _kill)) shell command.)
1762 import core.sys.posix.signal : SIGKILL;
1763 auto pid = spawnProcess("some_app");
1765 assert(wait(pid) == -SIGKILL); // Negative return value on POSIX!
1769 $(LREF ProcessException) on error (e.g. if codeOrSignal is invalid).
1770 or on attempt to kill detached process.
1771 Note that failure to terminate the process is considered a "normal"
1772 outcome, not an error.$(BR)
1776 version (Windows) kill(pid, 1);
1777 else version (Posix)
1779 import core.sys.posix.signal : SIGTERM;
1785 void kill(Pid pid, int codeOrSignal)
1787 import std.exception : enforceEx;
1788 enforceEx!ProcessException(pid.owned, "Can't kill detached process");
1791 if (codeOrSignal < 0) throw new ProcessException("Invalid exit code");
1792 // On Windows, TerminateProcess() appears to terminate the
1793 // *current* process if it is passed an invalid handle...
1794 if (pid.osHandle == INVALID_HANDLE_VALUE)
1795 throw new ProcessException("Invalid process handle");
1796 if (!TerminateProcess(pid.osHandle, codeOrSignal))
1797 throw ProcessException.newFromLastError();
1799 else version (Posix)
1801 import core.sys.posix.signal : kill;
1802 if (kill(pid.osHandle, codeOrSignal) == -1)
1803 throw ProcessException.newFromErrno();
1807 @system unittest // tryWait() and kill()
1810 import std.exception : assertThrown;
1811 // The test script goes into an infinite loop.
1814 TestScript prog = ":loop
1817 else version (Posix)
1819 import core.sys.posix.signal : SIGTERM, SIGKILL;
1820 TestScript prog = "while true; do sleep 1; done";
1822 auto pid = spawnProcess(prog.path);
1823 // Android appears to automatically kill sleeping processes very quickly,
1824 // so shorten the wait before killing here.
1826 Thread.sleep(dur!"msecs"(5));
1828 Thread.sleep(dur!"seconds"(1));
1830 version (Windows) assert(wait(pid) == 1);
1831 else version (Posix) assert(wait(pid) == -SIGTERM);
1833 pid = spawnProcess(prog.path);
1834 Thread.sleep(dur!"seconds"(1));
1835 auto s = tryWait(pid);
1836 assert(!s.terminated && s.status == 0);
1837 assertThrown!ProcessException(kill(pid, -123)); // Negative code not allowed.
1838 version (Windows) kill(pid, 123);
1839 else version (Posix) kill(pid, SIGKILL);
1840 do { s = tryWait(pid); } while (!s.terminated);
1841 version (Windows) assert(s.status == 123);
1842 else version (Posix) assert(s.status == -SIGKILL);
1843 assertThrown!ProcessException(kill(pid));
1846 @system unittest // wait() and kill() detached process
1849 import std.exception : assertThrown;
1850 TestScript prog = "exit 0";
1851 auto pid = spawnProcess([prog.path], null, Config.detached);
1853 This sleep is needed because we can't wait() for detached process to end
1854 and therefore TestScript destructor may run at the same time as /bin/sh tries to start the script.
1855 This leads to the annoying message like "/bin/sh: 0: Can't open /tmp/std.process temporary file" to appear when running tests.
1856 It does not happen in unittests with non-detached processes because we always wait() for them to finish.
1858 Thread.sleep(1.seconds);
1860 version (Windows) assert(pid.osHandle == INVALID_HANDLE_VALUE);
1861 assertThrown!ProcessException(wait(pid));
1862 assertThrown!ProcessException(kill(pid));
1867 Creates a unidirectional _pipe.
1869 Data is written to one end of the _pipe and read from the other.
1872 p.writeEnd.writeln("Hello World");
1874 assert(p.readEnd.readln().chomp() == "Hello World");
1876 Pipes can, for example, be used for interprocess communication
1877 by spawning a new process and passing one end of the _pipe to
1878 the child, while the parent uses the other end.
1879 (See also $(LREF pipeProcess) and $(LREF pipeShell) for an easier
1882 // Use cURL to download the dlang.org front page, pipe its
1883 // output to grep to extract a list of links to ZIP files,
1884 // and write the list to the file "D downloads.txt":
1886 auto outFile = File("D downloads.txt", "w");
1887 auto cpid = spawnProcess(["curl", "http://dlang.org/download.html"],
1888 std.stdio.stdin, p.writeEnd);
1889 scope(exit) wait(cpid);
1890 auto gpid = spawnProcess(["grep", "-o", `http://\S*\.zip`],
1891 p.readEnd, outFile);
1892 scope(exit) wait(gpid);
1896 A $(LREF Pipe) object that corresponds to the created _pipe.
1899 $(REF StdioException, std,stdio) on failure.
1902 Pipe pipe() @trusted //TODO: @safe
1904 import core.sys.posix.stdio : fdopen;
1906 if (core.sys.posix.unistd.pipe(fds) != 0)
1907 throw new StdioException("Unable to create pipe");
1909 auto readFP = fdopen(fds[0], "r");
1911 throw new StdioException("Cannot open read end of pipe");
1912 p._read = File(readFP, null);
1913 auto writeFP = fdopen(fds[1], "w");
1914 if (writeFP == null)
1915 throw new StdioException("Cannot open write end of pipe");
1916 p._write = File(writeFP, null);
1919 else version (Windows)
1920 Pipe pipe() @trusted //TODO: @safe
1922 // use CreatePipe to create an anonymous pipe
1925 if (!CreatePipe(&readHandle, &writeHandle, null, 0))
1927 throw new StdioException(
1928 "Error creating pipe (" ~ sysErrorString(GetLastError()) ~ ')',
1934 CloseHandle(readHandle);
1935 CloseHandle(writeHandle);
1941 p._read .windowsHandleOpen(readHandle , "r");
1942 p._write.windowsHandleOpen(writeHandle, "a");
1947 throw new StdioException("Error attaching pipe (" ~ e.msg ~ ")",
1953 /// An interface to a pipe created by the $(LREF pipe) function.
1956 /// The read end of the pipe.
1957 @property File readEnd() @safe nothrow { return _read; }
1960 /// The write end of the pipe.
1961 @property File writeEnd() @safe nothrow { return _write; }
1965 Closes both ends of the pipe.
1967 Normally it is not necessary to do this manually, as $(REF File, std,stdio)
1968 objects are automatically closed when there are no more references
1971 Note that if either end of the pipe has been passed to a child process,
1972 it will only be closed in the parent process. (What happens in the
1973 child process is platform dependent.)
1976 $(REF ErrnoException, std,exception) if an error occurs.
1992 p.writeEnd.writeln("Hello World");
1994 assert(p.readEnd.readln().chomp() == "Hello World");
1996 assert(!p.readEnd.isOpen);
1997 assert(!p.writeEnd.isOpen);
2002 Starts a new process, creating pipes to redirect its standard
2003 input, output and/or error streams.
2005 $(D pipeProcess) and $(D pipeShell) are convenient wrappers around
2006 $(LREF spawnProcess) and $(LREF spawnShell), respectively, and
2007 automate the task of redirecting one or more of the child process'
2008 standard streams through pipes. Like the functions they wrap,
2009 these functions return immediately, leaving the child process to
2010 execute in parallel with the invoking process. It is recommended
2011 to always call $(LREF wait) on the returned $(LREF ProcessPipes.pid),
2012 as detailed in the documentation for $(D wait).
2014 The $(D args)/$(D program)/$(D command), $(D env) and $(D config)
2015 parameters are forwarded straight to the underlying spawn functions,
2016 and we refer to their documentation for details.
2019 args = An array which contains the program name as the zeroth element
2020 and any command-line arguments in the following elements.
2021 (See $(LREF spawnProcess) for details.)
2022 program = The program name, $(I without) command-line arguments.
2023 (See $(LREF spawnProcess) for details.)
2024 command = A shell command which is passed verbatim to the command
2025 interpreter. (See $(LREF spawnShell) for details.)
2026 redirect = Flags that determine which streams are redirected, and
2027 how. See $(LREF Redirect) for an overview of available
2029 env = Additional environment variables for the child process.
2030 (See $(LREF spawnProcess) for details.)
2031 config = Flags that control process creation. See $(LREF Config)
2032 for an overview of available flags, and note that the
2033 $(D retainStd...) flags have no effect in this function.
2034 workDir = The working directory for the new process.
2035 By default the child process inherits the parent's working
2037 shellPath = The path to the shell to use to run the specified program.
2038 By default this is $(LREF nativeShell).
2041 A $(LREF ProcessPipes) object which contains $(REF File, std,stdio)
2042 handles that communicate with the redirected streams of the child
2043 process, along with a $(LREF Pid) object that corresponds to the
2047 $(LREF ProcessException) on failure to start the process.$(BR)
2048 $(REF StdioException, std,stdio) on failure to redirect any of the streams.$(BR)
2052 // my_application writes to stdout and might write to stderr
2053 auto pipes = pipeProcess("my_application", Redirect.stdout | Redirect.stderr);
2054 scope(exit) wait(pipes.pid);
2056 // Store lines of output.
2058 foreach (line; pipes.stdout.byLine) output ~= line.idup;
2060 // Store lines of errors.
2062 foreach (line; pipes.stderr.byLine) errors ~= line.idup;
2065 // sendmail expects to read from stdin
2066 pipes = pipeProcess(["/usr/bin/sendmail", "-t"], Redirect.stdin);
2067 pipes.stdin.writeln("To: you");
2068 pipes.stdin.writeln("From: me");
2069 pipes.stdin.writeln("Subject: dlang");
2070 pipes.stdin.writeln("");
2071 pipes.stdin.writeln(message);
2073 // a single period tells sendmail we are finished
2074 pipes.stdin.writeln(".");
2076 // but at this point sendmail might not see it, we need to flush
2077 pipes.stdin.flush();
2079 // sendmail happens to exit on ".", but some you have to close the file:
2080 pipes.stdin.close();
2082 // otherwise this wait will wait forever
2087 ProcessPipes pipeProcess(in char[][] args,
2088 Redirect redirect = Redirect.all,
2089 const string[string] env = null,
2090 Config config = Config.none,
2091 in char[] workDir = null)
2094 return pipeProcessImpl!spawnProcess(args, redirect, env, config, workDir);
2098 ProcessPipes pipeProcess(in char[] program,
2099 Redirect redirect = Redirect.all,
2100 const string[string] env = null,
2101 Config config = Config.none,
2102 in char[] workDir = null)
2105 return pipeProcessImpl!spawnProcess(program, redirect, env, config, workDir);
2109 ProcessPipes pipeShell(in char[] command,
2110 Redirect redirect = Redirect.all,
2111 const string[string] env = null,
2112 Config config = Config.none,
2113 in char[] workDir = null,
2114 string shellPath = nativeShell)
2117 return pipeProcessImpl!spawnShell(command,
2125 // Implementation of the pipeProcess() family of functions.
2126 private ProcessPipes pipeProcessImpl(alias spawnFunc, Cmd, ExtraSpawnFuncArgs...)
2128 Redirect redirectFlags,
2129 const string[string] env = null,
2130 Config config = Config.none,
2131 in char[] workDir = null,
2132 ExtraSpawnFuncArgs extraArgs = ExtraSpawnFuncArgs.init)
2133 @trusted //TODO: @safe
2135 File childStdin, childStdout, childStderr;
2137 pipes._redirectFlags = redirectFlags;
2139 if (redirectFlags & Redirect.stdin)
2142 childStdin = p.readEnd;
2143 pipes._stdin = p.writeEnd;
2147 childStdin = std.stdio.stdin;
2150 if (redirectFlags & Redirect.stdout)
2152 if ((redirectFlags & Redirect.stdoutToStderr) != 0)
2153 throw new StdioException("Cannot create pipe for stdout AND "
2154 ~"redirect it to stderr", 0);
2156 childStdout = p.writeEnd;
2157 pipes._stdout = p.readEnd;
2161 childStdout = std.stdio.stdout;
2164 if (redirectFlags & Redirect.stderr)
2166 if ((redirectFlags & Redirect.stderrToStdout) != 0)
2167 throw new StdioException("Cannot create pipe for stderr AND "
2168 ~"redirect it to stdout", 0);
2170 childStderr = p.writeEnd;
2171 pipes._stderr = p.readEnd;
2175 childStderr = std.stdio.stderr;
2178 if (redirectFlags & Redirect.stdoutToStderr)
2180 if (redirectFlags & Redirect.stderrToStdout)
2182 // We know that neither of the other options have been
2183 // set, so we assign the std.stdio.std* streams directly.
2184 childStdout = std.stdio.stderr;
2185 childStderr = std.stdio.stdout;
2189 childStdout = childStderr;
2192 else if (redirectFlags & Redirect.stderrToStdout)
2194 childStderr = childStdout;
2197 config &= ~(Config.retainStdin | Config.retainStdout | Config.retainStderr);
2198 pipes._pid = spawnFunc(command, childStdin, childStdout, childStderr,
2199 env, config, workDir, extraArgs);
2205 Flags that can be passed to $(LREF pipeProcess) and $(LREF pipeShell)
2206 to specify which of the child process' standard streams are redirected.
2207 Use bitwise OR to combine flags.
2211 /// Redirect the standard input, output or error streams, respectively.
2213 stdout = 2, /// ditto
2214 stderr = 4, /// ditto
2217 Redirect _all three streams. This is equivalent to
2218 $(D Redirect.stdin | Redirect.stdout | Redirect.stderr).
2220 all = stdin | stdout | stderr,
2223 Redirect the standard error stream into the standard output stream.
2224 This can not be combined with $(D Redirect.stderr).
2229 Redirect the standard output stream into the standard error stream.
2230 This can not be combined with $(D Redirect.stdout).
2232 stdoutToStderr = 16,
2238 version (Windows) TestScript prog =
2239 "call :sub %~1 %~2 0
2247 if -%INPUT%-==-stop- ( exit %~3 )
2249 echo %INPUT% %~2 1>&2";
2250 else version (Posix) TestScript prog =
2251 `for EXITCODE in 0 1 2 3; do
2253 if test "$INPUT" = stop; then break; fi
2255 echo "$INPUT $2" >&2
2258 auto pp = pipeProcess([prog.path, "bar", "baz"]);
2259 pp.stdin.writeln("foo");
2261 assert(pp.stdout.readln().chomp() == "foo bar");
2262 assert(pp.stderr.readln().chomp().stripRight() == "foo baz");
2263 pp.stdin.writeln("1234567890");
2265 assert(pp.stdout.readln().chomp() == "1234567890 bar");
2266 assert(pp.stderr.readln().chomp().stripRight() == "1234567890 baz");
2267 pp.stdin.writeln("stop");
2269 assert(wait(pp.pid) == 2);
2271 pp = pipeProcess([prog.path, "12345", "67890"],
2272 Redirect.stdin | Redirect.stdout | Redirect.stderrToStdout);
2273 pp.stdin.writeln("xyz");
2275 assert(pp.stdout.readln().chomp() == "xyz 12345");
2276 assert(pp.stdout.readln().chomp().stripRight() == "xyz 67890");
2277 pp.stdin.writeln("stop");
2279 assert(wait(pp.pid) == 1);
2281 pp = pipeShell(escapeShellCommand(prog.path, "AAAAA", "BBB"),
2282 Redirect.stdin | Redirect.stdoutToStderr | Redirect.stderr);
2283 pp.stdin.writeln("ab");
2285 assert(pp.stderr.readln().chomp() == "ab AAAAA");
2286 assert(pp.stderr.readln().chomp().stripRight() == "ab BBB");
2287 pp.stdin.writeln("stop");
2289 assert(wait(pp.pid) == 1);
2294 import std.exception : assertThrown;
2295 TestScript prog = "exit 0";
2296 assertThrown!StdioException(pipeProcess(
2298 Redirect.stdout | Redirect.stdoutToStderr));
2299 assertThrown!StdioException(pipeProcess(
2301 Redirect.stderr | Redirect.stderrToStdout));
2302 auto p = pipeProcess(prog.path, Redirect.stdin);
2303 assertThrown!Error(p.stdout);
2304 assertThrown!Error(p.stderr);
2306 p = pipeProcess(prog.path, Redirect.stderr);
2307 assertThrown!Error(p.stdin);
2308 assertThrown!Error(p.stdout);
2313 Object which contains $(REF File, std,stdio) handles that allow communication
2314 with a child process through its standard streams.
2318 /// The $(LREF Pid) of the child process.
2319 @property Pid pid() @safe nothrow
2325 An $(REF File, std,stdio) that allows writing to the child process'
2326 standard input stream.
2329 $(OBJECTREF Error) if the child process' standard input stream hasn't
2332 @property File stdin() @safe nothrow
2334 if ((_redirectFlags & Redirect.stdin) == 0)
2335 throw new Error("Child process' standard input stream hasn't "
2336 ~"been redirected.");
2341 An $(REF File, std,stdio) that allows reading from the child process'
2342 standard output stream.
2345 $(OBJECTREF Error) if the child process' standard output stream hasn't
2348 @property File stdout() @safe nothrow
2350 if ((_redirectFlags & Redirect.stdout) == 0)
2351 throw new Error("Child process' standard output stream hasn't "
2352 ~"been redirected.");
2357 An $(REF File, std,stdio) that allows reading from the child process'
2358 standard error stream.
2361 $(OBJECTREF Error) if the child process' standard error stream hasn't
2364 @property File stderr() @safe nothrow
2366 if ((_redirectFlags & Redirect.stderr) == 0)
2367 throw new Error("Child process' standard error stream hasn't "
2368 ~"been redirected.");
2373 Redirect _redirectFlags;
2375 File _stdin, _stdout, _stderr;
2381 Executes the given program or shell command and returns its exit
2384 $(D execute) and $(D executeShell) start a new process using
2385 $(LREF spawnProcess) and $(LREF spawnShell), respectively, and wait
2386 for the process to complete before returning. The functions capture
2387 what the child process prints to both its standard output and
2388 standard error streams, and return this together with its exit code.
2390 auto dmd = execute(["dmd", "myapp.d"]);
2391 if (dmd.status != 0) writeln("Compilation failed:\n", dmd.output);
2393 auto ls = executeShell("ls -l");
2394 if (ls.status != 0) writeln("Failed to retrieve file listing");
2395 else writeln(ls.output);
2398 The $(D args)/$(D program)/$(D command), $(D env) and $(D config)
2399 parameters are forwarded straight to the underlying spawn functions,
2400 and we refer to their documentation for details.
2403 args = An array which contains the program name as the zeroth element
2404 and any command-line arguments in the following elements.
2405 (See $(LREF spawnProcess) for details.)
2406 program = The program name, $(I without) command-line arguments.
2407 (See $(LREF spawnProcess) for details.)
2408 command = A shell command which is passed verbatim to the command
2409 interpreter. (See $(LREF spawnShell) for details.)
2410 env = Additional environment variables for the child process.
2411 (See $(LREF spawnProcess) for details.)
2412 config = Flags that control process creation. See $(LREF Config)
2413 for an overview of available flags, and note that the
2414 $(D retainStd...) flags have no effect in this function.
2415 maxOutput = The maximum number of bytes of output that should be
2417 workDir = The working directory for the new process.
2418 By default the child process inherits the parent's working
2420 shellPath = The path to the shell to use to run the specified program.
2421 By default this is $(LREF nativeShell).
2425 An $(D std.typecons.Tuple!(int, "status", string, "output")).
2428 If the process is terminated by a signal, the $(D status) field of
2429 the return value will contain a negative number whose absolute
2430 value is the signal number. (See $(LREF wait) for details.)
2433 $(LREF ProcessException) on failure to start the process.$(BR)
2434 $(REF StdioException, std,stdio) on failure to capture output.
2436 auto execute(in char[][] args,
2437 const string[string] env = null,
2438 Config config = Config.none,
2439 size_t maxOutput = size_t.max,
2440 in char[] workDir = null)
2441 @trusted //TODO: @safe
2443 return executeImpl!pipeProcess(args, env, config, maxOutput, workDir);
2447 auto execute(in char[] program,
2448 const string[string] env = null,
2449 Config config = Config.none,
2450 size_t maxOutput = size_t.max,
2451 in char[] workDir = null)
2452 @trusted //TODO: @safe
2454 return executeImpl!pipeProcess(program, env, config, maxOutput, workDir);
2458 auto executeShell(in char[] command,
2459 const string[string] env = null,
2460 Config config = Config.none,
2461 size_t maxOutput = size_t.max,
2462 in char[] workDir = null,
2463 string shellPath = nativeShell)
2464 @trusted //TODO: @safe
2466 return executeImpl!pipeShell(command,
2474 // Does the actual work for execute() and executeShell().
2475 private auto executeImpl(alias pipeFunc, Cmd, ExtraPipeFuncArgs...)(
2477 const string[string] env = null,
2478 Config config = Config.none,
2479 size_t maxOutput = size_t.max,
2480 in char[] workDir = null,
2481 ExtraPipeFuncArgs extraArgs = ExtraPipeFuncArgs.init)
2483 import std.algorithm.comparison : min;
2484 import std.array : appender;
2485 import std.typecons : Tuple;
2487 auto p = pipeFunc(commandLine, Redirect.stdout | Redirect.stderrToStdout,
2488 env, config, workDir, extraArgs);
2490 auto a = appender!(ubyte[])();
2491 enum size_t defaultChunkSize = 4096;
2492 immutable chunkSize = min(maxOutput, defaultChunkSize);
2494 // Store up to maxOutput bytes in a.
2495 foreach (ubyte[] chunk; p.stdout.byChunk(chunkSize))
2497 immutable size_t remain = maxOutput - a.data.length;
2499 if (chunk.length < remain) a.put(chunk);
2502 a.put(chunk[0 .. remain]);
2506 // Exhaust the stream, if necessary.
2507 foreach (ubyte[] chunk; p.stdout.byChunk(defaultChunkSize)) { }
2509 return Tuple!(int, "status", string, "output")(wait(p.pid), cast(string) a.data);
2515 // To avoid printing the newline characters, we use the echo|set trick on
2516 // Windows, and printf on POSIX (neither echo -n nor echo \c are portable).
2517 version (Windows) TestScript prog =
2519 echo|set /p=%~2 1>&2
2521 else version (Android) TestScript prog =
2525 else version (Posix) TestScript prog =
2529 auto r = execute([prog.path, "foo", "bar"]);
2530 assert(r.status == 123);
2531 assert(r.output.stripRight() == "foobar");
2532 auto s = execute([prog.path, "Hello", "World"]);
2533 assert(s.status == 123);
2534 assert(s.output.stripRight() == "HelloWorld");
2540 auto r1 = executeShell("echo foo");
2541 assert(r1.status == 0);
2542 assert(r1.output.chomp() == "foo");
2543 auto r2 = executeShell("echo bar 1>&2");
2544 assert(r2.status == 0);
2545 assert(r2.output.chomp().stripRight() == "bar");
2546 auto r3 = executeShell("exit 123");
2547 assert(r3.status == 123);
2548 assert(r3.output.empty);
2553 import std.typecons : Tuple;
2554 void foo() //Just test the compilation
2556 auto ret1 = execute(["dummy", "arg"]);
2557 auto ret2 = executeShell("dummy arg");
2558 static assert(is(typeof(ret1) == typeof(ret2)));
2560 Tuple!(int, string) ret3 = execute(["dummy", "arg"]);
2564 /// An exception that signals a problem with starting or waiting for a process.
2565 class ProcessException : Exception
2567 import std.exception : basicExceptionCtors;
2568 mixin basicExceptionCtors;
2570 // Creates a new ProcessException based on errno.
2571 static ProcessException newFromErrno(string customMsg = null,
2572 string file = __FILE__,
2573 size_t line = __LINE__)
2575 import core.stdc.errno : errno;
2576 return newFromErrno(errno, customMsg, file, line);
2579 // ditto, but error number is provided by caller
2580 static ProcessException newFromErrno(int error,
2581 string customMsg = null,
2582 string file = __FILE__,
2583 size_t line = __LINE__)
2585 import std.exception : errnoString;
2586 auto errnoMsg = errnoString(error);
2587 auto msg = customMsg.empty ? errnoMsg
2588 : customMsg ~ " (" ~ errnoMsg ~ ')';
2589 return new ProcessException(msg, file, line);
2592 // Creates a new ProcessException based on GetLastError() (Windows only).
2594 static ProcessException newFromLastError(string customMsg = null,
2595 string file = __FILE__,
2596 size_t line = __LINE__)
2598 auto lastMsg = sysErrorString(GetLastError());
2599 auto msg = customMsg.empty ? lastMsg
2600 : customMsg ~ " (" ~ lastMsg ~ ')';
2601 return new ProcessException(msg, file, line);
2607 Determines the path to the current user's preferred command interpreter.
2609 On Windows, this function returns the contents of the COMSPEC environment
2610 variable, if it exists. Otherwise, it returns the result of $(LREF nativeShell).
2612 On POSIX, $(D userShell) returns the contents of the SHELL environment
2613 variable, if it exists and is non-empty. Otherwise, it returns the result of
2614 $(LREF nativeShell).
2616 @property string userShell() @safe
2618 version (Windows) return environment.get("COMSPEC", nativeShell);
2619 else version (Posix) return environment.get("SHELL", nativeShell);
2623 The platform-specific native shell path.
2625 This function returns $(D "cmd.exe") on Windows, $(D "/bin/sh") on POSIX, and
2626 $(D "/system/bin/sh") on Android.
2628 @property string nativeShell() @safe @nogc pure nothrow
2630 version (Windows) return "cmd.exe";
2631 else version (Android) return "/system/bin/sh";
2632 else version (Posix) return "/bin/sh";
2635 // A command-line switch that indicates to the shell that it should
2636 // interpret the following argument as a command to be executed.
2637 version (Posix) private immutable string shellSwitch = "-c";
2638 version (Windows) private immutable string shellSwitch = "/C";
2642 * Returns the process ID of the current process,
2643 * which is guaranteed to be unique on the system.
2647 * writefln("Current process ID: %d", thisProcessID);
2650 @property int thisProcessID() @trusted nothrow //TODO: @safe
2652 version (Windows) return GetCurrentProcessId();
2653 else version (Posix) return core.sys.posix.unistd.getpid();
2658 * Returns the process ID of the current thread,
2659 * which is guaranteed to be unique within the current process.
2662 * A $(REF ThreadID, core,thread) value for the calling thread.
2666 * writefln("Current thread ID: %s", thisThreadID);
2669 @property ThreadID thisThreadID() @trusted nothrow //TODO: @safe
2672 return GetCurrentThreadId();
2676 import core.sys.posix.pthread : pthread_self;
2677 return pthread_self();
2685 ThreadID tidA, tidB;
2686 pidA = thisProcessID;
2687 tidA = thisThreadID;
2690 auto t = new Thread({
2691 pidB = thisProcessID;
2692 tidB = thisThreadID;
2697 assert(pidA == pidB);
2698 assert(tidA != tidB);
2702 // Unittest support code: TestScript takes a string that contains a
2703 // shell script for the current platform, and writes it to a temporary
2704 // file. On Windows the file name gets a .cmd extension, while on
2705 // POSIX its executable permission bit is set. The file is
2706 // automatically deleted when the object goes out of scope.
2708 private struct TestScript
2710 this(string code) @system
2712 // @system due to chmod
2713 import std.ascii : newline;
2714 import std.file : write;
2718 auto firstLine = "@echo off";
2720 else version (Posix)
2723 auto firstLine = "#!" ~ nativeShell;
2725 path = uniqueTempPath()~ext;
2726 write(path, firstLine ~ newline ~ code ~ newline);
2729 import core.sys.posix.sys.stat : chmod;
2730 chmod(path.tempCString(), octal!777);
2736 import std.file : remove, exists;
2737 if (!path.empty && exists(path))
2739 try { remove(path); }
2742 debug std.stdio.stderr.writeln(e.msg);
2751 private string uniqueTempPath() @safe
2753 import std.file : tempDir;
2754 import std.path : buildPath;
2755 import std.uuid : randomUUID;
2756 // Path should contain spaces to test escaping whitespace
2757 return buildPath(tempDir(), "std.process temporary file " ~
2758 randomUUID().toString());
2762 // =============================================================================
2763 // Functions for shell command quoting/escaping.
2764 // =============================================================================
2768 Command line arguments exist in three forms:
2769 1) string or char* array, as received by main.
2770 Also used internally on POSIX systems.
2771 2) Command line string, as used in Windows'
2772 CreateProcess and CommandLineToArgvW functions.
2773 A specific quoting and escaping algorithm is used
2774 to distinguish individual arguments.
2775 3) Shell command string, as written at a shell prompt
2776 or passed to cmd /C - this one may contain shell
2777 control characters, e.g. > or | for redirection /
2778 piping - thus, yet another layer of escaping is
2779 used to distinguish them from program arguments.
2781 Except for escapeWindowsArgument, the intermediary
2782 format (2) is hidden away from the user in this module.
2786 Escapes an argv-style argument array to be used with $(LREF spawnShell),
2787 $(LREF pipeShell) or $(LREF executeShell).
2789 string url = "http://dlang.org/";
2790 executeShell(escapeShellCommand("wget", url, "-O", "dlang-index.html"));
2793 Concatenate multiple $(D escapeShellCommand) and
2794 $(LREF escapeShellFileName) results to use shell redirection or
2798 escapeShellCommand("curl", "http://dlang.org/download.html") ~
2800 escapeShellCommand("grep", "-o", `http://\S*\.zip`) ~
2802 escapeShellFileName("D download links.txt"));
2806 $(OBJECTREF Exception) if any part of the command line contains unescapable
2807 characters (NUL on all platforms, as well as CR and LF on Windows).
2809 string escapeShellCommand(in char[][] args...) @safe pure
2815 // Do not ^-escape the first argument (the program path),
2816 // as the shell parses it differently from parameters.
2817 // ^-escaping a program path that contains spaces will fail.
2818 string result = escapeShellFileName(args[0]);
2819 if (args.length > 1)
2821 result ~= " " ~ escapeShellCommandString(
2822 escapeShellArguments(args[1..$]));
2828 return escapeShellCommandString(escapeShellArguments(args));
2834 // This is a simple unit test without any special requirements,
2835 // in addition to the unittest_burnin one below which requires
2836 // special preparation.
2838 struct TestVector { string[] args; string windows, posix; }
2839 TestVector[] tests =
2843 windows : `"foo bar"`,
2847 args : ["foo bar", "hello"],
2848 windows : `"foo bar" hello`,
2849 posix : `'foo bar' 'hello'`
2852 args : ["foo bar", "hello world"],
2853 windows : `"foo bar" ^"hello world^"`,
2854 posix : `'foo bar' 'hello world'`
2857 args : ["foo bar", "hello", "world"],
2858 windows : `"foo bar" hello world`,
2859 posix : `'foo bar' 'hello' 'world'`
2862 args : ["foo bar", `'"^\`],
2863 windows : `"foo bar" ^"'\^"^^\\^"`,
2864 posix : `'foo bar' ''\''"^\'`
2868 foreach (test; tests)
2870 assert(escapeShellCommand(test.args) == test.windows);
2872 assert(escapeShellCommand(test.args) == test.posix );
2875 private string escapeShellCommandString(string command) @safe pure
2878 return escapeWindowsShellCommand(command);
2883 private string escapeWindowsShellCommand(in char[] command) @safe pure
2885 import std.array : appender;
2886 auto result = appender!string();
2887 result.reserve(command.length);
2889 foreach (c; command)
2893 throw new Exception("Cannot put NUL in command line");
2896 throw new Exception("CR/LF are not escapable");
2897 case '\x01': .. case '\x09':
2898 case '\x0B': .. case '\x0C':
2899 case '\x0E': .. case '\x1F':
2914 private string escapeShellArguments(in char[][] args...)
2915 @trusted pure nothrow
2917 import std.exception : assumeUnique;
2921 char[] allocator(size_t size)
2923 if (buf.length == 0)
2924 return buf = new char[size];
2927 auto p = buf.length;
2928 buf.length = buf.length + 1 + size;
2930 return buf[p .. p+size];
2935 escapeShellArgument!allocator(arg);
2936 return assumeUnique(buf);
2939 private auto escapeShellArgument(alias allocator)(in char[] arg) @safe nothrow
2941 // The unittest for this function requires special
2942 // preparation - see below.
2945 return escapeWindowsArgumentImpl!allocator(arg);
2947 return escapePosixArgumentImpl!allocator(arg);
2951 Quotes a command-line argument in a manner conforming to the behavior of
2952 $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx,
2953 CommandLineToArgvW).
2955 string escapeWindowsArgument(in char[] arg) @trusted pure nothrow
2957 // Rationale for leaving this function as public:
2958 // this algorithm of escaping paths is also used in other software,
2959 // e.g. DMD's response files.
2960 import std.exception : assumeUnique;
2961 auto buf = escapeWindowsArgumentImpl!charAllocator(arg);
2962 return assumeUnique(buf);
2966 private char[] charAllocator(size_t size) @safe pure nothrow
2968 return new char[size];
2972 private char[] escapeWindowsArgumentImpl(alias allocator)(in char[] arg)
2974 if (is(typeof(allocator(size_t.init)[0] = char.init)))
2977 // * http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx
2978 // * http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx
2980 // Check if the string needs to be escaped,
2981 // and calculate the total string size.
2983 // Trailing backslashes must be escaped
2984 bool escaping = true;
2985 bool needEscape = false;
2986 // Result size = input size + 2 for surrounding quotes + 1 for the
2987 // backslash for each escaped character.
2988 size_t size = 1 + arg.length + 1;
2990 foreach_reverse (char c; arg)
3006 if (c == ' ' || c == '\t')
3012 import std.ascii : isDigit;
3013 // Empty arguments need to be specified as ""
3017 // Arguments ending with digits need to be escaped,
3018 // to disambiguate with 1>file redirection syntax
3019 if (isDigit(arg[$-1]))
3023 return allocator(arg.length)[] = arg;
3025 // Construct result string.
3027 auto buf = allocator(size);
3031 foreach_reverse (char c; arg)
3049 version (Windows) version (unittest)
3051 import core.stdc.stddef;
3052 import core.stdc.wchar_ : wcslen;
3053 import core.sys.windows.shellapi : CommandLineToArgvW;
3054 import core.sys.windows.windows;
3057 string[] parseCommandLine(string line)
3059 import std.algorithm.iteration : map;
3060 import std.array : array;
3061 LPWSTR lpCommandLine = (to!(wchar[])(line) ~ "\0"w).ptr;
3063 LPWSTR* args = CommandLineToArgvW(lpCommandLine, &numArgs);
3064 scope(exit) LocalFree(args);
3065 return args[0 .. numArgs]
3066 .map!(arg => to!string(arg[0 .. wcslen(arg)]))
3072 string[] testStrings = [
3078 `C:\Program Files\`,
3081 enum CHARS = `_x\" *&^` ~ "\t"; // _ is placeholder for nothing
3086 testStrings ~= [c1, c2, c3, c4].replace("_", "");
3088 foreach (s; testStrings)
3090 auto q = escapeWindowsArgument(s);
3091 auto args = parseCommandLine("Dummy.exe " ~ q);
3092 assert(args.length == 2, s ~ " => " ~ q ~ " #" ~ text(args.length-1));
3093 assert(args[1] == s, s ~ " => " ~ q ~ " => " ~ args[1]);
3098 private string escapePosixArgument(in char[] arg) @trusted pure nothrow
3100 import std.exception : assumeUnique;
3101 auto buf = escapePosixArgumentImpl!charAllocator(arg);
3102 return assumeUnique(buf);
3105 private char[] escapePosixArgumentImpl(alias allocator)(in char[] arg)
3107 if (is(typeof(allocator(size_t.init)[0] = char.init)))
3109 // '\'' means: close quoted part of argument, append an escaped
3110 // single quote, and reopen quotes
3112 // Below code is equivalent to:
3113 // return `'` ~ std.array.replace(arg, `'`, `'\''`) ~ `'`;
3115 size_t size = 1 + arg.length + 1;
3116 foreach (char c; arg)
3120 auto buf = allocator(size);
3123 foreach (char c; arg)
3126 buf[p .. p+4] = `'\''`;
3138 Escapes a filename to be used for shell redirection with $(LREF spawnShell),
3139 $(LREF pipeShell) or $(LREF executeShell).
3141 string escapeShellFileName(in char[] fileName) @trusted pure nothrow
3143 // The unittest for this function requires special
3144 // preparation - see below.
3148 // If a file starts with &, it can cause cmd.exe to misinterpret
3149 // the file name as the stream redirection syntax:
3150 // command > "&foo.txt"
3151 // gets interpreted as
3152 // command >&foo.txt
3153 // Prepend .\ to disambiguate.
3155 if (fileName.length && fileName[0] == '&')
3156 return cast(string)(`".\` ~ fileName ~ '"');
3158 return cast(string)('"' ~ fileName ~ '"');
3161 return escapePosixArgument(fileName);
3164 // Loop generating strings with random characters
3165 //version = unittest_burnin;
3167 version (unittest_burnin)
3170 // There are no readily-available commands on all platforms suitable
3171 // for properly testing command escaping. The behavior of CMD's "echo"
3172 // built-in differs from the POSIX program, and Windows ports of POSIX
3173 // environments (Cygwin, msys, gnuwin32) may interfere with their own
3176 // To run this unit test, create std_process_unittest_helper.d with the
3177 // following content and compile it:
3178 // import std.stdio, std.array; void main(string[] args) { write(args.join("\0")); }
3179 // Then, test this module with:
3180 // rdmd --main -unittest -version=unittest_burnin process.d
3182 auto helper = absolutePath("std_process_unittest_helper");
3183 assert(executeShell(helper ~ " hello").output.split("\0")[1..$] == ["hello"], "Helper malfunction");
3185 void test(string[] s, string fn)
3190 e = escapeShellCommand(helper ~ s);
3192 scope(failure) writefln("executeShell() failed.\nExpected:\t%s\nEncoded:\t%s", s, [e]);
3193 auto result = executeShell(e);
3194 assert(result.status == 0, "std_process_unittest_helper failed");
3195 g = result.output.split("\0")[1..$];
3197 assert(s == g, format("executeShell() test failed.\nExpected:\t%s\nGot:\t\t%s\nEncoded:\t%s", s, g, [e]));
3199 e = escapeShellCommand(helper ~ s) ~ ">" ~ escapeShellFileName(fn);
3201 scope(failure) writefln(
3202 "executeShell() with redirect failed.\nExpected:\t%s\nFilename:\t%s\nEncoded:\t%s", s, [fn], [e]);
3203 auto result = executeShell(e);
3204 assert(result.status == 0, "std_process_unittest_helper failed");
3205 assert(!result.output.length, "No output expected, got:\n" ~ result.output);
3206 g = readText(fn).split("\0")[1..$];
3210 format("executeShell() with redirect test failed.\nExpected:\t%s\nGot:\t\t%s\nEncoded:\t%s", s, g, [e]));
3216 foreach (n; 0 .. uniform(1, 4))
3219 foreach (l; 0 .. uniform(0, 10))
3226 // As long as DMD's system() uses CreateProcessA,
3227 // we can't reliably pass Unicode
3228 c = uniform(0, 128);
3231 c = uniform!ubyte();
3234 continue; // argv-strings are zero-terminated
3236 if (c == '\r' || c == '\n')
3237 continue; // newlines are unescapable on Windows
3245 // generate filename
3247 foreach (l; 0 .. uniform(1, 10))
3253 c = uniform(0, 128); // as above
3255 c = uniform!ubyte();
3257 if (c == 0 || c == '/')
3258 continue; // NUL and / are the only characters
3259 // forbidden in POSIX filenames
3261 if (c < '\x20' || c == '<' || c == '>' || c == ':' ||
3262 c == '"' || c == '\\' || c == '|' || c == '?' || c == '*')
3263 continue; // http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx
3269 fn = fn[0..$/2] ~ "_testfile_" ~ fn[$/2..$];
3276 // =============================================================================
3277 // Environment variable manipulation.
3278 // =============================================================================
3282 Manipulates _environment variables using an associative-array-like
3285 This class contains only static methods, and cannot be instantiated.
3286 See below for examples of use.
3288 abstract final class environment
3292 Retrieves the value of the environment variable with the given $(D name).
3294 auto path = environment["PATH"];
3298 $(OBJECTREF Exception) if the environment variable does not exist,
3299 or $(REF UTFException, std,utf) if the variable contains invalid UTF-16
3300 characters (Windows only).
3303 $(LREF environment.get), which doesn't throw on failure.
3305 string opIndex(in char[] name) @safe
3307 import std.exception : enforce;
3309 enforce(getImpl(name, value), "Environment variable not found: "~name);
3314 Retrieves the value of the environment variable with the given $(D name),
3315 or a default value if the variable doesn't exist.
3317 Unlike $(LREF environment.opIndex), this function never throws.
3319 auto sh = environment.get("SHELL", "/bin/sh");
3321 This function is also useful in checking for the existence of an
3322 environment variable.
3324 auto myVar = environment.get("MYVAR");
3327 // Environment variable doesn't exist.
3328 // Note that we have to use 'is' for the comparison, since
3329 // myVar == null is also true if the variable exists but is
3335 $(REF UTFException, std,utf) if the variable contains invalid UTF-16
3336 characters (Windows only).
3338 string get(in char[] name, string defaultValue = null) @safe
3341 auto found = getImpl(name, value);
3342 return found ? value : defaultValue;
3346 Assigns the given $(D value) to the environment variable with the given
3348 If $(D value) is null the variable is removed from environment.
3350 If the variable does not exist, it will be created. If it already exists,
3351 it will be overwritten.
3353 environment["foo"] = "bar";
3357 $(OBJECTREF Exception) if the environment variable could not be added
3358 (e.g. if the name is invalid).
3361 On some platforms, modifying environment variables may not be allowed in
3362 multi-threaded programs. See e.g.
3363 $(LINK2 https://www.gnu.org/software/libc/manual/html_node/Environment-Access.html#Environment-Access, glibc).
3365 inout(char)[] opIndexAssign(inout char[] value, in char[] name) @trusted
3369 import std.exception : enforce, errnoEnforce;
3375 if (core.sys.posix.stdlib.setenv(name.tempCString(), value.tempCString(), 1) != -1)
3379 // The default errno error message is very uninformative
3380 // in the most common case, so we handle it manually.
3381 enforce(errno != EINVAL,
3382 "Invalid environment variable name: '"~name~"'");
3384 "Failed to add environment variable");
3387 else version (Windows)
3389 import std.exception : enforce;
3391 SetEnvironmentVariableW(name.tempCStringW(), value.tempCStringW()),
3392 sysErrorString(GetLastError())
3396 else static assert(0);
3400 Removes the environment variable with the given $(D name).
3402 If the variable isn't in the environment, this function returns
3403 successfully without doing anything.
3406 On some platforms, modifying environment variables may not be allowed in
3407 multi-threaded programs. See e.g.
3408 $(LINK2 https://www.gnu.org/software/libc/manual/html_node/Environment-Access.html#Environment-Access, glibc).
3410 void remove(in char[] name) @trusted nothrow @nogc // TODO: @safe
3412 version (Windows) SetEnvironmentVariableW(name.tempCStringW(), null);
3413 else version (Posix) core.sys.posix.stdlib.unsetenv(name.tempCString());
3414 else static assert(0);
3418 Identify whether a variable is defined in the environment.
3420 Because it doesn't return the value, this function is cheaper than `get`.
3421 However, if you do need the value as well, you should just check the
3422 return of `get` for `null` instead of using this function first.
3427 if ("MY_ENV_FLAG" in environment)
3431 if ("MY_ENV_VAR" in environment)
3432 doSomething(environment["MY_ENV_VAR"]);
3435 if (auto var = environment.get("MY_ENV_VAR"))
3439 bool opBinaryRight(string op : "in")(in char[] name) @trusted
3442 return core.sys.posix.stdlib.getenv(name.tempCString()) !is null;
3443 else version (Windows)
3445 SetLastError(NO_ERROR);
3446 if (GetEnvironmentVariableW(name.tempCStringW, null, 0) > 0)
3448 immutable err = GetLastError();
3449 if (err == ERROR_ENVVAR_NOT_FOUND)
3451 // some other windows error. Might actually be NO_ERROR, because
3452 // GetEnvironmentVariable doesn't specify whether it sets on all
3454 throw new WindowsException(err);
3456 else static assert(0);
3460 Copies all environment variables into an associative array.
3463 While Windows environment variable names are case insensitive, D's
3464 built-in associative arrays are not. This function will store all
3465 variable names in uppercase (e.g. $(D PATH)).
3468 $(OBJECTREF Exception) if the environment variables could not
3469 be retrieved (Windows only).
3471 string[string] toAA() @trusted
3473 import std.conv : to;
3477 auto environ = getEnvironPtr;
3478 for (int i=0; environ[i] != null; ++i)
3480 import std.string : indexOf;
3482 immutable varDef = to!string(environ[i]);
3483 immutable eq = indexOf(varDef, '=');
3486 immutable name = varDef[0 .. eq];
3487 immutable value = varDef[eq+1 .. $];
3489 // In POSIX, environment variables may be defined more
3490 // than once. This is a security issue, which we avoid
3491 // by checking whether the key already exists in the array.
3493 // http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/environment-variables.html
3494 if (name !in aa) aa[name] = value;
3497 else version (Windows)
3499 import std.exception : enforce;
3500 import std.uni : toUpper;
3501 auto envBlock = GetEnvironmentStringsW();
3502 enforce(envBlock, "Failed to retrieve environment variables.");
3503 scope(exit) FreeEnvironmentStringsW(envBlock);
3505 for (int i=0; envBlock[i] != '\0'; ++i)
3508 while (envBlock[i] != '=') ++i;
3509 immutable name = toUTF8(toUpper(envBlock[start .. i]));
3512 while (envBlock[i] != '\0') ++i;
3514 // Ignore variables with empty names. These are used internally
3515 // by Windows to keep track of each drive's individual current
3520 // Just like in POSIX systems, environment variables may be
3521 // defined more than once in an environment block on Windows,
3522 // and it is just as much of a security issue there. Moreso,
3523 // in fact, due to the case insensensitivity of variable names,
3524 // which is not handled correctly by all programs.
3525 auto val = toUTF8(envBlock[start .. i]);
3526 if (name !in aa) aa[name] = val is null ? "" : val;
3529 else static assert(0);
3534 // Retrieves the environment variable, returns false on failure.
3535 bool getImpl(in char[] name, out string value) @trusted
3539 // first we ask windows how long the environment variable is,
3540 // then we try to read it in to a buffer of that length. Lots
3541 // of error conditions because the windows API is nasty.
3543 import std.conv : to;
3544 const namezTmp = name.tempCStringW();
3547 // clear error because GetEnvironmentVariable only says it sets it
3548 // if the environment variable is missing, not on other errors.
3549 SetLastError(NO_ERROR);
3550 // len includes terminating null
3551 immutable len = GetEnvironmentVariableW(namezTmp, null, 0);
3554 immutable err = GetLastError();
3555 if (err == ERROR_ENVVAR_NOT_FOUND)
3557 // some other windows error. Might actually be NO_ERROR, because
3558 // GetEnvironmentVariable doesn't specify whether it sets on all
3560 throw new WindowsException(err);
3571 // lenRead is either the number of bytes read w/o null - if buf was long enough - or
3572 // the number of bytes necessary *including* null if buf wasn't long enough
3573 immutable lenRead = GetEnvironmentVariableW(namezTmp, buf.ptr, to!DWORD(buf.length));
3576 immutable err = GetLastError();
3577 if (err == NO_ERROR) // sucessfully read a 0-length variable
3582 if (err == ERROR_ENVVAR_NOT_FOUND) // variable didn't exist
3584 // some other windows error
3585 throw new WindowsException(err);
3587 assert(lenRead != buf.length, "impossible according to msft docs");
3588 if (lenRead < buf.length) // the buffer was long enough
3590 value = toUTF8(buf[0 .. lenRead]);
3593 // resize and go around again, because the environment variable grew
3594 buf.length = lenRead;
3597 else version (Posix)
3599 const vz = core.sys.posix.stdlib.getenv(name.tempCString());
3600 if (vz == null) return false;
3601 auto v = vz[0 .. strlen(vz)];
3603 // Cache the last call's result.
3604 static string lastResult;
3607 // Return non-null array for blank result to distinguish from
3608 // not-present result.
3611 else if (v != lastResult)
3613 lastResult = v.idup;
3618 else static assert(0);
3624 import std.exception : assertThrown;
3626 environment["std_process"] = "foo";
3627 assert(environment["std_process"] == "foo");
3628 assert("std_process" in environment);
3630 // Set variable again (also tests length 1 case)
3631 environment["std_process"] = "b";
3632 assert(environment["std_process"] == "b");
3633 assert("std_process" in environment);
3636 environment.remove("std_process");
3637 assert("std_process" !in environment);
3639 // Remove again, should succeed
3640 environment.remove("std_process");
3641 assert("std_process" !in environment);
3643 // Throw on not found.
3644 assertThrown(environment["std_process"]);
3646 // get() without default value
3647 assert(environment.get("std_process") is null);
3649 // get() with default value
3650 assert(environment.get("std_process", "baz") == "baz");
3652 // get() on an empty (but present) value
3653 environment["std_process"] = "";
3654 auto res = environment.get("std_process");
3655 assert(res !is null);
3657 assert("std_process" in environment);
3659 // Important to do the following round-trip after the previous test
3660 // because it tests toAA with an empty var
3662 // Convert to associative array
3663 auto aa = environment.toAA();
3664 assert(aa.length > 0);
3667 // Wine has some bugs related to environment variables:
3668 // - Wine allows the existence of an env. variable with the name
3669 // "\0", but GetEnvironmentVariable refuses to retrieve it.
3670 // As of 2.067 we filter these out anyway (see comment in toAA).
3672 assert(v == environment[n]);
3675 // ... and back again.
3679 // Complete the roundtrip
3680 auto aa2 = environment.toAA();
3681 import std.conv : text;
3682 assert(aa == aa2, text(aa, " != ", aa2));
3683 assert("std_process" in environment);
3685 // Setting null must have the same effect as remove
3686 environment["std_process"] = null;
3687 assert("std_process" !in environment);
3693 // =============================================================================
3694 // Everything below this line was part of the old std.process, and most of
3695 // it will be deprecated and removed.
3696 // =============================================================================
3700 Copyright: Copyright Digital Mars 2007 - 2009.
3701 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
3702 Authors: $(HTTP digitalmars.com, Walter Bright),
3703 $(HTTP erdani.org, Andrei Alexandrescu),
3704 $(HTTP thecybershadow.net, Vladimir Panteleev)
3705 Source: $(PHOBOSSRC std/_process.d)
3708 Copyright Digital Mars 2007 - 2009.
3709 Distributed under the Boost Software License, Version 1.0.
3710 (See accompanying file LICENSE_1_0.txt or copy at
3711 http://www.boost.org/LICENSE_1_0.txt)
3715 import core.stdc.errno;
3716 import core.stdc.stdlib;
3717 import core.stdc.string;
3722 import std.file, std.format, std.random;
3726 import core.sys.posix.stdlib;
3730 import std.conv, std.file, std.random;
3734 private void toAStringz(in string[] a, const(char)**az)
3736 import std.string : toStringz;
3737 foreach (string s; a)
3739 *az++ = toStringz(s);
3745 /* ========================================================== */
3749 // int spawnvp(int mode, string pathname, string[] argv)
3751 // char** argv_ = cast(char**) core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length));
3752 // scope(exit) core.stdc.stdlib.free(argv_);
3754 // toAStringz(argv, argv_);
3756 // return spawnvp(mode, pathname.tempCString(), argv_);
3760 // Incorporating idea (for spawnvp() on Posix) from Dave Fladebo
3762 enum { _P_WAIT, _P_NOWAIT, _P_OVERLAY }
3763 version (Windows) extern(C) int spawnvp(int, in char *, in char **);
3764 alias P_WAIT = _P_WAIT;
3765 alias P_NOWAIT = _P_NOWAIT;
3767 /* ========================================================== */
3772 Replaces the current process by executing a command, $(D pathname), with
3773 the arguments in $(D argv).
3775 $(BLUE This functions is Posix-Only.)
3777 Typically, the first element of $(D argv) is
3778 the command being executed, i.e. $(D argv[0] == pathname). The 'p'
3779 versions of $(D exec) search the PATH environment variable for $(D
3780 pathname). The 'e' versions additionally take the new process'
3781 environment variables as an array of strings of the form key=value.
3783 Does not return on success (the current process will have been
3784 replaced). Returns -1 on failure with no indication of the
3788 These functions are only supported on POSIX platforms, as the Windows
3789 operating systems do not provide the ability to overwrite the current
3790 process image with another. In single-threaded programs it is possible
3791 to approximate the effect of $(D execv*) by using $(LREF spawnProcess)
3792 and terminating the current process once the child process has returned.
3795 auto commandLine = [ "program", "arg1", "arg2" ];
3798 execv(commandLine[0], commandLine);
3799 throw new Exception("Failed to execute program");
3801 else version (Windows)
3803 import core.stdc.stdlib : _exit;
3804 _exit(wait(spawnProcess(commandLine)));
3807 This is, however, NOT equivalent to POSIX' $(D execv*). For one thing, the
3808 executed program is started as a separate process, with all this entails.
3809 Secondly, in a multithreaded program, other threads will continue to do
3810 work while the current thread is waiting for the child process to complete.
3812 A better option may sometimes be to terminate the current program immediately
3813 after spawning the child process. This is the behaviour exhibited by the
3814 $(LINK2 http://msdn.microsoft.com/en-us/library/431x4c1w.aspx,$(D __exec))
3815 functions in Microsoft's C runtime library, and it is how D's now-deprecated
3816 Windows $(D execv*) functions work. Example:
3818 auto commandLine = [ "program", "arg1", "arg2" ];
3821 execv(commandLine[0], commandLine);
3822 throw new Exception("Failed to execute program");
3824 else version (Windows)
3826 spawnProcess(commandLine);
3827 import core.stdc.stdlib : _exit;
3832 int execv(in string pathname, in string[] argv);
3834 int execve(in string pathname, in string[] argv, in string[] envp);
3836 int execvp(in string pathname, in string[] argv);
3838 int execvpe(in string pathname, in string[] argv, in string[] envp);
3840 else version (Posix)
3842 int execv(in string pathname, in string[] argv)
3844 return execv_(pathname, argv);
3846 int execve(in string pathname, in string[] argv, in string[] envp)
3848 return execve_(pathname, argv, envp);
3850 int execvp(in string pathname, in string[] argv)
3852 return execvp_(pathname, argv);
3854 int execvpe(in string pathname, in string[] argv, in string[] envp)
3856 return execvpe_(pathname, argv, envp);
3860 // Move these C declarations to druntime if we decide to keep the D wrappers
3863 int execv(in char *, in char **);
3864 int execve(in char *, in char **, in char **);
3865 int execvp(in char *, in char **);
3866 version (Windows) int execvpe(in char *, in char **, in char **);
3869 private int execv_(in string pathname, in string[] argv)
3871 auto argv_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length));
3872 scope(exit) core.stdc.stdlib.free(argv_);
3874 toAStringz(argv, argv_);
3876 return execv(pathname.tempCString(), argv_);
3879 private int execve_(in string pathname, in string[] argv, in string[] envp)
3881 auto argv_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length));
3882 scope(exit) core.stdc.stdlib.free(argv_);
3883 auto envp_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + envp.length));
3884 scope(exit) core.stdc.stdlib.free(envp_);
3886 toAStringz(argv, argv_);
3887 toAStringz(envp, envp_);
3889 return execve(pathname.tempCString(), argv_, envp_);
3892 private int execvp_(in string pathname, in string[] argv)
3894 auto argv_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length));
3895 scope(exit) core.stdc.stdlib.free(argv_);
3897 toAStringz(argv, argv_);
3899 return execvp(pathname.tempCString(), argv_);
3902 private int execvpe_(in string pathname, in string[] argv, in string[] envp)
3906 import std.array : split;
3907 import std.conv : to;
3908 // Is pathname rooted?
3909 if (pathname[0] == '/')
3911 // Yes, so just call execve()
3912 return execve(pathname, argv, envp);
3916 // No, so must traverse PATHs, looking for first match
3917 string[] envPaths = split(
3918 to!string(core.stdc.stdlib.getenv("PATH")), ":");
3921 // Note: if any call to execve() succeeds, this process will cease
3922 // execution, so there's no need to check the execve() result through
3925 foreach (string pathDir; envPaths)
3927 string composite = cast(string) (pathDir ~ "/" ~ pathname);
3929 iRet = execve(composite, argv, envp);
3933 iRet = execve(pathname, argv, envp);
3939 else version (Windows)
3941 auto argv_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length));
3942 scope(exit) core.stdc.stdlib.free(argv_);
3943 auto envp_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + envp.length));
3944 scope(exit) core.stdc.stdlib.free(envp_);
3946 toAStringz(argv, argv_);
3947 toAStringz(envp, envp_);
3949 return execvpe(pathname.tempCString(), argv_, envp_);
3959 /****************************************
3960 * Start up the browser and set it to viewing the page at url.
3962 void browse(const(char)[] url);
3967 import core.sys.windows.windows;
3970 else pragma(lib,"shell32.lib");
3972 void browse(const(char)[] url)
3974 ShellExecuteW(null, "open", url.tempCStringW(), null, null, SW_SHOWNORMAL);
3979 import core.stdc.stdio;
3980 import core.stdc.string;
3981 import core.sys.posix.unistd;
3983 void browse(const(char)[] url) nothrow @nogc
3985 const(char)*[5] args;
3987 auto curl = url.tempCString();
3988 const(char)* browser = core.stdc.stdlib.getenv("BROWSER");
3990 { browser = strdup(browser);
3997 args[0] = "open".ptr;
4002 auto childpid = core.sys.posix.unistd.fork();
4005 core.sys.posix.unistd.execvp(args[0], cast(char**) args.ptr);
4006 perror(args[0]); // failed to execute
4010 free(cast(void*) browser);
4013 else version (Posix)
4015 import core.stdc.stdio;
4016 import core.stdc.string;
4017 import core.sys.posix.unistd;
4019 void browse(const(char)[] url) nothrow @nogc
4021 const(char)*[3] args;
4023 const(char)* browser = core.stdc.stdlib.getenv("BROWSER");
4025 { browser = strdup(browser);
4029 //args[0] = "x-www-browser".ptr; // doesn't work on some systems
4030 args[0] = "xdg-open".ptr;
4032 args[1] = url.tempCString();
4035 auto childpid = core.sys.posix.unistd.fork();
4038 core.sys.posix.unistd.execvp(args[0], cast(char**) args.ptr);
4039 perror(args[0]); // failed to execute
4043 free(cast(void*) browser);
4047 static assert(0, "os not supported");