d: Merge upstream dmd 568496d5b, druntime 178c44ff, phobos 574bf883b.
[official-gcc.git] / libphobos / src / std / process.d
blob98c5b9467485ebcf787609a5496203cc3558f954
1 // Written in the D programming language.
3 /**
4 Functions for starting and interacting with other processes, and for
5 working with the current process' execution environment.
7 Process_handling:
8 $(UL $(LI
9 $(LREF spawnProcess) spawns a new process, optionally assigning it an
10 arbitrary set of standard input, output, and error streams.
11 The function returns immediately, leaving the child process to execute
12 in parallel with its parent. All other functions in this module that
13 spawn processes are built around `spawnProcess`.)
14 $(LI
15 $(LREF wait) makes the parent process wait for a child process to
16 terminate. In general one should always do this, to avoid
17 child processes becoming "zombies" when the parent process exits.
18 Scope guards are perfect for this – see the $(LREF spawnProcess)
19 documentation for examples. $(LREF tryWait) is similar to `wait`,
20 but does not block if the process has not yet terminated.)
21 $(LI
22 $(LREF pipeProcess) also spawns a child process which runs
23 in parallel with its parent. However, instead of taking
24 arbitrary streams, it automatically creates a set of
25 pipes that allow the parent to communicate with the child
26 through the child's standard input, output, and/or error streams.
27 This function corresponds roughly to C's `popen` function.)
28 $(LI
29 $(LREF execute) starts a new process and waits for it
30 to complete before returning. Additionally, it captures
31 the process' standard output and error streams and returns
32 the output of these as a string.)
33 $(LI
34 $(LREF spawnShell), $(LREF pipeShell) and $(LREF executeShell) work like
35 `spawnProcess`, `pipeProcess` and `execute`, respectively,
36 except that they take a single command string and run it through
37 the current user's default command interpreter.
38 `executeShell` corresponds roughly to C's `system` function.)
39 $(LI
40 $(LREF kill) attempts to terminate a running process.)
43 The following table compactly summarises the different process creation
44 functions and how they relate to each other:
45 $(BOOKTABLE,
46 $(TR $(TH )
47 $(TH Runs program directly)
48 $(TH Runs shell command))
49 $(TR $(TD Low-level process creation)
50 $(TD $(LREF spawnProcess))
51 $(TD $(LREF spawnShell)))
52 $(TR $(TD Automatic input/output redirection using pipes)
53 $(TD $(LREF pipeProcess))
54 $(TD $(LREF pipeShell)))
55 $(TR $(TD Execute and wait for completion, collect output)
56 $(TD $(LREF execute))
57 $(TD $(LREF executeShell)))
60 Other_functionality:
61 $(UL
62 $(LI
63 $(LREF pipe) is used to create unidirectional pipes.)
64 $(LI
65 $(LREF environment) is an interface through which the current process'
66 environment variables can be read and manipulated.)
67 $(LI
68 $(LREF escapeShellCommand) and $(LREF escapeShellFileName) are useful
69 for constructing shell command lines in a portable way.)
72 Authors:
73 $(LINK2 https://github.com/kyllingstad, Lars Tandle Kyllingstad),
74 $(LINK2 https://github.com/schveiguy, Steven Schveighoffer),
75 $(HTTP thecybershadow.net, Vladimir Panteleev)
76 Copyright:
77 Copyright (c) 2013, the authors. All rights reserved.
78 License:
79 $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
80 Source:
81 $(PHOBOSSRC std/process.d)
82 Macros:
83 OBJECTREF=$(REF1 $0, object)
85 Note:
86 Most of the functionality in this module is not available on iOS, tvOS
87 and watchOS. The only functions available on those platforms are:
88 $(LREF environment), $(LREF thisProcessID) and $(LREF thisThreadID).
90 module std.process;
92 import core.thread : ThreadID;
94 version (Posix)
96 import core.sys.posix.sys.wait;
97 import core.sys.posix.unistd;
99 version (Windows)
101 import core.stdc.stdio;
102 import core.sys.windows.winbase;
103 import core.sys.windows.winnt;
104 import std.utf;
105 import std.windows.syserror;
108 import std.internal.cstring;
109 import std.range.primitives;
110 import std.stdio;
111 import std.traits : isSomeChar;
113 version (OSX)
114 version = Darwin;
115 else version (iOS)
117 version = Darwin;
118 version = iOSDerived;
120 else version (TVOS)
122 version = Darwin;
123 version = iOSDerived;
125 else version (WatchOS)
127 version = Darwin;
128 version = iOSDerived;
131 // When the DMC runtime is used, we have to use some custom functions
132 // to convert between Windows file handles and FILE*s.
133 version (Win32) version (CRuntime_DigitalMars) version = DMC_RUNTIME;
136 // Some of the following should be moved to druntime.
137 private
139 // Microsoft Visual C Runtime (MSVCRT) declarations.
140 version (Windows)
142 version (DMC_RUNTIME) { } else
144 import core.stdc.stdint;
145 enum
147 STDIN_FILENO = 0,
148 STDOUT_FILENO = 1,
149 STDERR_FILENO = 2,
154 // POSIX API declarations.
155 version (Posix)
157 version (Darwin)
159 extern(C) char*** _NSGetEnviron() nothrow;
160 const(char**) getEnvironPtr() @trusted
162 return *_NSGetEnviron;
165 else
167 // Made available by the C runtime:
168 extern(C) extern __gshared const char** environ;
169 const(char**) getEnvironPtr() @trusted
171 return environ;
175 @system unittest
177 import core.thread : Thread;
178 new Thread({assert(getEnvironPtr !is null);}).start();
181 } // private
183 // =============================================================================
184 // Environment variable manipulation.
185 // =============================================================================
188 Manipulates _environment variables using an associative-array-like
189 interface.
191 This class contains only static methods, and cannot be instantiated.
192 See below for examples of use.
194 abstract final class environment
196 static import core.sys.posix.stdlib;
197 import core.stdc.errno : errno, EINVAL;
199 static:
201 Retrieves the value of the environment variable with the given `name`.
203 auto path = environment["PATH"];
206 Throws:
207 $(OBJECTREF Exception) if the environment variable does not exist,
208 or $(REF UTFException, std,utf) if the variable contains invalid UTF-16
209 characters (Windows only).
211 See_also:
212 $(LREF environment.get), which doesn't throw on failure.
214 string opIndex(scope const(char)[] name) @safe
216 import std.exception : enforce;
217 return get(name, null).enforce("Environment variable not found: "~name);
221 Retrieves the value of the environment variable with the given `name`,
222 or a default value if the variable doesn't exist.
224 Unlike $(LREF environment.opIndex), this function never throws on Posix.
226 auto sh = environment.get("SHELL", "/bin/sh");
228 This function is also useful in checking for the existence of an
229 environment variable.
231 auto myVar = environment.get("MYVAR");
232 if (myVar is null)
234 // Environment variable doesn't exist.
235 // Note that we have to use 'is' for the comparison, since
236 // myVar == null is also true if the variable exists but is
237 // empty.
240 Params:
241 name = name of the environment variable to retrieve
242 defaultValue = default value to return if the environment variable doesn't exist.
244 Returns:
245 the value of the environment variable if found, otherwise
246 `null` if the environment doesn't exist.
248 Throws:
249 $(REF UTFException, std,utf) if the variable contains invalid UTF-16
250 characters (Windows only).
252 string get(scope const(char)[] name, string defaultValue = null) @safe
254 string value;
255 getImpl(name, (result) { value = result ? cachedToString(result) : defaultValue; });
256 return value;
260 Assigns the given `value` to the environment variable with the given
261 `name`.
262 If `value` is null the variable is removed from environment.
264 If the variable does not exist, it will be created. If it already exists,
265 it will be overwritten.
267 environment["foo"] = "bar";
270 Throws:
271 $(OBJECTREF Exception) if the environment variable could not be added
272 (e.g. if the name is invalid).
274 Note:
275 On some platforms, modifying environment variables may not be allowed in
276 multi-threaded programs. See e.g.
277 $(LINK2 https://www.gnu.org/software/libc/manual/html_node/Environment-Access.html#Environment-Access, glibc).
279 inout(char)[] opIndexAssign(return inout char[] value, scope const(char)[] name) @trusted
281 version (Posix)
283 import std.exception : enforce, errnoEnforce;
284 if (value is null)
286 remove(name);
287 return value;
289 if (core.sys.posix.stdlib.setenv(name.tempCString(), value.tempCString(), 1) != -1)
291 return value;
293 // The default errno error message is very uninformative
294 // in the most common case, so we handle it manually.
295 enforce(errno != EINVAL,
296 "Invalid environment variable name: '"~name~"'");
297 errnoEnforce(false,
298 "Failed to add environment variable");
299 assert(0);
301 else version (Windows)
303 import std.exception : enforce;
304 enforce(
305 SetEnvironmentVariableW(name.tempCStringW(), value.tempCStringW()),
306 sysErrorString(GetLastError())
308 return value;
310 else static assert(0);
314 Removes the environment variable with the given `name`.
316 If the variable isn't in the environment, this function returns
317 successfully without doing anything.
319 Note:
320 On some platforms, modifying environment variables may not be allowed in
321 multi-threaded programs. See e.g.
322 $(LINK2 https://www.gnu.org/software/libc/manual/html_node/Environment-Access.html#Environment-Access, glibc).
324 void remove(scope const(char)[] name) @trusted nothrow @nogc
326 version (Windows) SetEnvironmentVariableW(name.tempCStringW(), null);
327 else version (Posix) core.sys.posix.stdlib.unsetenv(name.tempCString());
328 else static assert(0);
332 Identify whether a variable is defined in the environment.
334 Because it doesn't return the value, this function is cheaper than `get`.
335 However, if you do need the value as well, you should just check the
336 return of `get` for `null` instead of using this function first.
338 Example:
339 -------------
340 // good usage
341 if ("MY_ENV_FLAG" in environment)
342 doSomething();
344 // bad usage
345 if ("MY_ENV_VAR" in environment)
346 doSomething(environment["MY_ENV_VAR"]);
348 // do this instead
349 if (auto var = environment.get("MY_ENV_VAR"))
350 doSomething(var);
351 -------------
353 bool opBinaryRight(string op : "in")(scope const(char)[] name) @trusted
355 version (Posix)
356 return core.sys.posix.stdlib.getenv(name.tempCString()) !is null;
357 else version (Windows)
359 SetLastError(NO_ERROR);
360 if (GetEnvironmentVariableW(name.tempCStringW, null, 0) > 0)
361 return true;
362 immutable err = GetLastError();
363 if (err == NO_ERROR)
364 return true; // zero-length environment variable on Wine / XP
365 if (err == ERROR_ENVVAR_NOT_FOUND)
366 return false;
367 // Some other Windows error, throw.
368 throw new WindowsException(err);
370 else static assert(0);
374 Copies all environment variables into an associative array.
376 Windows_specific:
377 While Windows environment variable names are case insensitive, D's
378 built-in associative arrays are not. This function will store all
379 variable names in uppercase (e.g. `PATH`).
381 Throws:
382 $(OBJECTREF Exception) if the environment variables could not
383 be retrieved (Windows only).
385 string[string] toAA() @trusted
387 import std.conv : to;
388 string[string] aa;
389 version (Posix)
391 auto environ = getEnvironPtr;
392 for (int i=0; environ[i] != null; ++i)
394 import std.string : indexOf;
396 immutable varDef = to!string(environ[i]);
397 immutable eq = indexOf(varDef, '=');
398 assert(eq >= 0);
400 immutable name = varDef[0 .. eq];
401 immutable value = varDef[eq+1 .. $];
403 // In POSIX, environment variables may be defined more
404 // than once. This is a security issue, which we avoid
405 // by checking whether the key already exists in the array.
406 // For more info:
407 // http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/environment-variables.html
408 if (name !in aa) aa[name] = value;
411 else version (Windows)
413 import std.exception : enforce;
414 import std.uni : toUpper;
415 auto envBlock = GetEnvironmentStringsW();
416 enforce(envBlock, "Failed to retrieve environment variables.");
417 scope(exit) FreeEnvironmentStringsW(envBlock);
419 for (int i=0; envBlock[i] != '\0'; ++i)
421 auto start = i;
422 while (envBlock[i] != '=') ++i;
423 immutable name = toUTF8(toUpper(envBlock[start .. i]));
425 start = i+1;
426 while (envBlock[i] != '\0') ++i;
428 // Ignore variables with empty names. These are used internally
429 // by Windows to keep track of each drive's individual current
430 // directory.
431 if (!name.length)
432 continue;
434 // Just like in POSIX systems, environment variables may be
435 // defined more than once in an environment block on Windows,
436 // and it is just as much of a security issue there. Moreso,
437 // in fact, due to the case insensensitivity of variable names,
438 // which is not handled correctly by all programs.
439 auto val = toUTF8(envBlock[start .. i]);
440 if (name !in aa) aa[name] = val is null ? "" : val;
443 else static assert(0);
444 return aa;
447 private:
448 version (Windows) alias OSChar = WCHAR;
449 else version (Posix) alias OSChar = char;
451 // Retrieves the environment variable. Calls `sink` with a
452 // temporary buffer of OS characters, or `null` if the variable
453 // doesn't exist.
454 void getImpl(scope const(char)[] name, scope void delegate(const(OSChar)[]) @safe sink) @trusted
456 version (Windows)
458 // first we ask windows how long the environment variable is,
459 // then we try to read it in to a buffer of that length. Lots
460 // of error conditions because the windows API is nasty.
462 import std.conv : to;
463 const namezTmp = name.tempCStringW();
464 WCHAR[] buf;
466 // clear error because GetEnvironmentVariable only says it sets it
467 // if the environment variable is missing, not on other errors.
468 SetLastError(NO_ERROR);
469 // len includes terminating null
470 immutable len = GetEnvironmentVariableW(namezTmp, null, 0);
471 if (len == 0)
473 immutable err = GetLastError();
474 if (err == ERROR_ENVVAR_NOT_FOUND)
475 return sink(null);
476 if (err != NO_ERROR) // Some other Windows error, throw.
477 throw new WindowsException(err);
479 if (len <= 1)
480 return sink("");
481 buf.length = len;
483 while (true)
485 // lenRead is either the number of bytes read w/o null - if buf was long enough - or
486 // the number of bytes necessary *including* null if buf wasn't long enough
487 immutable lenRead = GetEnvironmentVariableW(namezTmp, buf.ptr, to!DWORD(buf.length));
488 if (lenRead == 0)
490 immutable err = GetLastError();
491 if (err == NO_ERROR) // sucessfully read a 0-length variable
492 return sink("");
493 if (err == ERROR_ENVVAR_NOT_FOUND) // variable didn't exist
494 return sink(null);
495 // some other windows error
496 throw new WindowsException(err);
498 assert(lenRead != buf.length, "impossible according to msft docs");
499 if (lenRead < buf.length) // the buffer was long enough
500 return sink(buf[0 .. lenRead]);
501 // resize and go around again, because the environment variable grew
502 buf.length = lenRead;
505 else version (Posix)
507 import core.stdc.string : strlen;
509 const vz = core.sys.posix.stdlib.getenv(name.tempCString());
510 if (vz == null) return sink(null);
511 return sink(vz[0 .. strlen(vz)]);
513 else static assert(0);
516 string cachedToString(C)(scope const(C)[] v) @safe
518 import std.algorithm.comparison : equal;
520 // Cache the last call's result.
521 static string lastResult;
522 if (v.empty)
524 // Return non-null array for blank result to distinguish from
525 // not-present result.
526 lastResult = "";
528 else if (!v.equal(lastResult))
530 import std.conv : to;
531 lastResult = v.to!string;
533 return lastResult;
537 @safe unittest
539 import std.exception : assertThrown;
540 // New variable
541 environment["std_process"] = "foo";
542 assert(environment["std_process"] == "foo");
543 assert("std_process" in environment);
545 // Set variable again (also tests length 1 case)
546 environment["std_process"] = "b";
547 assert(environment["std_process"] == "b");
548 assert("std_process" in environment);
550 // Remove variable
551 environment.remove("std_process");
552 assert("std_process" !in environment);
554 // Remove again, should succeed
555 environment.remove("std_process");
556 assert("std_process" !in environment);
558 // Throw on not found.
559 assertThrown(environment["std_process"]);
561 // get() without default value
562 assert(environment.get("std_process") is null);
564 // get() with default value
565 assert(environment.get("std_process", "baz") == "baz");
567 // get() on an empty (but present) value
568 environment["std_process"] = "";
569 auto res = environment.get("std_process");
570 assert(res !is null);
571 assert(res == "");
572 assert("std_process" in environment);
574 // Important to do the following round-trip after the previous test
575 // because it tests toAA with an empty var
577 // Convert to associative array
578 auto aa = environment.toAA();
579 assert(aa.length > 0);
580 foreach (n, v; aa)
582 // Wine has some bugs related to environment variables:
583 // - Wine allows the existence of an env. variable with the name
584 // "\0", but GetEnvironmentVariable refuses to retrieve it.
585 // As of 2.067 we filter these out anyway (see comment in toAA).
587 assert(v == environment[n]);
590 // ... and back again.
591 foreach (n, v; aa)
592 environment[n] = v;
594 // Complete the roundtrip
595 auto aa2 = environment.toAA();
596 import std.conv : text;
597 assert(aa == aa2, text(aa, " != ", aa2));
598 assert("std_process" in environment);
600 // Setting null must have the same effect as remove
601 environment["std_process"] = null;
602 assert("std_process" !in environment);
605 // =============================================================================
606 // Functions and classes for process management.
607 // =============================================================================
610 * Returns the process ID of the current process,
611 * which is guaranteed to be unique on the system.
613 * Example:
614 * ---
615 * writefln("Current process ID: %d", thisProcessID);
616 * ---
618 @property int thisProcessID() @trusted nothrow //TODO: @safe
620 version (Windows) return GetCurrentProcessId();
621 else version (Posix) return core.sys.posix.unistd.getpid();
626 * Returns the process ID of the current thread,
627 * which is guaranteed to be unique within the current process.
629 * Returns:
630 * A $(REF ThreadID, core,thread) value for the calling thread.
632 * Example:
633 * ---
634 * writefln("Current thread ID: %s", thisThreadID);
635 * ---
637 @property ThreadID thisThreadID() @trusted nothrow //TODO: @safe
639 version (Windows)
640 return GetCurrentThreadId();
641 else
642 version (Posix)
644 import core.sys.posix.pthread : pthread_self;
645 return pthread_self();
650 @system unittest
652 int pidA, pidB;
653 ThreadID tidA, tidB;
654 pidA = thisProcessID;
655 tidA = thisThreadID;
657 import core.thread;
658 auto t = new Thread({
659 pidB = thisProcessID;
660 tidB = thisThreadID;
662 t.start();
663 t.join();
665 assert(pidA == pidB);
666 assert(tidA != tidB);
670 package(std) string uniqueTempPath() @safe
672 import std.file : tempDir;
673 import std.path : buildPath;
674 import std.uuid : randomUUID;
675 // Path should contain spaces to test escaping whitespace
676 return buildPath(tempDir(), "std.process temporary file " ~
677 randomUUID().toString());
681 version (iOSDerived) {}
682 else:
685 Spawns a new process, optionally assigning it an arbitrary set of standard
686 input, output, and error streams.
688 The function returns immediately, leaving the child process to execute
689 in parallel with its parent. It is recommended to always call $(LREF wait)
690 on the returned $(LREF Pid) unless the process was spawned with
691 `Config.detached` flag, as detailed in the documentation for `wait`.
693 Command_line:
694 There are four overloads of this function. The first two take an array
695 of strings, `args`, which should contain the program name as the
696 zeroth element and any command-line arguments in subsequent elements.
697 The third and fourth versions are included for convenience, and may be
698 used when there are no command-line arguments. They take a single string,
699 `program`, which specifies the program name.
701 Unless a directory is specified in `args[0]` or `program`,
702 `spawnProcess` will search for the program in a platform-dependent
703 manner. On POSIX systems, it will look for the executable in the
704 directories listed in the PATH environment variable, in the order
705 they are listed. On Windows, it will search for the executable in
706 the following sequence:
707 $(OL
708 $(LI The directory from which the application loaded.)
709 $(LI The current directory for the parent process.)
710 $(LI The 32-bit Windows system directory.)
711 $(LI The 16-bit Windows system directory.)
712 $(LI The Windows directory.)
713 $(LI The directories listed in the PATH environment variable.)
716 // Run an executable called "prog" located in the current working
717 // directory:
718 auto pid = spawnProcess("./prog");
719 scope(exit) wait(pid);
720 // We can do something else while the program runs. The scope guard
721 // ensures that the process is waited for at the end of the scope.
724 // Run DMD on the file "myprog.d", specifying a few compiler switches:
725 auto dmdPid = spawnProcess(["dmd", "-O", "-release", "-inline", "myprog.d" ]);
726 if (wait(dmdPid) != 0)
727 writeln("Compilation failed!");
730 Environment_variables:
731 By default, the child process inherits the environment of the parent
732 process, along with any additional variables specified in the `env`
733 parameter. If the same variable exists in both the parent's environment
734 and in `env`, the latter takes precedence.
736 If the $(LREF Config.newEnv) flag is set in `config`, the child
737 process will $(I not) inherit the parent's environment. Its entire
738 environment will then be determined by `env`.
740 wait(spawnProcess("myapp", ["foo" : "bar"], Config.newEnv));
743 Standard_streams:
744 The optional arguments `stdin`, `stdout` and `stderr` may
745 be used to assign arbitrary $(REF File, std,stdio) objects as the standard
746 input, output and error streams, respectively, of the child process. The
747 former must be opened for reading, while the latter two must be opened for
748 writing. The default is for the child process to inherit the standard
749 streams of its parent.
751 // Run DMD on the file myprog.d, logging any error messages to a
752 // file named errors.log.
753 auto logFile = File("errors.log", "w");
754 auto pid = spawnProcess(["dmd", "myprog.d"],
755 std.stdio.stdin,
756 std.stdio.stdout,
757 logFile);
758 if (wait(pid) != 0)
759 writeln("Compilation failed. See errors.log for details.");
762 Note that if you pass a `File` object that is $(I not)
763 one of the standard input/output/error streams of the parent process,
764 that stream will by default be $(I closed) in the parent process when
765 this function returns. See the $(LREF Config) documentation below for
766 information about how to disable this behaviour.
768 Beware of buffering issues when passing `File` objects to
769 `spawnProcess`. The child process will inherit the low-level raw
770 read/write offset associated with the underlying file descriptor, but
771 it will not be aware of any buffered data. In cases where this matters
772 (e.g. when a file should be aligned before being passed on to the
773 child process), it may be a good idea to use unbuffered streams, or at
774 least ensure all relevant buffers are flushed.
776 Params:
777 args = An array which contains the program name as the zeroth element
778 and any command-line arguments in the following elements.
779 stdin = The standard input stream of the child process.
780 This can be any $(REF File, std,stdio) that is opened for reading.
781 By default the child process inherits the parent's input
782 stream.
783 stdout = The standard output stream of the child process.
784 This can be any $(REF File, std,stdio) that is opened for writing.
785 By default the child process inherits the parent's output stream.
786 stderr = The standard error stream of the child process.
787 This can be any $(REF File, std,stdio) that is opened for writing.
788 By default the child process inherits the parent's error stream.
789 env = Additional environment variables for the child process.
790 config = Flags that control process creation. See $(LREF Config)
791 for an overview of available flags.
792 workDir = The working directory for the new process.
793 By default the child process inherits the parent's working
794 directory.
796 Returns:
797 A $(LREF Pid) object that corresponds to the spawned process.
799 Throws:
800 $(LREF ProcessException) on failure to start the process.$(BR)
801 $(REF StdioException, std,stdio) on failure to pass one of the streams
802 to the child process (Windows only).$(BR)
803 $(REF RangeError, core,exception) if `args` is empty.
805 Pid spawnProcess(scope const(char[])[] args,
806 File stdin = std.stdio.stdin,
807 File stdout = std.stdio.stdout,
808 File stderr = std.stdio.stderr,
809 const string[string] env = null,
810 Config config = Config.none,
811 scope const char[] workDir = null)
812 @safe
814 version (Windows)
816 const commandLine = escapeShellArguments(args);
817 const program = args.length ? args[0] : null;
818 return spawnProcessWin(commandLine, program, stdin, stdout, stderr, env, config, workDir);
820 else version (Posix)
822 return spawnProcessPosix(args, stdin, stdout, stderr, env, config, workDir);
824 else
825 static assert(0);
828 /// ditto
829 Pid spawnProcess(scope const(char[])[] args,
830 const string[string] env,
831 Config config = Config.none,
832 scope const(char)[] workDir = null)
833 @trusted // TODO: Should be @safe
835 return spawnProcess(args,
836 std.stdio.stdin,
837 std.stdio.stdout,
838 std.stdio.stderr,
839 env,
840 config,
841 workDir);
844 /// ditto
845 Pid spawnProcess(scope const(char)[] program,
846 File stdin = std.stdio.stdin,
847 File stdout = std.stdio.stdout,
848 File stderr = std.stdio.stderr,
849 const string[string] env = null,
850 Config config = Config.none,
851 scope const(char)[] workDir = null)
852 @trusted
854 return spawnProcess((&program)[0 .. 1],
855 stdin, stdout, stderr, env, config, workDir);
858 /// ditto
859 Pid spawnProcess(scope const(char)[] program,
860 const string[string] env,
861 Config config = Config.none,
862 scope const(char)[] workDir = null)
863 @trusted
865 return spawnProcess((&program)[0 .. 1], env, config, workDir);
868 version (Posix) private enum InternalError : ubyte
870 noerror,
871 exec,
872 chdir,
873 getrlimit,
874 doubleFork,
875 malloc,
876 preExec,
880 Implementation of spawnProcess() for POSIX.
882 envz should be a zero-terminated array of zero-terminated strings
883 on the form "var=value".
885 version (Posix)
886 private Pid spawnProcessPosix(scope const(char[])[] args,
887 File stdin,
888 File stdout,
889 File stderr,
890 scope const string[string] env,
891 Config config,
892 scope const(char)[] workDir)
893 @trusted // TODO: Should be @safe
895 import core.exception : RangeError;
896 import std.algorithm.searching : any;
897 import std.conv : text;
898 import std.path : isDirSeparator;
899 import std.string : toStringz;
901 if (args.empty) throw new RangeError();
902 const(char)[] name = args[0];
903 if (!any!isDirSeparator(name))
905 name = searchPathFor(name);
906 if (name is null)
907 throw new ProcessException(text("Executable file not found: ", args[0]));
910 // Convert program name and arguments to C-style strings.
911 auto argz = new const(char)*[args.length+1];
912 argz[0] = toStringz(name);
913 foreach (i; 1 .. args.length) argz[i] = toStringz(args[i]);
914 argz[$-1] = null;
916 // Prepare environment.
917 auto envz = createEnv(env, !(config.flags & Config.Flags.newEnv));
919 // Open the working directory.
920 // We use open in the parent and fchdir in the child
921 // so that most errors (directory doesn't exist, not a directory)
922 // can be propagated as exceptions before forking.
923 int workDirFD = -1;
924 scope(exit) if (workDirFD >= 0) close(workDirFD);
925 if (workDir.length)
927 import core.sys.posix.fcntl : open, O_RDONLY, stat_t, fstat, S_ISDIR;
928 workDirFD = open(workDir.tempCString(), O_RDONLY);
929 if (workDirFD < 0)
930 throw ProcessException.newFromErrno("Failed to open working directory");
931 stat_t s;
932 if (fstat(workDirFD, &s) < 0)
933 throw ProcessException.newFromErrno("Failed to stat working directory");
934 if (!S_ISDIR(s.st_mode))
935 throw new ProcessException("Not a directory: " ~ cast(string) workDir);
938 static int getFD(ref File f) { return core.stdc.stdio.fileno(f.getFP()); }
940 // Get the file descriptors of the streams.
941 // These could potentially be invalid, but that is OK. If so, later calls
942 // to dup2() and close() will just silently fail without causing any harm.
943 auto stdinFD = getFD(stdin);
944 auto stdoutFD = getFD(stdout);
945 auto stderrFD = getFD(stderr);
947 // We don't have direct access to the errors that may happen in a child process.
948 // So we use this pipe to deliver them.
949 int[2] forkPipe;
950 if (core.sys.posix.unistd.pipe(forkPipe) == 0)
951 setCLOEXEC(forkPipe[1], true);
952 else
953 throw ProcessException.newFromErrno("Could not create pipe to check startup of child");
954 scope(exit) close(forkPipe[0]);
957 To create detached process, we use double fork technique
958 but we don't have a direct access to the second fork pid from the caller side thus use a pipe.
959 We also can't reuse forkPipe for that purpose
960 because we can't predict the order in which pid and possible error will be written
961 since the first and the second forks will run in parallel.
963 int[2] pidPipe;
964 if (config.flags & Config.Flags.detached)
966 if (core.sys.posix.unistd.pipe(pidPipe) != 0)
967 throw ProcessException.newFromErrno("Could not create pipe to get process pid");
968 setCLOEXEC(pidPipe[1], true);
970 scope(exit) if (config.flags & Config.Flags.detached) close(pidPipe[0]);
972 static void abortOnError(int forkPipeOut, InternalError errorType, int error) nothrow
974 core.sys.posix.unistd.write(forkPipeOut, &errorType, errorType.sizeof);
975 core.sys.posix.unistd.write(forkPipeOut, &error, error.sizeof);
976 close(forkPipeOut);
977 core.sys.posix.unistd._exit(1);
978 assert(0);
981 void closePipeWriteEnds()
983 close(forkPipe[1]);
984 if (config.flags & Config.Flags.detached)
985 close(pidPipe[1]);
988 auto id = core.sys.posix.unistd.fork();
989 if (id < 0)
991 closePipeWriteEnds();
992 throw ProcessException.newFromErrno("Failed to spawn new process");
995 void forkChild() nothrow @nogc
997 static import core.sys.posix.stdio;
999 // Child process
1001 // no need for the read end of pipe on child side
1002 if (config.flags & Config.Flags.detached)
1003 close(pidPipe[0]);
1004 close(forkPipe[0]);
1005 immutable forkPipeOut = forkPipe[1];
1006 immutable pidPipeOut = pidPipe[1];
1008 // Set the working directory.
1009 if (workDirFD >= 0)
1011 if (fchdir(workDirFD) < 0)
1013 // Fail. It is dangerous to run a program
1014 // in an unexpected working directory.
1015 abortOnError(forkPipeOut, InternalError.chdir, .errno);
1017 close(workDirFD);
1020 void execProcess()
1022 // Redirect streams and close the old file descriptors.
1023 // In the case that stderr is redirected to stdout, we need
1024 // to backup the file descriptor since stdout may be redirected
1025 // as well.
1026 if (stderrFD == STDOUT_FILENO) stderrFD = dup(stderrFD);
1027 dup2(stdinFD, STDIN_FILENO);
1028 dup2(stdoutFD, STDOUT_FILENO);
1029 dup2(stderrFD, STDERR_FILENO);
1031 // Ensure that the standard streams aren't closed on execute, and
1032 // optionally close all other file descriptors.
1033 setCLOEXEC(STDIN_FILENO, false);
1034 setCLOEXEC(STDOUT_FILENO, false);
1035 setCLOEXEC(STDERR_FILENO, false);
1037 if (!(config.flags & Config.Flags.inheritFDs))
1039 // NOTE: malloc() and getrlimit() are not on the POSIX async
1040 // signal safe functions list, but practically this should
1041 // not be a problem. Java VM and CPython also use malloc()
1042 // in its own implementation via opendir().
1043 import core.stdc.stdlib : malloc;
1044 import core.sys.posix.poll : pollfd, poll, POLLNVAL;
1045 import core.sys.posix.sys.resource : rlimit, getrlimit, RLIMIT_NOFILE;
1047 // Get the maximum number of file descriptors that could be open.
1048 rlimit r;
1049 if (getrlimit(RLIMIT_NOFILE, &r) != 0)
1051 abortOnError(forkPipeOut, InternalError.getrlimit, .errno);
1053 immutable maxDescriptors = cast(int) r.rlim_cur;
1055 // The above, less stdin, stdout, and stderr
1056 immutable maxToClose = maxDescriptors - 3;
1058 // Call poll() to see which ones are actually open:
1059 auto pfds = cast(pollfd*) malloc(pollfd.sizeof * maxToClose);
1060 if (pfds is null)
1062 abortOnError(forkPipeOut, InternalError.malloc, .errno);
1064 foreach (i; 0 .. maxToClose)
1066 pfds[i].fd = i + 3;
1067 pfds[i].events = 0;
1068 pfds[i].revents = 0;
1070 if (poll(pfds, maxToClose, 0) >= 0)
1072 foreach (i; 0 .. maxToClose)
1074 // don't close pipe write end
1075 if (pfds[i].fd == forkPipeOut) continue;
1076 // POLLNVAL will be set if the file descriptor is invalid.
1077 if (!(pfds[i].revents & POLLNVAL)) close(pfds[i].fd);
1080 else
1082 // Fall back to closing everything.
1083 foreach (i; 3 .. maxDescriptors)
1085 if (i == forkPipeOut) continue;
1086 close(i);
1090 else // This is already done if we don't inherit descriptors.
1092 // Close the old file descriptors, unless they are
1093 // either of the standard streams.
1094 if (stdinFD > STDERR_FILENO) close(stdinFD);
1095 if (stdoutFD > STDERR_FILENO) close(stdoutFD);
1096 if (stderrFD > STDERR_FILENO) close(stderrFD);
1099 if (config.preExecFunction !is null)
1101 if (config.preExecFunction() != true)
1103 abortOnError(forkPipeOut, InternalError.preExec, .errno);
1107 // Execute program.
1108 core.sys.posix.unistd.execve(argz[0], argz.ptr, envz);
1110 // If execution fails, exit as quickly as possible.
1111 abortOnError(forkPipeOut, InternalError.exec, .errno);
1114 if (config.flags & Config.Flags.detached)
1116 auto secondFork = core.sys.posix.unistd.fork();
1117 if (secondFork == 0)
1119 close(pidPipeOut);
1120 execProcess();
1122 else if (secondFork == -1)
1124 auto secondForkErrno = .errno;
1125 close(pidPipeOut);
1126 abortOnError(forkPipeOut, InternalError.doubleFork, secondForkErrno);
1128 else
1130 core.sys.posix.unistd.write(pidPipeOut, &secondFork, pid_t.sizeof);
1131 close(pidPipeOut);
1132 close(forkPipeOut);
1133 _exit(0);
1136 else
1138 execProcess();
1142 if (id == 0)
1144 forkChild();
1145 assert(0);
1147 else
1149 closePipeWriteEnds();
1150 auto status = InternalError.noerror;
1151 auto readExecResult = core.sys.posix.unistd.read(forkPipe[0], &status, status.sizeof);
1152 // Save error number just in case if subsequent "waitpid" fails and overrides errno
1153 immutable lastError = .errno;
1155 if (config.flags & Config.Flags.detached)
1157 // Forked child exits right after creating second fork. So it should be safe to wait here.
1158 import core.sys.posix.sys.wait : waitpid;
1159 int waitResult;
1160 waitpid(id, &waitResult, 0);
1163 if (readExecResult == -1)
1164 throw ProcessException.newFromErrno(lastError, "Could not read from pipe to get child status");
1166 bool owned = true;
1167 if (status != InternalError.noerror)
1169 int error;
1170 readExecResult = read(forkPipe[0], &error, error.sizeof);
1171 string errorMsg;
1172 final switch (status)
1174 case InternalError.chdir:
1175 errorMsg = "Failed to set working directory";
1176 break;
1177 case InternalError.getrlimit:
1178 errorMsg = "getrlimit failed";
1179 break;
1180 case InternalError.exec:
1181 errorMsg = "Failed to execute '" ~ cast(string) name ~ "'";
1182 break;
1183 case InternalError.doubleFork:
1184 // Can happen only when starting detached process
1185 assert(config.flags & Config.Flags.detached);
1186 errorMsg = "Failed to fork twice";
1187 break;
1188 case InternalError.malloc:
1189 errorMsg = "Failed to allocate memory";
1190 break;
1191 case InternalError.preExec:
1192 errorMsg = "Failed to execute preExecFunction";
1193 break;
1194 case InternalError.noerror:
1195 assert(false);
1197 if (readExecResult == error.sizeof)
1198 throw ProcessException.newFromErrno(error, errorMsg);
1199 throw new ProcessException(errorMsg);
1201 else if (config.flags & Config.Flags.detached)
1203 owned = false;
1204 if (read(pidPipe[0], &id, id.sizeof) != id.sizeof)
1205 throw ProcessException.newFromErrno("Could not read from pipe to get detached process id");
1208 // Parent process: Close streams and return.
1209 if (!(config.flags & Config.Flags.retainStdin ) && stdinFD > STDERR_FILENO
1210 && stdinFD != getFD(std.stdio.stdin ))
1211 stdin.close();
1212 if (!(config.flags & Config.Flags.retainStdout) && stdoutFD > STDERR_FILENO
1213 && stdoutFD != getFD(std.stdio.stdout))
1214 stdout.close();
1215 if (!(config.flags & Config.Flags.retainStderr) && stderrFD > STDERR_FILENO
1216 && stderrFD != getFD(std.stdio.stderr))
1217 stderr.close();
1218 return new Pid(id, owned);
1222 version (Posix)
1223 @system unittest
1225 import std.concurrency : ownerTid, receiveTimeout, send, spawn;
1226 import std.datetime : seconds;
1228 sigset_t ss;
1229 sigemptyset(&ss);
1230 sigaddset(&ss, SIGINT);
1231 pthread_sigmask(SIG_BLOCK, &ss, null);
1233 Config config = {
1234 preExecFunction: () @trusted @nogc nothrow {
1235 // Reset signal handlers
1236 sigset_t ss;
1237 if (sigfillset(&ss) != 0)
1239 return false;
1241 if (sigprocmask(SIG_UNBLOCK, &ss, null) != 0)
1243 return false;
1245 return true;
1249 auto pid = spawnProcess(["sleep", "10000"],
1250 std.stdio.stdin,
1251 std.stdio.stdout,
1252 std.stdio.stderr,
1253 null,
1254 config,
1255 null);
1256 scope(failure)
1258 kill(pid, SIGKILL);
1259 wait(pid);
1262 // kill the spawned process with SIGINT
1263 // and send its return code
1264 spawn((shared Pid pid) {
1265 auto p = cast() pid;
1266 kill(p, SIGINT);
1267 auto code = wait(p);
1268 assert(code < 0);
1269 send(ownerTid, code);
1270 }, cast(shared) pid);
1272 auto received = receiveTimeout(3.seconds, (int) {});
1273 assert(received);
1277 Implementation of spawnProcess() for Windows.
1279 commandLine must contain the entire command line, properly
1280 quoted/escaped as required by CreateProcessW().
1282 envz must be a pointer to a block of UTF-16 characters on the form
1283 "var1=value1\0var2=value2\0...varN=valueN\0\0".
1285 version (Windows)
1286 private Pid spawnProcessWin(scope const(char)[] commandLine,
1287 scope const(char)[] program,
1288 File stdin,
1289 File stdout,
1290 File stderr,
1291 scope const string[string] env,
1292 Config config,
1293 scope const(char)[] workDir)
1294 @trusted
1296 import core.exception : RangeError;
1297 import std.conv : text;
1299 if (commandLine.empty) throw new RangeError("Command line is empty");
1301 // Prepare environment.
1302 auto envz = createEnv(env, !(config.flags & Config.Flags.newEnv));
1304 // Startup info for CreateProcessW().
1305 STARTUPINFO_W startinfo;
1306 startinfo.cb = startinfo.sizeof;
1307 static int getFD(ref File f) { return f.isOpen ? f.fileno : -1; }
1309 // Extract file descriptors and HANDLEs from the streams and make the
1310 // handles inheritable.
1311 static void prepareStream(ref File file, DWORD stdHandle, string which,
1312 out int fileDescriptor, out HANDLE handle)
1314 enum _NO_CONSOLE_FILENO = cast(HANDLE)-2;
1315 fileDescriptor = getFD(file);
1316 handle = null;
1317 if (fileDescriptor >= 0)
1318 handle = file.windowsHandle;
1319 // Windows GUI applications have a fd but not a valid Windows HANDLE.
1320 if (handle is null || handle == INVALID_HANDLE_VALUE || handle == _NO_CONSOLE_FILENO)
1321 handle = GetStdHandle(stdHandle);
1323 DWORD dwFlags;
1324 if (GetHandleInformation(handle, &dwFlags))
1326 if (!(dwFlags & HANDLE_FLAG_INHERIT))
1328 if (!SetHandleInformation(handle,
1329 HANDLE_FLAG_INHERIT,
1330 HANDLE_FLAG_INHERIT))
1332 throw new StdioException(
1333 "Failed to make "~which~" stream inheritable by child process ("
1334 ~sysErrorString(GetLastError()) ~ ')',
1340 int stdinFD = -1, stdoutFD = -1, stderrFD = -1;
1341 prepareStream(stdin, STD_INPUT_HANDLE, "stdin" , stdinFD, startinfo.hStdInput );
1342 prepareStream(stdout, STD_OUTPUT_HANDLE, "stdout", stdoutFD, startinfo.hStdOutput);
1343 prepareStream(stderr, STD_ERROR_HANDLE, "stderr", stderrFD, startinfo.hStdError );
1345 if ((startinfo.hStdInput != null && startinfo.hStdInput != INVALID_HANDLE_VALUE)
1346 || (startinfo.hStdOutput != null && startinfo.hStdOutput != INVALID_HANDLE_VALUE)
1347 || (startinfo.hStdError != null && startinfo.hStdError != INVALID_HANDLE_VALUE))
1348 startinfo.dwFlags = STARTF_USESTDHANDLES;
1350 // Create process.
1351 PROCESS_INFORMATION pi;
1352 DWORD dwCreationFlags =
1353 CREATE_UNICODE_ENVIRONMENT |
1354 ((config.flags & Config.Flags.suppressConsole) ? CREATE_NO_WINDOW : 0);
1355 // workaround until https://issues.dlang.org/show_bug.cgi?id=14696 is fixed
1356 auto pworkDir = workDir.tempCStringW();
1357 if (!CreateProcessW(null, commandLine.tempCStringW().buffPtr,
1358 null, null, true, dwCreationFlags,
1359 envz, workDir.length ? pworkDir : null, &startinfo, &pi))
1360 throw ProcessException.newFromLastError("Failed to spawn process \"" ~ cast(string) program ~ '"');
1362 // figure out if we should close any of the streams
1363 if (!(config.flags & Config.Flags.retainStdin ) && stdinFD > STDERR_FILENO
1364 && stdinFD != getFD(std.stdio.stdin ))
1365 stdin.close();
1366 if (!(config.flags & Config.Flags.retainStdout) && stdoutFD > STDERR_FILENO
1367 && stdoutFD != getFD(std.stdio.stdout))
1368 stdout.close();
1369 if (!(config.flags & Config.Flags.retainStderr) && stderrFD > STDERR_FILENO
1370 && stderrFD != getFD(std.stdio.stderr))
1371 stderr.close();
1373 // close the thread handle in the process info structure
1374 CloseHandle(pi.hThread);
1375 if (config.flags & Config.Flags.detached)
1377 CloseHandle(pi.hProcess);
1378 return new Pid(pi.dwProcessId);
1380 return new Pid(pi.dwProcessId, pi.hProcess);
1383 // Converts childEnv to a zero-terminated array of zero-terminated strings
1384 // on the form "name=value", optionally adding those of the current process'
1385 // environment strings that are not present in childEnv. If the parent's
1386 // environment should be inherited without modification, this function
1387 // returns environ directly.
1388 version (Posix)
1389 private const(char*)* createEnv(const string[string] childEnv,
1390 bool mergeWithParentEnv)
1392 // Determine the number of strings in the parent's environment.
1393 int parentEnvLength = 0;
1394 auto environ = getEnvironPtr;
1395 if (mergeWithParentEnv)
1397 if (childEnv.length == 0) return environ;
1398 while (environ[parentEnvLength] != null) ++parentEnvLength;
1401 // Convert the "new" variables to C-style strings.
1402 auto envz = new const(char)*[parentEnvLength + childEnv.length + 1];
1403 int pos = 0;
1404 foreach (var, val; childEnv)
1405 envz[pos++] = (var~'='~val~'\0').ptr;
1407 // Add the parent's environment.
1408 foreach (environStr; environ[0 .. parentEnvLength])
1410 int eqPos = 0;
1411 while (environStr[eqPos] != '=' && environStr[eqPos] != '\0') ++eqPos;
1412 if (environStr[eqPos] != '=') continue;
1413 auto var = environStr[0 .. eqPos];
1414 if (var in childEnv) continue;
1415 envz[pos++] = environStr;
1417 envz[pos] = null;
1418 return envz.ptr;
1421 version (Posix) @system unittest
1423 auto e1 = createEnv(null, false);
1424 assert(e1 != null && *e1 == null);
1426 auto e2 = createEnv(null, true);
1427 assert(e2 != null);
1428 int i = 0;
1429 auto environ = getEnvironPtr;
1430 for (; environ[i] != null; ++i)
1432 assert(e2[i] != null);
1433 import core.stdc.string;
1434 assert(strcmp(e2[i], environ[i]) == 0);
1436 assert(e2[i] == null);
1438 auto e3 = createEnv(["foo" : "bar", "hello" : "world"], false);
1439 assert(e3 != null && e3[0] != null && e3[1] != null && e3[2] == null);
1440 assert((e3[0][0 .. 8] == "foo=bar\0" && e3[1][0 .. 12] == "hello=world\0")
1441 || (e3[0][0 .. 12] == "hello=world\0" && e3[1][0 .. 8] == "foo=bar\0"));
1445 // Converts childEnv to a Windows environment block, which is on the form
1446 // "name1=value1\0name2=value2\0...nameN=valueN\0\0", optionally adding
1447 // those of the current process' environment strings that are not present
1448 // in childEnv. Returns null if the parent's environment should be
1449 // inherited without modification, as this is what is expected by
1450 // CreateProcess().
1451 version (Windows)
1452 private LPVOID createEnv(const string[string] childEnv,
1453 bool mergeWithParentEnv)
1455 if (mergeWithParentEnv && childEnv.length == 0) return null;
1456 import std.array : appender;
1457 import std.uni : toUpper;
1458 auto envz = appender!(wchar[])();
1459 void put(string var, string val)
1461 envz.put(var);
1462 envz.put('=');
1463 envz.put(val);
1464 envz.put(cast(wchar) '\0');
1467 // Add the variables in childEnv, removing them from parentEnv
1468 // if they exist there too.
1469 auto parentEnv = mergeWithParentEnv ? environment.toAA() : null;
1470 foreach (k, v; childEnv)
1472 auto uk = toUpper(k);
1473 put(uk, v);
1474 if (uk in parentEnv) parentEnv.remove(uk);
1477 // Add remaining parent environment variables.
1478 foreach (k, v; parentEnv) put(k, v);
1480 // Two final zeros are needed in case there aren't any environment vars,
1481 // and the last one does no harm when there are.
1482 envz.put("\0\0"w);
1483 return envz.data.ptr;
1486 version (Windows) @system unittest
1488 assert(createEnv(null, true) == null);
1489 assert((cast(wchar*) createEnv(null, false))[0 .. 2] == "\0\0"w);
1490 auto e1 = (cast(wchar*) createEnv(["foo":"bar", "ab":"c"], false))[0 .. 14];
1491 assert(e1 == "FOO=bar\0AB=c\0\0"w || e1 == "AB=c\0FOO=bar\0\0"w);
1494 // Searches the PATH variable for the given executable file,
1495 // (checking that it is in fact executable).
1496 version (Posix)
1497 package(std) string searchPathFor(scope const(char)[] executable)
1498 @safe
1500 import std.algorithm.iteration : splitter;
1501 import std.conv : to;
1502 import std.path : chainPath;
1504 typeof(return) result;
1506 environment.getImpl("PATH",
1507 (scope const(char)[] path)
1509 if (!path)
1510 return;
1512 foreach (dir; splitter(path, ":"))
1514 auto execPath = chainPath(dir, executable);
1515 if (isExecutable(execPath))
1517 result = execPath.to!(typeof(result));
1518 return;
1523 return result;
1526 // Checks whether the file exists and can be executed by the
1527 // current user.
1528 version (Posix)
1529 private bool isExecutable(R)(R path) @trusted nothrow @nogc
1530 if (isInputRange!R && isSomeChar!(ElementEncodingType!R))
1532 return (access(path.tempCString(), X_OK) == 0);
1535 version (Posix) @safe unittest
1537 import std.algorithm;
1538 auto lsPath = searchPathFor("ls");
1539 assert(!lsPath.empty);
1540 assert(lsPath[0] == '/');
1541 assert(lsPath.endsWith("ls"));
1542 auto unlikely = searchPathFor("lkmqwpoialhggyaofijadsohufoiqezm");
1543 assert(unlikely is null, "Are you kidding me?");
1546 // Sets or unsets the FD_CLOEXEC flag on the given file descriptor.
1547 version (Posix)
1548 private void setCLOEXEC(int fd, bool on) nothrow @nogc
1550 import core.sys.posix.fcntl : fcntl, F_GETFD, FD_CLOEXEC, F_SETFD;
1551 auto flags = fcntl(fd, F_GETFD);
1552 if (flags >= 0)
1554 if (on) flags |= FD_CLOEXEC;
1555 else flags &= ~(cast(typeof(flags)) FD_CLOEXEC);
1556 flags = fcntl(fd, F_SETFD, flags);
1558 assert(flags != -1 || .errno == EBADF);
1561 @system unittest // Command line arguments in spawnProcess().
1563 version (Windows) TestScript prog =
1564 "if not [%~1]==[foo] ( exit 1 )
1565 if not [%~2]==[bar] ( exit 2 )
1566 exit 0";
1567 else version (Posix) TestScript prog =
1568 `if test "$1" != "foo"; then exit 1; fi
1569 if test "$2" != "bar"; then exit 2; fi
1570 exit 0`;
1571 assert(wait(spawnProcess(prog.path)) == 1);
1572 assert(wait(spawnProcess([prog.path])) == 1);
1573 assert(wait(spawnProcess([prog.path, "foo"])) == 2);
1574 assert(wait(spawnProcess([prog.path, "foo", "baz"])) == 2);
1575 assert(wait(spawnProcess([prog.path, "foo", "bar"])) == 0);
1578 // test that file descriptors are correctly closed / left open.
1579 // ideally this would be done by the child process making libc
1580 // calls, but we make do...
1581 version (Posix) @system unittest
1583 import core.stdc.errno : errno;
1584 import core.sys.posix.fcntl : open, O_RDONLY;
1585 import core.sys.posix.unistd : close;
1586 import std.algorithm.searching : canFind, findSplitBefore;
1587 import std.array : split;
1588 import std.conv : to;
1589 static import std.file;
1590 import std.functional : reverseArgs;
1591 import std.path : buildPath;
1593 auto directory = uniqueTempPath();
1594 std.file.mkdir(directory);
1595 scope(exit) std.file.rmdirRecurse(directory);
1596 auto path = buildPath(directory, "tmp");
1597 std.file.write(path, null);
1598 errno = 0;
1599 auto fd = open(path.tempCString, O_RDONLY);
1600 if (fd == -1)
1602 import core.stdc.string : strerror;
1603 import std.stdio : stderr;
1604 import std.string : fromStringz;
1606 // For the CI logs
1607 stderr.writefln("%s: could not open '%s': %s",
1608 __FUNCTION__, path, strerror(errno).fromStringz);
1609 // TODO: should we retry here instead?
1610 return;
1612 scope(exit) close(fd);
1614 // command >&2 (or any other number) checks whethether that number
1615 // file descriptor is open.
1616 // Can't use this for arbitrary descriptors as many shells only support
1617 // single digit fds.
1618 TestScript testDefaults = `command >&0 && command >&1 && command >&2`;
1619 assert(execute(testDefaults.path).status == 0);
1620 assert(execute(testDefaults.path, null, Config.inheritFDs).status == 0);
1622 // Try a few different methods to check whether there are any
1623 // incorrectly-open files.
1624 void testFDs()
1626 // try /proc/<pid>/fd/ on linux
1627 version (linux)
1629 TestScript proc = "ls /proc/$$/fd";
1630 auto procRes = execute(proc.path, null);
1631 if (procRes.status == 0)
1633 auto fdStr = fd.to!string;
1634 assert(!procRes.output.split.canFind(fdStr));
1635 assert(execute(proc.path, null, Config.inheritFDs)
1636 .output.split.canFind(fdStr));
1637 return;
1641 // try fuser (might sometimes need permissions)
1642 TestScript fuser = "echo $$ && fuser -f " ~ path;
1643 auto fuserRes = execute(fuser.path, null);
1644 if (fuserRes.status == 0)
1646 assert(!reverseArgs!canFind(fuserRes
1647 .output.findSplitBefore("\n").expand));
1648 assert(reverseArgs!canFind(execute(fuser.path, null, Config.inheritFDs)
1649 .output.findSplitBefore("\n").expand));
1650 return;
1653 // last resort, try lsof (not available on all Posix)
1654 TestScript lsof = "lsof -p$$";
1655 auto lsofRes = execute(lsof.path, null);
1656 if (lsofRes.status == 0)
1658 assert(!lsofRes.output.canFind(path));
1659 auto lsofOut = execute(lsof.path, null, Config.inheritFDs).output;
1660 if (!lsofOut.canFind(path))
1662 std.stdio.stderr.writeln(__FILE__, ':', __LINE__,
1663 ": Warning: unexpected lsof output:", lsofOut);
1665 return;
1668 std.stdio.stderr.writeln(__FILE__, ':', __LINE__,
1669 ": Warning: Couldn't find any way to check open files");
1671 testFDs();
1674 @system unittest // Environment variables in spawnProcess().
1676 // We really should use set /a on Windows, but Wine doesn't support it.
1677 version (Windows) TestScript envProg =
1678 `if [%STD_PROCESS_UNITTEST1%] == [1] (
1679 if [%STD_PROCESS_UNITTEST2%] == [2] (exit 3)
1680 exit 1
1682 if [%STD_PROCESS_UNITTEST1%] == [4] (
1683 if [%STD_PROCESS_UNITTEST2%] == [2] (exit 6)
1684 exit 4
1686 if [%STD_PROCESS_UNITTEST2%] == [2] (exit 2)
1687 exit 0`;
1688 version (Posix) TestScript envProg =
1689 `if test "$std_process_unittest1" = ""; then
1690 std_process_unittest1=0
1692 if test "$std_process_unittest2" = ""; then
1693 std_process_unittest2=0
1695 exit $(($std_process_unittest1+$std_process_unittest2))`;
1697 environment.remove("std_process_unittest1"); // Just in case.
1698 environment.remove("std_process_unittest2");
1699 assert(wait(spawnProcess(envProg.path)) == 0);
1700 assert(wait(spawnProcess(envProg.path, null, Config.newEnv)) == 0);
1702 environment["std_process_unittest1"] = "1";
1703 assert(wait(spawnProcess(envProg.path)) == 1);
1704 assert(wait(spawnProcess(envProg.path, null, Config.newEnv)) == 0);
1706 auto env = ["std_process_unittest2" : "2"];
1707 assert(wait(spawnProcess(envProg.path, env)) == 3);
1708 assert(wait(spawnProcess(envProg.path, env, Config.newEnv)) == 2);
1710 env["std_process_unittest1"] = "4";
1711 assert(wait(spawnProcess(envProg.path, env)) == 6);
1712 assert(wait(spawnProcess(envProg.path, env, Config.newEnv)) == 6);
1714 environment.remove("std_process_unittest1");
1715 assert(wait(spawnProcess(envProg.path, env)) == 6);
1716 assert(wait(spawnProcess(envProg.path, env, Config.newEnv)) == 6);
1719 @system unittest // Stream redirection in spawnProcess().
1721 import std.path : buildPath;
1722 import std.string;
1723 version (Windows) TestScript prog =
1724 "set /p INPUT=
1725 echo %INPUT% output %~1
1726 echo %INPUT% error %~2 1>&2
1727 echo done > %3";
1728 else version (Posix) TestScript prog =
1729 "read INPUT
1730 echo $INPUT output $1
1731 echo $INPUT error $2 >&2
1732 echo done > \"$3\"";
1734 // Pipes
1735 void testPipes(Config config)
1737 import std.file, std.uuid, core.thread, std.exception;
1738 auto pipei = pipe();
1739 auto pipeo = pipe();
1740 auto pipee = pipe();
1741 auto done = buildPath(tempDir(), randomUUID().toString());
1742 auto pid = spawnProcess([prog.path, "foo", "bar", done],
1743 pipei.readEnd, pipeo.writeEnd, pipee.writeEnd, null, config);
1744 pipei.writeEnd.writeln("input");
1745 pipei.writeEnd.flush();
1746 assert(pipeo.readEnd.readln().chomp() == "input output foo");
1747 assert(pipee.readEnd.readln().chomp().stripRight() == "input error bar");
1748 if (config.flags & Config.Flags.detached)
1749 while (!done.exists) Thread.sleep(10.msecs);
1750 else
1751 wait(pid);
1752 while (remove(done).collectException) Thread.sleep(10.msecs);
1755 // Files
1756 void testFiles(Config config)
1758 import std.ascii, std.file, std.uuid, core.thread, std.exception;
1759 auto pathi = buildPath(tempDir(), randomUUID().toString());
1760 auto patho = buildPath(tempDir(), randomUUID().toString());
1761 auto pathe = buildPath(tempDir(), randomUUID().toString());
1762 std.file.write(pathi, "INPUT"~std.ascii.newline);
1763 auto filei = File(pathi, "r");
1764 auto fileo = File(patho, "w");
1765 auto filee = File(pathe, "w");
1766 auto done = buildPath(tempDir(), randomUUID().toString());
1767 auto pid = spawnProcess([prog.path, "bar", "baz", done], filei, fileo, filee, null, config);
1768 if (config.flags & Config.Flags.detached)
1769 while (!done.exists) Thread.sleep(10.msecs);
1770 else
1771 wait(pid);
1772 assert(readText(patho).chomp() == "INPUT output bar");
1773 assert(readText(pathe).chomp().stripRight() == "INPUT error baz");
1774 while (remove(pathi).collectException) Thread.sleep(10.msecs);
1775 while (remove(patho).collectException) Thread.sleep(10.msecs);
1776 while (remove(pathe).collectException) Thread.sleep(10.msecs);
1777 while (remove(done).collectException) Thread.sleep(10.msecs);
1780 testPipes(Config.none);
1781 testFiles(Config.none);
1782 testPipes(Config.detached);
1783 testFiles(Config.detached);
1786 @system unittest // Error handling in spawnProcess()
1788 import std.algorithm.searching : canFind;
1789 import std.exception : assertThrown, collectExceptionMsg;
1791 static void testNotFoundException(string program)
1793 assert(collectExceptionMsg!ProcessException(spawnProcess(program)).canFind(program));
1794 assert(collectExceptionMsg!ProcessException(spawnProcess(program, null, Config.detached)).canFind(program));
1796 testNotFoundException("ewrgiuhrifuheiohnmnvqweoijwf");
1797 testNotFoundException("./rgiuhrifuheiohnmnvqweoijwf");
1799 // can't execute malformed file with executable permissions
1800 version (Posix)
1802 import std.path : buildPath;
1803 import std.file : remove, write, setAttributes, tempDir;
1804 import core.sys.posix.sys.stat : S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IXGRP, S_IROTH, S_IXOTH;
1805 import std.conv : to;
1806 string deleteme = buildPath(tempDir(), "deleteme.std.process.unittest.pid") ~ to!string(thisProcessID);
1807 write(deleteme, "");
1808 scope(exit) remove(deleteme);
1809 setAttributes(deleteme, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
1810 assertThrown!ProcessException(spawnProcess(deleteme));
1811 assertThrown!ProcessException(spawnProcess(deleteme, null, Config.detached));
1815 @system unittest // Specifying a working directory.
1817 import std.path;
1818 import std.file;
1819 TestScript prog = "echo foo>bar";
1821 auto directory = uniqueTempPath();
1822 mkdir(directory);
1823 scope(exit) rmdirRecurse(directory);
1825 auto pid = spawnProcess([prog.path], null, Config.none, directory);
1826 wait(pid);
1827 assert(exists(buildPath(directory, "bar")));
1830 @system unittest // Specifying a bad working directory.
1832 import std.exception : assertThrown;
1833 import std.file;
1834 TestScript prog = "echo";
1836 auto directory = uniqueTempPath();
1837 assertThrown!ProcessException(spawnProcess([prog.path], null, Config.none, directory));
1838 assertThrown!ProcessException(spawnProcess([prog.path], null, Config.detached, directory));
1840 std.file.write(directory, "foo");
1841 scope(exit) remove(directory);
1842 assertThrown!ProcessException(spawnProcess([prog.path], null, Config.none, directory));
1843 assertThrown!ProcessException(spawnProcess([prog.path], null, Config.detached, directory));
1845 // can't run in directory if user does not have search permission on this directory
1846 version (Posix)
1848 if (core.sys.posix.unistd.getuid() != 0)
1850 import core.sys.posix.sys.stat : S_IRUSR;
1851 auto directoryNoSearch = uniqueTempPath();
1852 mkdir(directoryNoSearch);
1853 scope(exit) rmdirRecurse(directoryNoSearch);
1854 setAttributes(directoryNoSearch, S_IRUSR);
1855 assertThrown!ProcessException(spawnProcess(prog.path, null, Config.none, directoryNoSearch));
1856 assertThrown!ProcessException(spawnProcess(prog.path, null, Config.detached, directoryNoSearch));
1861 @system unittest // Specifying empty working directory.
1863 TestScript prog = "";
1865 string directory = "";
1866 assert(directory.ptr && !directory.length);
1867 spawnProcess([prog.path], null, Config.none, directory).wait();
1870 // Reopening the standard streams (https://issues.dlang.org/show_bug.cgi?id=13258)
1871 @system unittest
1873 import std.string;
1874 import std.file;
1875 void fun()
1877 spawnShell("echo foo").wait();
1878 spawnShell("echo bar").wait();
1881 auto tmpFile = uniqueTempPath();
1882 scope(exit) if (exists(tmpFile)) remove(tmpFile);
1885 auto oldOut = std.stdio.stdout;
1886 scope(exit) std.stdio.stdout = oldOut;
1888 std.stdio.stdout = File(tmpFile, "w");
1889 fun();
1890 std.stdio.stdout.close();
1893 auto lines = readText(tmpFile).splitLines();
1894 assert(lines == ["foo", "bar"]);
1897 // MSVCRT workaround (https://issues.dlang.org/show_bug.cgi?id=14422)
1898 version (Windows)
1899 @system unittest
1901 auto fn = uniqueTempPath();
1902 scope(exit) if (exists(fn)) remove(fn);
1903 std.file.write(fn, "AAAAAAAAAA");
1905 auto f = File(fn, "a");
1906 spawnProcess(["cmd", "/c", "echo BBBBB"], std.stdio.stdin, f).wait();
1908 auto data = readText(fn);
1909 assert(data == "AAAAAAAAAABBBBB\r\n", data);
1912 // https://issues.dlang.org/show_bug.cgi?id=20765
1913 // Test that running processes with relative path works in conjunction
1914 // with indicating a workDir.
1915 version (Posix) @system unittest
1917 import std.file : mkdir, write, setAttributes, rmdirRecurse;
1918 import std.conv : octal;
1920 auto dir = uniqueTempPath();
1921 mkdir(dir);
1922 scope(exit) rmdirRecurse(dir);
1923 write(dir ~ "/program", "#!/bin/sh\necho Hello");
1924 setAttributes(dir ~ "/program", octal!700);
1926 assert(execute(["./program"], null, Config.none, size_t.max, dir).output == "Hello\n");
1930 A variation on $(LREF spawnProcess) that runs the given _command through
1931 the current user's preferred _command interpreter (aka. shell).
1933 The string `command` is passed verbatim to the shell, and is therefore
1934 subject to its rules about _command structure, argument/filename quoting
1935 and escaping of special characters.
1936 The path to the shell executable defaults to $(LREF nativeShell).
1938 In all other respects this function works just like `spawnProcess`.
1939 Please refer to the $(LREF spawnProcess) documentation for descriptions
1940 of the other function parameters, the return value and any exceptions
1941 that may be thrown.
1943 // Run the command/program "foo" on the file named "my file.txt", and
1944 // redirect its output into foo.log.
1945 auto pid = spawnShell(`foo "my file.txt" > foo.log`);
1946 wait(pid);
1949 See_also:
1950 $(LREF escapeShellCommand), which may be helpful in constructing a
1951 properly quoted and escaped shell _command line for the current platform.
1953 Pid spawnShell(scope const(char)[] command,
1954 File stdin = std.stdio.stdin,
1955 File stdout = std.stdio.stdout,
1956 File stderr = std.stdio.stderr,
1957 scope const string[string] env = null,
1958 Config config = Config.none,
1959 scope const(char)[] workDir = null,
1960 scope string shellPath = nativeShell)
1961 @trusted // See reason below
1963 version (Windows)
1965 // CMD does not parse its arguments like other programs.
1966 // It does not use CommandLineToArgvW.
1967 // Instead, it treats the first and last quote specially.
1968 // See CMD.EXE /? for details.
1969 const commandLine = escapeShellFileName(shellPath)
1970 ~ ` ` ~ shellSwitch ~ ` "` ~ command ~ `"`;
1971 return spawnProcessWin(commandLine, shellPath, stdin, stdout, stderr, env, config, workDir);
1973 else version (Posix)
1975 const(char)[][3] args;
1976 args[0] = shellPath;
1977 args[1] = shellSwitch;
1978 args[2] = command;
1979 /* The passing of args converts the static array, which is initialized with `scope` pointers,
1980 * to a dynamic array, which is also a scope parameter. So, it is a scope pointer to a
1981 * scope pointer, which although is safely used here, D doesn't allow transitive scope.
1982 * See https://github.com/dlang/dmd/pull/10951
1984 return spawnProcessPosix(args, stdin, stdout, stderr, env, config, workDir);
1986 else
1987 static assert(0);
1990 /// ditto
1991 Pid spawnShell(scope const(char)[] command,
1992 scope const string[string] env,
1993 Config config = Config.none,
1994 scope const(char)[] workDir = null,
1995 scope string shellPath = nativeShell)
1996 @trusted // TODO: Should be @safe
1998 return spawnShell(command,
1999 std.stdio.stdin,
2000 std.stdio.stdout,
2001 std.stdio.stderr,
2002 env,
2003 config,
2004 workDir,
2005 shellPath);
2008 @system unittest
2010 version (Windows)
2011 auto cmd = "echo %FOO%";
2012 else version (Posix)
2013 auto cmd = "echo $foo";
2014 import std.file;
2015 auto tmpFile = uniqueTempPath();
2016 scope(exit) if (exists(tmpFile)) remove(tmpFile);
2017 auto redir = "> \""~tmpFile~'"';
2018 auto env = ["foo" : "bar"];
2019 assert(wait(spawnShell(cmd~redir, env)) == 0);
2020 auto f = File(tmpFile, "a");
2021 version (CRuntime_Microsoft) f.seek(0, SEEK_END); // MSVCRT probably seeks to the end when writing, not before
2022 assert(wait(spawnShell(cmd, std.stdio.stdin, f, std.stdio.stderr, env)) == 0);
2023 f.close();
2024 auto output = std.file.readText(tmpFile);
2025 assert(output == "bar\nbar\n" || output == "bar\r\nbar\r\n");
2028 version (Windows)
2029 @system unittest
2031 import std.string;
2032 import std.conv : text;
2033 TestScript prog = "echo %0 %*";
2034 auto outputFn = uniqueTempPath();
2035 scope(exit) if (exists(outputFn)) remove(outputFn);
2036 auto args = [`a b c`, `a\b\c\`, `a"b"c"`];
2037 auto result = executeShell(
2038 escapeShellCommand([prog.path] ~ args)
2039 ~ " > " ~
2040 escapeShellFileName(outputFn));
2041 assert(result.status == 0);
2042 auto args2 = outputFn.readText().strip().parseCommandLine()[1..$];
2043 assert(args == args2, text(args2));
2048 Options that control the behaviour of process creation functions in this
2049 module. Most options only apply to $(LREF spawnProcess) and
2050 $(LREF spawnShell).
2052 Example:
2054 auto logFile = File("myapp_error.log", "w");
2056 // Start program, suppressing the console window (Windows only),
2057 // redirect its error stream to logFile, and leave logFile open
2058 // in the parent process as well.
2059 auto pid = spawnProcess("myapp", stdin, stdout, logFile,
2060 Config.retainStderr | Config.suppressConsole);
2061 scope(exit)
2063 auto exitCode = wait(pid);
2064 logFile.writeln("myapp exited with code ", exitCode);
2065 logFile.close();
2069 struct Config
2072 Flag options.
2073 Use bitwise OR to combine flags.
2075 enum Flags
2077 none = 0,
2080 By default, the child process inherits the parent's environment,
2081 and any environment variables passed to $(LREF spawnProcess) will
2082 be added to it. If this flag is set, the only variables in the
2083 child process' environment will be those given to spawnProcess.
2085 newEnv = 1,
2088 Unless the child process inherits the standard input/output/error
2089 streams of its parent, one almost always wants the streams closed
2090 in the parent when $(LREF spawnProcess) returns. Therefore, by
2091 default, this is done. If this is not desirable, pass any of these
2092 options to spawnProcess.
2094 retainStdin = 2,
2095 retainStdout = 4, /// ditto
2096 retainStderr = 8, /// ditto
2099 On Windows, if the child process is a console application, this
2100 flag will prevent the creation of a console window. Otherwise,
2101 it will be ignored. On POSIX, `suppressConsole` has no effect.
2103 suppressConsole = 16,
2106 On POSIX, open $(LINK2 http://en.wikipedia.org/wiki/File_descriptor,file descriptors)
2107 are by default inherited by the child process. As this may lead
2108 to subtle bugs when pipes or multiple threads are involved,
2109 $(LREF spawnProcess) ensures that all file descriptors except the
2110 ones that correspond to standard input/output/error are closed
2111 in the child process when it starts. Use `inheritFDs` to prevent
2112 this.
2114 On Windows, this option has no effect, and any handles which have been
2115 explicitly marked as inheritable will always be inherited by the child
2116 process.
2118 inheritFDs = 32,
2121 Spawn process in detached state. This removes the need in calling
2122 $(LREF wait) to clean up the process resources.
2124 Note:
2125 Calling $(LREF wait) or $(LREF kill) with the resulting `Pid` is invalid.
2127 detached = 64,
2130 By default, the $(LREF execute) and $(LREF executeShell) functions
2131 will capture child processes' both stdout and stderr. This can be
2132 undesirable if the standard output is to be processed or otherwise
2133 used by the invoking program, as `execute`'s result would then
2134 contain a mix of output and warning/error messages.
2136 Specify this flag when calling `execute` or `executeShell` to
2137 cause invoked processes' stderr stream to be sent to $(REF stderr,
2138 std,stdio), and only capture and return standard output.
2140 This flag has no effect on $(LREF spawnProcess) or $(LREF spawnShell).
2142 stderrPassThrough = 128,
2144 Flags flags; /// ditto
2147 For backwards compatibility, and cases when only flags need to
2148 be specified in the `Config`, these allow building `Config`
2149 instances using flag names only.
2151 enum Config none = Config.init;
2152 enum Config newEnv = Config(Flags.newEnv); /// ditto
2153 enum Config retainStdin = Config(Flags.retainStdin); /// ditto
2154 enum Config retainStdout = Config(Flags.retainStdout); /// ditto
2155 enum Config retainStderr = Config(Flags.retainStderr); /// ditto
2156 enum Config suppressConsole = Config(Flags.suppressConsole); /// ditto
2157 enum Config inheritFDs = Config(Flags.inheritFDs); /// ditto
2158 enum Config detached = Config(Flags.detached); /// ditto
2159 enum Config stderrPassThrough = Config(Flags.stderrPassThrough); /// ditto
2160 Config opUnary(string op)()
2161 if (is(typeof(mixin(op ~ q{flags}))))
2163 return Config(mixin(op ~ q{flags}));
2164 } /// ditto
2165 Config opBinary(string op)(Config other)
2166 if (is(typeof(mixin(q{flags} ~ op ~ q{other.flags}))))
2168 return Config(mixin(q{flags} ~ op ~ q{other.flags}));
2169 } /// ditto
2170 Config opOpAssign(string op)(Config other)
2171 if (is(typeof(mixin(q{flags} ~ op ~ q{=other.flags}))))
2173 return Config(mixin(q{flags} ~ op ~ q{=other.flags}));
2174 } /// ditto
2176 version (StdDdoc)
2179 A function that is called before `exec` in $(LREF spawnProcess).
2180 It returns `true` if succeeded and otherwise returns `false`.
2182 $(RED Warning:
2183 Please note that the code in this function must only use
2184 async-signal-safe functions.)
2186 On Windows, this member is not available.
2188 bool function() nothrow @nogc @safe preExecFunction;
2190 else version (Posix)
2192 bool function() nothrow @nogc @safe preExecFunction;
2196 // https://issues.dlang.org/show_bug.cgi?id=22125
2197 @safe unittest
2199 Config c = Config.retainStdin;
2200 c |= Config.retainStdout;
2201 c |= Config.retainStderr;
2202 c &= ~Config.retainStderr;
2203 assert(c == (Config.retainStdin | Config.retainStdout));
2206 /// A handle that corresponds to a spawned process.
2207 final class Pid
2210 The process ID number.
2212 This is a number that uniquely identifies the process on the operating
2213 system, for at least as long as the process is running. Once $(LREF wait)
2214 has been called on the $(LREF Pid), this method will return an
2215 invalid (negative) process ID.
2217 @property int processID() const @safe pure nothrow
2219 return _processID;
2223 An operating system handle to the process.
2225 This handle is used to specify the process in OS-specific APIs.
2226 On POSIX, this function returns a `core.sys.posix.sys.types.pid_t`
2227 with the same value as $(LREF Pid.processID), while on Windows it returns
2228 a `core.sys.windows.windows.HANDLE`.
2230 Once $(LREF wait) has been called on the $(LREF Pid), this method
2231 will return an invalid handle.
2233 // Note: Since HANDLE is a reference, this function cannot be const.
2234 version (Windows)
2235 @property HANDLE osHandle() @nogc @safe pure nothrow
2237 return _handle;
2239 else version (Posix)
2240 @property pid_t osHandle() @nogc @safe pure nothrow
2242 return _processID;
2245 private:
2247 Pid.performWait() does the dirty work for wait() and nonBlockingWait().
2249 If block == true, this function blocks until the process terminates,
2250 sets _processID to terminated, and returns the exit code or terminating
2251 signal as described in the wait() documentation.
2253 If block == false, this function returns immediately, regardless
2254 of the status of the process. If the process has terminated, the
2255 function has the exact same effect as the blocking version. If not,
2256 it returns 0 and does not modify _processID.
2258 version (Posix)
2259 int performWait(bool block) @trusted
2261 import std.exception : enforce;
2262 enforce!ProcessException(owned, "Can't wait on a detached process");
2263 if (_processID == terminated) return _exitCode;
2264 int exitCode;
2265 while (true)
2267 int status;
2268 auto check = waitpid(_processID, &status, block ? 0 : WNOHANG);
2269 if (check == -1)
2271 if (errno == ECHILD)
2273 throw new ProcessException(
2274 "Process does not exist or is not a child process.");
2276 else
2278 // waitpid() was interrupted by a signal. We simply
2279 // restart it.
2280 assert(errno == EINTR);
2281 continue;
2284 if (!block && check == 0) return 0;
2285 if (WIFEXITED(status))
2287 exitCode = WEXITSTATUS(status);
2288 break;
2290 else if (WIFSIGNALED(status))
2292 exitCode = -WTERMSIG(status);
2293 break;
2295 // We check again whether the call should be blocking,
2296 // since we don't care about other status changes besides
2297 // "exited" and "terminated by signal".
2298 if (!block) return 0;
2300 // Process has stopped, but not terminated, so we continue waiting.
2302 // Mark Pid as terminated, and cache and return exit code.
2303 _processID = terminated;
2304 _exitCode = exitCode;
2305 return exitCode;
2307 else version (Windows)
2309 int performWait(const bool block, const DWORD timeout = INFINITE) @trusted
2311 import std.exception : enforce;
2312 enforce!ProcessException(owned, "Can't wait on a detached process");
2313 if (_processID == terminated) return _exitCode;
2314 assert(_handle != INVALID_HANDLE_VALUE);
2315 if (block)
2317 auto result = WaitForSingleObject(_handle, timeout);
2318 if (result != WAIT_OBJECT_0)
2320 // Wait time exceeded `timeout` milliseconds?
2321 if (result == WAIT_TIMEOUT && timeout != INFINITE)
2322 return 0;
2324 throw ProcessException.newFromLastError("Wait failed.");
2327 if (!GetExitCodeProcess(_handle, cast(LPDWORD)&_exitCode))
2328 throw ProcessException.newFromLastError();
2329 if (!block && _exitCode == STILL_ACTIVE) return 0;
2330 CloseHandle(_handle);
2331 _handle = INVALID_HANDLE_VALUE;
2332 _processID = terminated;
2333 return _exitCode;
2336 int performWait(Duration timeout) @safe
2338 import std.exception : enforce;
2339 const msecs = timeout.total!"msecs";
2341 // Limit this implementation the maximum wait time offered by
2342 // WaitForSingleObject. One could theoretically break up larger
2343 // durations into multiple waits but (DWORD.max - 1).msecs
2344 // (> 7 weeks, 17 hours) should be enough for the usual case.
2345 // DWORD.max is reserved for INFINITE
2346 enforce!ProcessException(msecs < DWORD.max, "Timeout exceeds maximum wait time!");
2347 return performWait(true, cast(DWORD) msecs);
2350 ~this()
2352 if (_handle != INVALID_HANDLE_VALUE)
2354 CloseHandle(_handle);
2355 _handle = INVALID_HANDLE_VALUE;
2360 // Special values for _processID.
2361 enum invalid = -1, terminated = -2;
2363 // OS process ID number. Only nonnegative IDs correspond to
2364 // running processes.
2365 int _processID = invalid;
2367 // Exit code cached by wait(). This is only expected to hold a
2368 // sensible value if _processID == terminated.
2369 int _exitCode;
2371 // Whether the process can be waited for by wait() for or killed by kill().
2372 // False if process was started as detached. True otherwise.
2373 bool owned;
2375 // Pids are only meant to be constructed inside this module, so
2376 // we make the constructor private.
2377 version (Windows)
2379 HANDLE _handle = INVALID_HANDLE_VALUE;
2380 this(int pid, HANDLE handle) @safe pure nothrow
2382 _processID = pid;
2383 _handle = handle;
2384 this.owned = true;
2386 this(int pid) @safe pure nothrow
2388 _processID = pid;
2389 this.owned = false;
2392 else
2394 this(int id, bool owned) @safe pure nothrow
2396 _processID = id;
2397 this.owned = owned;
2404 Waits for the process associated with `pid` to terminate, and returns
2405 its exit status.
2407 In general one should always _wait for child processes to terminate
2408 before exiting the parent process unless the process was spawned as detached
2409 (that was spawned with `Config.detached` flag).
2410 Otherwise, they may become "$(HTTP en.wikipedia.org/wiki/Zombie_process,zombies)"
2411 – processes that are defunct, yet still occupy a slot in the OS process table.
2412 You should not and must not wait for detached processes, since you don't own them.
2414 If the process has already terminated, this function returns directly.
2415 The exit code is cached, so that if wait() is called multiple times on
2416 the same $(LREF Pid) it will always return the same value.
2418 POSIX_specific:
2419 If the process is terminated by a signal, this function returns a
2420 negative number whose absolute value is the signal number.
2421 Since POSIX restricts normal exit codes to the range 0-255, a
2422 negative return value will always indicate termination by signal.
2423 Signal codes are defined in the `core.sys.posix.signal` module
2424 (which corresponds to the `signal.h` POSIX header).
2426 Throws:
2427 $(LREF ProcessException) on failure or on attempt to wait for detached process.
2429 Example:
2430 See the $(LREF spawnProcess) documentation.
2432 See_also:
2433 $(LREF tryWait), for a non-blocking function.
2435 int wait(Pid pid) @safe
2437 assert(pid !is null, "Called wait on a null Pid.");
2438 return pid.performWait(true);
2442 @system unittest // Pid and wait()
2444 version (Windows) TestScript prog = "exit %~1";
2445 else version (Posix) TestScript prog = "exit $1";
2446 assert(wait(spawnProcess([prog.path, "0"])) == 0);
2447 assert(wait(spawnProcess([prog.path, "123"])) == 123);
2448 auto pid = spawnProcess([prog.path, "10"]);
2449 assert(pid.processID > 0);
2450 version (Windows) assert(pid.osHandle != INVALID_HANDLE_VALUE);
2451 else version (Posix) assert(pid.osHandle == pid.processID);
2452 assert(wait(pid) == 10);
2453 assert(wait(pid) == 10); // cached exit code
2454 assert(pid.processID < 0);
2455 version (Windows) assert(pid.osHandle == INVALID_HANDLE_VALUE);
2456 else version (Posix) assert(pid.osHandle < 0);
2459 private import std.typecons : Tuple;
2462 Waits until either the process associated with `pid` terminates or the
2463 elapsed time exceeds the given timeout.
2465 If the process terminates within the given duration it behaves exactly like
2466 `wait`, except that it returns a tuple `(true, exit code)`.
2468 If the process does not terminate within the given duration it will stop
2469 waiting and return `(false, 0).`
2471 The timeout may not exceed `(uint.max - 1).msecs` (~ 7 weeks, 17 hours).
2473 $(BLUE This function is Windows-Only.)
2475 Returns:
2476 An $(D std.typecons.Tuple!(bool, "terminated", int, "status")).
2478 Throws:
2479 $(LREF ProcessException) on failure or on attempt to wait for detached process.
2481 Example:
2482 See the $(LREF spawnProcess) documentation.
2484 See_also:
2485 $(LREF wait), for a blocking function without timeout.
2486 $(LREF tryWait), for a non-blocking function without timeout.
2488 version (StdDdoc)
2489 Tuple!(bool, "terminated", int, "status") waitTimeout(Pid pid, Duration timeout) @safe;
2491 else version (Windows)
2492 Tuple!(bool, "terminated", int, "status") waitTimeout(Pid pid, Duration timeout) @safe
2494 assert(pid !is null, "Called wait on a null Pid.");
2495 auto code = pid.performWait(timeout);
2496 return typeof(return)(pid._processID == Pid.terminated, code);
2499 version (Windows)
2500 @system unittest // Pid and waitTimeout()
2502 import std.exception : collectException;
2503 import std.typecons : tuple;
2505 TestScript prog = ":Loop\ngoto Loop;";
2506 auto pid = spawnProcess(prog.path);
2508 // Doesn't block longer than one second
2509 assert(waitTimeout(pid, 1.seconds) == tuple(false, 0));
2511 kill(pid);
2512 assert(waitTimeout(pid, 1.seconds) == tuple(true, 1)); // exit 1 because the process is killed
2514 // Rejects timeouts exceeding the Windows API capabilities
2515 const dur = DWORD.max.msecs;
2516 const ex = collectException!ProcessException(waitTimeout(pid, dur));
2517 assert(ex);
2518 assert(ex.msg == "Timeout exceeds maximum wait time!");
2522 A non-blocking version of $(LREF wait).
2524 If the process associated with `pid` has already terminated,
2525 `tryWait` has the exact same effect as `wait`.
2526 In this case, it returns a tuple where the `terminated` field
2527 is set to `true` and the `status` field has the same
2528 interpretation as the return value of `wait`.
2530 If the process has $(I not) yet terminated, this function differs
2531 from `wait` in that does not wait for this to happen, but instead
2532 returns immediately. The `terminated` field of the returned
2533 tuple will then be set to `false`, while the `status` field
2534 will always be 0 (zero). `wait` or `tryWait` should then be
2535 called again on the same `Pid` at some later time; not only to
2536 get the exit code, but also to avoid the process becoming a "zombie"
2537 when it finally terminates. (See $(LREF wait) for details).
2539 Returns:
2540 An $(D std.typecons.Tuple!(bool, "terminated", int, "status")).
2542 Throws:
2543 $(LREF ProcessException) on failure or on attempt to wait for detached process.
2545 Example:
2547 auto pid = spawnProcess("dmd myapp.d");
2548 scope(exit) wait(pid);
2550 auto dmd = tryWait(pid);
2551 if (dmd.terminated)
2553 if (dmd.status == 0) writeln("Compilation succeeded!");
2554 else writeln("Compilation failed");
2556 else writeln("Still compiling...");
2559 Note that in this example, the first `wait` call will have no
2560 effect if the process has already terminated by the time `tryWait`
2561 is called. In the opposite case, however, the `scope` statement
2562 ensures that we always wait for the process if it hasn't terminated
2563 by the time we reach the end of the scope.
2565 auto tryWait(Pid pid) @safe
2567 import std.typecons : Tuple;
2568 assert(pid !is null, "Called tryWait on a null Pid.");
2569 auto code = pid.performWait(false);
2570 return Tuple!(bool, "terminated", int, "status")(pid._processID == Pid.terminated, code);
2572 // unittest: This function is tested together with kill() below.
2576 Attempts to terminate the process associated with `pid`.
2578 The effect of this function, as well as the meaning of `codeOrSignal`,
2579 is highly platform dependent. Details are given below. Common to all
2580 platforms is that this function only $(I initiates) termination of the process,
2581 and returns immediately. It does not wait for the process to end,
2582 nor does it guarantee that the process does in fact get terminated.
2584 Always call $(LREF wait) to wait for a process to complete, even if `kill`
2585 has been called on it.
2587 Windows_specific:
2588 The process will be
2589 $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/ms686714%28v=vs.100%29.aspx,
2590 forcefully and abruptly terminated). If `codeOrSignal` is specified, it
2591 must be a nonnegative number which will be used as the exit code of the process.
2592 If not, the process wil exit with code 1. Do not use $(D codeOrSignal = 259),
2593 as this is a special value (aka. $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/ms683189.aspx,STILL_ACTIVE))
2594 used by Windows to signal that a process has in fact $(I not) terminated yet.
2596 auto pid = spawnProcess("some_app");
2597 kill(pid, 10);
2598 assert(wait(pid) == 10);
2601 POSIX_specific:
2602 A $(LINK2 http://en.wikipedia.org/wiki/Unix_signal,signal) will be sent to
2603 the process, whose value is given by `codeOrSignal`. Depending on the
2604 signal sent, this may or may not terminate the process. Symbolic constants
2605 for various $(LINK2 http://en.wikipedia.org/wiki/Unix_signal#POSIX_signals,
2606 POSIX signals) are defined in `core.sys.posix.signal`, which corresponds to the
2607 $(LINK2 http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html,
2608 `signal.h` POSIX header). If `codeOrSignal` is omitted, the
2609 `SIGTERM` signal will be sent. (This matches the behaviour of the
2610 $(LINK2 http://pubs.opengroup.org/onlinepubs/9699919799/utilities/kill.html,
2611 `_kill`) shell command.)
2613 import core.sys.posix.signal : SIGKILL;
2614 auto pid = spawnProcess("some_app");
2615 kill(pid, SIGKILL);
2616 assert(wait(pid) == -SIGKILL); // Negative return value on POSIX!
2619 Throws:
2620 $(LREF ProcessException) on error (e.g. if codeOrSignal is invalid).
2621 or on attempt to kill detached process.
2622 Note that failure to terminate the process is considered a "normal"
2623 outcome, not an error.$(BR)
2625 void kill(Pid pid)
2627 version (Windows) kill(pid, 1);
2628 else version (Posix)
2630 import core.sys.posix.signal : SIGTERM;
2631 kill(pid, SIGTERM);
2635 /// ditto
2636 void kill(Pid pid, int codeOrSignal)
2638 import std.exception : enforce;
2639 enforce!ProcessException(pid.owned, "Can't kill detached process");
2640 version (Windows)
2642 if (codeOrSignal < 0) throw new ProcessException("Invalid exit code");
2643 // On Windows, TerminateProcess() appears to terminate the
2644 // *current* process if it is passed an invalid handle...
2645 if (pid.osHandle == INVALID_HANDLE_VALUE)
2646 throw new ProcessException("Invalid process handle");
2647 if (!TerminateProcess(pid.osHandle, codeOrSignal))
2648 throw ProcessException.newFromLastError();
2650 else version (Posix)
2652 import core.sys.posix.signal : kill;
2653 if (kill(pid.osHandle, codeOrSignal) == -1)
2654 throw ProcessException.newFromErrno();
2658 @system unittest // tryWait() and kill()
2660 import core.thread;
2661 import std.exception : assertThrown;
2662 // The test script goes into an infinite loop.
2663 version (Windows)
2665 TestScript prog = ":loop
2666 goto loop";
2668 else version (Posix)
2670 import core.sys.posix.signal : SIGTERM, SIGKILL;
2671 TestScript prog = "while true; do sleep 1; done";
2673 auto pid = spawnProcess(prog.path);
2674 // Android appears to automatically kill sleeping processes very quickly,
2675 // so shorten the wait before killing here.
2676 version (Android)
2677 Thread.sleep(dur!"msecs"(5));
2678 else
2679 Thread.sleep(dur!"msecs"(500));
2680 kill(pid);
2681 version (Windows) assert(wait(pid) == 1);
2682 else version (Posix) assert(wait(pid) == -SIGTERM);
2684 pid = spawnProcess(prog.path);
2685 Thread.sleep(dur!"msecs"(500));
2686 auto s = tryWait(pid);
2687 assert(!s.terminated && s.status == 0);
2688 assertThrown!ProcessException(kill(pid, -123)); // Negative code not allowed.
2689 version (Windows) kill(pid, 123);
2690 else version (Posix) kill(pid, SIGKILL);
2691 do { s = tryWait(pid); } while (!s.terminated);
2692 version (Windows) assert(s.status == 123);
2693 else version (Posix) assert(s.status == -SIGKILL);
2694 assertThrown!ProcessException(kill(pid));
2697 @system unittest // wait() and kill() detached process
2699 import core.thread;
2700 import std.exception : assertThrown;
2701 TestScript prog = "exit 0";
2702 auto pid = spawnProcess([prog.path], null, Config.detached);
2704 This sleep is needed because we can't wait() for detached process to end
2705 and therefore TestScript destructor may run at the same time as /bin/sh tries to start the script.
2706 This leads to the annoying message like "/bin/sh: 0: Can't open /tmp/std.process temporary file" to appear when running tests.
2707 It does not happen in unittests with non-detached processes because we always wait() for them to finish.
2709 Thread.sleep(500.msecs);
2710 assert(!pid.owned);
2711 version (Windows) assert(pid.osHandle == INVALID_HANDLE_VALUE);
2712 assertThrown!ProcessException(wait(pid));
2713 assertThrown!ProcessException(kill(pid));
2718 Creates a unidirectional _pipe.
2720 Data is written to one end of the _pipe and read from the other.
2722 auto p = pipe();
2723 p.writeEnd.writeln("Hello World");
2724 p.writeEnd.flush();
2725 assert(p.readEnd.readln().chomp() == "Hello World");
2727 Pipes can, for example, be used for interprocess communication
2728 by spawning a new process and passing one end of the _pipe to
2729 the child, while the parent uses the other end.
2730 (See also $(LREF pipeProcess) and $(LREF pipeShell) for an easier
2731 way of doing this.)
2733 // Use cURL to download the dlang.org front page, pipe its
2734 // output to grep to extract a list of links to ZIP files,
2735 // and write the list to the file "D downloads.txt":
2736 auto p = pipe();
2737 auto outFile = File("D downloads.txt", "w");
2738 auto cpid = spawnProcess(["curl", "http://dlang.org/download.html"],
2739 std.stdio.stdin, p.writeEnd);
2740 scope(exit) wait(cpid);
2741 auto gpid = spawnProcess(["grep", "-o", `http://\S*\.zip`],
2742 p.readEnd, outFile);
2743 scope(exit) wait(gpid);
2746 Returns:
2747 A $(LREF Pipe) object that corresponds to the created _pipe.
2749 Throws:
2750 $(REF StdioException, std,stdio) on failure.
2752 version (Posix)
2753 Pipe pipe() @trusted //TODO: @safe
2755 import core.sys.posix.stdio : fdopen;
2756 int[2] fds;
2757 if (core.sys.posix.unistd.pipe(fds) != 0)
2758 throw new StdioException("Unable to create pipe");
2759 Pipe p;
2760 auto readFP = fdopen(fds[0], "r");
2761 if (readFP == null)
2762 throw new StdioException("Cannot open read end of pipe");
2763 p._read = File(readFP, null);
2764 auto writeFP = fdopen(fds[1], "w");
2765 if (writeFP == null)
2766 throw new StdioException("Cannot open write end of pipe");
2767 p._write = File(writeFP, null);
2768 return p;
2770 else version (Windows)
2771 Pipe pipe() @trusted //TODO: @safe
2773 // use CreatePipe to create an anonymous pipe
2774 HANDLE readHandle;
2775 HANDLE writeHandle;
2776 if (!CreatePipe(&readHandle, &writeHandle, null, 0))
2778 throw new StdioException(
2779 "Error creating pipe (" ~ sysErrorString(GetLastError()) ~ ')',
2783 scope(failure)
2785 CloseHandle(readHandle);
2786 CloseHandle(writeHandle);
2791 Pipe p;
2792 p._read .windowsHandleOpen(readHandle , "r");
2793 p._write.windowsHandleOpen(writeHandle, "a");
2794 return p;
2796 catch (Exception e)
2798 throw new StdioException("Error attaching pipe (" ~ e.msg ~ ")",
2804 /// An interface to a pipe created by the $(LREF pipe) function.
2805 struct Pipe
2807 /// The read end of the pipe.
2808 @property File readEnd() @safe nothrow { return _read; }
2811 /// The write end of the pipe.
2812 @property File writeEnd() @safe nothrow { return _write; }
2816 Closes both ends of the pipe.
2818 Normally it is not necessary to do this manually, as $(REF File, std,stdio)
2819 objects are automatically closed when there are no more references
2820 to them.
2822 Note that if either end of the pipe has been passed to a child process,
2823 it will only be closed in the parent process. (What happens in the
2824 child process is platform dependent.)
2826 Throws:
2827 $(REF ErrnoException, std,exception) if an error occurs.
2829 void close() @safe
2831 _read.close();
2832 _write.close();
2835 private:
2836 File _read, _write;
2839 @system unittest
2841 import std.string;
2842 auto p = pipe();
2843 p.writeEnd.writeln("Hello World");
2844 p.writeEnd.flush();
2845 assert(p.readEnd.readln().chomp() == "Hello World");
2846 p.close();
2847 assert(!p.readEnd.isOpen);
2848 assert(!p.writeEnd.isOpen);
2853 Starts a new process, creating pipes to redirect its standard
2854 input, output and/or error streams.
2856 `pipeProcess` and `pipeShell` are convenient wrappers around
2857 $(LREF spawnProcess) and $(LREF spawnShell), respectively, and
2858 automate the task of redirecting one or more of the child process'
2859 standard streams through pipes. Like the functions they wrap,
2860 these functions return immediately, leaving the child process to
2861 execute in parallel with the invoking process. It is recommended
2862 to always call $(LREF wait) on the returned $(LREF ProcessPipes.pid),
2863 as detailed in the documentation for `wait`.
2865 The `args`/`program`/`command`, `env` and `config`
2866 parameters are forwarded straight to the underlying spawn functions,
2867 and we refer to their documentation for details.
2869 Params:
2870 args = An array which contains the program name as the zeroth element
2871 and any command-line arguments in the following elements.
2872 (See $(LREF spawnProcess) for details.)
2873 program = The program name, $(I without) command-line arguments.
2874 (See $(LREF spawnProcess) for details.)
2875 command = A shell command which is passed verbatim to the command
2876 interpreter. (See $(LREF spawnShell) for details.)
2877 redirect = Flags that determine which streams are redirected, and
2878 how. See $(LREF Redirect) for an overview of available
2879 flags.
2880 env = Additional environment variables for the child process.
2881 (See $(LREF spawnProcess) for details.)
2882 config = Flags that control process creation. See $(LREF Config)
2883 for an overview of available flags, and note that the
2884 `retainStd...` flags have no effect in this function.
2885 workDir = The working directory for the new process.
2886 By default the child process inherits the parent's working
2887 directory.
2888 shellPath = The path to the shell to use to run the specified program.
2889 By default this is $(LREF nativeShell).
2891 Returns:
2892 A $(LREF ProcessPipes) object which contains $(REF File, std,stdio)
2893 handles that communicate with the redirected streams of the child
2894 process, along with a $(LREF Pid) object that corresponds to the
2895 spawned process.
2897 Throws:
2898 $(LREF ProcessException) on failure to start the process.$(BR)
2899 $(REF StdioException, std,stdio) on failure to redirect any of the streams.$(BR)
2901 Example:
2903 // my_application writes to stdout and might write to stderr
2904 auto pipes = pipeProcess("my_application", Redirect.stdout | Redirect.stderr);
2905 scope(exit) wait(pipes.pid);
2907 // Store lines of output.
2908 string[] output;
2909 foreach (line; pipes.stdout.byLine) output ~= line.idup;
2911 // Store lines of errors.
2912 string[] errors;
2913 foreach (line; pipes.stderr.byLine) errors ~= line.idup;
2916 // sendmail expects to read from stdin
2917 pipes = pipeProcess(["/usr/bin/sendmail", "-t"], Redirect.stdin);
2918 pipes.stdin.writeln("To: you");
2919 pipes.stdin.writeln("From: me");
2920 pipes.stdin.writeln("Subject: dlang");
2921 pipes.stdin.writeln("");
2922 pipes.stdin.writeln(message);
2924 // a single period tells sendmail we are finished
2925 pipes.stdin.writeln(".");
2927 // but at this point sendmail might not see it, we need to flush
2928 pipes.stdin.flush();
2930 // sendmail happens to exit on ".", but some you have to close the file:
2931 pipes.stdin.close();
2933 // otherwise this wait will wait forever
2934 wait(pipes.pid);
2938 ProcessPipes pipeProcess(scope const(char[])[] args,
2939 Redirect redirect = Redirect.all,
2940 const string[string] env = null,
2941 Config config = Config.none,
2942 scope const(char)[] workDir = null)
2943 @safe
2945 return pipeProcessImpl!spawnProcess(args, redirect, env, config, workDir);
2948 /// ditto
2949 ProcessPipes pipeProcess(scope const(char)[] program,
2950 Redirect redirect = Redirect.all,
2951 const string[string] env = null,
2952 Config config = Config.none,
2953 scope const(char)[] workDir = null)
2954 @safe
2956 return pipeProcessImpl!spawnProcess(program, redirect, env, config, workDir);
2959 /// ditto
2960 ProcessPipes pipeShell(scope const(char)[] command,
2961 Redirect redirect = Redirect.all,
2962 const string[string] env = null,
2963 Config config = Config.none,
2964 scope const(char)[] workDir = null,
2965 string shellPath = nativeShell)
2966 @safe
2968 return pipeProcessImpl!spawnShell(command,
2969 redirect,
2970 env,
2971 config,
2972 workDir,
2973 shellPath);
2976 // Implementation of the pipeProcess() family of functions.
2977 private ProcessPipes pipeProcessImpl(alias spawnFunc, Cmd, ExtraSpawnFuncArgs...)
2978 (scope Cmd command,
2979 Redirect redirectFlags,
2980 const string[string] env = null,
2981 Config config = Config.none,
2982 scope const(char)[] workDir = null,
2983 ExtraSpawnFuncArgs extraArgs = ExtraSpawnFuncArgs.init)
2984 @trusted //TODO: @safe
2986 File childStdin, childStdout, childStderr;
2987 ProcessPipes pipes;
2988 pipes._redirectFlags = redirectFlags;
2990 if (redirectFlags & Redirect.stdin)
2992 auto p = pipe();
2993 childStdin = p.readEnd;
2994 pipes._stdin = p.writeEnd;
2996 else
2998 childStdin = std.stdio.stdin;
3001 if (redirectFlags & Redirect.stdout)
3003 if ((redirectFlags & Redirect.stdoutToStderr) != 0)
3004 throw new StdioException("Cannot create pipe for stdout AND "
3005 ~"redirect it to stderr", 0);
3006 auto p = pipe();
3007 childStdout = p.writeEnd;
3008 pipes._stdout = p.readEnd;
3010 else
3012 childStdout = std.stdio.stdout;
3015 if (redirectFlags & Redirect.stderr)
3017 if ((redirectFlags & Redirect.stderrToStdout) != 0)
3018 throw new StdioException("Cannot create pipe for stderr AND "
3019 ~"redirect it to stdout", 0);
3020 auto p = pipe();
3021 childStderr = p.writeEnd;
3022 pipes._stderr = p.readEnd;
3024 else
3026 childStderr = std.stdio.stderr;
3029 if (redirectFlags & Redirect.stdoutToStderr)
3031 if (redirectFlags & Redirect.stderrToStdout)
3033 // We know that neither of the other options have been
3034 // set, so we assign the std.stdio.std* streams directly.
3035 childStdout = std.stdio.stderr;
3036 childStderr = std.stdio.stdout;
3038 else
3040 childStdout = childStderr;
3043 else if (redirectFlags & Redirect.stderrToStdout)
3045 childStderr = childStdout;
3048 config.flags &= ~(Config.Flags.retainStdin | Config.Flags.retainStdout | Config.Flags.retainStderr);
3049 pipes._pid = spawnFunc(command, childStdin, childStdout, childStderr,
3050 env, config, workDir, extraArgs);
3051 return pipes;
3056 Flags that can be passed to $(LREF pipeProcess) and $(LREF pipeShell)
3057 to specify which of the child process' standard streams are redirected.
3058 Use bitwise OR to combine flags.
3060 enum Redirect
3062 /// Redirect the standard input, output or error streams, respectively.
3063 stdin = 1,
3064 stdout = 2, /// ditto
3065 stderr = 4, /// ditto
3068 Redirect _all three streams. This is equivalent to
3069 $(D Redirect.stdin | Redirect.stdout | Redirect.stderr).
3071 all = stdin | stdout | stderr,
3074 Redirect the standard error stream into the standard output stream.
3075 This can not be combined with `Redirect.stderr`.
3077 stderrToStdout = 8,
3080 Redirect the standard output stream into the standard error stream.
3081 This can not be combined with `Redirect.stdout`.
3083 stdoutToStderr = 16,
3086 @system unittest
3088 import std.string;
3089 version (Windows) TestScript prog =
3090 "call :sub %~1 %~2 0
3091 call :sub %~1 %~2 1
3092 call :sub %~1 %~2 2
3093 call :sub %~1 %~2 3
3094 exit 3
3096 :sub
3097 set /p INPUT=
3098 if -%INPUT%-==-stop- ( exit %~3 )
3099 echo %INPUT% %~1
3100 echo %INPUT% %~2 1>&2";
3101 else version (Posix) TestScript prog =
3102 `for EXITCODE in 0 1 2 3; do
3103 read INPUT
3104 if test "$INPUT" = stop; then break; fi
3105 echo "$INPUT $1"
3106 echo "$INPUT $2" >&2
3107 done
3108 exit $EXITCODE`;
3109 auto pp = pipeProcess([prog.path, "bar", "baz"]);
3110 pp.stdin.writeln("foo");
3111 pp.stdin.flush();
3112 assert(pp.stdout.readln().chomp() == "foo bar");
3113 assert(pp.stderr.readln().chomp().stripRight() == "foo baz");
3114 pp.stdin.writeln("1234567890");
3115 pp.stdin.flush();
3116 assert(pp.stdout.readln().chomp() == "1234567890 bar");
3117 assert(pp.stderr.readln().chomp().stripRight() == "1234567890 baz");
3118 pp.stdin.writeln("stop");
3119 pp.stdin.flush();
3120 assert(wait(pp.pid) == 2);
3122 pp = pipeProcess([prog.path, "12345", "67890"],
3123 Redirect.stdin | Redirect.stdout | Redirect.stderrToStdout);
3124 pp.stdin.writeln("xyz");
3125 pp.stdin.flush();
3126 assert(pp.stdout.readln().chomp() == "xyz 12345");
3127 assert(pp.stdout.readln().chomp().stripRight() == "xyz 67890");
3128 pp.stdin.writeln("stop");
3129 pp.stdin.flush();
3130 assert(wait(pp.pid) == 1);
3132 pp = pipeShell(escapeShellCommand(prog.path, "AAAAA", "BBB"),
3133 Redirect.stdin | Redirect.stdoutToStderr | Redirect.stderr);
3134 pp.stdin.writeln("ab");
3135 pp.stdin.flush();
3136 assert(pp.stderr.readln().chomp() == "ab AAAAA");
3137 assert(pp.stderr.readln().chomp().stripRight() == "ab BBB");
3138 pp.stdin.writeln("stop");
3139 pp.stdin.flush();
3140 assert(wait(pp.pid) == 1);
3143 @system unittest
3145 import std.exception : assertThrown;
3146 TestScript prog = "exit 0";
3147 assertThrown!StdioException(pipeProcess(
3148 prog.path,
3149 Redirect.stdout | Redirect.stdoutToStderr));
3150 assertThrown!StdioException(pipeProcess(
3151 prog.path,
3152 Redirect.stderr | Redirect.stderrToStdout));
3153 auto p = pipeProcess(prog.path, Redirect.stdin);
3154 assertThrown!Error(p.stdout);
3155 assertThrown!Error(p.stderr);
3156 wait(p.pid);
3157 p = pipeProcess(prog.path, Redirect.stderr);
3158 assertThrown!Error(p.stdin);
3159 assertThrown!Error(p.stdout);
3160 wait(p.pid);
3164 Object which contains $(REF File, std,stdio) handles that allow communication
3165 with a child process through its standard streams.
3167 struct ProcessPipes
3169 /// The $(LREF Pid) of the child process.
3170 @property Pid pid() @safe nothrow
3172 return _pid;
3176 An $(REF File, std,stdio) that allows writing to the child process'
3177 standard input stream.
3179 Throws:
3180 $(OBJECTREF Error) if the child process' standard input stream hasn't
3181 been redirected.
3183 @property File stdin() @safe nothrow
3185 if ((_redirectFlags & Redirect.stdin) == 0)
3186 throw new Error("Child process' standard input stream hasn't "
3187 ~"been redirected.");
3188 return _stdin;
3192 An $(REF File, std,stdio) that allows reading from the child process'
3193 standard output stream.
3195 Throws:
3196 $(OBJECTREF Error) if the child process' standard output stream hasn't
3197 been redirected.
3199 @property File stdout() @safe nothrow
3201 if ((_redirectFlags & Redirect.stdout) == 0)
3202 throw new Error("Child process' standard output stream hasn't "
3203 ~"been redirected.");
3204 return _stdout;
3208 An $(REF File, std,stdio) that allows reading from the child process'
3209 standard error stream.
3211 Throws:
3212 $(OBJECTREF Error) if the child process' standard error stream hasn't
3213 been redirected.
3215 @property File stderr() @safe nothrow
3217 if ((_redirectFlags & Redirect.stderr) == 0)
3218 throw new Error("Child process' standard error stream hasn't "
3219 ~"been redirected.");
3220 return _stderr;
3223 private:
3224 Redirect _redirectFlags;
3225 Pid _pid;
3226 File _stdin, _stdout, _stderr;
3232 Executes the given program or shell command and returns its exit
3233 code and output.
3235 `execute` and `executeShell` start a new process using
3236 $(LREF spawnProcess) and $(LREF spawnShell), respectively, and wait
3237 for the process to complete before returning. The functions capture
3238 what the child process prints to both its standard output and
3239 standard error streams, and return this together with its exit code.
3241 auto dmd = execute(["dmd", "myapp.d"]);
3242 if (dmd.status != 0) writeln("Compilation failed:\n", dmd.output);
3244 auto ls = executeShell("ls -l");
3245 if (ls.status != 0) writeln("Failed to retrieve file listing");
3246 else writeln(ls.output);
3249 The `args`/`program`/`command`, `env` and `config`
3250 parameters are forwarded straight to the underlying spawn functions,
3251 and we refer to their documentation for details.
3253 Params:
3254 args = An array which contains the program name as the zeroth element
3255 and any command-line arguments in the following elements.
3256 (See $(LREF spawnProcess) for details.)
3257 program = The program name, $(I without) command-line arguments.
3258 (See $(LREF spawnProcess) for details.)
3259 command = A shell command which is passed verbatim to the command
3260 interpreter. (See $(LREF spawnShell) for details.)
3261 env = Additional environment variables for the child process.
3262 (See $(LREF spawnProcess) for details.)
3263 config = Flags that control process creation. See $(LREF Config)
3264 for an overview of available flags, and note that the
3265 `retainStd...` flags have no effect in this function.
3266 maxOutput = The maximum number of bytes of output that should be
3267 captured.
3268 workDir = The working directory for the new process.
3269 By default the child process inherits the parent's working
3270 directory.
3271 shellPath = The path to the shell to use to run the specified program.
3272 By default this is $(LREF nativeShell).
3275 Returns:
3276 An $(D std.typecons.Tuple!(int, "status", string, "output")).
3278 POSIX_specific:
3279 If the process is terminated by a signal, the `status` field of
3280 the return value will contain a negative number whose absolute
3281 value is the signal number. (See $(LREF wait) for details.)
3283 Throws:
3284 $(LREF ProcessException) on failure to start the process.$(BR)
3285 $(REF StdioException, std,stdio) on failure to capture output.
3287 auto execute(scope const(char[])[] args,
3288 const string[string] env = null,
3289 Config config = Config.none,
3290 size_t maxOutput = size_t.max,
3291 scope const(char)[] workDir = null)
3292 @safe
3294 return executeImpl!pipeProcess(args, env, config, maxOutput, workDir);
3297 /// ditto
3298 auto execute(scope const(char)[] program,
3299 const string[string] env = null,
3300 Config config = Config.none,
3301 size_t maxOutput = size_t.max,
3302 scope const(char)[] workDir = null)
3303 @safe
3305 return executeImpl!pipeProcess(program, env, config, maxOutput, workDir);
3308 /// ditto
3309 auto executeShell(scope const(char)[] command,
3310 const string[string] env = null,
3311 Config config = Config.none,
3312 size_t maxOutput = size_t.max,
3313 scope const(char)[] workDir = null,
3314 string shellPath = nativeShell)
3315 @safe
3317 return executeImpl!pipeShell(command,
3318 env,
3319 config,
3320 maxOutput,
3321 workDir,
3322 shellPath);
3325 // Does the actual work for execute() and executeShell().
3326 private auto executeImpl(alias pipeFunc, Cmd, ExtraPipeFuncArgs...)(
3327 Cmd commandLine,
3328 const string[string] env = null,
3329 Config config = Config.none,
3330 size_t maxOutput = size_t.max,
3331 scope const(char)[] workDir = null,
3332 ExtraPipeFuncArgs extraArgs = ExtraPipeFuncArgs.init)
3333 @trusted //TODO: @safe
3335 import std.algorithm.comparison : min;
3336 import std.array : appender;
3337 import std.typecons : Tuple;
3339 auto redirect = (config.flags & Config.Flags.stderrPassThrough)
3340 ? Redirect.stdout
3341 : Redirect.stdout | Redirect.stderrToStdout;
3343 auto p = pipeFunc(commandLine, redirect,
3344 env, config, workDir, extraArgs);
3346 auto a = appender!string;
3347 enum size_t defaultChunkSize = 4096;
3348 immutable chunkSize = min(maxOutput, defaultChunkSize);
3350 // Store up to maxOutput bytes in a.
3351 foreach (ubyte[] chunk; p.stdout.byChunk(chunkSize))
3353 immutable size_t remain = maxOutput - a.data.length;
3355 if (chunk.length < remain) a.put(chunk);
3356 else
3358 a.put(chunk[0 .. remain]);
3359 break;
3362 // Exhaust the stream, if necessary.
3363 foreach (ubyte[] chunk; p.stdout.byChunk(defaultChunkSize)) { }
3365 return Tuple!(int, "status", string, "output")(wait(p.pid), a.data);
3368 @system unittest
3370 import std.string;
3371 // To avoid printing the newline characters, we use the echo|set trick on
3372 // Windows, and printf on POSIX (neither echo -n nor echo \c are portable).
3373 version (Windows) TestScript prog =
3374 "echo|set /p=%~1
3375 echo|set /p=%~2 1>&2
3376 exit 123";
3377 else version (Android) TestScript prog =
3378 `echo -n $1
3379 echo -n $2 >&2
3380 exit 123`;
3381 else version (Posix) TestScript prog =
3382 `printf '%s' $1
3383 printf '%s' $2 >&2
3384 exit 123`;
3385 auto r = execute([prog.path, "foo", "bar"]);
3386 assert(r.status == 123);
3387 assert(r.output.stripRight() == "foobar");
3388 auto s = execute([prog.path, "Hello", "World"]);
3389 assert(s.status == 123);
3390 assert(s.output.stripRight() == "HelloWorld");
3393 @safe unittest
3395 import std.string;
3396 auto r1 = executeShell("echo foo");
3397 assert(r1.status == 0);
3398 assert(r1.output.chomp() == "foo");
3399 auto r2 = executeShell("echo bar 1>&2");
3400 assert(r2.status == 0);
3401 assert(r2.output.chomp().stripRight() == "bar");
3402 auto r3 = executeShell("exit 123");
3403 assert(r3.status == 123);
3404 assert(r3.output.empty);
3407 @system unittest
3409 // Temporarily disable output to stderr so as to not spam the build log.
3410 import std.stdio : stderr;
3411 import std.typecons : Tuple;
3412 import std.file : readText, exists, remove;
3413 import std.traits : ReturnType;
3415 ReturnType!executeShell r;
3416 auto tmpname = uniqueTempPath;
3417 scope(exit) if (exists(tmpname)) remove(tmpname);
3418 auto t = stderr;
3419 // Open a new scope to minimize code ran with stderr redirected.
3421 stderr.open(tmpname, "w");
3422 scope(exit) stderr = t;
3423 r = executeShell("echo D rox>&2", null, Config.stderrPassThrough);
3425 assert(r.status == 0);
3426 assert(r.output.empty);
3427 auto witness = readText(tmpname);
3428 import std.ascii : newline;
3429 assert(witness == "D rox" ~ newline, "'" ~ witness ~ "'");
3432 @safe unittest
3434 import std.typecons : Tuple;
3435 void foo() //Just test the compilation
3437 auto ret1 = execute(["dummy", "arg"]);
3438 auto ret2 = executeShell("dummy arg");
3439 static assert(is(typeof(ret1) == typeof(ret2)));
3441 Tuple!(int, string) ret3 = execute(["dummy", "arg"]);
3445 /// An exception that signals a problem with starting or waiting for a process.
3446 class ProcessException : Exception
3448 import std.exception : basicExceptionCtors;
3449 mixin basicExceptionCtors;
3451 // Creates a new ProcessException based on errno.
3452 static ProcessException newFromErrno(string customMsg = null,
3453 string file = __FILE__,
3454 size_t line = __LINE__)
3456 import core.stdc.errno : errno;
3457 return newFromErrno(errno, customMsg, file, line);
3460 // ditto, but error number is provided by caller
3461 static ProcessException newFromErrno(int error,
3462 string customMsg = null,
3463 string file = __FILE__,
3464 size_t line = __LINE__)
3466 import std.exception : errnoString;
3467 auto errnoMsg = errnoString(error);
3468 auto msg = customMsg.empty ? errnoMsg
3469 : customMsg ~ " (" ~ errnoMsg ~ ')';
3470 return new ProcessException(msg, file, line);
3473 // Creates a new ProcessException based on GetLastError() (Windows only).
3474 version (Windows)
3475 static ProcessException newFromLastError(string customMsg = null,
3476 string file = __FILE__,
3477 size_t line = __LINE__)
3479 auto lastMsg = sysErrorString(GetLastError());
3480 auto msg = customMsg.empty ? lastMsg
3481 : customMsg ~ " (" ~ lastMsg ~ ')';
3482 return new ProcessException(msg, file, line);
3488 Determines the path to the current user's preferred command interpreter.
3490 On Windows, this function returns the contents of the COMSPEC environment
3491 variable, if it exists. Otherwise, it returns the result of $(LREF nativeShell).
3493 On POSIX, `userShell` returns the contents of the SHELL environment
3494 variable, if it exists and is non-empty. Otherwise, it returns the result of
3495 $(LREF nativeShell).
3497 @property string userShell() @safe
3499 version (Windows) return environment.get("COMSPEC", nativeShell);
3500 else version (Posix) return environment.get("SHELL", nativeShell);
3504 The platform-specific native shell path.
3506 This function returns `"cmd.exe"` on Windows, `"/bin/sh"` on POSIX, and
3507 `"/system/bin/sh"` on Android.
3509 @property string nativeShell() @safe @nogc pure nothrow
3511 version (Windows) return "cmd.exe";
3512 else version (Android) return "/system/bin/sh";
3513 else version (Posix) return "/bin/sh";
3516 // A command-line switch that indicates to the shell that it should
3517 // interpret the following argument as a command to be executed.
3518 version (Posix) private immutable string shellSwitch = "-c";
3519 version (Windows) private immutable string shellSwitch = "/C";
3521 // Unittest support code: TestScript takes a string that contains a
3522 // shell script for the current platform, and writes it to a temporary
3523 // file. On Windows the file name gets a .cmd extension, while on
3524 // POSIX its executable permission bit is set. The file is
3525 // automatically deleted when the object goes out of scope.
3526 version (StdUnittest)
3527 private struct TestScript
3529 this(string code) @system
3531 // @system due to chmod
3532 import std.ascii : newline;
3533 import std.file : write;
3534 version (Windows)
3536 auto ext = ".cmd";
3537 auto firstLine = "@echo off";
3539 else version (Posix)
3541 auto ext = "";
3542 auto firstLine = "#!" ~ nativeShell;
3544 path = uniqueTempPath()~ext;
3545 write(path, firstLine ~ newline ~ code ~ newline);
3546 version (Posix)
3548 import core.sys.posix.sys.stat : chmod;
3549 import std.conv : octal;
3550 chmod(path.tempCString(), octal!777);
3554 ~this()
3556 import std.file : remove, exists;
3557 if (!path.empty && exists(path))
3559 try { remove(path); }
3560 catch (Exception e)
3562 debug std.stdio.stderr.writeln(e.msg);
3567 string path;
3571 // =============================================================================
3572 // Functions for shell command quoting/escaping.
3573 // =============================================================================
3577 Command line arguments exist in three forms:
3578 1) string or char* array, as received by main.
3579 Also used internally on POSIX systems.
3580 2) Command line string, as used in Windows'
3581 CreateProcess and CommandLineToArgvW functions.
3582 A specific quoting and escaping algorithm is used
3583 to distinguish individual arguments.
3584 3) Shell command string, as written at a shell prompt
3585 or passed to cmd /C - this one may contain shell
3586 control characters, e.g. > or | for redirection /
3587 piping - thus, yet another layer of escaping is
3588 used to distinguish them from program arguments.
3590 Except for escapeWindowsArgument, the intermediary
3591 format (2) is hidden away from the user in this module.
3595 Escapes an argv-style argument array to be used with $(LREF spawnShell),
3596 $(LREF pipeShell) or $(LREF executeShell).
3598 string url = "http://dlang.org/";
3599 executeShell(escapeShellCommand("wget", url, "-O", "dlang-index.html"));
3602 Concatenate multiple `escapeShellCommand` and
3603 $(LREF escapeShellFileName) results to use shell redirection or
3604 piping operators.
3606 executeShell(
3607 escapeShellCommand("curl", "http://dlang.org/download.html") ~
3608 "|" ~
3609 escapeShellCommand("grep", "-o", `http://\S*\.zip`) ~
3610 ">" ~
3611 escapeShellFileName("D download links.txt"));
3614 Throws:
3615 $(OBJECTREF Exception) if any part of the command line contains unescapable
3616 characters (NUL on all platforms, as well as CR and LF on Windows).
3618 string escapeShellCommand(scope const(char[])[] args...) @safe pure
3620 if (args.empty)
3621 return null;
3622 version (Windows)
3624 // Do not ^-escape the first argument (the program path),
3625 // as the shell parses it differently from parameters.
3626 // ^-escaping a program path that contains spaces will fail.
3627 string result = escapeShellFileName(args[0]);
3628 if (args.length > 1)
3630 result ~= " " ~ escapeShellCommandString(
3631 escapeShellArguments(args[1..$]));
3633 return result;
3635 version (Posix)
3637 return escapeShellCommandString(escapeShellArguments(args));
3641 @safe unittest
3643 // This is a simple unit test without any special requirements,
3644 // in addition to the unittest_burnin one below which requires
3645 // special preparation.
3647 struct TestVector { string[] args; string windows, posix; }
3648 TestVector[] tests =
3651 args : ["foo bar"],
3652 windows : `"foo bar"`,
3653 posix : `'foo bar'`
3656 args : ["foo bar", "hello"],
3657 windows : `"foo bar" hello`,
3658 posix : `'foo bar' 'hello'`
3661 args : ["foo bar", "hello world"],
3662 windows : `"foo bar" ^"hello world^"`,
3663 posix : `'foo bar' 'hello world'`
3666 args : ["foo bar", "hello", "world"],
3667 windows : `"foo bar" hello world`,
3668 posix : `'foo bar' 'hello' 'world'`
3671 args : ["foo bar", `'"^\`],
3672 windows : `"foo bar" ^"'\^"^^\\^"`,
3673 posix : `'foo bar' ''\''"^\'`
3677 foreach (test; tests)
3678 version (Windows)
3679 assert(escapeShellCommand(test.args) == test.windows);
3680 else
3681 assert(escapeShellCommand(test.args) == test.posix );
3684 private string escapeShellCommandString(return scope string command) @safe pure
3686 version (Windows)
3687 return escapeWindowsShellCommand(command);
3688 else
3689 return command;
3692 private string escapeWindowsShellCommand(scope const(char)[] command) @safe pure
3694 import std.array : appender;
3695 auto result = appender!string();
3696 result.reserve(command.length);
3698 foreach (c; command)
3699 switch (c)
3701 case '\0':
3702 throw new Exception("Cannot put NUL in command line");
3703 case '\r':
3704 case '\n':
3705 throw new Exception("CR/LF are not escapable");
3706 case '\x01': .. case '\x09':
3707 case '\x0B': .. case '\x0C':
3708 case '\x0E': .. case '\x1F':
3709 case '"':
3710 case '^':
3711 case '&':
3712 case '<':
3713 case '>':
3714 case '|':
3715 result.put('^');
3716 goto default;
3717 default:
3718 result.put(c);
3720 return result.data;
3723 private string escapeShellArguments(scope const(char[])[] args...)
3724 @trusted pure nothrow
3726 import std.exception : assumeUnique;
3727 char[] buf;
3729 @safe nothrow
3730 char[] allocator(size_t size)
3732 if (buf.length == 0)
3733 return buf = new char[size];
3734 else
3736 auto p = buf.length;
3737 buf.length = buf.length + 1 + size;
3738 buf[p++] = ' ';
3739 return buf[p .. p+size];
3743 foreach (arg; args)
3744 escapeShellArgument!allocator(arg);
3745 return assumeUnique(buf);
3748 private auto escapeShellArgument(alias allocator)(scope const(char)[] arg) @safe nothrow
3750 // The unittest for this function requires special
3751 // preparation - see below.
3753 version (Windows)
3754 return escapeWindowsArgumentImpl!allocator(arg);
3755 else
3756 return escapePosixArgumentImpl!allocator(arg);
3760 Quotes a command-line argument in a manner conforming to the behavior of
3761 $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx,
3762 CommandLineToArgvW).
3764 string escapeWindowsArgument(scope const(char)[] arg) @trusted pure nothrow
3766 // Rationale for leaving this function as public:
3767 // this algorithm of escaping paths is also used in other software,
3768 // e.g. DMD's response files.
3769 import std.exception : assumeUnique;
3770 auto buf = escapeWindowsArgumentImpl!charAllocator(arg);
3771 return assumeUnique(buf);
3775 private char[] charAllocator(size_t size) @safe pure nothrow
3777 return new char[size];
3781 private char[] escapeWindowsArgumentImpl(alias allocator)(scope const(char)[] arg)
3782 @safe nothrow
3783 if (is(typeof(allocator(size_t.init)[0] = char.init)))
3785 // References:
3786 // * http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx
3787 // * http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx
3789 // Check if the string needs to be escaped,
3790 // and calculate the total string size.
3792 // Trailing backslashes must be escaped
3793 bool escaping = true;
3794 bool needEscape = false;
3795 // Result size = input size + 2 for surrounding quotes + 1 for the
3796 // backslash for each escaped character.
3797 size_t size = 1 + arg.length + 1;
3799 foreach_reverse (char c; arg)
3801 if (c == '"')
3803 needEscape = true;
3804 escaping = true;
3805 size++;
3807 else
3808 if (c == '\\')
3810 if (escaping)
3811 size++;
3813 else
3815 if (c == ' ' || c == '\t')
3816 needEscape = true;
3817 escaping = false;
3821 import std.ascii : isDigit;
3822 // Empty arguments need to be specified as ""
3823 if (!arg.length)
3824 needEscape = true;
3825 else
3826 // Arguments ending with digits need to be escaped,
3827 // to disambiguate with 1>file redirection syntax
3828 if (isDigit(arg[$-1]))
3829 needEscape = true;
3831 if (!needEscape)
3832 return allocator(arg.length)[] = arg;
3834 // Construct result string.
3836 auto buf = allocator(size);
3837 size_t p = size;
3838 buf[--p] = '"';
3839 escaping = true;
3840 foreach_reverse (char c; arg)
3842 if (c == '"')
3843 escaping = true;
3844 else
3845 if (c != '\\')
3846 escaping = false;
3848 buf[--p] = c;
3849 if (escaping)
3850 buf[--p] = '\\';
3852 buf[--p] = '"';
3853 assert(p == 0);
3855 return buf;
3858 version (Windows) version (StdUnittest)
3860 private:
3861 import core.stdc.stddef;
3862 import core.stdc.wchar_ : wcslen;
3863 import core.sys.windows.shellapi : CommandLineToArgvW;
3864 import core.sys.windows.winbase;
3865 import core.sys.windows.winnt;
3866 import std.array;
3868 string[] parseCommandLine(string line)
3870 import std.algorithm.iteration : map;
3871 import std.array : array;
3872 import std.conv : to;
3873 auto lpCommandLine = (to!(WCHAR[])(line) ~ '\0').ptr;
3874 int numArgs;
3875 auto args = CommandLineToArgvW(lpCommandLine, &numArgs);
3876 scope(exit) LocalFree(args);
3877 return args[0 .. numArgs]
3878 .map!(arg => to!string(arg[0 .. wcslen(arg)]))
3879 .array();
3882 @system unittest
3884 import std.conv : text;
3885 string[] testStrings = [
3886 `Hello`,
3887 `Hello, world`,
3888 `Hello, "world"`,
3889 `C:\`,
3890 `C:\dmd`,
3891 `C:\Program Files\`,
3894 enum CHARS = `_x\" *&^` ~ "\t"; // _ is placeholder for nothing
3895 foreach (c1; CHARS)
3896 foreach (c2; CHARS)
3897 foreach (c3; CHARS)
3898 foreach (c4; CHARS)
3899 testStrings ~= [c1, c2, c3, c4].replace("_", "");
3901 foreach (s; testStrings)
3903 auto q = escapeWindowsArgument(s);
3904 auto args = parseCommandLine("Dummy.exe " ~ q);
3905 assert(args.length == 2, s ~ " => " ~ q ~ " #" ~ text(args.length-1));
3906 assert(args[1] == s, s ~ " => " ~ q ~ " => " ~ args[1]);
3911 private string escapePosixArgument(scope const(char)[] arg) @trusted pure nothrow
3913 import std.exception : assumeUnique;
3914 auto buf = escapePosixArgumentImpl!charAllocator(arg);
3915 return assumeUnique(buf);
3918 private char[] escapePosixArgumentImpl(alias allocator)(scope const(char)[] arg)
3919 @safe nothrow
3920 if (is(typeof(allocator(size_t.init)[0] = char.init)))
3922 // '\'' means: close quoted part of argument, append an escaped
3923 // single quote, and reopen quotes
3925 // Below code is equivalent to:
3926 // return `'` ~ std.array.replace(arg, `'`, `'\''`) ~ `'`;
3928 size_t size = 1 + arg.length + 1;
3929 foreach (char c; arg)
3930 if (c == '\'')
3931 size += 3;
3933 auto buf = allocator(size);
3934 size_t p = 0;
3935 buf[p++] = '\'';
3936 foreach (char c; arg)
3937 if (c == '\'')
3939 buf[p .. p+4] = `'\''`;
3940 p += 4;
3942 else
3943 buf[p++] = c;
3944 buf[p++] = '\'';
3945 assert(p == size);
3947 return buf;
3951 Escapes a filename to be used for shell redirection with $(LREF spawnShell),
3952 $(LREF pipeShell) or $(LREF executeShell).
3954 string escapeShellFileName(scope const(char)[] fileName) @trusted pure nothrow
3956 // The unittest for this function requires special
3957 // preparation - see below.
3959 version (Windows)
3961 // If a file starts with &, it can cause cmd.exe to misinterpret
3962 // the file name as the stream redirection syntax:
3963 // command > "&foo.txt"
3964 // gets interpreted as
3965 // command >&foo.txt
3966 // Prepend .\ to disambiguate.
3968 if (fileName.length && fileName[0] == '&')
3969 return cast(string)(`".\` ~ fileName ~ '"');
3971 return cast(string)('"' ~ fileName ~ '"');
3973 else
3974 return escapePosixArgument(fileName);
3977 // Loop generating strings with random characters
3978 //version = unittest_burnin;
3980 version (unittest_burnin)
3981 @system unittest
3983 // There are no readily-available commands on all platforms suitable
3984 // for properly testing command escaping. The behavior of CMD's "echo"
3985 // built-in differs from the POSIX program, and Windows ports of POSIX
3986 // environments (Cygwin, msys, gnuwin32) may interfere with their own
3987 // "echo" ports.
3989 // To run this unit test, create std_process_unittest_helper.d with the
3990 // following content and compile it:
3991 // import std.stdio, std.array; void main(string[] args) { write(args.join("\0")); }
3992 // Then, test this module with:
3993 // rdmd --main -unittest -version=unittest_burnin process.d
3995 auto helper = absolutePath("std_process_unittest_helper");
3996 assert(executeShell(helper ~ " hello").output.split("\0")[1..$] == ["hello"], "Helper malfunction");
3998 void test(string[] s, string fn)
4000 string e;
4001 string[] g;
4003 e = escapeShellCommand(helper ~ s);
4005 scope(failure) writefln("executeShell() failed.\nExpected:\t%s\nEncoded:\t%s", s, [e]);
4006 auto result = executeShell(e);
4007 assert(result.status == 0, "std_process_unittest_helper failed");
4008 g = result.output.split("\0")[1..$];
4010 assert(s == g, format("executeShell() test failed.\nExpected:\t%s\nGot:\t\t%s\nEncoded:\t%s", s, g, [e]));
4012 e = escapeShellCommand(helper ~ s) ~ ">" ~ escapeShellFileName(fn);
4014 scope(failure) writefln(
4015 "executeShell() with redirect failed.\nExpected:\t%s\nFilename:\t%s\nEncoded:\t%s", s, [fn], [e]);
4016 auto result = executeShell(e);
4017 assert(result.status == 0, "std_process_unittest_helper failed");
4018 assert(!result.output.length, "No output expected, got:\n" ~ result.output);
4019 g = readText(fn).split("\0")[1..$];
4021 remove(fn);
4022 assert(s == g,
4023 format("executeShell() with redirect test failed.\nExpected:\t%s\nGot:\t\t%s\nEncoded:\t%s", s, g, [e]));
4026 while (true)
4028 string[] args;
4029 foreach (n; 0 .. uniform(1, 4))
4031 string arg;
4032 foreach (l; 0 .. uniform(0, 10))
4034 dchar c;
4035 while (true)
4037 version (Windows)
4039 // As long as DMD's system() uses CreateProcessA,
4040 // we can't reliably pass Unicode
4041 c = uniform(0, 128);
4043 else
4044 c = uniform!ubyte();
4046 if (c == 0)
4047 continue; // argv-strings are zero-terminated
4048 version (Windows)
4049 if (c == '\r' || c == '\n')
4050 continue; // newlines are unescapable on Windows
4051 break;
4053 arg ~= c;
4055 args ~= arg;
4058 // generate filename
4059 string fn;
4060 foreach (l; 0 .. uniform(1, 10))
4062 dchar c;
4063 while (true)
4065 version (Windows)
4066 c = uniform(0, 128); // as above
4067 else
4068 c = uniform!ubyte();
4070 if (c == 0 || c == '/')
4071 continue; // NUL and / are the only characters
4072 // forbidden in POSIX filenames
4073 version (Windows)
4074 if (c < '\x20' || c == '<' || c == '>' || c == ':' ||
4075 c == '"' || c == '\\' || c == '|' || c == '?' || c == '*')
4076 continue; // http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx
4077 break;
4080 fn ~= c;
4082 fn = fn[0..$/2] ~ "_testfile_" ~ fn[$/2..$];
4084 test(args, fn);
4088 // =============================================================================
4089 // Everything below this line was part of the old std.process, and most of
4090 // it will be deprecated and removed.
4091 // =============================================================================
4095 Copyright: Copyright The D Language Foundation 2007 - 2009.
4096 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
4097 Authors: $(HTTP digitalmars.com, Walter Bright),
4098 $(HTTP erdani.org, Andrei Alexandrescu),
4099 $(HTTP thecybershadow.net, Vladimir Panteleev)
4100 Source: $(PHOBOSSRC std/_process.d)
4103 Copyright The D Language Foundation 2007 - 2009.
4104 Distributed under the Boost Software License, Version 1.0.
4105 (See accompanying file LICENSE_1_0.txt or copy at
4106 http://www.boost.org/LICENSE_1_0.txt)
4110 import core.stdc.errno;
4111 import core.stdc.stdlib;
4112 import core.stdc.string;
4113 import core.thread;
4115 version (Windows)
4117 import std.file, std.format, std.random;
4119 version (Posix)
4121 import core.sys.posix.stdlib;
4124 private void toAStringz(in string[] a, const(char)**az)
4126 import std.string : toStringz;
4127 foreach (string s; a)
4129 *az++ = toStringz(s);
4131 *az = null;
4135 /* ========================================================== */
4137 //version (Windows)
4139 // int spawnvp(int mode, string pathname, string[] argv)
4140 // {
4141 // char** argv_ = cast(char**) core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length));
4142 // scope(exit) core.stdc.stdlib.free(argv_);
4144 // toAStringz(argv, argv_);
4146 // return spawnvp(mode, pathname.tempCString(), argv_);
4147 // }
4150 // Incorporating idea (for spawnvp() on Posix) from Dave Fladebo
4152 enum { _P_WAIT, _P_NOWAIT, _P_OVERLAY }
4153 version (Windows) extern(C) int spawnvp(int, scope const(char) *, scope const(char*)*);
4154 alias P_WAIT = _P_WAIT;
4155 alias P_NOWAIT = _P_NOWAIT;
4157 /* ========================================================== */
4159 version (StdDdoc)
4162 Replaces the current process by executing a command, `pathname`, with
4163 the arguments in `argv`.
4165 $(BLUE This function is Posix-Only.)
4167 Typically, the first element of `argv` is
4168 the command being executed, i.e. $(D argv[0] == pathname). The 'p'
4169 versions of `exec` search the PATH environment variable for $(D
4170 pathname). The 'e' versions additionally take the new process'
4171 environment variables as an array of strings of the form key=value.
4173 Does not return on success (the current process will have been
4174 replaced). Returns -1 on failure with no indication of the
4175 underlying error.
4177 Windows_specific:
4178 These functions are only supported on POSIX platforms, as the Windows
4179 operating systems do not provide the ability to overwrite the current
4180 process image with another. In single-threaded programs it is possible
4181 to approximate the effect of `execv*` by using $(LREF spawnProcess)
4182 and terminating the current process once the child process has returned.
4183 For example:
4185 auto commandLine = [ "program", "arg1", "arg2" ];
4186 version (Posix)
4188 execv(commandLine[0], commandLine);
4189 throw new Exception("Failed to execute program");
4191 else version (Windows)
4193 import core.stdc.stdlib : _Exit;
4194 _Exit(wait(spawnProcess(commandLine)));
4197 This is, however, NOT equivalent to POSIX' `execv*`. For one thing, the
4198 executed program is started as a separate process, with all this entails.
4199 Secondly, in a multithreaded program, other threads will continue to do
4200 work while the current thread is waiting for the child process to complete.
4202 A better option may sometimes be to terminate the current program immediately
4203 after spawning the child process. This is the behaviour exhibited by the
4204 $(LINK2 http://msdn.microsoft.com/en-us/library/431x4c1w.aspx,`__exec`)
4205 functions in Microsoft's C runtime library, and it is how D's now-deprecated
4206 Windows `execv*` functions work. Example:
4208 auto commandLine = [ "program", "arg1", "arg2" ];
4209 version (Posix)
4211 execv(commandLine[0], commandLine);
4212 throw new Exception("Failed to execute program");
4214 else version (Windows)
4216 spawnProcess(commandLine);
4217 import core.stdc.stdlib : _exit;
4218 _exit(0);
4222 int execv(in string pathname, in string[] argv);
4223 ///ditto
4224 int execve(in string pathname, in string[] argv, in string[] envp);
4225 /// ditto
4226 int execvp(in string pathname, in string[] argv);
4227 /// ditto
4228 int execvpe(in string pathname, in string[] argv, in string[] envp);
4230 else version (Posix)
4232 int execv(in string pathname, in string[] argv)
4234 return execv_(pathname, argv);
4236 int execve(in string pathname, in string[] argv, in string[] envp)
4238 return execve_(pathname, argv, envp);
4240 int execvp(in string pathname, in string[] argv)
4242 return execvp_(pathname, argv);
4244 int execvpe(in string pathname, in string[] argv, in string[] envp)
4246 return execvpe_(pathname, argv, envp);
4250 // Move these C declarations to druntime if we decide to keep the D wrappers
4251 extern(C)
4253 int execv(scope const(char) *, scope const(char *)*);
4254 int execve(scope const(char)*, scope const(char*)*, scope const(char*)*);
4255 int execvp(scope const(char)*, scope const(char*)*);
4256 version (Windows) int execvpe(scope const(char)*, scope const(char*)*, scope const(char*)*);
4259 private int execv_(in string pathname, in string[] argv)
4261 import core.exception : OutOfMemoryError;
4262 import std.exception : enforce;
4263 auto argv_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length));
4264 enforce!OutOfMemoryError(argv_ !is null, "Out of memory in std.process.");
4265 scope(exit) core.stdc.stdlib.free(argv_);
4267 toAStringz(argv, argv_);
4269 return execv(pathname.tempCString(), argv_);
4272 private int execve_(in string pathname, in string[] argv, in string[] envp)
4274 import core.exception : OutOfMemoryError;
4275 import std.exception : enforce;
4276 auto argv_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length));
4277 enforce!OutOfMemoryError(argv_ !is null, "Out of memory in std.process.");
4278 scope(exit) core.stdc.stdlib.free(argv_);
4279 auto envp_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + envp.length));
4280 enforce!OutOfMemoryError(envp_ !is null, "Out of memory in std.process.");
4281 scope(exit) core.stdc.stdlib.free(envp_);
4283 toAStringz(argv, argv_);
4284 toAStringz(envp, envp_);
4286 return execve(pathname.tempCString(), argv_, envp_);
4289 private int execvp_(in string pathname, in string[] argv)
4291 import core.exception : OutOfMemoryError;
4292 import std.exception : enforce;
4293 auto argv_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length));
4294 enforce!OutOfMemoryError(argv_ !is null, "Out of memory in std.process.");
4295 scope(exit) core.stdc.stdlib.free(argv_);
4297 toAStringz(argv, argv_);
4299 return execvp(pathname.tempCString(), argv_);
4302 private int execvpe_(in string pathname, in string[] argv, in string[] envp)
4304 version (Posix)
4306 import std.array : split;
4307 import std.conv : to;
4308 // Is pathname rooted?
4309 if (pathname[0] == '/')
4311 // Yes, so just call execve()
4312 return execve(pathname, argv, envp);
4314 else
4316 // No, so must traverse PATHs, looking for first match
4317 string[] envPaths = split(
4318 to!string(core.stdc.stdlib.getenv("PATH")), ":");
4319 int iRet = 0;
4321 // Note: if any call to execve() succeeds, this process will cease
4322 // execution, so there's no need to check the execve() result through
4323 // the loop.
4325 foreach (string pathDir; envPaths)
4327 string composite = cast(string) (pathDir ~ "/" ~ pathname);
4329 iRet = execve(composite, argv, envp);
4331 if (0 != iRet)
4333 iRet = execve(pathname, argv, envp);
4336 return iRet;
4339 else version (Windows)
4341 import core.exception : OutOfMemoryError;
4342 import std.exception : enforce;
4343 auto argv_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length));
4344 enforce!OutOfMemoryError(argv_ !is null, "Out of memory in std.process.");
4345 scope(exit) core.stdc.stdlib.free(argv_);
4346 auto envp_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + envp.length));
4347 enforce!OutOfMemoryError(envp_ !is null, "Out of memory in std.process.");
4348 scope(exit) core.stdc.stdlib.free(envp_);
4350 toAStringz(argv, argv_);
4351 toAStringz(envp, envp_);
4353 return execvpe(pathname.tempCString(), argv_, envp_);
4355 else
4357 static assert(0);
4358 } // version
4361 version (StdDdoc)
4363 /****************************************
4364 * Start up the browser and set it to viewing the page at url.
4366 void browse(scope const(char)[] url);
4368 else
4369 version (Windows)
4371 import core.sys.windows.shellapi, core.sys.windows.winuser;
4373 pragma(lib,"shell32.lib");
4375 void browse(scope const(char)[] url) nothrow @nogc @trusted
4377 ShellExecuteW(null, "open", url.tempCStringW(), null, null, SW_SHOWNORMAL);
4380 else version (Posix)
4382 import core.stdc.stdio;
4383 import core.stdc.string;
4384 import core.sys.posix.unistd;
4386 void browse(scope const(char)[] url) nothrow @nogc @safe
4388 const(char)*[3] args;
4390 // Trusted because it's called with a zero-terminated literal
4391 const(char)* browser = (() @trusted => core.stdc.stdlib.getenv("BROWSER"))();
4392 if (browser)
4394 // String already zero-terminated
4395 browser = (() @trusted => strdup(browser))();
4396 args[0] = browser;
4398 else
4400 version (OSX)
4402 args[0] = "open";
4404 else
4406 //args[0] = "x-www-browser"; // doesn't work on some systems
4407 args[0] = "xdg-open";
4411 const buffer = url.tempCString(); // Retain buffer until end of scope
4412 args[1] = buffer;
4413 args[2] = null;
4415 auto childpid = core.sys.posix.unistd.fork();
4416 if (childpid == 0)
4418 // Trusted because args and all entries are always zero-terminated
4419 (() @trusted =>
4420 core.sys.posix.unistd.execvp(args[0], &args[0]) ||
4421 perror(args[0]) // failed to execute
4422 )();
4423 return;
4425 if (browser)
4426 // Trusted because it's allocated via strdup above
4427 (() @trusted => free(cast(void*) browser))();
4429 version (StdUnittest)
4431 // Verify that the test script actually suceeds
4432 int status;
4433 const check = (() @trusted => waitpid(childpid, &status, 0))();
4434 assert(check != -1);
4435 assert(status == 0);
4439 else
4440 static assert(0, "os not supported");
4442 // Verify attributes are consistent between all implementations
4443 @safe @nogc nothrow unittest
4445 if (false)
4446 browse("");
4449 version (Windows) { /* Doesn't use BROWSER */ }
4450 else
4451 @system unittest
4453 import std.conv : text;
4454 import std.range : repeat;
4455 immutable string url = text("http://", repeat('x', 249));
4457 TestScript prog = `if [ "$1" != "` ~ url ~ `" ]; then exit 1; fi`;
4458 environment["BROWSER"] = prog.path;
4459 browse(url);