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 `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 `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 `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 `spawnProcess`, `pipeProcess` and `execute`, respectively,
36 except that they take a single command string and run it through
37 the current user's default command interpreter.
38 `executeShell` corresponds roughly to C's `system` function.)
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=$(REF1 $0, object)
86 Most of the functionality in this module is not available on iOS, tvOS
87 and watchOS. The only functions available on those platforms are:
88 $(LREF environment), $(LREF thisProcessID) and $(LREF thisThreadID).
92 import core.thread : ThreadID;
96 import core.sys.posix.sys.wait;
97 import core.sys.posix.unistd;
101 import core.stdc.stdio;
102 import core.sys.windows.winbase;
103 import core.sys.windows.winnt;
105 import std.windows.syserror;
108 import std.internal.cstring;
117 version = iOSDerived;
122 version = iOSDerived;
124 else version (WatchOS)
127 version = iOSDerived;
131 // Some of the following should be moved to druntime.
134 // Microsoft Visual C Runtime (MSVCRT) declarations.
135 version (CRuntime_Microsoft)
137 import core.stdc.stdint;
146 // POSIX API declarations.
149 import core.sys.posix.unistd : getEnvironPtr = environ;
153 import core.thread : Thread;
154 new Thread({assert(getEnvironPtr !is null);}).start();
159 // =============================================================================
160 // Environment variable manipulation.
161 // =============================================================================
164 Manipulates _environment variables using an associative-array-like
167 This class contains only static methods, and cannot be instantiated.
168 See below for examples of use.
170 abstract final class environment
172 static import core.sys.posix.stdlib;
173 import core.stdc.errno : errno, EINVAL;
177 Retrieves the value of the environment variable with the given `name`.
179 auto path = environment["PATH"];
183 $(OBJECTREF Exception) if the environment variable does not exist,
184 or $(REF UTFException, std,utf) if the variable contains invalid UTF-16
185 characters (Windows only).
188 $(LREF environment.get), which doesn't throw on failure.
190 string opIndex(scope const(char)[] name) @safe
192 import std.exception : enforce;
193 return get(name, null).enforce("Environment variable not found: "~name);
197 Retrieves the value of the environment variable with the given `name`,
198 or a default value if the variable doesn't exist.
200 Unlike $(LREF environment.opIndex), this function never throws on Posix.
202 auto sh = environment.get("SHELL", "/bin/sh");
204 This function is also useful in checking for the existence of an
205 environment variable.
207 auto myVar = environment.get("MYVAR");
210 // Environment variable doesn't exist.
211 // Note that we have to use 'is' for the comparison, since
212 // myVar == null is also true if the variable exists but is
217 name = name of the environment variable to retrieve
218 defaultValue = default value to return if the environment variable doesn't exist.
221 the value of the environment variable if found, otherwise
222 `null` if the environment doesn't exist.
225 $(REF UTFException, std,utf) if the variable contains invalid UTF-16
226 characters (Windows only).
228 string get(scope const(char)[] name, string defaultValue = null) @safe
231 getImpl(name, (result) { value = result ? cachedToString(result) : defaultValue; });
236 Assigns the given `value` to the environment variable with the given
238 If `value` is null the variable is removed from environment.
240 If the variable does not exist, it will be created. If it already exists,
241 it will be overwritten.
243 environment["foo"] = "bar";
247 $(OBJECTREF Exception) if the environment variable could not be added
248 (e.g. if the name is invalid).
251 On some platforms, modifying environment variables may not be allowed in
252 multi-threaded programs. See e.g.
253 $(LINK2 https://www.gnu.org/software/libc/manual/html_node/Environment-Access.html#Environment-Access, glibc).
255 inout(char)[] opIndexAssign(return scope inout char[] value, scope const(char)[] name) @trusted
259 import std.exception : enforce, errnoEnforce;
265 if (core.sys.posix.stdlib.setenv(name.tempCString(), value.tempCString(), 1) != -1)
269 // The default errno error message is very uninformative
270 // in the most common case, so we handle it manually.
271 enforce(errno != EINVAL,
272 "Invalid environment variable name: '"~name~"'");
274 "Failed to add environment variable");
277 else version (Windows)
279 import std.windows.syserror : wenforce;
281 SetEnvironmentVariableW(name.tempCStringW(), value.tempCStringW()),
285 else static assert(0);
289 Removes the environment variable with the given `name`.
291 If the variable isn't in the environment, this function returns
292 successfully without doing anything.
295 On some platforms, modifying environment variables may not be allowed in
296 multi-threaded programs. See e.g.
297 $(LINK2 https://www.gnu.org/software/libc/manual/html_node/Environment-Access.html#Environment-Access, glibc).
299 void remove(scope const(char)[] name) @trusted nothrow @nogc
301 version (Windows) SetEnvironmentVariableW(name.tempCStringW(), null);
302 else version (Posix) core.sys.posix.stdlib.unsetenv(name.tempCString());
303 else static assert(0);
307 Identify whether a variable is defined in the environment.
309 Because it doesn't return the value, this function is cheaper than `get`.
310 However, if you do need the value as well, you should just check the
311 return of `get` for `null` instead of using this function first.
316 if ("MY_ENV_FLAG" in environment)
320 if ("MY_ENV_VAR" in environment)
321 doSomething(environment["MY_ENV_VAR"]);
324 if (auto var = environment.get("MY_ENV_VAR"))
328 bool opBinaryRight(string op : "in")(scope const(char)[] name) @trusted
333 return core.sys.posix.stdlib.getenv(name.tempCString()) !is null;
334 else version (Windows)
336 SetLastError(NO_ERROR);
337 if (GetEnvironmentVariableW(name.tempCStringW, null, 0) > 0)
339 immutable err = GetLastError();
341 return true; // zero-length environment variable on Wine / XP
342 if (err == ERROR_ENVVAR_NOT_FOUND)
344 // Some other Windows error, throw.
345 throw new WindowsException(err);
347 else static assert(0);
351 Copies all environment variables into an associative array.
354 While Windows environment variable names are case insensitive, D's
355 built-in associative arrays are not. This function will store all
356 variable names in uppercase (e.g. `PATH`).
359 $(OBJECTREF Exception) if the environment variables could not
360 be retrieved (Windows only).
362 string[string] toAA() @trusted
364 import std.conv : to;
368 auto environ = getEnvironPtr;
369 for (int i=0; environ[i] != null; ++i)
371 import std.string : indexOf;
373 immutable varDef = to!string(environ[i]);
374 immutable eq = indexOf(varDef, '=');
377 immutable name = varDef[0 .. eq];
378 immutable value = varDef[eq+1 .. $];
380 // In POSIX, environment variables may be defined more
381 // than once. This is a security issue, which we avoid
382 // by checking whether the key already exists in the array.
384 // http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/environment-variables.html
385 if (name !in aa) aa[name] = value;
388 else version (Windows)
390 import std.exception : enforce;
391 import std.uni : toUpper;
392 auto envBlock = GetEnvironmentStringsW();
393 enforce(envBlock, "Failed to retrieve environment variables.");
394 scope(exit) FreeEnvironmentStringsW(envBlock);
396 for (int i=0; envBlock[i] != '\0'; ++i)
399 while (envBlock[i] != '=') ++i;
400 immutable name = toUTF8(toUpper(envBlock[start .. i]));
403 while (envBlock[i] != '\0') ++i;
405 // Ignore variables with empty names. These are used internally
406 // by Windows to keep track of each drive's individual current
411 // Just like in POSIX systems, environment variables may be
412 // defined more than once in an environment block on Windows,
413 // and it is just as much of a security issue there. Moreso,
414 // in fact, due to the case insensensitivity of variable names,
415 // which is not handled correctly by all programs.
416 auto val = toUTF8(envBlock[start .. i]);
417 if (name !in aa) aa[name] = val is null ? "" : val;
420 else static assert(0);
425 version (Windows) alias OSChar = WCHAR;
426 else version (Posix) alias OSChar = char;
428 // Retrieves the environment variable. Calls `sink` with a
429 // temporary buffer of OS characters, or `null` if the variable
431 void getImpl(scope const(char)[] name, scope void delegate(const(OSChar)[]) @safe sink) @trusted
433 // fix issue https://issues.dlang.org/show_bug.cgi?id=24549
439 // first we ask windows how long the environment variable is,
440 // then we try to read it in to a buffer of that length. Lots
441 // of error conditions because the windows API is nasty.
443 import std.conv : to;
444 const namezTmp = name.tempCStringW();
447 // clear error because GetEnvironmentVariable only says it sets it
448 // if the environment variable is missing, not on other errors.
449 SetLastError(NO_ERROR);
450 // len includes terminating null
451 immutable len = GetEnvironmentVariableW(namezTmp, null, 0);
454 immutable err = GetLastError();
455 if (err == ERROR_ENVVAR_NOT_FOUND)
457 if (err != NO_ERROR) // Some other Windows error, throw.
458 throw new WindowsException(err);
466 // lenRead is either the number of bytes read w/o null - if buf was long enough - or
467 // the number of bytes necessary *including* null if buf wasn't long enough
468 immutable lenRead = GetEnvironmentVariableW(namezTmp, buf.ptr, to!DWORD(buf.length));
471 immutable err = GetLastError();
472 if (err == NO_ERROR) // sucessfully read a 0-length variable
474 if (err == ERROR_ENVVAR_NOT_FOUND) // variable didn't exist
476 // some other windows error
477 throw new WindowsException(err);
479 assert(lenRead != buf.length, "impossible according to msft docs");
480 if (lenRead < buf.length) // the buffer was long enough
481 return sink(buf[0 .. lenRead]);
482 // resize and go around again, because the environment variable grew
483 buf.length = lenRead;
488 import core.stdc.string : strlen;
490 const vz = core.sys.posix.stdlib.getenv(name.tempCString());
491 if (vz == null) return sink(null);
492 return sink(vz[0 .. strlen(vz)]);
494 else static assert(0);
497 string cachedToString(C)(scope const(C)[] v) @safe
499 import std.algorithm.comparison : equal;
501 // Cache the last call's result.
502 static string lastResult;
505 // Return non-null array for blank result to distinguish from
506 // not-present result.
509 else if (!v.equal(lastResult))
511 import std.conv : to;
512 lastResult = v.to!string;
520 import std.exception : assertThrown;
522 environment["std_process"] = "foo";
523 assert(environment["std_process"] == "foo");
524 assert("std_process" in environment);
526 // Set variable again (also tests length 1 case)
527 environment["std_process"] = "b";
528 assert(environment["std_process"] == "b");
529 assert("std_process" in environment);
532 environment.remove("std_process");
533 assert("std_process" !in environment);
535 // Remove again, should succeed
536 environment.remove("std_process");
537 assert("std_process" !in environment);
539 // Throw on not found.
540 assertThrown(environment["std_process"]);
542 // get() without default value
543 assert(environment.get("std_process") is null);
545 // get() with default value
546 assert(environment.get("std_process", "baz") == "baz");
548 // get() on an empty (but present) value
549 environment["std_process"] = "";
550 auto res = environment.get("std_process");
551 assert(res !is null);
553 assert("std_process" in environment);
555 // Important to do the following round-trip after the previous test
556 // because it tests toAA with an empty var
558 // Convert to associative array
559 auto aa = environment.toAA();
560 assert(aa.length > 0);
563 // Wine has some bugs related to environment variables:
564 // - Wine allows the existence of an env. variable with the name
565 // "\0", but GetEnvironmentVariable refuses to retrieve it.
566 // As of 2.067 we filter these out anyway (see comment in toAA).
568 assert(v == environment[n]);
571 // ... and back again.
575 // Complete the roundtrip
576 auto aa2 = environment.toAA();
577 import std.conv : text;
578 assert(aa == aa2, text(aa, " != ", aa2));
579 assert("std_process" in environment);
581 // Setting null must have the same effect as remove
582 environment["std_process"] = null;
583 assert("std_process" !in environment);
586 // https://issues.dlang.org/show_bug.cgi?id=24549
589 import std.exception : assertThrown;
590 assert(environment.get(null) is null);
591 assertThrown(environment[null]);
592 assert(!(null in environment));
595 // =============================================================================
596 // Functions and classes for process management.
597 // =============================================================================
600 * Returns the process ID of the current process,
601 * which is guaranteed to be unique on the system.
605 * writefln("Current process ID: %d", thisProcessID);
608 @property int thisProcessID() @trusted nothrow @nogc //TODO: @safe
610 version (Windows) return GetCurrentProcessId();
611 else version (Posix) return core.sys.posix.unistd.getpid();
616 * Returns the process ID of the current thread,
617 * which is guaranteed to be unique within the current process.
620 * A $(REF ThreadID, core,thread) value for the calling thread.
624 * writefln("Current thread ID: %s", thisThreadID);
627 @property ThreadID thisThreadID() @trusted nothrow @nogc //TODO: @safe
630 return GetCurrentThreadId();
634 import core.sys.posix.pthread : pthread_self;
635 return pthread_self();
644 pidA = thisProcessID;
648 auto t = new Thread({
649 pidB = thisProcessID;
655 assert(pidA == pidB);
656 assert(tidA != tidB);
660 package(std) string uniqueTempPath() @safe
662 import std.file : tempDir;
663 import std.path : buildPath;
664 import std.uuid : randomUUID;
665 // Path should contain spaces to test escaping whitespace
666 return buildPath(tempDir(), "std.process temporary file " ~
667 randomUUID().toString());
671 version (iOSDerived) {}
675 Spawns a new process, optionally assigning it an arbitrary set of standard
676 input, output, and error streams.
678 The function returns immediately, leaving the child process to execute
679 in parallel with its parent. It is recommended to always call $(LREF wait)
680 on the returned $(LREF Pid) unless the process was spawned with
681 `Config.detached` flag, as detailed in the documentation for `wait`.
684 There are four overloads of this function. The first two take an array
685 of strings, `args`, which should contain the program name as the
686 zeroth element and any command-line arguments in subsequent elements.
687 The third and fourth versions are included for convenience, and may be
688 used when there are no command-line arguments. They take a single string,
689 `program`, which specifies the program name.
691 Unless a directory is specified in `args[0]` or `program`,
692 `spawnProcess` will search for the program in a platform-dependent
693 manner. On POSIX systems, it will look for the executable in the
694 directories listed in the PATH environment variable, in the order
695 they are listed. On Windows, it will search for the executable in
696 the following sequence:
698 $(LI The directory from which the application loaded.)
699 $(LI The current directory for the parent process.)
700 $(LI The 32-bit Windows system directory.)
701 $(LI The 16-bit Windows system directory.)
702 $(LI The Windows directory.)
703 $(LI The directories listed in the PATH environment variable.)
706 // Run an executable called "prog" located in the current working
708 auto pid = spawnProcess("./prog");
709 scope(exit) wait(pid);
710 // We can do something else while the program runs. The scope guard
711 // ensures that the process is waited for at the end of the scope.
714 // Run DMD on the file "myprog.d", specifying a few compiler switches:
715 auto dmdPid = spawnProcess(["dmd", "-O", "-release", "-inline", "myprog.d" ]);
716 if (wait(dmdPid) != 0)
717 writeln("Compilation failed!");
720 Environment_variables:
721 By default, the child process inherits the environment of the parent
722 process, along with any additional variables specified in the `env`
723 parameter. If the same variable exists in both the parent's environment
724 and in `env`, the latter takes precedence.
726 If the $(LREF Config.newEnv) flag is set in `config`, the child
727 process will $(I not) inherit the parent's environment. Its entire
728 environment will then be determined by `env`.
730 wait(spawnProcess("myapp", ["foo" : "bar"], Config.newEnv));
734 The optional arguments `stdin`, `stdout` and `stderr` may
735 be used to assign arbitrary $(REF File, std,stdio) objects as the standard
736 input, output and error streams, respectively, of the child process. The
737 former must be opened for reading, while the latter two must be opened for
738 writing. The default is for the child process to inherit the standard
739 streams of its parent.
741 // Run DMD on the file myprog.d, logging any error messages to a
742 // file named errors.log.
743 auto logFile = File("errors.log", "w");
744 auto pid = spawnProcess(["dmd", "myprog.d"],
749 writeln("Compilation failed. See errors.log for details.");
752 Note that if you pass a `File` object that is $(I not)
753 one of the standard input/output/error streams of the parent process,
754 that stream will by default be $(I closed) in the parent process when
755 this function returns. See the $(LREF Config) documentation below for
756 information about how to disable this behaviour.
758 Beware of buffering issues when passing `File` objects to
759 `spawnProcess`. The child process will inherit the low-level raw
760 read/write offset associated with the underlying file descriptor, but
761 it will not be aware of any buffered data. In cases where this matters
762 (e.g. when a file should be aligned before being passed on to the
763 child process), it may be a good idea to use unbuffered streams, or at
764 least ensure all relevant buffers are flushed.
767 args = An array which contains the program name as the zeroth element
768 and any command-line arguments in the following elements.
769 stdin = The standard input stream of the child process.
770 This can be any $(REF File, std,stdio) that is opened for reading.
771 By default the child process inherits the parent's input
773 stdout = The standard output stream of the child process.
774 This can be any $(REF File, std,stdio) that is opened for writing.
775 By default the child process inherits the parent's output stream.
776 stderr = The standard error stream of the child process.
777 This can be any $(REF File, std,stdio) that is opened for writing.
778 By default the child process inherits the parent's error stream.
779 env = Additional environment variables for the child process.
780 config = Flags that control process creation. See $(LREF Config)
781 for an overview of available flags.
782 workDir = The working directory for the new process.
783 By default the child process inherits the parent's working
787 A $(LREF Pid) object that corresponds to the spawned process.
790 $(LREF ProcessException) on failure to start the process.$(BR)
791 $(REF StdioException, std,stdio) on failure to pass one of the streams
792 to the child process (Windows only).$(BR)
793 $(REF RangeError, core,exception) if `args` is empty.
795 Pid spawnProcess(scope const(char[])[] args,
796 File stdin = std.stdio.stdin,
797 File stdout = std.stdio.stdout,
798 File stderr = std.stdio.stderr,
799 const string[string] env = null,
800 Config config = Config.none,
801 scope const char[] workDir = null)
806 const commandLine = escapeShellArguments(args);
807 const program = args.length ? args[0] : null;
808 return spawnProcessWin(commandLine, program, stdin, stdout, stderr, env, config, workDir);
812 return spawnProcessPosix(args, stdin, stdout, stderr, env, config, workDir);
819 Pid spawnProcess(scope const(char[])[] args,
820 const string[string] env,
821 Config config = Config.none,
822 scope const(char)[] workDir = null)
823 @trusted // TODO: Should be @safe
825 return spawnProcess(args,
835 Pid spawnProcess(scope const(char)[] program,
836 File stdin = std.stdio.stdin,
837 File stdout = std.stdio.stdout,
838 File stderr = std.stdio.stderr,
839 const string[string] env = null,
840 Config config = Config.none,
841 scope const(char)[] workDir = null)
844 return spawnProcess((&program)[0 .. 1],
845 stdin, stdout, stderr, env, config, workDir);
849 Pid spawnProcess(scope const(char)[] program,
850 const string[string] env,
851 Config config = Config.none,
852 scope const(char)[] workDir = null)
855 return spawnProcess((&program)[0 .. 1], env, config, workDir);
858 version (Posix) private enum InternalError : ubyte
871 Implementation of spawnProcess() for POSIX.
873 envz should be a zero-terminated array of zero-terminated strings
874 on the form "var=value".
877 private Pid spawnProcessPosix(scope const(char[])[] args,
881 scope const string[string] env,
883 scope const(char)[] workDir)
884 @trusted // TODO: Should be @safe
886 import core.exception : RangeError;
887 import std.algorithm.searching : any;
888 import std.conv : text;
889 import std.path : isDirSeparator;
890 import std.string : toStringz;
892 if (args.empty) throw new RangeError();
893 const(char)[] name = args[0];
894 if (!any!isDirSeparator(name))
896 name = searchPathFor(name);
898 throw new ProcessException(text("Executable file not found: ", args[0]));
901 // Convert program name and arguments to C-style strings.
902 auto argz = new const(char)*[args.length+1];
903 argz[0] = toStringz(name);
904 foreach (i; 1 .. args.length) argz[i] = toStringz(args[i]);
907 // Prepare environment.
908 auto envz = createEnv(env, !(config.flags & Config.Flags.newEnv));
910 // Open the working directory.
911 // We use open in the parent and fchdir in the child
912 // so that most errors (directory doesn't exist, not a directory)
913 // can be propagated as exceptions before forking.
915 scope(exit) if (workDirFD >= 0) close(workDirFD);
918 import core.sys.posix.fcntl : open, O_RDONLY, stat_t, fstat, S_ISDIR;
919 workDirFD = open(workDir.tempCString(), O_RDONLY);
921 throw ProcessException.newFromErrno("Failed to open working directory");
923 if (fstat(workDirFD, &s) < 0)
924 throw ProcessException.newFromErrno("Failed to stat working directory");
925 if (!S_ISDIR(s.st_mode))
926 throw new ProcessException("Not a directory: " ~ cast(string) workDir);
929 static int getFD(ref File f) { return core.stdc.stdio.fileno(f.getFP()); }
931 // Get the file descriptors of the streams.
932 // These could potentially be invalid, but that is OK. If so, later calls
933 // to dup2() and close() will just silently fail without causing any harm.
934 auto stdinFD = getFD(stdin);
935 auto stdoutFD = getFD(stdout);
936 auto stderrFD = getFD(stderr);
938 // We don't have direct access to the errors that may happen in a child process.
939 // So we use this pipe to deliver them.
941 if (core.sys.posix.unistd.pipe(forkPipe) == 0)
942 setCLOEXEC(forkPipe[1], true);
944 throw ProcessException.newFromErrno("Could not create pipe to check startup of child");
945 scope(exit) close(forkPipe[0]);
948 To create detached process, we use double fork technique
949 but we don't have a direct access to the second fork pid from the caller side thus use a pipe.
950 We also can't reuse forkPipe for that purpose
951 because we can't predict the order in which pid and possible error will be written
952 since the first and the second forks will run in parallel.
955 if (config.flags & Config.Flags.detached)
957 if (core.sys.posix.unistd.pipe(pidPipe) != 0)
958 throw ProcessException.newFromErrno("Could not create pipe to get process pid");
959 setCLOEXEC(pidPipe[1], true);
961 scope(exit) if (config.flags & Config.Flags.detached) close(pidPipe[0]);
963 static void abortOnError(int forkPipeOut, InternalError errorType, int error) nothrow
965 core.sys.posix.unistd.write(forkPipeOut, &errorType, errorType.sizeof);
966 core.sys.posix.unistd.write(forkPipeOut, &error, error.sizeof);
968 core.sys.posix.unistd._exit(1);
972 void closePipeWriteEnds()
975 if (config.flags & Config.Flags.detached)
979 auto id = core.sys.posix.unistd.fork();
982 closePipeWriteEnds();
983 throw ProcessException.newFromErrno("Failed to spawn new process");
986 void forkChild() nothrow @nogc
988 static import core.sys.posix.stdio;
992 // no need for the read end of pipe on child side
993 if (config.flags & Config.Flags.detached)
996 auto forkPipeOut = forkPipe[1];
997 immutable pidPipeOut = pidPipe[1];
999 // Set the working directory.
1002 if (fchdir(workDirFD) < 0)
1004 // Fail. It is dangerous to run a program
1005 // in an unexpected working directory.
1006 abortOnError(forkPipeOut, InternalError.chdir, .errno);
1013 // Redirect streams and close the old file descriptors.
1014 // In the case that stderr is redirected to stdout, we need
1015 // to backup the file descriptor since stdout may be redirected
1017 if (stderrFD == STDOUT_FILENO) stderrFD = dup(stderrFD);
1018 dup2(stdinFD, STDIN_FILENO);
1019 dup2(stdoutFD, STDOUT_FILENO);
1020 dup2(stderrFD, STDERR_FILENO);
1022 // Ensure that the standard streams aren't closed on execute, and
1023 // optionally close all other file descriptors.
1024 setCLOEXEC(STDIN_FILENO, false);
1025 setCLOEXEC(STDOUT_FILENO, false);
1026 setCLOEXEC(STDERR_FILENO, false);
1028 if (!(config.flags & Config.Flags.inheritFDs))
1031 import core.sys.freebsd.unistd : closefrom;
1032 else version (OpenBSD)
1033 import core.sys.openbsd.unistd : closefrom;
1035 static if (!__traits(compiles, closefrom))
1037 void fallback (int lowfd)
1039 import core.sys.posix.dirent : dirent, opendir, readdir, closedir, DIR;
1040 import core.sys.posix.unistd : close;
1041 import core.sys.posix.stdlib : atoi, malloc, free;
1042 import core.sys.posix.sys.resource : rlimit, getrlimit, RLIMIT_NOFILE;
1044 // Get the maximum number of file descriptors that could be open.
1046 if (getrlimit(RLIMIT_NOFILE, &r) != 0)
1047 abortOnError(forkPipeOut, InternalError.getrlimit, .errno);
1049 immutable maxDescriptors = cast(int) r.rlim_cur;
1051 // Missing druntime declaration
1052 pragma(mangle, "dirfd")
1053 extern(C) nothrow @nogc int dirfd(DIR* dir);
1057 // We read from /dev/fd or /proc/self/fd only if the limit is high enough
1058 if (maxDescriptors > 128*1024)
1060 // Try to open the directory /dev/fd or /proc/self/fd
1061 dir = opendir("/dev/fd");
1062 if (dir is null) dir = opendir("/proc/self/fd");
1065 // If we have a directory, close all file descriptors except stdin, stdout, and stderr
1068 scope(exit) closedir(dir);
1070 int opendirfd = dirfd(dir);
1072 // Iterate over all file descriptors
1075 dirent* entry = readdir(dir);
1077 if (entry is null) break;
1078 if (entry.d_name[0] == '.') continue;
1080 int fd = atoi(cast(char*) entry.d_name);
1082 // Don't close stdin, stdout, stderr, or the directory file descriptor
1083 if (fd < lowfd || fd == opendirfd) continue;
1090 // This is going to allocate 8 bytes for each possible file descriptor from lowfd to r.rlim_cur
1091 if (maxDescriptors <= 128*1024)
1093 // NOTE: malloc() and getrlimit() are not on the POSIX async
1094 // signal safe functions list, but practically this should
1095 // not be a problem. Java VM and CPython also use malloc()
1096 // in its own implementation via opendir().
1097 import core.stdc.stdlib : malloc;
1098 import core.sys.posix.poll : pollfd, poll, POLLNVAL;
1100 immutable maxToClose = maxDescriptors - lowfd;
1102 // Call poll() to see which ones are actually open:
1103 auto pfds = cast(pollfd*) malloc(pollfd.sizeof * maxToClose);
1106 abortOnError(forkPipeOut, InternalError.malloc, .errno);
1109 foreach (i; 0 .. maxToClose)
1111 pfds[i].fd = i + lowfd;
1113 pfds[i].revents = 0;
1116 if (poll(pfds, maxToClose, 0) < 0)
1117 // couldn't use poll, use the slow path.
1120 foreach (i; 0 .. maxToClose)
1122 // POLLNVAL will be set if the file descriptor is invalid.
1123 if (!(pfds[i].revents & POLLNVAL)) close(pfds[i].fd);
1129 // Fall back to closing everything.
1130 foreach (i; lowfd .. maxDescriptors)
1138 // closefrom may not be available on the version of glibc we build against.
1139 // Until we find a way to perform this check we will try to use dlsym to
1140 // check for the function. See: https://github.com/dlang/phobos/pull/9048
1141 version (CRuntime_Glibc)
1143 void closefrom (int lowfd) {
1144 static bool tryGlibcClosefrom (int lowfd) {
1145 import core.sys.posix.dlfcn : dlopen, dlclose, dlsym, dlerror, RTLD_LAZY;
1147 void *handle = dlopen("libc.so.6", RTLD_LAZY);
1150 scope(exit) dlclose(handle);
1154 alias closefromT = extern(C) void function(int) @nogc @system nothrow;
1155 auto closefrom = cast(closefromT) dlsym(handle, "closefrom");
1163 if (!tryGlibcClosefrom(lowfd))
1168 alias closefrom = fallback;
1171 // We need to close all open file descriptors excluding std{in,out,err}
1172 // and forkPipeOut because we still need it.
1173 // Since the various libc's provide us with `closefrom` move forkPipeOut
1174 // to position 3, right after STDERR_FILENO, and close all FDs following that.
1175 if (dup2(forkPipeOut, 3) == -1)
1176 abortOnError(forkPipeOut, InternalError.closefds_dup2, .errno);
1178 // forkPipeOut needs to be closed after we call `exec`.
1179 setCLOEXEC(forkPipeOut, true);
1180 closefrom(forkPipeOut + 1);
1182 else // This is already done if we don't inherit descriptors.
1184 // Close the old file descriptors, unless they are
1185 // either of the standard streams.
1186 if (stdinFD > STDERR_FILENO) close(stdinFD);
1187 if (stdoutFD > STDERR_FILENO) close(stdoutFD);
1188 if (stderrFD > STDERR_FILENO) close(stderrFD);
1191 if (config.preExecFunction !is null)
1193 if (config.preExecFunction() != true)
1195 abortOnError(forkPipeOut, InternalError.preExec, .errno);
1199 if (config.preExecDelegate !is null)
1201 if (config.preExecDelegate() != true)
1203 abortOnError(forkPipeOut, InternalError.preExec, .errno);
1208 core.sys.posix.unistd.execve(argz[0], argz.ptr, envz is null ? getEnvironPtr : envz);
1210 // If execution fails, exit as quickly as possible.
1211 abortOnError(forkPipeOut, InternalError.exec, .errno);
1214 if (config.flags & Config.Flags.detached)
1216 auto secondFork = core.sys.posix.unistd.fork();
1217 if (secondFork == 0)
1222 else if (secondFork == -1)
1224 auto secondForkErrno = .errno;
1226 abortOnError(forkPipeOut, InternalError.doubleFork, secondForkErrno);
1230 core.sys.posix.unistd.write(pidPipeOut, &secondFork, pid_t.sizeof);
1249 closePipeWriteEnds();
1250 auto status = InternalError.noerror;
1251 auto readExecResult = core.sys.posix.unistd.read(forkPipe[0], &status, status.sizeof);
1252 // Save error number just in case if subsequent "waitpid" fails and overrides errno
1253 immutable lastError = .errno;
1255 if (config.flags & Config.Flags.detached)
1257 // Forked child exits right after creating second fork. So it should be safe to wait here.
1258 import core.sys.posix.sys.wait : waitpid;
1260 waitpid(id, &waitResult, 0);
1263 if (readExecResult == -1)
1264 throw ProcessException.newFromErrno(lastError, "Could not read from pipe to get child status");
1267 if (status != InternalError.noerror)
1270 readExecResult = read(forkPipe[0], &error, error.sizeof);
1272 final switch (status)
1274 case InternalError.chdir:
1275 errorMsg = "Failed to set working directory";
1277 case InternalError.getrlimit:
1278 errorMsg = "getrlimit failed";
1280 case InternalError.exec:
1281 errorMsg = "Failed to execute '" ~ cast(string) name ~ "'";
1283 case InternalError.doubleFork:
1284 // Can happen only when starting detached process
1285 assert(config.flags & Config.Flags.detached);
1286 errorMsg = "Failed to fork twice";
1288 case InternalError.malloc:
1289 errorMsg = "Failed to allocate memory";
1291 case InternalError.preExec:
1292 errorMsg = "Failed to execute preExecFunction or preExecDelegate";
1294 case InternalError.closefds_dup2:
1295 assert(!(config.flags & Config.Flags.inheritFDs));
1296 errorMsg = "Failed to close inherited file descriptors";
1298 case InternalError.noerror:
1301 if (readExecResult == error.sizeof)
1302 throw ProcessException.newFromErrno(error, errorMsg);
1303 throw new ProcessException(errorMsg);
1305 else if (config.flags & Config.Flags.detached)
1308 if (read(pidPipe[0], &id, id.sizeof) != id.sizeof)
1309 throw ProcessException.newFromErrno("Could not read from pipe to get detached process id");
1312 // Parent process: Close streams and return.
1313 if (!(config.flags & Config.Flags.retainStdin ) && stdinFD > STDERR_FILENO
1314 && stdinFD != getFD(std.stdio.stdin ))
1316 if (!(config.flags & Config.Flags.retainStdout) && stdoutFD > STDERR_FILENO
1317 && stdoutFD != getFD(std.stdio.stdout))
1319 if (!(config.flags & Config.Flags.retainStderr) && stderrFD > STDERR_FILENO
1320 && stderrFD != getFD(std.stdio.stderr))
1322 return new Pid(id, owned);
1329 import std.concurrency : ownerTid, receiveTimeout, send, spawn;
1330 import std.datetime : seconds;
1334 sigaddset(&ss, SIGINT);
1335 pthread_sigmask(SIG_BLOCK, &ss, null);
1338 preExecFunction: () @trusted @nogc nothrow {
1339 // Reset signal handlers
1341 if (sigfillset(&ss) != 0)
1345 if (sigprocmask(SIG_UNBLOCK, &ss, null) != 0)
1353 auto pid = spawnProcess(["sleep", "10000"],
1366 // kill the spawned process with SIGINT
1367 // and send its return code
1368 spawn((shared Pid pid) {
1369 auto p = cast() pid;
1371 auto code = wait(p);
1373 send(ownerTid, code);
1374 }, cast(shared) pid);
1376 auto received = receiveTimeout(3.seconds, (int) {});
1386 auto config = Config(
1387 preExecFunction: function() @trusted {
1391 preExecDelegate: delegate() @trusted {
1392 // j should now be 1, as preExecFunction is called before
1393 // preExecDelegate is.
1398 auto pid = spawnProcess(["false"], config: config);
1399 assert(wait(pid) == i + 1);
1404 Implementation of spawnProcess() for Windows.
1406 commandLine must contain the entire command line, properly
1407 quoted/escaped as required by CreateProcessW().
1409 envz must be a pointer to a block of UTF-16 characters on the form
1410 "var1=value1\0var2=value2\0...varN=valueN\0\0".
1413 private Pid spawnProcessWin(scope const(char)[] commandLine,
1414 scope const(char)[] program,
1418 scope const string[string] env,
1420 scope const(char)[] workDir)
1423 import core.exception : RangeError;
1424 import std.conv : text;
1426 if (commandLine.empty) throw new RangeError("Command line is empty");
1428 // Prepare environment.
1429 auto envz = createEnv(env, !(config.flags & Config.Flags.newEnv));
1431 // Startup info for CreateProcessW().
1432 STARTUPINFO_W startinfo;
1433 startinfo.cb = startinfo.sizeof;
1434 static int getFD(ref File f) { return f.isOpen ? f.fileno : -1; }
1436 // Extract file descriptors and HANDLEs from the streams and make the
1437 // handles inheritable.
1438 static void prepareStream(ref File file, DWORD stdHandle, string which,
1439 out int fileDescriptor, out HANDLE handle)
1441 enum _NO_CONSOLE_FILENO = cast(HANDLE)-2;
1442 fileDescriptor = getFD(file);
1444 if (fileDescriptor >= 0)
1445 handle = file.windowsHandle;
1446 // Windows GUI applications have a fd but not a valid Windows HANDLE.
1447 if (handle is null || handle == INVALID_HANDLE_VALUE || handle == _NO_CONSOLE_FILENO)
1448 handle = GetStdHandle(stdHandle);
1451 if (GetHandleInformation(handle, &dwFlags))
1453 if (!(dwFlags & HANDLE_FLAG_INHERIT))
1455 if (!SetHandleInformation(handle,
1456 HANDLE_FLAG_INHERIT,
1457 HANDLE_FLAG_INHERIT))
1459 throw new StdioException(
1460 "Failed to make "~which~" stream inheritable by child process ("
1461 ~generateSysErrorMsg() ~ ')',
1467 int stdinFD = -1, stdoutFD = -1, stderrFD = -1;
1468 prepareStream(stdin, STD_INPUT_HANDLE, "stdin" , stdinFD, startinfo.hStdInput );
1469 prepareStream(stdout, STD_OUTPUT_HANDLE, "stdout", stdoutFD, startinfo.hStdOutput);
1470 prepareStream(stderr, STD_ERROR_HANDLE, "stderr", stderrFD, startinfo.hStdError );
1472 if ((startinfo.hStdInput != null && startinfo.hStdInput != INVALID_HANDLE_VALUE)
1473 || (startinfo.hStdOutput != null && startinfo.hStdOutput != INVALID_HANDLE_VALUE)
1474 || (startinfo.hStdError != null && startinfo.hStdError != INVALID_HANDLE_VALUE))
1475 startinfo.dwFlags = STARTF_USESTDHANDLES;
1478 PROCESS_INFORMATION pi;
1479 DWORD dwCreationFlags =
1480 CREATE_UNICODE_ENVIRONMENT |
1481 ((config.flags & Config.Flags.suppressConsole) ? CREATE_NO_WINDOW : 0);
1482 // workaround until https://issues.dlang.org/show_bug.cgi?id=14696 is fixed
1483 auto pworkDir = workDir.tempCStringW();
1484 if (!CreateProcessW(null, commandLine.tempCStringW().buffPtr,
1485 null, null, true, dwCreationFlags,
1486 envz, workDir.length ? pworkDir : null, &startinfo, &pi))
1487 throw ProcessException.newFromLastError("Failed to spawn process \"" ~ cast(string) program ~ '"');
1489 // figure out if we should close any of the streams
1490 if (!(config.flags & Config.Flags.retainStdin ) && stdinFD > STDERR_FILENO
1491 && stdinFD != getFD(std.stdio.stdin ))
1493 if (!(config.flags & Config.Flags.retainStdout) && stdoutFD > STDERR_FILENO
1494 && stdoutFD != getFD(std.stdio.stdout))
1496 if (!(config.flags & Config.Flags.retainStderr) && stderrFD > STDERR_FILENO
1497 && stderrFD != getFD(std.stdio.stderr))
1500 // close the thread handle in the process info structure
1501 CloseHandle(pi.hThread);
1502 if (config.flags & Config.Flags.detached)
1504 CloseHandle(pi.hProcess);
1505 return new Pid(pi.dwProcessId);
1507 return new Pid(pi.dwProcessId, pi.hProcess);
1510 // Converts childEnv to a zero-terminated array of zero-terminated strings
1511 // on the form "name=value", optionally adding those of the current process'
1512 // environment strings that are not present in childEnv. If the parent's
1513 // environment should be inherited without modification, this function
1516 private const(char*)* createEnv(const string[string] childEnv,
1517 bool mergeWithParentEnv)
1519 // Determine the number of strings in the parent's environment.
1520 int parentEnvLength = 0;
1521 auto environ = getEnvironPtr;
1522 if (mergeWithParentEnv)
1524 if (childEnv.length == 0) return null;
1525 while (environ[parentEnvLength] != null) ++parentEnvLength;
1528 // Convert the "new" variables to C-style strings.
1529 auto envz = new const(char)*[parentEnvLength + childEnv.length + 1];
1531 foreach (var, val; childEnv)
1532 envz[pos++] = (var~'='~val~'\0').ptr;
1534 // Add the parent's environment.
1535 foreach (environStr; environ[0 .. parentEnvLength])
1538 while (environStr[eqPos] != '=' && environStr[eqPos] != '\0') ++eqPos;
1539 if (environStr[eqPos] != '=') continue;
1540 auto var = environStr[0 .. eqPos];
1541 if (var in childEnv) continue;
1542 envz[pos++] = environStr;
1548 version (Posix) @system unittest
1550 auto e1 = createEnv(null, false);
1551 assert(e1 != null && *e1 == null);
1553 auto e2 = createEnv(null, true);
1556 auto e3 = createEnv(["foo" : "bar", "hello" : "world"], false);
1557 assert(e3 != null && e3[0] != null && e3[1] != null && e3[2] == null);
1558 assert((e3[0][0 .. 8] == "foo=bar\0" && e3[1][0 .. 12] == "hello=world\0")
1559 || (e3[0][0 .. 12] == "hello=world\0" && e3[1][0 .. 8] == "foo=bar\0"));
1563 // Converts childEnv to a Windows environment block, which is on the form
1564 // "name1=value1\0name2=value2\0...nameN=valueN\0\0", optionally adding
1565 // those of the current process' environment strings that are not present
1566 // in childEnv. Returns null if the parent's environment should be
1567 // inherited without modification, as this is what is expected by
1570 private LPVOID createEnv(const string[string] childEnv,
1571 bool mergeWithParentEnv)
1573 if (mergeWithParentEnv && childEnv.length == 0) return null;
1574 import std.array : appender;
1575 import std.uni : toUpper;
1576 auto envz = appender!(wchar[])();
1577 void put(string var, string val)
1582 envz.put(cast(wchar) '\0');
1585 // Add the variables in childEnv, removing them from parentEnv
1586 // if they exist there too.
1587 auto parentEnv = mergeWithParentEnv ? environment.toAA() : null;
1588 foreach (k, v; childEnv)
1590 auto uk = toUpper(k);
1592 if (uk in parentEnv) parentEnv.remove(uk);
1595 // Add remaining parent environment variables.
1596 foreach (k, v; parentEnv) put(k, v);
1598 // Two final zeros are needed in case there aren't any environment vars,
1599 // and the last one does no harm when there are.
1601 return envz.data.ptr;
1604 version (Windows) @system unittest
1606 assert(createEnv(null, true) == null);
1607 assert((cast(wchar*) createEnv(null, false))[0 .. 2] == "\0\0"w);
1608 auto e1 = (cast(wchar*) createEnv(["foo":"bar", "ab":"c"], false))[0 .. 14];
1609 assert(e1 == "FOO=bar\0AB=c\0\0"w || e1 == "AB=c\0FOO=bar\0\0"w);
1612 // Searches the PATH variable for the given executable file,
1613 // (checking that it is in fact executable).
1615 package(std) string searchPathFor(scope const(char)[] executable)
1618 import std.algorithm.iteration : splitter;
1619 import std.conv : to;
1620 import std.path : chainPath;
1622 typeof(return) result;
1624 environment.getImpl("PATH",
1625 (scope const(char)[] path)
1630 foreach (dir; splitter(path, ":"))
1632 auto execPath = chainPath(dir, executable);
1633 if (isExecutable(execPath))
1635 result = execPath.to!(typeof(result));
1644 // Checks whether the file exists and can be executed by the
1647 private bool isExecutable(R)(R path) @trusted nothrow @nogc
1648 if (isSomeFiniteCharInputRange!R)
1650 return (access(path.tempCString(), X_OK) == 0);
1653 version (Posix) @safe unittest
1655 import std.algorithm;
1656 auto lsPath = searchPathFor("ls");
1657 assert(!lsPath.empty);
1658 assert(lsPath[0] == '/');
1659 assert(lsPath.endsWith("ls"));
1660 auto unlikely = searchPathFor("lkmqwpoialhggyaofijadsohufoiqezm");
1661 assert(unlikely is null, "Are you kidding me?");
1664 // Sets or unsets the FD_CLOEXEC flag on the given file descriptor.
1666 private void setCLOEXEC(int fd, bool on) nothrow @nogc
1668 import core.sys.posix.fcntl : fcntl, F_GETFD, FD_CLOEXEC, F_SETFD;
1669 auto flags = fcntl(fd, F_GETFD);
1672 if (on) flags |= FD_CLOEXEC;
1673 else flags &= ~(cast(typeof(flags)) FD_CLOEXEC);
1674 flags = fcntl(fd, F_SETFD, flags);
1676 assert(flags != -1 || .errno == EBADF);
1679 @system unittest // Command line arguments in spawnProcess().
1681 version (Windows) TestScript prog =
1682 "if not [%~1]==[foo] ( exit 1 )
1683 if not [%~2]==[bar] ( exit 2 )
1685 else version (Posix) TestScript prog =
1686 `if test "$1" != "foo"; then exit 1; fi
1687 if test "$2" != "bar"; then exit 2; fi
1689 assert(wait(spawnProcess(prog.path)) == 1);
1690 assert(wait(spawnProcess([prog.path])) == 1);
1691 assert(wait(spawnProcess([prog.path, "foo"])) == 2);
1692 assert(wait(spawnProcess([prog.path, "foo", "baz"])) == 2);
1693 assert(wait(spawnProcess([prog.path, "foo", "bar"])) == 0);
1696 // test that file descriptors are correctly closed / left open.
1697 // ideally this would be done by the child process making libc
1698 // calls, but we make do...
1699 version (Posix) @system unittest
1701 import core.stdc.errno : errno;
1702 import core.sys.posix.fcntl : open, O_RDONLY;
1703 import core.sys.posix.unistd : close;
1704 import std.algorithm.searching : canFind, findSplitBefore;
1705 import std.array : split;
1706 import std.conv : to;
1707 static import std.file;
1708 import std.functional : reverseArgs;
1709 import std.path : buildPath;
1711 auto directory = uniqueTempPath();
1712 std.file.mkdir(directory);
1713 scope(exit) std.file.rmdirRecurse(directory);
1714 auto path = buildPath(directory, "tmp");
1715 std.file.write(path, null);
1717 auto fd = open(path.tempCString, O_RDONLY);
1720 import core.stdc.string : strerror;
1721 import std.stdio : stderr;
1722 import std.string : fromStringz;
1725 stderr.writefln("%s: could not open '%s': %s",
1726 __FUNCTION__, path, strerror(errno).fromStringz);
1727 // TODO: should we retry here instead?
1730 scope(exit) close(fd);
1732 // command >&2 (or any other number) checks whethether that number
1733 // file descriptor is open.
1734 // Can't use this for arbitrary descriptors as many shells only support
1735 // single digit fds.
1736 TestScript testDefaults = `command >&0 && command >&1 && command >&2`;
1737 assert(execute(testDefaults.path).status == 0);
1738 assert(execute(testDefaults.path, null, Config.inheritFDs).status == 0);
1740 // Try a few different methods to check whether there are any
1741 // incorrectly-open files.
1744 // try /proc/<pid>/fd/ on linux
1747 TestScript proc = "ls /proc/$$/fd";
1748 auto procRes = execute(proc.path, null);
1749 if (procRes.status == 0)
1751 auto fdStr = fd.to!string;
1752 assert(!procRes.output.split.canFind(fdStr));
1753 assert(execute(proc.path, null, Config.inheritFDs)
1754 .output.split.canFind(fdStr));
1759 // try fuser (might sometimes need permissions)
1760 TestScript fuser = "echo $$ && fuser -f " ~ path;
1761 auto fuserRes = execute(fuser.path, null);
1762 if (fuserRes.status == 0)
1764 assert(!reverseArgs!canFind(fuserRes
1765 .output.findSplitBefore("\n").expand));
1766 assert(reverseArgs!canFind(execute(fuser.path, null, Config.inheritFDs)
1767 .output.findSplitBefore("\n").expand));
1771 // last resort, try lsof (not available on all Posix)
1772 TestScript lsof = "lsof -p$$";
1773 auto lsofRes = execute(lsof.path, null);
1774 if (lsofRes.status == 0)
1776 assert(!lsofRes.output.canFind(path));
1777 auto lsofOut = execute(lsof.path, null, Config.inheritFDs).output;
1778 if (!lsofOut.canFind(path))
1780 std.stdio.stderr.writeln(__FILE__, ':', __LINE__,
1781 ": Warning: unexpected lsof output:", lsofOut);
1786 std.stdio.stderr.writeln(__FILE__, ':', __LINE__,
1787 ": Warning: Couldn't find any way to check open files");
1792 @system unittest // Environment variables in spawnProcess().
1794 // We really should use set /a on Windows, but Wine doesn't support it.
1795 version (Windows) TestScript envProg =
1796 `if [%STD_PROCESS_UNITTEST1%] == [1] (
1797 if [%STD_PROCESS_UNITTEST2%] == [2] (exit 3)
1800 if [%STD_PROCESS_UNITTEST1%] == [4] (
1801 if [%STD_PROCESS_UNITTEST2%] == [2] (exit 6)
1804 if [%STD_PROCESS_UNITTEST2%] == [2] (exit 2)
1806 version (Posix) TestScript envProg =
1807 `if test "$std_process_unittest1" = ""; then
1808 std_process_unittest1=0
1810 if test "$std_process_unittest2" = ""; then
1811 std_process_unittest2=0
1813 exit $(($std_process_unittest1+$std_process_unittest2))`;
1815 environment.remove("std_process_unittest1"); // Just in case.
1816 environment.remove("std_process_unittest2");
1817 assert(wait(spawnProcess(envProg.path)) == 0);
1818 assert(wait(spawnProcess(envProg.path, null, Config.newEnv)) == 0);
1820 environment["std_process_unittest1"] = "1";
1821 assert(wait(spawnProcess(envProg.path)) == 1);
1822 assert(wait(spawnProcess(envProg.path, null, Config.newEnv)) == 0);
1824 auto env = ["std_process_unittest2" : "2"];
1825 assert(wait(spawnProcess(envProg.path, env)) == 3);
1826 assert(wait(spawnProcess(envProg.path, env, Config.newEnv)) == 2);
1828 env["std_process_unittest1"] = "4";
1829 assert(wait(spawnProcess(envProg.path, env)) == 6);
1830 assert(wait(spawnProcess(envProg.path, env, Config.newEnv)) == 6);
1832 environment.remove("std_process_unittest1");
1833 assert(wait(spawnProcess(envProg.path, env)) == 6);
1834 assert(wait(spawnProcess(envProg.path, env, Config.newEnv)) == 6);
1837 @system unittest // Stream redirection in spawnProcess().
1839 import std.path : buildPath;
1841 version (Windows) TestScript prog =
1843 echo %INPUT% output %~1
1844 echo %INPUT% error %~2 1>&2
1846 else version (Posix) TestScript prog =
1848 echo $INPUT output $1
1849 echo $INPUT error $2 >&2
1850 echo done > \"$3\"";
1853 void testPipes(Config config)
1855 import std.file : tempDir, exists, remove;
1856 import std.uuid : randomUUID;
1857 import std.exception : collectException;
1858 auto pipei = pipe();
1859 auto pipeo = pipe();
1860 auto pipee = pipe();
1861 auto done = buildPath(tempDir(), randomUUID().toString());
1862 auto pid = spawnProcess([prog.path, "foo", "bar", done],
1863 pipei.readEnd, pipeo.writeEnd, pipee.writeEnd, null, config);
1864 pipei.writeEnd.writeln("input");
1865 pipei.writeEnd.flush();
1866 assert(pipeo.readEnd.readln().chomp() == "input output foo");
1867 assert(pipee.readEnd.readln().chomp().stripRight() == "input error bar");
1868 if (config.flags & Config.Flags.detached)
1869 while (!done.exists) Thread.sleep(10.msecs);
1872 while (remove(done).collectException) Thread.sleep(10.msecs);
1876 void testFiles(Config config)
1878 import std.ascii : newline;
1879 import std.file : tempDir, exists, remove, readText, write;
1880 import std.uuid : randomUUID;
1881 import std.exception : collectException;
1882 auto pathi = buildPath(tempDir(), randomUUID().toString());
1883 auto patho = buildPath(tempDir(), randomUUID().toString());
1884 auto pathe = buildPath(tempDir(), randomUUID().toString());
1885 write(pathi, "INPUT" ~ newline);
1886 auto filei = File(pathi, "r");
1887 auto fileo = File(patho, "w");
1888 auto filee = File(pathe, "w");
1889 auto done = buildPath(tempDir(), randomUUID().toString());
1890 auto pid = spawnProcess([prog.path, "bar", "baz", done], filei, fileo, filee, null, config);
1891 if (config.flags & Config.Flags.detached)
1892 while (!done.exists) Thread.sleep(10.msecs);
1895 assert(readText(patho).chomp() == "INPUT output bar");
1896 assert(readText(pathe).chomp().stripRight() == "INPUT error baz");
1897 while (remove(pathi).collectException) Thread.sleep(10.msecs);
1898 while (remove(patho).collectException) Thread.sleep(10.msecs);
1899 while (remove(pathe).collectException) Thread.sleep(10.msecs);
1900 while (remove(done).collectException) Thread.sleep(10.msecs);
1903 testPipes(Config.none);
1904 testFiles(Config.none);
1905 testPipes(Config.detached);
1906 testFiles(Config.detached);
1909 @system unittest // Error handling in spawnProcess()
1911 import std.algorithm.searching : canFind;
1912 import std.exception : assertThrown, collectExceptionMsg;
1914 static void testNotFoundException(string program)
1916 assert(collectExceptionMsg!ProcessException(spawnProcess(program)).canFind(program));
1917 assert(collectExceptionMsg!ProcessException(spawnProcess(program, null, Config.detached)).canFind(program));
1919 testNotFoundException("ewrgiuhrifuheiohnmnvqweoijwf");
1920 testNotFoundException("./rgiuhrifuheiohnmnvqweoijwf");
1922 // can't execute malformed file with executable permissions
1925 import std.path : buildPath;
1926 import std.file : remove, write, setAttributes, tempDir;
1927 import core.sys.posix.sys.stat : S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IXGRP, S_IROTH, S_IXOTH;
1928 import std.conv : to;
1929 string deleteme = buildPath(tempDir(), "deleteme.std.process.unittest.pid") ~ to!string(thisProcessID);
1930 write(deleteme, "");
1931 scope(exit) remove(deleteme);
1932 setAttributes(deleteme, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
1933 assertThrown!ProcessException(spawnProcess(deleteme));
1934 assertThrown!ProcessException(spawnProcess(deleteme, null, Config.detached));
1938 @system unittest // Specifying a working directory.
1942 TestScript prog = "echo foo>bar";
1944 auto directory = uniqueTempPath();
1946 scope(exit) rmdirRecurse(directory);
1948 auto pid = spawnProcess([prog.path], null, Config.none, directory);
1950 assert(exists(buildPath(directory, "bar")));
1953 @system unittest // Specifying a bad working directory.
1955 import std.exception : assertThrown;
1957 TestScript prog = "echo";
1959 auto directory = uniqueTempPath();
1960 assertThrown!ProcessException(spawnProcess([prog.path], null, Config.none, directory));
1961 assertThrown!ProcessException(spawnProcess([prog.path], null, Config.detached, directory));
1963 std.file.write(directory, "foo");
1964 scope(exit) remove(directory);
1965 assertThrown!ProcessException(spawnProcess([prog.path], null, Config.none, directory));
1966 assertThrown!ProcessException(spawnProcess([prog.path], null, Config.detached, directory));
1968 // can't run in directory if user does not have search permission on this directory
1971 if (core.sys.posix.unistd.getuid() != 0)
1973 import core.sys.posix.sys.stat : S_IRUSR;
1974 auto directoryNoSearch = uniqueTempPath();
1975 mkdir(directoryNoSearch);
1976 scope(exit) rmdirRecurse(directoryNoSearch);
1977 setAttributes(directoryNoSearch, S_IRUSR);
1978 assertThrown!ProcessException(spawnProcess(prog.path, null, Config.none, directoryNoSearch));
1979 assertThrown!ProcessException(spawnProcess(prog.path, null, Config.detached, directoryNoSearch));
1984 @system unittest // Specifying empty working directory.
1986 TestScript prog = "";
1988 string directory = "";
1989 assert(directory.ptr && !directory.length);
1990 spawnProcess([prog.path], null, Config.none, directory).wait();
1993 // Reopening the standard streams (https://issues.dlang.org/show_bug.cgi?id=13258)
2000 spawnShell("echo foo").wait();
2001 spawnShell("echo bar").wait();
2004 auto tmpFile = uniqueTempPath();
2005 scope(exit) if (exists(tmpFile)) remove(tmpFile);
2008 auto oldOut = std.stdio.stdout;
2009 scope(exit) std.stdio.stdout = oldOut;
2011 std.stdio.stdout = File(tmpFile, "w");
2013 std.stdio.stdout.close();
2016 auto lines = readText(tmpFile).splitLines();
2017 assert(lines == ["foo", "bar"]);
2020 // MSVCRT workaround (https://issues.dlang.org/show_bug.cgi?id=14422)
2024 auto fn = uniqueTempPath();
2025 scope(exit) if (exists(fn)) remove(fn);
2026 std.file.write(fn, "AAAAAAAAAA");
2028 auto f = File(fn, "a");
2029 spawnProcess(["cmd", "/c", "echo BBBBB"], std.stdio.stdin, f).wait();
2031 auto data = readText(fn);
2032 assert(data == "AAAAAAAAAABBBBB\r\n", data);
2035 // https://issues.dlang.org/show_bug.cgi?id=20765
2036 // Test that running processes with relative path works in conjunction
2037 // with indicating a workDir.
2038 version (Posix) @system unittest
2040 import std.file : mkdir, write, setAttributes, rmdirRecurse;
2041 import std.conv : octal;
2043 auto dir = uniqueTempPath();
2045 scope(exit) rmdirRecurse(dir);
2046 write(dir ~ "/program", "#!/bin/sh\necho Hello");
2047 setAttributes(dir ~ "/program", octal!700);
2049 assert(execute(["./program"], null, Config.none, size_t.max, dir).output == "Hello\n");
2053 A variation on $(LREF spawnProcess) that runs the given _command through
2054 the current user's preferred _command interpreter (aka. shell).
2056 The string `command` is passed verbatim to the shell, and is therefore
2057 subject to its rules about _command structure, argument/filename quoting
2058 and escaping of special characters.
2059 The path to the shell executable defaults to $(LREF nativeShell).
2061 In all other respects this function works just like `spawnProcess`.
2062 Please refer to the $(LREF spawnProcess) documentation for descriptions
2063 of the other function parameters, the return value and any exceptions
2066 // Run the command/program "foo" on the file named "my file.txt", and
2067 // redirect its output into foo.log.
2068 auto pid = spawnShell(`foo "my file.txt" > foo.log`);
2073 $(LREF escapeShellCommand), which may be helpful in constructing a
2074 properly quoted and escaped shell _command line for the current platform.
2076 Pid spawnShell(scope const(char)[] command,
2077 File stdin = std.stdio.stdin,
2078 File stdout = std.stdio.stdout,
2079 File stderr = std.stdio.stderr,
2080 scope const string[string] env = null,
2081 Config config = Config.none,
2082 scope const(char)[] workDir = null,
2083 scope string shellPath = nativeShell)
2084 @trusted // See reason below
2088 // CMD does not parse its arguments like other programs.
2089 // It does not use CommandLineToArgvW.
2090 // Instead, it treats the first and last quote specially.
2091 // See CMD.EXE /? for details.
2092 const commandLine = escapeShellFileName(shellPath)
2093 ~ ` ` ~ shellSwitch ~ ` "` ~ command ~ `"`;
2094 return spawnProcessWin(commandLine, shellPath, stdin, stdout, stderr, env, config, workDir);
2096 else version (Posix)
2098 const(char)[][3] args;
2099 args[0] = shellPath;
2100 args[1] = shellSwitch;
2102 /* The passing of args converts the static array, which is initialized with `scope` pointers,
2103 * to a dynamic array, which is also a scope parameter. So, it is a scope pointer to a
2104 * scope pointer, which although is safely used here, D doesn't allow transitive scope.
2105 * See https://github.com/dlang/dmd/pull/10951
2107 return spawnProcessPosix(args, stdin, stdout, stderr, env, config, workDir);
2114 Pid spawnShell(scope const(char)[] command,
2115 scope const string[string] env,
2116 Config config = Config.none,
2117 scope const(char)[] workDir = null,
2118 scope string shellPath = nativeShell)
2119 @trusted // TODO: Should be @safe
2121 return spawnShell(command,
2134 auto cmd = "echo %FOO%";
2135 else version (Posix)
2136 auto cmd = "echo $foo";
2138 auto tmpFile = uniqueTempPath();
2139 scope(exit) if (exists(tmpFile)) remove(tmpFile);
2140 auto redir = "> \""~tmpFile~'"';
2141 auto env = ["foo" : "bar"];
2142 assert(wait(spawnShell(cmd~redir, env)) == 0);
2143 auto f = File(tmpFile, "a");
2144 version (CRuntime_Microsoft) f.seek(0, SEEK_END); // MSVCRT probably seeks to the end when writing, not before
2145 assert(wait(spawnShell(cmd, std.stdio.stdin, f, std.stdio.stderr, env)) == 0);
2147 auto output = std.file.readText(tmpFile);
2148 assert(output == "bar\nbar\n" || output == "bar\r\nbar\r\n");
2155 import std.conv : text;
2156 TestScript prog = "echo %0 %*";
2157 auto outputFn = uniqueTempPath();
2158 scope(exit) if (exists(outputFn)) remove(outputFn);
2159 auto args = [`a b c`, `a\b\c\`, `a"b"c"`];
2160 auto result = executeShell(
2161 escapeShellCommand([prog.path] ~ args)
2163 escapeShellFileName(outputFn));
2164 assert(result.status == 0);
2165 auto args2 = outputFn.readText().strip().parseCommandLine()[1..$];
2166 assert(args == args2, text(args2));
2171 Options that control the behaviour of process creation functions in this
2172 module. Most options only apply to $(LREF spawnProcess) and
2177 auto logFile = File("myapp_error.log", "w");
2179 // Start program, suppressing the console window (Windows only),
2180 // redirect its error stream to logFile, and leave logFile open
2181 // in the parent process as well.
2182 auto pid = spawnProcess("myapp", stdin, stdout, logFile,
2183 Config.retainStderr | Config.suppressConsole);
2186 auto exitCode = wait(pid);
2187 logFile.writeln("myapp exited with code ", exitCode);
2196 Use bitwise OR to combine flags.
2203 By default, the child process inherits the parent's environment,
2204 and any environment variables passed to $(LREF spawnProcess) will
2205 be added to it. If this flag is set, the only variables in the
2206 child process' environment will be those given to spawnProcess.
2211 Unless the child process inherits the standard input/output/error
2212 streams of its parent, one almost always wants the streams closed
2213 in the parent when $(LREF spawnProcess) returns. Therefore, by
2214 default, this is done. If this is not desirable, pass any of these
2215 options to spawnProcess.
2218 retainStdout = 4, /// ditto
2219 retainStderr = 8, /// ditto
2222 On Windows, if the child process is a console application, this
2223 flag will prevent the creation of a console window. Otherwise,
2224 it will be ignored. On POSIX, `suppressConsole` has no effect.
2226 suppressConsole = 16,
2229 On POSIX, open $(LINK2 http://en.wikipedia.org/wiki/File_descriptor,file descriptors)
2230 are by default inherited by the child process. As this may lead
2231 to subtle bugs when pipes or multiple threads are involved,
2232 $(LREF spawnProcess) ensures that all file descriptors except the
2233 ones that correspond to standard input/output/error are closed
2234 in the child process when it starts. Use `inheritFDs` to prevent
2237 On Windows, this option has no effect, and any handles which have been
2238 explicitly marked as inheritable will always be inherited by the child
2244 Spawn process in detached state. This removes the need in calling
2245 $(LREF wait) to clean up the process resources.
2248 Calling $(LREF wait) or $(LREF kill) with the resulting `Pid` is invalid.
2253 By default, the $(LREF execute) and $(LREF executeShell) functions
2254 will capture child processes' both stdout and stderr. This can be
2255 undesirable if the standard output is to be processed or otherwise
2256 used by the invoking program, as `execute`'s result would then
2257 contain a mix of output and warning/error messages.
2259 Specify this flag when calling `execute` or `executeShell` to
2260 cause invoked processes' stderr stream to be sent to $(REF stderr,
2261 std,stdio), and only capture and return standard output.
2263 This flag has no effect on $(LREF spawnProcess) or $(LREF spawnShell).
2265 stderrPassThrough = 128,
2267 Flags flags; /// ditto
2270 For backwards compatibility, and cases when only flags need to
2271 be specified in the `Config`, these allow building `Config`
2272 instances using flag names only.
2274 enum Config none = Config.init;
2275 enum Config newEnv = Config(Flags.newEnv); /// ditto
2276 enum Config retainStdin = Config(Flags.retainStdin); /// ditto
2277 enum Config retainStdout = Config(Flags.retainStdout); /// ditto
2278 enum Config retainStderr = Config(Flags.retainStderr); /// ditto
2279 enum Config suppressConsole = Config(Flags.suppressConsole); /// ditto
2280 enum Config inheritFDs = Config(Flags.inheritFDs); /// ditto
2281 enum Config detached = Config(Flags.detached); /// ditto
2282 enum Config stderrPassThrough = Config(Flags.stderrPassThrough); /// ditto
2283 Config opUnary(string op)()
2284 if (is(typeof(mixin(op ~ q{flags}))))
2286 return Config(mixin(op ~ q{flags}));
2288 Config opBinary(string op)(Config other)
2289 if (is(typeof(mixin(q{flags} ~ op ~ q{other.flags}))))
2291 return Config(mixin(q{flags} ~ op ~ q{other.flags}));
2293 Config opOpAssign(string op)(Config other)
2294 if (is(typeof(mixin(q{flags} ~ op ~ q{=other.flags}))))
2296 return Config(mixin(q{flags} ~ op ~ q{=other.flags}));
2302 A function that is called before `exec` in $(LREF spawnProcess).
2303 It returns `true` if succeeded and otherwise returns `false`.
2306 Please note that the code in this function must only use
2307 async-signal-safe functions.)
2309 If $(LREF preExecDelegate) is also set, it is called last.
2311 On Windows, this member is not available.
2313 bool function() nothrow @nogc @safe preExecFunction;
2316 A delegate that is called before `exec` in $(LREF spawnProcess).
2317 It returns `true` if succeeded and otherwise returns `false`.
2320 Please note that the code in this function must only use
2321 async-signal-safe functions.)
2323 If $(LREF preExecFunction) is also set, it is called first.
2325 On Windows, this member is not available.
2327 bool delegate() nothrow @nogc @safe preExecDelegate;
2329 else version (Posix)
2331 bool function() nothrow @nogc @safe preExecFunction;
2332 bool delegate() nothrow @nogc @safe preExecDelegate;
2336 // https://issues.dlang.org/show_bug.cgi?id=22125
2339 Config c = Config.retainStdin;
2340 c |= Config.retainStdout;
2341 c |= Config.retainStderr;
2342 c &= ~Config.retainStderr;
2343 assert(c == (Config.retainStdin | Config.retainStdout));
2346 /// A handle that corresponds to a spawned process.
2350 The process ID number.
2352 This is a number that uniquely identifies the process on the operating
2353 system, for at least as long as the process is running. Once $(LREF wait)
2354 has been called on the $(LREF Pid), this method will return an
2355 invalid (negative) process ID.
2357 @property int processID() const @safe pure nothrow
2363 An operating system handle to the process.
2365 This handle is used to specify the process in OS-specific APIs.
2366 On POSIX, this function returns a `core.sys.posix.sys.types.pid_t`
2367 with the same value as $(LREF Pid.processID), while on Windows it returns
2368 a `core.sys.windows.windows.HANDLE`.
2370 Once $(LREF wait) has been called on the $(LREF Pid), this method
2371 will return an invalid handle.
2373 // Note: Since HANDLE is a reference, this function cannot be const.
2375 @property HANDLE osHandle() @nogc @safe pure nothrow
2379 else version (Posix)
2380 @property pid_t osHandle() @nogc @safe pure nothrow
2387 Pid.performWait() does the dirty work for wait() and nonBlockingWait().
2389 If block == true, this function blocks until the process terminates,
2390 sets _processID to terminated, and returns the exit code or terminating
2391 signal as described in the wait() documentation.
2393 If block == false, this function returns immediately, regardless
2394 of the status of the process. If the process has terminated, the
2395 function has the exact same effect as the blocking version. If not,
2396 it returns 0 and does not modify _processID.
2399 int performWait(bool block) @trusted
2401 import std.exception : enforce;
2402 enforce!ProcessException(owned, "Can't wait on a detached process");
2403 if (_processID == terminated) return _exitCode;
2408 auto check = waitpid(_processID, &status, block ? 0 : WNOHANG);
2411 if (errno == ECHILD)
2413 throw new ProcessException(
2414 "Process does not exist or is not a child process.");
2418 // waitpid() was interrupted by a signal. We simply
2420 assert(errno == EINTR);
2424 if (!block && check == 0) return 0;
2425 if (WIFEXITED(status))
2427 exitCode = WEXITSTATUS(status);
2430 else if (WIFSIGNALED(status))
2432 exitCode = -WTERMSIG(status);
2435 // We check again whether the call should be blocking,
2436 // since we don't care about other status changes besides
2437 // "exited" and "terminated by signal".
2438 if (!block) return 0;
2440 // Process has stopped, but not terminated, so we continue waiting.
2442 // Mark Pid as terminated, and cache and return exit code.
2443 _processID = terminated;
2444 _exitCode = exitCode;
2447 else version (Windows)
2449 int performWait(const bool block, const DWORD timeout = INFINITE) @trusted
2451 import std.exception : enforce;
2452 enforce!ProcessException(owned, "Can't wait on a detached process");
2453 if (_processID == terminated) return _exitCode;
2454 assert(_handle != INVALID_HANDLE_VALUE);
2457 auto result = WaitForSingleObject(_handle, timeout);
2458 if (result != WAIT_OBJECT_0)
2460 // Wait time exceeded `timeout` milliseconds?
2461 if (result == WAIT_TIMEOUT && timeout != INFINITE)
2464 throw ProcessException.newFromLastError("Wait failed.");
2467 if (!GetExitCodeProcess(_handle, cast(LPDWORD)&_exitCode))
2468 throw ProcessException.newFromLastError();
2469 if (!block && _exitCode == STILL_ACTIVE) return 0;
2470 CloseHandle(_handle);
2471 _handle = INVALID_HANDLE_VALUE;
2472 _processID = terminated;
2476 int performWait(Duration timeout) @safe
2478 import std.exception : enforce;
2479 const msecs = timeout.total!"msecs";
2481 // Limit this implementation the maximum wait time offered by
2482 // WaitForSingleObject. One could theoretically break up larger
2483 // durations into multiple waits but (DWORD.max - 1).msecs
2484 // (> 7 weeks, 17 hours) should be enough for the usual case.
2485 // DWORD.max is reserved for INFINITE
2486 enforce!ProcessException(msecs < DWORD.max, "Timeout exceeds maximum wait time!");
2487 return performWait(true, cast(DWORD) msecs);
2492 if (_handle != INVALID_HANDLE_VALUE)
2494 CloseHandle(_handle);
2495 _handle = INVALID_HANDLE_VALUE;
2500 // Special values for _processID.
2501 enum invalid = -1, terminated = -2;
2503 // OS process ID number. Only nonnegative IDs correspond to
2504 // running processes.
2505 int _processID = invalid;
2507 // Exit code cached by wait(). This is only expected to hold a
2508 // sensible value if _processID == terminated.
2511 // Whether the process can be waited for by wait() for or killed by kill().
2512 // False if process was started as detached. True otherwise.
2515 // Pids are only meant to be constructed inside this module, so
2516 // we make the constructor private.
2519 HANDLE _handle = INVALID_HANDLE_VALUE;
2520 this(int pid, HANDLE handle) @safe pure nothrow
2526 this(int pid) @safe pure nothrow
2534 this(int id, bool owned) @safe pure nothrow
2544 Waits for the process associated with `pid` to terminate, and returns
2547 In general one should always _wait for child processes to terminate
2548 before exiting the parent process unless the process was spawned as detached
2549 (that was spawned with `Config.detached` flag).
2550 Otherwise, they may become "$(HTTP en.wikipedia.org/wiki/Zombie_process,zombies)"
2551 – processes that are defunct, yet still occupy a slot in the OS process table.
2552 You should not and must not wait for detached processes, since you don't own them.
2554 If the process has already terminated, this function returns directly.
2555 The exit code is cached, so that if wait() is called multiple times on
2556 the same $(LREF Pid) it will always return the same value.
2559 If the process is terminated by a signal, this function returns a
2560 negative number whose absolute value is the signal number.
2561 Since POSIX restricts normal exit codes to the range 0-255, a
2562 negative return value will always indicate termination by signal.
2563 Signal codes are defined in the `core.sys.posix.signal` module
2564 (which corresponds to the `signal.h` POSIX header).
2567 $(LREF ProcessException) on failure or on attempt to wait for detached process.
2570 See the $(LREF spawnProcess) documentation.
2573 $(LREF tryWait), for a non-blocking function.
2575 int wait(Pid pid) @safe
2577 assert(pid !is null, "Called wait on a null Pid.");
2578 return pid.performWait(true);
2582 @system unittest // Pid and wait()
2584 version (Windows) TestScript prog = "exit %~1";
2585 else version (Posix) TestScript prog = "exit $1";
2586 assert(wait(spawnProcess([prog.path, "0"])) == 0);
2587 assert(wait(spawnProcess([prog.path, "123"])) == 123);
2588 auto pid = spawnProcess([prog.path, "10"]);
2589 assert(pid.processID > 0);
2590 version (Windows) assert(pid.osHandle != INVALID_HANDLE_VALUE);
2591 else version (Posix) assert(pid.osHandle == pid.processID);
2592 assert(wait(pid) == 10);
2593 assert(wait(pid) == 10); // cached exit code
2594 assert(pid.processID < 0);
2595 version (Windows) assert(pid.osHandle == INVALID_HANDLE_VALUE);
2596 else version (Posix) assert(pid.osHandle < 0);
2599 private import std.typecons : Tuple;
2602 Waits until either the process associated with `pid` terminates or the
2603 elapsed time exceeds the given timeout.
2605 If the process terminates within the given duration it behaves exactly like
2606 `wait`, except that it returns a tuple `(true, exit code)`.
2608 If the process does not terminate within the given duration it will stop
2609 waiting and return `(false, 0).`
2611 The timeout may not exceed `(uint.max - 1).msecs` (~ 7 weeks, 17 hours).
2613 $(BLUE This function is Windows-Only.)
2616 An $(D std.typecons.Tuple!(bool, "terminated", int, "status")).
2619 $(LREF ProcessException) on failure or on attempt to wait for detached process.
2622 See the $(LREF spawnProcess) documentation.
2625 $(LREF wait), for a blocking function without timeout.
2626 $(LREF tryWait), for a non-blocking function without timeout.
2629 Tuple!(bool, "terminated", int, "status") waitTimeout(Pid pid, Duration timeout) @safe;
2631 else version (Windows)
2632 Tuple!(bool, "terminated", int, "status") waitTimeout(Pid pid, Duration timeout) @safe
2634 assert(pid !is null, "Called wait on a null Pid.");
2635 auto code = pid.performWait(timeout);
2636 return typeof(return)(pid._processID == Pid.terminated, code);
2640 @system unittest // Pid and waitTimeout()
2642 import std.exception : collectException;
2643 import std.typecons : tuple;
2645 TestScript prog = ":Loop\r\n" ~ "goto Loop";
2646 auto pid = spawnProcess(prog.path);
2648 // Doesn't block longer than one second
2649 assert(waitTimeout(pid, 1.seconds) == tuple(false, 0));
2652 assert(waitTimeout(pid, 1.seconds) == tuple(true, 1)); // exit 1 because the process is killed
2654 // Rejects timeouts exceeding the Windows API capabilities
2655 const dur = DWORD.max.msecs;
2656 const ex = collectException!ProcessException(waitTimeout(pid, dur));
2658 assert(ex.msg == "Timeout exceeds maximum wait time!");
2662 A non-blocking version of $(LREF wait).
2664 If the process associated with `pid` has already terminated,
2665 `tryWait` has the exact same effect as `wait`.
2666 In this case, it returns a tuple where the `terminated` field
2667 is set to `true` and the `status` field has the same
2668 interpretation as the return value of `wait`.
2670 If the process has $(I not) yet terminated, this function differs
2671 from `wait` in that does not wait for this to happen, but instead
2672 returns immediately. The `terminated` field of the returned
2673 tuple will then be set to `false`, while the `status` field
2674 will always be 0 (zero). `wait` or `tryWait` should then be
2675 called again on the same `Pid` at some later time; not only to
2676 get the exit code, but also to avoid the process becoming a "zombie"
2677 when it finally terminates. (See $(LREF wait) for details).
2680 An $(D std.typecons.Tuple!(bool, "terminated", int, "status")).
2683 $(LREF ProcessException) on failure or on attempt to wait for detached process.
2687 auto pid = spawnProcess("dmd myapp.d");
2688 scope(exit) wait(pid);
2690 auto dmd = tryWait(pid);
2693 if (dmd.status == 0) writeln("Compilation succeeded!");
2694 else writeln("Compilation failed");
2696 else writeln("Still compiling...");
2699 Note that in this example, the first `wait` call will have no
2700 effect if the process has already terminated by the time `tryWait`
2701 is called. In the opposite case, however, the `scope` statement
2702 ensures that we always wait for the process if it hasn't terminated
2703 by the time we reach the end of the scope.
2705 auto tryWait(Pid pid) @safe
2707 import std.typecons : Tuple;
2708 assert(pid !is null, "Called tryWait on a null Pid.");
2709 auto code = pid.performWait(false);
2710 return Tuple!(bool, "terminated", int, "status")(pid._processID == Pid.terminated, code);
2712 // unittest: This function is tested together with kill() below.
2716 Attempts to terminate the process associated with `pid`.
2718 The effect of this function, as well as the meaning of `codeOrSignal`,
2719 is highly platform dependent. Details are given below. Common to all
2720 platforms is that this function only $(I initiates) termination of the process,
2721 and returns immediately. It does not wait for the process to end,
2722 nor does it guarantee that the process does in fact get terminated.
2724 Always call $(LREF wait) to wait for a process to complete, even if `kill`
2725 has been called on it.
2729 $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/ms686714%28v=vs.100%29.aspx,
2730 forcefully and abruptly terminated). If `codeOrSignal` is specified, it
2731 must be a nonnegative number which will be used as the exit code of the process.
2732 If not, the process wil exit with code 1. Do not use $(D codeOrSignal = 259),
2733 as this is a special value (aka. $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/ms683189.aspx,STILL_ACTIVE))
2734 used by Windows to signal that a process has in fact $(I not) terminated yet.
2736 auto pid = spawnProcess("some_app");
2738 assert(wait(pid) == 10);
2742 A $(LINK2 http://en.wikipedia.org/wiki/Unix_signal,signal) will be sent to
2743 the process, whose value is given by `codeOrSignal`. Depending on the
2744 signal sent, this may or may not terminate the process. Symbolic constants
2745 for various $(LINK2 http://en.wikipedia.org/wiki/Unix_signal#POSIX_signals,
2746 POSIX signals) are defined in `core.sys.posix.signal`, which corresponds to the
2747 $(LINK2 http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html,
2748 `signal.h` POSIX header). If `codeOrSignal` is omitted, the
2749 `SIGTERM` signal will be sent. (This matches the behaviour of the
2750 $(LINK2 http://pubs.opengroup.org/onlinepubs/9699919799/utilities/kill.html,
2751 `_kill`) shell command.)
2753 import core.sys.posix.signal : SIGKILL;
2754 auto pid = spawnProcess("some_app");
2756 assert(wait(pid) == -SIGKILL); // Negative return value on POSIX!
2760 $(LREF ProcessException) on error (e.g. if codeOrSignal is invalid).
2761 or on attempt to kill detached process.
2762 Note that failure to terminate the process is considered a "normal"
2763 outcome, not an error.$(BR)
2767 version (Windows) kill(pid, 1);
2768 else version (Posix)
2770 import core.sys.posix.signal : SIGTERM;
2776 void kill(Pid pid, int codeOrSignal)
2778 import std.exception : enforce;
2779 enforce!ProcessException(pid.owned, "Can't kill detached process");
2782 if (codeOrSignal < 0) throw new ProcessException("Invalid exit code");
2783 // On Windows, TerminateProcess() appears to terminate the
2784 // *current* process if it is passed an invalid handle...
2785 if (pid.osHandle == INVALID_HANDLE_VALUE)
2786 throw new ProcessException("Invalid process handle");
2787 if (!TerminateProcess(pid.osHandle, codeOrSignal))
2788 throw ProcessException.newFromLastError();
2790 else version (Posix)
2792 import core.sys.posix.signal : kill;
2793 if (pid.osHandle == Pid.invalid)
2794 throw new ProcessException("Pid is invalid");
2795 if (pid.osHandle == Pid.terminated)
2796 throw new ProcessException("Pid is already terminated");
2797 if (kill(pid.osHandle, codeOrSignal) == -1)
2798 throw ProcessException.newFromErrno();
2802 @system unittest // tryWait() and kill()
2805 import std.exception : assertThrown;
2806 // The test script goes into an infinite loop.
2809 TestScript prog = ":loop
2812 else version (Posix)
2814 import core.sys.posix.signal : SIGTERM, SIGKILL;
2815 TestScript prog = "while true; do sleep 1; done";
2817 auto pid = spawnProcess(prog.path);
2818 // Android appears to automatically kill sleeping processes very quickly,
2819 // so shorten the wait before killing here.
2821 Thread.sleep(dur!"msecs"(5));
2823 Thread.sleep(dur!"msecs"(500));
2825 version (Windows) assert(wait(pid) == 1);
2826 else version (Posix) assert(wait(pid) == -SIGTERM);
2828 pid = spawnProcess(prog.path);
2829 Thread.sleep(dur!"msecs"(500));
2830 auto s = tryWait(pid);
2831 assert(!s.terminated && s.status == 0);
2832 assertThrown!ProcessException(kill(pid, -123)); // Negative code not allowed.
2833 version (Windows) kill(pid, 123);
2834 else version (Posix) kill(pid, SIGKILL);
2835 do { s = tryWait(pid); } while (!s.terminated);
2836 version (Windows) assert(s.status == 123);
2837 else version (Posix) assert(s.status == -SIGKILL);
2838 assertThrown!ProcessException(kill(pid)); // Already terminated
2841 @system unittest // wait() and kill() detached process
2844 import std.exception : assertThrown;
2845 TestScript prog = "exit 0";
2846 auto pid = spawnProcess([prog.path], null, Config.detached);
2848 This sleep is needed because we can't wait() for detached process to end
2849 and therefore TestScript destructor may run at the same time as /bin/sh tries to start the script.
2850 This leads to the annoying message like "/bin/sh: 0: Can't open /tmp/std.process temporary file" to appear when running tests.
2851 It does not happen in unittests with non-detached processes because we always wait() for them to finish.
2853 Thread.sleep(500.msecs);
2855 version (Windows) assert(pid.osHandle == INVALID_HANDLE_VALUE);
2856 assertThrown!ProcessException(wait(pid));
2857 assertThrown!ProcessException(kill(pid));
2862 Creates a unidirectional _pipe.
2864 Data is written to one end of the _pipe and read from the other.
2867 p.writeEnd.writeln("Hello World");
2869 assert(p.readEnd.readln().chomp() == "Hello World");
2871 Pipes can, for example, be used for interprocess communication
2872 by spawning a new process and passing one end of the _pipe to
2873 the child, while the parent uses the other end.
2874 (See also $(LREF pipeProcess) and $(LREF pipeShell) for an easier
2877 // Use cURL to download the dlang.org front page, pipe its
2878 // output to grep to extract a list of links to ZIP files,
2879 // and write the list to the file "D downloads.txt":
2881 auto outFile = File("D downloads.txt", "w");
2882 auto cpid = spawnProcess(["curl", "http://dlang.org/download.html"],
2883 std.stdio.stdin, p.writeEnd);
2884 scope(exit) wait(cpid);
2885 auto gpid = spawnProcess(["grep", "-o", `http://\S*\.zip`],
2886 p.readEnd, outFile);
2887 scope(exit) wait(gpid);
2891 A $(LREF Pipe) object that corresponds to the created _pipe.
2894 $(REF StdioException, std,stdio) on failure.
2897 Pipe pipe() @trusted //TODO: @safe
2899 import core.sys.posix.stdio : fdopen;
2901 if (core.sys.posix.unistd.pipe(fds) != 0)
2902 throw new StdioException("Unable to create pipe");
2904 auto readFP = fdopen(fds[0], "r");
2906 throw new StdioException("Cannot open read end of pipe");
2907 p._read = File(readFP, null);
2908 auto writeFP = fdopen(fds[1], "w");
2909 if (writeFP == null)
2910 throw new StdioException("Cannot open write end of pipe");
2911 p._write = File(writeFP, null);
2914 else version (Windows)
2915 Pipe pipe() @trusted //TODO: @safe
2917 // use CreatePipe to create an anonymous pipe
2920 if (!CreatePipe(&readHandle, &writeHandle, null, 0))
2922 throw new StdioException(
2923 "Error creating pipe (" ~ generateSysErrorMsg() ~ ')',
2929 CloseHandle(readHandle);
2930 CloseHandle(writeHandle);
2936 p._read .windowsHandleOpen(readHandle , "r");
2937 p._write.windowsHandleOpen(writeHandle, "a");
2942 throw new StdioException("Error attaching pipe (" ~ e.msg ~ ")",
2948 /// An interface to a pipe created by the $(LREF pipe) function.
2951 /// The read end of the pipe.
2952 @property File readEnd() @safe nothrow { return _read; }
2955 /// The write end of the pipe.
2956 @property File writeEnd() @safe nothrow { return _write; }
2960 Closes both ends of the pipe.
2962 Normally it is not necessary to do this manually, as $(REF File, std,stdio)
2963 objects are automatically closed when there are no more references
2966 Note that if either end of the pipe has been passed to a child process,
2967 it will only be closed in the parent process. (What happens in the
2968 child process is platform dependent.)
2971 $(REF ErrnoException, std,exception) if an error occurs.
2987 p.writeEnd.writeln("Hello World");
2989 assert(p.readEnd.readln().chomp() == "Hello World");
2991 assert(!p.readEnd.isOpen);
2992 assert(!p.writeEnd.isOpen);
2997 Starts a new process, creating pipes to redirect its standard
2998 input, output and/or error streams.
3000 `pipeProcess` and `pipeShell` are convenient wrappers around
3001 $(LREF spawnProcess) and $(LREF spawnShell), respectively, and
3002 automate the task of redirecting one or more of the child process'
3003 standard streams through pipes. Like the functions they wrap,
3004 these functions return immediately, leaving the child process to
3005 execute in parallel with the invoking process. It is recommended
3006 to always call $(LREF wait) on the returned $(LREF ProcessPipes.pid),
3007 as detailed in the documentation for `wait`.
3009 The `args`/`program`/`command`, `env` and `config`
3010 parameters are forwarded straight to the underlying spawn functions,
3011 and we refer to their documentation for details.
3014 args = An array which contains the program name as the zeroth element
3015 and any command-line arguments in the following elements.
3016 (See $(LREF spawnProcess) for details.)
3017 program = The program name, $(I without) command-line arguments.
3018 (See $(LREF spawnProcess) for details.)
3019 command = A shell command which is passed verbatim to the command
3020 interpreter. (See $(LREF spawnShell) for details.)
3021 redirect = Flags that determine which streams are redirected, and
3022 how. See $(LREF Redirect) for an overview of available
3024 env = Additional environment variables for the child process.
3025 (See $(LREF spawnProcess) for details.)
3026 config = Flags that control process creation. See $(LREF Config)
3027 for an overview of available flags, and note that the
3028 `retainStd...` flags have no effect in this function.
3029 workDir = The working directory for the new process.
3030 By default the child process inherits the parent's working
3032 shellPath = The path to the shell to use to run the specified program.
3033 By default this is $(LREF nativeShell).
3036 A $(LREF ProcessPipes) object which contains $(REF File, std,stdio)
3037 handles that communicate with the redirected streams of the child
3038 process, along with a $(LREF Pid) object that corresponds to the
3042 $(LREF ProcessException) on failure to start the process.$(BR)
3043 $(REF StdioException, std,stdio) on failure to redirect any of the streams.$(BR)
3047 // my_application writes to stdout and might write to stderr
3048 auto pipes = pipeProcess("my_application", Redirect.stdout | Redirect.stderr);
3049 scope(exit) wait(pipes.pid);
3051 // Store lines of output.
3053 foreach (line; pipes.stdout.byLine) output ~= line.idup;
3055 // Store lines of errors.
3057 foreach (line; pipes.stderr.byLine) errors ~= line.idup;
3060 // sendmail expects to read from stdin
3061 pipes = pipeProcess(["/usr/bin/sendmail", "-t"], Redirect.stdin);
3062 pipes.stdin.writeln("To: you");
3063 pipes.stdin.writeln("From: me");
3064 pipes.stdin.writeln("Subject: dlang");
3065 pipes.stdin.writeln("");
3066 pipes.stdin.writeln(message);
3068 // a single period tells sendmail we are finished
3069 pipes.stdin.writeln(".");
3071 // but at this point sendmail might not see it, we need to flush
3072 pipes.stdin.flush();
3074 // sendmail happens to exit on ".", but some you have to close the file:
3075 pipes.stdin.close();
3077 // otherwise this wait will wait forever
3082 ProcessPipes pipeProcess(scope const(char[])[] args,
3083 Redirect redirect = Redirect.all,
3084 const string[string] env = null,
3085 Config config = Config.none,
3086 scope const(char)[] workDir = null)
3089 return pipeProcessImpl!spawnProcess(args, redirect, env, config, workDir);
3093 ProcessPipes pipeProcess(scope const(char)[] program,
3094 Redirect redirect = Redirect.all,
3095 const string[string] env = null,
3096 Config config = Config.none,
3097 scope const(char)[] workDir = null)
3100 return pipeProcessImpl!spawnProcess(program, redirect, env, config, workDir);
3104 ProcessPipes pipeShell(scope const(char)[] command,
3105 Redirect redirect = Redirect.all,
3106 const string[string] env = null,
3107 Config config = Config.none,
3108 scope const(char)[] workDir = null,
3109 string shellPath = nativeShell)
3112 return pipeProcessImpl!spawnShell(command,
3120 // Implementation of the pipeProcess() family of functions.
3121 private ProcessPipes pipeProcessImpl(alias spawnFunc, Cmd, ExtraSpawnFuncArgs...)
3123 Redirect redirectFlags,
3124 const string[string] env = null,
3125 Config config = Config.none,
3126 scope const(char)[] workDir = null,
3127 ExtraSpawnFuncArgs extraArgs = ExtraSpawnFuncArgs.init)
3128 @trusted //TODO: @safe
3130 File childStdin, childStdout, childStderr;
3132 pipes._redirectFlags = redirectFlags;
3134 if (redirectFlags & Redirect.stdin)
3137 childStdin = p.readEnd;
3138 pipes._stdin = p.writeEnd;
3142 childStdin = std.stdio.stdin;
3145 if (redirectFlags & Redirect.stdout)
3147 if ((redirectFlags & Redirect.stdoutToStderr) != 0)
3148 throw new StdioException("Cannot create pipe for stdout AND "
3149 ~"redirect it to stderr", 0);
3151 childStdout = p.writeEnd;
3152 pipes._stdout = p.readEnd;
3156 childStdout = std.stdio.stdout;
3159 if (redirectFlags & Redirect.stderr)
3161 if ((redirectFlags & Redirect.stderrToStdout) != 0)
3162 throw new StdioException("Cannot create pipe for stderr AND "
3163 ~"redirect it to stdout", 0);
3165 childStderr = p.writeEnd;
3166 pipes._stderr = p.readEnd;
3170 childStderr = std.stdio.stderr;
3173 if (redirectFlags & Redirect.stdoutToStderr)
3175 if (redirectFlags & Redirect.stderrToStdout)
3177 // We know that neither of the other options have been
3178 // set, so we assign the std.stdio.std* streams directly.
3179 childStdout = std.stdio.stderr;
3180 childStderr = std.stdio.stdout;
3184 childStdout = childStderr;
3187 else if (redirectFlags & Redirect.stderrToStdout)
3189 childStderr = childStdout;
3192 config.flags &= ~(Config.Flags.retainStdin | Config.Flags.retainStdout | Config.Flags.retainStderr);
3193 pipes._pid = spawnFunc(command, childStdin, childStdout, childStderr,
3194 env, config, workDir, extraArgs);
3200 Flags that can be passed to $(LREF pipeProcess) and $(LREF pipeShell)
3201 to specify which of the child process' standard streams are redirected.
3202 Use bitwise OR to combine flags.
3206 /// Redirect the standard input, output or error streams, respectively.
3208 stdout = 2, /// ditto
3209 stderr = 4, /// ditto
3212 Redirect _all three streams. This is equivalent to
3213 $(D Redirect.stdin | Redirect.stdout | Redirect.stderr).
3215 all = stdin | stdout | stderr,
3218 Redirect the standard error stream into the standard output stream.
3219 This can not be combined with `Redirect.stderr`.
3224 Redirect the standard output stream into the standard error stream.
3225 This can not be combined with `Redirect.stdout`.
3227 stdoutToStderr = 16,
3233 version (Windows) TestScript prog =
3234 "call :sub %~1 %~2 0
3242 if -%INPUT%-==-stop- ( exit %~3 )
3244 echo %INPUT% %~2 1>&2";
3245 else version (Posix) TestScript prog =
3246 `for EXITCODE in 0 1 2 3; do
3248 if test "$INPUT" = stop; then break; fi
3250 echo "$INPUT $2" >&2
3253 auto pp = pipeProcess([prog.path, "bar", "baz"]);
3254 pp.stdin.writeln("foo");
3256 assert(pp.stdout.readln().chomp() == "foo bar");
3257 assert(pp.stderr.readln().chomp().stripRight() == "foo baz");
3258 pp.stdin.writeln("1234567890");
3260 assert(pp.stdout.readln().chomp() == "1234567890 bar");
3261 assert(pp.stderr.readln().chomp().stripRight() == "1234567890 baz");
3262 pp.stdin.writeln("stop");
3264 assert(wait(pp.pid) == 2);
3266 pp = pipeProcess([prog.path, "12345", "67890"],
3267 Redirect.stdin | Redirect.stdout | Redirect.stderrToStdout);
3268 pp.stdin.writeln("xyz");
3270 assert(pp.stdout.readln().chomp() == "xyz 12345");
3271 assert(pp.stdout.readln().chomp().stripRight() == "xyz 67890");
3272 pp.stdin.writeln("stop");
3274 assert(wait(pp.pid) == 1);
3276 pp = pipeShell(escapeShellCommand(prog.path, "AAAAA", "BBB"),
3277 Redirect.stdin | Redirect.stdoutToStderr | Redirect.stderr);
3278 pp.stdin.writeln("ab");
3280 assert(pp.stderr.readln().chomp() == "ab AAAAA");
3281 assert(pp.stderr.readln().chomp().stripRight() == "ab BBB");
3282 pp.stdin.writeln("stop");
3284 assert(wait(pp.pid) == 1);
3289 import std.exception : assertThrown;
3290 TestScript prog = "exit 0";
3291 assertThrown!StdioException(pipeProcess(
3293 Redirect.stdout | Redirect.stdoutToStderr));
3294 assertThrown!StdioException(pipeProcess(
3296 Redirect.stderr | Redirect.stderrToStdout));
3297 auto p = pipeProcess(prog.path, Redirect.stdin);
3298 assertThrown!Error(p.stdout);
3299 assertThrown!Error(p.stderr);
3301 p = pipeProcess(prog.path, Redirect.stderr);
3302 assertThrown!Error(p.stdin);
3303 assertThrown!Error(p.stdout);
3308 Object which contains $(REF File, std,stdio) handles that allow communication
3309 with a child process through its standard streams.
3313 /// The $(LREF Pid) of the child process.
3314 @property Pid pid() @safe nothrow
3320 An $(REF File, std,stdio) that allows writing to the child process'
3321 standard input stream.
3324 $(OBJECTREF Error) if the child process' standard input stream hasn't
3327 @property File stdin() @safe nothrow
3329 if ((_redirectFlags & Redirect.stdin) == 0)
3330 throw new Error("Child process' standard input stream hasn't "
3331 ~"been redirected.");
3336 An $(REF File, std,stdio) that allows reading from the child process'
3337 standard output stream.
3340 $(OBJECTREF Error) if the child process' standard output stream hasn't
3343 @property File stdout() @safe nothrow
3345 if ((_redirectFlags & Redirect.stdout) == 0)
3346 throw new Error("Child process' standard output stream hasn't "
3347 ~"been redirected.");
3352 An $(REF File, std,stdio) that allows reading from the child process'
3353 standard error stream.
3356 $(OBJECTREF Error) if the child process' standard error stream hasn't
3359 @property File stderr() @safe nothrow
3361 if ((_redirectFlags & Redirect.stderr) == 0)
3362 throw new Error("Child process' standard error stream hasn't "
3363 ~"been redirected.");
3368 Redirect _redirectFlags;
3370 File _stdin, _stdout, _stderr;
3376 Executes the given program or shell command and returns its exit
3379 `execute` and `executeShell` start a new process using
3380 $(LREF spawnProcess) and $(LREF spawnShell), respectively, and wait
3381 for the process to complete before returning. The functions capture
3382 what the child process prints to both its standard output and
3383 standard error streams, and return this together with its exit code.
3385 auto dmd = execute(["dmd", "myapp.d"]);
3386 if (dmd.status != 0) writeln("Compilation failed:\n", dmd.output);
3388 auto ls = executeShell("ls -l");
3389 if (ls.status != 0) writeln("Failed to retrieve file listing");
3390 else writeln(ls.output);
3393 The `args`/`program`/`command`, `env` and `config`
3394 parameters are forwarded straight to the underlying spawn functions,
3395 and we refer to their documentation for details.
3398 args = An array which contains the program name as the zeroth element
3399 and any command-line arguments in the following elements.
3400 (See $(LREF spawnProcess) for details.)
3401 program = The program name, $(I without) command-line arguments.
3402 (See $(LREF spawnProcess) for details.)
3403 command = A shell command which is passed verbatim to the command
3404 interpreter. (See $(LREF spawnShell) for details.)
3405 env = Additional environment variables for the child process.
3406 (See $(LREF spawnProcess) for details.)
3407 config = Flags that control process creation. See $(LREF Config)
3408 for an overview of available flags, and note that the
3409 `retainStd...` flags have no effect in this function.
3410 maxOutput = The maximum number of bytes of output that should be
3412 workDir = The working directory for the new process.
3413 By default the child process inherits the parent's working
3415 shellPath = The path to the shell to use to run the specified program.
3416 By default this is $(LREF nativeShell).
3420 An $(D std.typecons.Tuple!(int, "status", string, "output")).
3423 If the process is terminated by a signal, the `status` field of
3424 the return value will contain a negative number whose absolute
3425 value is the signal number. (See $(LREF wait) for details.)
3428 $(LREF ProcessException) on failure to start the process.$(BR)
3429 $(REF StdioException, std,stdio) on failure to capture output.
3431 auto execute(scope const(char[])[] args,
3432 const string[string] env = null,
3433 Config config = Config.none,
3434 size_t maxOutput = size_t.max,
3435 scope const(char)[] workDir = null)
3438 return executeImpl!pipeProcess(args, env, config, maxOutput, workDir);
3442 auto execute(scope const(char)[] program,
3443 const string[string] env = null,
3444 Config config = Config.none,
3445 size_t maxOutput = size_t.max,
3446 scope const(char)[] workDir = null)
3449 return executeImpl!pipeProcess(program, env, config, maxOutput, workDir);
3453 auto executeShell(scope const(char)[] command,
3454 const string[string] env = null,
3455 Config config = Config.none,
3456 size_t maxOutput = size_t.max,
3457 scope const(char)[] workDir = null,
3458 string shellPath = nativeShell)
3461 return executeImpl!pipeShell(command,
3469 // Does the actual work for execute() and executeShell().
3470 private auto executeImpl(alias pipeFunc, Cmd, ExtraPipeFuncArgs...)(
3472 const string[string] env = null,
3473 Config config = Config.none,
3474 size_t maxOutput = size_t.max,
3475 scope const(char)[] workDir = null,
3476 ExtraPipeFuncArgs extraArgs = ExtraPipeFuncArgs.init)
3477 @trusted //TODO: @safe
3479 import std.algorithm.comparison : min;
3480 import std.array : appender;
3481 import std.typecons : Tuple;
3483 auto redirect = (config.flags & Config.Flags.stderrPassThrough)
3485 : Redirect.stdout | Redirect.stderrToStdout;
3487 auto p = pipeFunc(commandLine, redirect,
3488 env, config, workDir, extraArgs);
3490 auto a = appender!string;
3491 enum size_t defaultChunkSize = 4096;
3492 immutable chunkSize = min(maxOutput, defaultChunkSize);
3494 // Store up to maxOutput bytes in a.
3495 foreach (ubyte[] chunk; p.stdout.byChunk(chunkSize))
3497 immutable size_t remain = maxOutput - a.data.length;
3499 if (chunk.length < remain) a.put(chunk);
3502 a.put(chunk[0 .. remain]);
3506 // Exhaust the stream, if necessary.
3507 foreach (ubyte[] chunk; p.stdout.byChunk(defaultChunkSize)) { }
3509 return Tuple!(int, "status", string, "output")(wait(p.pid), a.data);
3515 // To avoid printing the newline characters, we use the echo|set trick on
3516 // Windows, and printf on POSIX (neither echo -n nor echo \c are portable).
3517 version (Windows) TestScript prog =
3519 echo|set /p=%~2 1>&2
3521 else version (Android) TestScript prog =
3525 else version (Posix) TestScript prog =
3529 auto r = execute([prog.path, "foo", "bar"]);
3530 assert(r.status == 123);
3531 assert(r.output.stripRight() == "foobar");
3532 auto s = execute([prog.path, "Hello", "World"]);
3533 assert(s.status == 123);
3534 assert(s.output.stripRight() == "HelloWorld");
3540 auto r1 = executeShell("echo foo");
3541 assert(r1.status == 0);
3542 assert(r1.output.chomp() == "foo");
3543 auto r2 = executeShell("echo bar 1>&2");
3544 assert(r2.status == 0);
3545 assert(r2.output.chomp().stripRight() == "bar");
3546 auto r3 = executeShell("exit 123");
3547 assert(r3.status == 123);
3548 assert(r3.output.empty);
3553 // Temporarily disable output to stderr so as to not spam the build log.
3554 import std.stdio : stderr;
3555 import std.typecons : Tuple;
3556 import std.file : readText, exists, remove;
3557 import std.traits : ReturnType;
3559 ReturnType!executeShell r;
3560 auto tmpname = uniqueTempPath;
3561 scope(exit) if (exists(tmpname)) remove(tmpname);
3563 // Open a new scope to minimize code ran with stderr redirected.
3565 stderr.open(tmpname, "w");
3566 scope(exit) stderr = t;
3567 r = executeShell("echo D rox>&2", null, Config.stderrPassThrough);
3569 assert(r.status == 0);
3570 assert(r.output.empty);
3571 auto witness = readText(tmpname);
3572 import std.ascii : newline;
3573 assert(witness == "D rox" ~ newline, "'" ~ witness ~ "'");
3578 import std.typecons : Tuple;
3579 void foo() //Just test the compilation
3581 auto ret1 = execute(["dummy", "arg"]);
3582 auto ret2 = executeShell("dummy arg");
3583 static assert(is(typeof(ret1) == typeof(ret2)));
3585 Tuple!(int, string) ret3 = execute(["dummy", "arg"]);
3589 /// An exception that signals a problem with starting or waiting for a process.
3590 class ProcessException : Exception
3592 import std.exception : basicExceptionCtors;
3593 mixin basicExceptionCtors;
3595 // Creates a new ProcessException based on errno.
3596 static ProcessException newFromErrno(string customMsg = null,
3597 string file = __FILE__,
3598 size_t line = __LINE__)
3600 import core.stdc.errno : errno;
3601 return newFromErrno(errno, customMsg, file, line);
3604 // ditto, but error number is provided by caller
3605 static ProcessException newFromErrno(int error,
3606 string customMsg = null,
3607 string file = __FILE__,
3608 size_t line = __LINE__)
3610 import std.exception : errnoString;
3611 auto errnoMsg = errnoString(error);
3612 auto msg = customMsg.empty ? errnoMsg
3613 : customMsg ~ " (" ~ errnoMsg ~ ')';
3614 return new ProcessException(msg, file, line);
3617 // Creates a new ProcessException based on GetLastError() (Windows only).
3619 static ProcessException newFromLastError(string customMsg = null,
3620 string file = __FILE__,
3621 size_t line = __LINE__)
3623 auto lastMsg = generateSysErrorMsg();
3624 auto msg = customMsg.empty ? lastMsg
3625 : customMsg ~ " (" ~ lastMsg ~ ')';
3626 return new ProcessException(msg, file, line);
3632 Determines the path to the current user's preferred command interpreter.
3634 On Windows, this function returns the contents of the COMSPEC environment
3635 variable, if it exists. Otherwise, it returns the result of $(LREF nativeShell).
3637 On POSIX, `userShell` returns the contents of the SHELL environment
3638 variable, if it exists and is non-empty. Otherwise, it returns the result of
3639 $(LREF nativeShell).
3641 @property string userShell() @safe
3643 version (Windows) return environment.get("COMSPEC", nativeShell);
3644 else version (Posix) return environment.get("SHELL", nativeShell);
3648 The platform-specific native shell path.
3650 This function returns `"cmd.exe"` on Windows, `"/bin/sh"` on POSIX, and
3651 `"/system/bin/sh"` on Android.
3653 @property string nativeShell() @safe @nogc pure nothrow
3655 version (Windows) return "cmd.exe";
3656 else version (Android) return "/system/bin/sh";
3657 else version (Posix) return "/bin/sh";
3660 // A command-line switch that indicates to the shell that it should
3661 // interpret the following argument as a command to be executed.
3662 version (Posix) private immutable string shellSwitch = "-c";
3663 version (Windows) private immutable string shellSwitch = "/C";
3665 // Unittest support code: TestScript takes a string that contains a
3666 // shell script for the current platform, and writes it to a temporary
3667 // file. On Windows the file name gets a .cmd extension, while on
3668 // POSIX its executable permission bit is set. The file is
3669 // automatically deleted when the object goes out of scope.
3670 version (StdUnittest)
3671 private struct TestScript
3673 this(string code) @system
3675 // @system due to chmod
3676 import std.ascii : newline;
3677 import std.file : write;
3681 auto firstLine = "@echo off";
3683 else version (Posix)
3686 auto firstLine = "#!" ~ nativeShell;
3688 path = uniqueTempPath()~ext;
3689 write(path, firstLine ~ newline ~ code ~ newline);
3692 import core.sys.posix.sys.stat : chmod;
3693 import std.conv : octal;
3694 chmod(path.tempCString(), octal!777);
3700 import std.file : remove, exists;
3701 if (!path.empty && exists(path))
3703 try { remove(path); }
3706 debug std.stdio.stderr.writeln(e.msg);
3715 // =============================================================================
3716 // Functions for shell command quoting/escaping.
3717 // =============================================================================
3721 Command line arguments exist in three forms:
3722 1) string or char* array, as received by main.
3723 Also used internally on POSIX systems.
3724 2) Command line string, as used in Windows'
3725 CreateProcess and CommandLineToArgvW functions.
3726 A specific quoting and escaping algorithm is used
3727 to distinguish individual arguments.
3728 3) Shell command string, as written at a shell prompt
3729 or passed to cmd /C - this one may contain shell
3730 control characters, e.g. > or | for redirection /
3731 piping - thus, yet another layer of escaping is
3732 used to distinguish them from program arguments.
3734 Except for escapeWindowsArgument, the intermediary
3735 format (2) is hidden away from the user in this module.
3739 Escapes an argv-style argument array to be used with $(LREF spawnShell),
3740 $(LREF pipeShell) or $(LREF executeShell).
3742 string url = "http://dlang.org/";
3743 executeShell(escapeShellCommand("wget", url, "-O", "dlang-index.html"));
3746 Concatenate multiple `escapeShellCommand` and
3747 $(LREF escapeShellFileName) results to use shell redirection or
3751 escapeShellCommand("curl", "http://dlang.org/download.html") ~
3753 escapeShellCommand("grep", "-o", `http://\S*\.zip`) ~
3755 escapeShellFileName("D download links.txt"));
3759 $(OBJECTREF Exception) if any part of the command line contains unescapable
3760 characters (NUL on all platforms, as well as CR and LF on Windows).
3762 string escapeShellCommand(scope const(char[])[] args...) @safe pure
3768 // Do not ^-escape the first argument (the program path),
3769 // as the shell parses it differently from parameters.
3770 // ^-escaping a program path that contains spaces will fail.
3771 string result = escapeShellFileName(args[0]);
3772 if (args.length > 1)
3774 result ~= " " ~ escapeShellCommandString(
3775 escapeShellArguments(args[1..$]));
3781 return escapeShellCommandString(escapeShellArguments(args));
3787 // This is a simple unit test without any special requirements,
3788 // in addition to the unittest_burnin one below which requires
3789 // special preparation.
3791 struct TestVector { string[] args; string windows, posix; }
3792 TestVector[] tests =
3796 windows : `"foo bar"`,
3800 args : ["foo bar", "hello"],
3801 windows : `"foo bar" hello`,
3802 posix : `'foo bar' hello`
3805 args : ["foo bar", "hello world"],
3806 windows : `"foo bar" ^"hello world^"`,
3807 posix : `'foo bar' 'hello world'`
3810 args : ["foo bar", "hello", "world"],
3811 windows : `"foo bar" hello world`,
3812 posix : `'foo bar' hello world`
3815 args : ["foo bar", `'"^\`],
3816 windows : `"foo bar" ^"'\^"^^\\^"`,
3817 posix : `'foo bar' ''\''"^\'`
3820 args : ["foo bar", ""],
3821 windows : `"foo bar" ^"^"`,
3822 posix : `'foo bar' ''`
3825 args : ["foo bar", "2"],
3826 windows : `"foo bar" ^"2^"`,
3827 posix : `'foo bar' '2'`
3831 foreach (test; tests)
3833 auto actual = escapeShellCommand(test.args);
3835 string expected = test.windows;
3837 string expected = test.posix;
3838 assert(actual == expected, "\nExpected: " ~ expected ~ "\nGot: " ~ actual);
3842 private string escapeShellCommandString(return scope string command) @safe pure
3845 return escapeWindowsShellCommand(command);
3850 private string escapeWindowsShellCommand(scope const(char)[] command) @safe pure
3852 import std.array : appender;
3853 auto result = appender!string();
3854 result.reserve(command.length);
3856 foreach (c; command)
3860 throw new Exception("Cannot put NUL in command line");
3863 throw new Exception("CR/LF are not escapable");
3864 case '\x01': .. case '\x09':
3865 case '\x0B': .. case '\x0C':
3866 case '\x0E': .. case '\x1F':
3881 private string escapeShellArguments(scope const(char[])[] args...)
3882 @trusted pure nothrow
3884 import std.exception : assumeUnique;
3888 char[] allocator(size_t size)
3890 if (buf.length == 0)
3891 return buf = new char[size];
3894 auto p = buf.length;
3895 buf.length = buf.length + 1 + size;
3897 return buf[p .. p+size];
3902 escapeShellArgument!allocator(arg);
3903 return assumeUnique(buf);
3906 private auto escapeShellArgument(alias allocator)(scope const(char)[] arg) @safe nothrow
3908 // The unittest for this function requires special
3909 // preparation - see below.
3912 return escapeWindowsArgumentImpl!allocator(arg);
3914 return escapePosixArgumentImpl!allocator(arg);
3918 Quotes a command-line argument in a manner conforming to the behavior of
3919 $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx,
3920 CommandLineToArgvW).
3922 string escapeWindowsArgument(scope const(char)[] arg) @trusted pure nothrow
3924 // Rationale for leaving this function as public:
3925 // this algorithm of escaping paths is also used in other software,
3926 // e.g. DMD's response files.
3927 import std.exception : assumeUnique;
3928 auto buf = escapeWindowsArgumentImpl!charAllocator(arg);
3929 return assumeUnique(buf);
3933 private char[] charAllocator(size_t size) @safe pure nothrow
3935 return new char[size];
3939 private char[] escapeWindowsArgumentImpl(alias allocator)(scope const(char)[] arg)
3941 if (is(typeof(allocator(size_t.init)[0] = char.init)))
3944 // * http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx
3945 // * http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx
3947 // Check if the string needs to be escaped,
3948 // and calculate the total string size.
3950 // Trailing backslashes must be escaped
3951 bool escaping = true;
3952 bool needEscape = false;
3953 // Result size = input size + 2 for surrounding quotes + 1 for the
3954 // backslash for each escaped character.
3955 size_t size = 1 + arg.length + 1;
3957 foreach_reverse (char c; arg)
3973 if (c == ' ' || c == '\t')
3979 import std.ascii : isDigit;
3980 // Empty arguments need to be specified as ""
3984 // Arguments ending with digits need to be escaped,
3985 // to disambiguate with 1>file redirection syntax
3986 if (isDigit(arg[$-1]))
3990 return allocator(arg.length)[] = arg;
3992 // Construct result string.
3994 auto buf = allocator(size);
3998 foreach_reverse (char c; arg)
4016 version (Windows) version (StdUnittest)
4019 import core.stdc.stddef;
4020 import core.stdc.wchar_ : wcslen;
4021 import core.sys.windows.shellapi : CommandLineToArgvW;
4022 import core.sys.windows.winbase;
4023 import core.sys.windows.winnt;
4026 string[] parseCommandLine(string line)
4028 import std.algorithm.iteration : map;
4029 import std.array : array;
4030 import std.conv : to;
4031 auto lpCommandLine = (to!(WCHAR[])(line) ~ '\0').ptr;
4033 auto args = CommandLineToArgvW(lpCommandLine, &numArgs);
4034 scope(exit) LocalFree(args);
4035 return args[0 .. numArgs]
4036 .map!(arg => to!string(arg[0 .. wcslen(arg)]))
4042 import std.conv : text;
4043 string[] testStrings = [
4049 `C:\Program Files\`,
4052 enum CHARS = `_x\" *&^` ~ "\t"; // _ is placeholder for nothing
4057 testStrings ~= [c1, c2, c3, c4].replace("_", "");
4059 foreach (s; testStrings)
4061 auto q = escapeWindowsArgument(s);
4062 auto args = parseCommandLine("Dummy.exe " ~ q);
4063 assert(args.length == 2, s ~ " => " ~ q ~ " #" ~ text(args.length-1));
4064 assert(args[1] == s, s ~ " => " ~ q ~ " => " ~ args[1]);
4069 private string escapePosixArgument(scope const(char)[] arg) @trusted pure nothrow
4071 import std.exception : assumeUnique;
4072 auto buf = escapePosixArgumentImpl!charAllocator(arg);
4073 return assumeUnique(buf);
4076 private char[] escapePosixArgumentImpl(alias allocator)(scope const(char)[] arg)
4078 if (is(typeof(allocator(size_t.init)[0] = char.init)))
4080 bool needQuoting = {
4081 import std.ascii : isAlphaNum, isDigit;
4082 import std.algorithm.comparison : among;
4084 // Empty arguments need to be specified as ''
4085 if (arg.length == 0)
4087 // Arguments ending with digits need to be escaped,
4088 // to disambiguate with 1>file redirection syntax
4089 if (isDigit(arg[$-1]))
4093 // for n in $(seq 1 255) ; do
4094 // c=$(printf \\$(printf "%o" $n))
4095 // q=$(/bin/printf '%q' "$c")
4096 // if [[ "$q" == "$c" ]] ; then printf "%s, " "'$c'" ; fi
4099 foreach (char c; arg)
4100 if (!isAlphaNum(c) && !c.among('%', '+', ',', '-', '.', '/', ':', '@', ']', '_'))
4106 auto buf = allocator(arg.length);
4111 // '\'' means: close quoted part of argument, append an escaped
4112 // single quote, and reopen quotes
4114 // Below code is equivalent to:
4115 // return `'` ~ std.array.replace(arg, `'`, `'\''`) ~ `'`;
4117 size_t size = 1 + arg.length + 1;
4118 foreach (char c; arg)
4122 auto buf = allocator(size);
4125 foreach (char c; arg)
4128 buf[p .. p+4] = `'\''`;
4140 Escapes a filename to be used for shell redirection with $(LREF spawnShell),
4141 $(LREF pipeShell) or $(LREF executeShell).
4143 string escapeShellFileName(scope const(char)[] fileName) @trusted pure nothrow
4145 // The unittest for this function requires special
4146 // preparation - see below.
4150 // If a file starts with &, it can cause cmd.exe to misinterpret
4151 // the file name as the stream redirection syntax:
4152 // command > "&foo.txt"
4153 // gets interpreted as
4154 // command >&foo.txt
4155 // Prepend .\ to disambiguate.
4157 if (fileName.length && fileName[0] == '&')
4158 return cast(string)(`".\` ~ fileName ~ '"');
4160 return cast(string)('"' ~ fileName ~ '"');
4163 return escapePosixArgument(fileName);
4166 // Loop generating strings with random characters
4167 //version = unittest_burnin;
4169 version (unittest_burnin)
4172 // There are no readily-available commands on all platforms suitable
4173 // for properly testing command escaping. The behavior of CMD's "echo"
4174 // built-in differs from the POSIX program, and Windows ports of POSIX
4175 // environments (Cygwin, msys, gnuwin32) may interfere with their own
4178 // To run this unit test, create std_process_unittest_helper.d with the
4179 // following content and compile it:
4180 // import std.stdio, std.array; void main(string[] args) { write(args.join("\0")); }
4181 // Then, test this module with:
4182 // rdmd --main -unittest -version=unittest_burnin process.d
4184 import std.file : readText, remove;
4185 import std.format : format;
4186 import std.path : absolutePath;
4187 import std.random : uniform;
4189 auto helper = absolutePath("std_process_unittest_helper");
4190 assert(executeShell(helper ~ " hello").output.split("\0")[1..$] == ["hello"], "Helper malfunction");
4192 void test(string[] s, string fn)
4197 e = escapeShellCommand(helper ~ s);
4199 scope(failure) writefln("executeShell() failed.\nExpected:\t%s\nEncoded:\t%s", s, [e]);
4200 auto result = executeShell(e);
4201 assert(result.status == 0, "std_process_unittest_helper failed");
4202 g = result.output.split("\0")[1..$];
4204 assert(s == g, format("executeShell() test failed.\nExpected:\t%s\nGot:\t\t%s\nEncoded:\t%s", s, g, [e]));
4206 e = escapeShellCommand(helper ~ s) ~ ">" ~ escapeShellFileName(fn);
4208 scope(failure) writefln(
4209 "executeShell() with redirect failed.\nExpected:\t%s\nFilename:\t%s\nEncoded:\t%s", s, [fn], [e]);
4210 auto result = executeShell(e);
4211 assert(result.status == 0, "std_process_unittest_helper failed");
4212 assert(!result.output.length, "No output expected, got:\n" ~ result.output);
4213 g = readText(fn).split("\0")[1..$];
4217 format("executeShell() with redirect test failed.\nExpected:\t%s\nGot:\t\t%s\nEncoded:\t%s", s, g, [e]));
4223 foreach (n; 0 .. uniform(1, 4))
4226 foreach (l; 0 .. uniform(0, 10))
4233 // As long as DMD's system() uses CreateProcessA,
4234 // we can't reliably pass Unicode
4235 c = uniform(0, 128);
4238 c = uniform!ubyte();
4241 continue; // argv-strings are zero-terminated
4243 if (c == '\r' || c == '\n')
4244 continue; // newlines are unescapable on Windows
4252 // generate filename
4254 foreach (l; 0 .. uniform(1, 10))
4260 c = uniform(0, 128); // as above
4262 c = uniform!ubyte();
4264 if (c == 0 || c == '/')
4265 continue; // NUL and / are the only characters
4266 // forbidden in POSIX filenames
4268 if (c < '\x20' || c == '<' || c == '>' || c == ':' ||
4269 c == '"' || c == '\\' || c == '|' || c == '?' || c == '*')
4270 continue; // http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx
4276 fn = fn[0..$/2] ~ "_testfile_" ~ fn[$/2..$];
4282 // =============================================================================
4283 // Everything below this line was part of the old std.process, and most of
4284 // it will be deprecated and removed.
4285 // =============================================================================
4289 Copyright: Copyright The D Language Foundation 2007 - 2009.
4290 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
4291 Authors: $(HTTP digitalmars.com, Walter Bright),
4292 $(HTTP erdani.org, Andrei Alexandrescu),
4293 $(HTTP thecybershadow.net, Vladimir Panteleev)
4294 Source: $(PHOBOSSRC std/_process.d)
4297 Copyright The D Language Foundation 2007 - 2009.
4298 Distributed under the Boost Software License, Version 1.0.
4299 (See accompanying file LICENSE_1_0.txt or copy at
4300 http://www.boost.org/LICENSE_1_0.txt)
4304 import core.stdc.errno;
4305 import core.stdc.stdlib;
4306 import core.stdc.string;
4311 import std.file, std.format, std.random;
4315 import core.sys.posix.stdlib;
4318 private const(char)** toAStringz(in string[] a)
4320 import std.string : toStringz;
4321 auto p = (new const(char)*[1 + a.length]).ptr;
4322 foreach (i, string s; a)
4323 p[i] = toStringz(s);
4329 /* ========================================================== */
4333 // int spawnvp(int mode, string pathname, string[] argv)
4335 // char** argv_ = cast(char**) core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length));
4336 // scope(exit) core.stdc.stdlib.free(argv_);
4338 // toAStringz(argv, argv_);
4340 // return spawnvp(mode, pathname.tempCString(), argv_);
4344 // Incorporating idea (for spawnvp() on Posix) from Dave Fladebo
4346 enum { _P_WAIT, _P_NOWAIT, _P_OVERLAY }
4347 version (Windows) extern(C) int spawnvp(int, scope const(char) *, scope const(char*)*);
4348 alias P_WAIT = _P_WAIT;
4349 alias P_NOWAIT = _P_NOWAIT;
4351 /* ========================================================== */
4356 Replaces the current process by executing a command, `pathname`, with
4357 the arguments in `argv`.
4359 $(BLUE This function is Posix-Only.)
4361 Typically, the first element of `argv` is
4362 the command being executed, i.e. $(D argv[0] == pathname). The 'p'
4363 versions of `exec` search the PATH environment variable for $(D
4364 pathname). The 'e' versions additionally take the new process'
4365 environment variables as an array of strings of the form key=value.
4367 Does not return on success (the current process will have been
4368 replaced). Returns -1 on failure with no indication of the
4372 These functions are only supported on POSIX platforms, as the Windows
4373 operating systems do not provide the ability to overwrite the current
4374 process image with another. In single-threaded programs it is possible
4375 to approximate the effect of `execv*` by using $(LREF spawnProcess)
4376 and terminating the current process once the child process has returned.
4379 auto commandLine = [ "program", "arg1", "arg2" ];
4382 execv(commandLine[0], commandLine);
4383 throw new Exception("Failed to execute program");
4385 else version (Windows)
4387 import core.stdc.stdlib : _Exit;
4388 _Exit(wait(spawnProcess(commandLine)));
4391 This is, however, NOT equivalent to POSIX' `execv*`. For one thing, the
4392 executed program is started as a separate process, with all this entails.
4393 Secondly, in a multithreaded program, other threads will continue to do
4394 work while the current thread is waiting for the child process to complete.
4396 A better option may sometimes be to terminate the current program immediately
4397 after spawning the child process. This is the behaviour exhibited by the
4398 $(LINK2 http://msdn.microsoft.com/en-us/library/431x4c1w.aspx,`__exec`)
4399 functions in Microsoft's C runtime library, and it is how D's now-deprecated
4400 Windows `execv*` functions work. Example:
4402 auto commandLine = [ "program", "arg1", "arg2" ];
4405 execv(commandLine[0], commandLine);
4406 throw new Exception("Failed to execute program");
4408 else version (Windows)
4410 spawnProcess(commandLine);
4411 import core.stdc.stdlib : _exit;
4416 int execv(in string pathname, in string[] argv);
4418 int execve(in string pathname, in string[] argv, in string[] envp);
4420 int execvp(in string pathname, in string[] argv);
4422 int execvpe(in string pathname, in string[] argv, in string[] envp);
4424 else version (Posix)
4426 int execv(in string pathname, in string[] argv)
4428 return execv_(pathname, argv);
4430 int execve(in string pathname, in string[] argv, in string[] envp)
4432 return execve_(pathname, argv, envp);
4434 int execvp(in string pathname, in string[] argv)
4436 return execvp_(pathname, argv);
4438 int execvpe(in string pathname, in string[] argv, in string[] envp)
4440 return execvpe_(pathname, argv, envp);
4444 // Move these C declarations to druntime if we decide to keep the D wrappers
4447 int execv(scope const(char) *, scope const(char *)*);
4448 int execve(scope const(char)*, scope const(char*)*, scope const(char*)*);
4449 int execvp(scope const(char)*, scope const(char*)*);
4450 version (Windows) int execvpe(scope const(char)*, scope const(char*)*, scope const(char*)*);
4453 private int execv_(in string pathname, in string[] argv)
4455 return execv(pathname.tempCString(), toAStringz(argv));
4458 private int execve_(in string pathname, in string[] argv, in string[] envp)
4460 return execve(pathname.tempCString(), toAStringz(argv), toAStringz(envp));
4463 private int execvp_(in string pathname, in string[] argv)
4465 return execvp(pathname.tempCString(), toAStringz(argv));
4468 private int execvpe_(in string pathname, in string[] argv, in string[] envp)
4472 import std.array : split;
4473 import std.conv : to;
4474 // Is pathname rooted?
4475 if (pathname[0] == '/')
4477 // Yes, so just call execve()
4478 return execve(pathname, argv, envp);
4482 // No, so must traverse PATHs, looking for first match
4483 string[] envPaths = split(
4484 to!string(core.stdc.stdlib.getenv("PATH")), ":");
4487 // Note: if any call to execve() succeeds, this process will cease
4488 // execution, so there's no need to check the execve() result through
4491 foreach (string pathDir; envPaths)
4493 string composite = cast(string) (pathDir ~ "/" ~ pathname);
4495 iRet = execve(composite, argv, envp);
4499 iRet = execve(pathname, argv, envp);
4505 else version (Windows)
4507 return execvpe(pathname.tempCString(), toAStringz(argv), toAStringz(envp));
4517 /****************************************
4518 * Start up the browser and set it to viewing the page at url.
4520 void browse(scope const(char)[] url);
4525 import core.sys.windows.shellapi, core.sys.windows.winuser;
4527 pragma(lib,"shell32.lib");
4529 void browse(scope const(char)[] url) nothrow @nogc @trusted
4531 ShellExecuteW(null, "open", url.tempCStringW(), null, null, SW_SHOWNORMAL);
4534 else version (Posix)
4536 import core.stdc.stdio;
4537 import core.stdc.string;
4538 import core.sys.posix.unistd;
4540 void browse(scope const(char)[] url) nothrow @nogc @safe
4542 const buffer = url.tempCString(); // Retain buffer until end of scope
4543 const(char)*[3] args;
4545 // Trusted because it's called with a zero-terminated literal
4546 const(char)* browser = (() @trusted => core.stdc.stdlib.getenv("BROWSER"))();
4549 // String already zero-terminated
4550 browser = (() @trusted => strdup(browser))();
4561 //args[0] = "x-www-browser"; // doesn't work on some systems
4562 args[0] = "xdg-open";
4569 auto childpid = core.sys.posix.unistd.fork();
4572 // Trusted because args and all entries are always zero-terminated
4574 core.sys.posix.unistd.execvp(args[0], &args[0]);
4576 core.sys.posix.unistd._exit(1);
4578 assert(0, "Child failed to exec");
4581 // Trusted because it's allocated via strdup above
4582 (() @trusted => free(cast(void*) browser))();
4584 version (StdUnittest)
4586 // Verify that the test script actually suceeds
4588 const check = (() @trusted => waitpid(childpid, &status, 0))();
4589 assert(check != -1);
4590 assert(status == 0);
4595 static assert(0, "os not supported");
4597 // Verify attributes are consistent between all implementations
4598 @safe @nogc nothrow unittest
4604 version (Windows) { /* Doesn't use BROWSER */ }
4608 import std.conv : text;
4609 import std.range : repeat;
4610 immutable string url = text("http://", repeat('x', 249));
4612 TestScript prog = `if [ "$1" != "` ~ url ~ `" ]; then exit 1; fi`;
4613 environment["BROWSER"] = prog.path;