d: Merge upstream dmd, druntime 4ca4140e58, phobos 454dff14d.
[official-gcc.git] / libphobos / src / std / process.d
blob494910f35350927a561c98c78f6b19fe20a579a9
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;
110 import std.stdio;
112 version (OSX)
113 version = Darwin;
114 else version (iOS)
116 version = Darwin;
117 version = iOSDerived;
119 else version (TVOS)
121 version = Darwin;
122 version = iOSDerived;
124 else version (WatchOS)
126 version = Darwin;
127 version = iOSDerived;
130 // When the DMC runtime is used, we have to use some custom functions
131 // to convert between Windows file handles and FILE*s.
132 version (Win32) version (CRuntime_DigitalMars) version = DMC_RUNTIME;
135 // Some of the following should be moved to druntime.
136 private
138 // Microsoft Visual C Runtime (MSVCRT) declarations.
139 version (Windows)
141 version (DMC_RUNTIME) { } else
143 import core.stdc.stdint;
144 enum
146 STDIN_FILENO = 0,
147 STDOUT_FILENO = 1,
148 STDERR_FILENO = 2,
153 // POSIX API declarations.
154 version (Posix)
156 version (Darwin)
158 extern(C) char*** _NSGetEnviron() nothrow;
159 const(char**) getEnvironPtr() @trusted
161 return *_NSGetEnviron;
164 else
166 // Made available by the C runtime:
167 extern(C) extern __gshared const char** environ;
168 const(char**) getEnvironPtr() @trusted
170 return environ;
174 @system unittest
176 import core.thread : Thread;
177 new Thread({assert(getEnvironPtr !is null);}).start();
180 } // private
182 // =============================================================================
183 // Environment variable manipulation.
184 // =============================================================================
187 Manipulates _environment variables using an associative-array-like
188 interface.
190 This class contains only static methods, and cannot be instantiated.
191 See below for examples of use.
193 abstract final class environment
195 static import core.sys.posix.stdlib;
196 import core.stdc.errno : errno, EINVAL;
198 static:
200 Retrieves the value of the environment variable with the given `name`.
202 auto path = environment["PATH"];
205 Throws:
206 $(OBJECTREF Exception) if the environment variable does not exist,
207 or $(REF UTFException, std,utf) if the variable contains invalid UTF-16
208 characters (Windows only).
210 See_also:
211 $(LREF environment.get), which doesn't throw on failure.
213 string opIndex(scope const(char)[] name) @safe
215 import std.exception : enforce;
216 return get(name, null).enforce("Environment variable not found: "~name);
220 Retrieves the value of the environment variable with the given `name`,
221 or a default value if the variable doesn't exist.
223 Unlike $(LREF environment.opIndex), this function never throws on Posix.
225 auto sh = environment.get("SHELL", "/bin/sh");
227 This function is also useful in checking for the existence of an
228 environment variable.
230 auto myVar = environment.get("MYVAR");
231 if (myVar is null)
233 // Environment variable doesn't exist.
234 // Note that we have to use 'is' for the comparison, since
235 // myVar == null is also true if the variable exists but is
236 // empty.
239 Params:
240 name = name of the environment variable to retrieve
241 defaultValue = default value to return if the environment variable doesn't exist.
243 Returns:
244 the value of the environment variable if found, otherwise
245 `null` if the environment doesn't exist.
247 Throws:
248 $(REF UTFException, std,utf) if the variable contains invalid UTF-16
249 characters (Windows only).
251 string get(scope const(char)[] name, string defaultValue = null) @safe
253 string value;
254 getImpl(name, (result) { value = result ? cachedToString(result) : defaultValue; });
255 return value;
259 Assigns the given `value` to the environment variable with the given
260 `name`.
261 If `value` is null the variable is removed from environment.
263 If the variable does not exist, it will be created. If it already exists,
264 it will be overwritten.
266 environment["foo"] = "bar";
269 Throws:
270 $(OBJECTREF Exception) if the environment variable could not be added
271 (e.g. if the name is invalid).
273 Note:
274 On some platforms, modifying environment variables may not be allowed in
275 multi-threaded programs. See e.g.
276 $(LINK2 https://www.gnu.org/software/libc/manual/html_node/Environment-Access.html#Environment-Access, glibc).
278 inout(char)[] opIndexAssign(return scope inout char[] value, scope const(char)[] name) @trusted
280 version (Posix)
282 import std.exception : enforce, errnoEnforce;
283 if (value is null)
285 remove(name);
286 return value;
288 if (core.sys.posix.stdlib.setenv(name.tempCString(), value.tempCString(), 1) != -1)
290 return value;
292 // The default errno error message is very uninformative
293 // in the most common case, so we handle it manually.
294 enforce(errno != EINVAL,
295 "Invalid environment variable name: '"~name~"'");
296 errnoEnforce(false,
297 "Failed to add environment variable");
298 assert(0);
300 else version (Windows)
302 import std.windows.syserror : wenforce;
303 wenforce(
304 SetEnvironmentVariableW(name.tempCStringW(), value.tempCStringW()),
306 return value;
308 else static assert(0);
312 Removes the environment variable with the given `name`.
314 If the variable isn't in the environment, this function returns
315 successfully without doing anything.
317 Note:
318 On some platforms, modifying environment variables may not be allowed in
319 multi-threaded programs. See e.g.
320 $(LINK2 https://www.gnu.org/software/libc/manual/html_node/Environment-Access.html#Environment-Access, glibc).
322 void remove(scope const(char)[] name) @trusted nothrow @nogc
324 version (Windows) SetEnvironmentVariableW(name.tempCStringW(), null);
325 else version (Posix) core.sys.posix.stdlib.unsetenv(name.tempCString());
326 else static assert(0);
330 Identify whether a variable is defined in the environment.
332 Because it doesn't return the value, this function is cheaper than `get`.
333 However, if you do need the value as well, you should just check the
334 return of `get` for `null` instead of using this function first.
336 Example:
337 -------------
338 // good usage
339 if ("MY_ENV_FLAG" in environment)
340 doSomething();
342 // bad usage
343 if ("MY_ENV_VAR" in environment)
344 doSomething(environment["MY_ENV_VAR"]);
346 // do this instead
347 if (auto var = environment.get("MY_ENV_VAR"))
348 doSomething(var);
349 -------------
351 bool opBinaryRight(string op : "in")(scope const(char)[] name) @trusted
353 version (Posix)
354 return core.sys.posix.stdlib.getenv(name.tempCString()) !is null;
355 else version (Windows)
357 SetLastError(NO_ERROR);
358 if (GetEnvironmentVariableW(name.tempCStringW, null, 0) > 0)
359 return true;
360 immutable err = GetLastError();
361 if (err == NO_ERROR)
362 return true; // zero-length environment variable on Wine / XP
363 if (err == ERROR_ENVVAR_NOT_FOUND)
364 return false;
365 // Some other Windows error, throw.
366 throw new WindowsException(err);
368 else static assert(0);
372 Copies all environment variables into an associative array.
374 Windows_specific:
375 While Windows environment variable names are case insensitive, D's
376 built-in associative arrays are not. This function will store all
377 variable names in uppercase (e.g. `PATH`).
379 Throws:
380 $(OBJECTREF Exception) if the environment variables could not
381 be retrieved (Windows only).
383 string[string] toAA() @trusted
385 import std.conv : to;
386 string[string] aa;
387 version (Posix)
389 auto environ = getEnvironPtr;
390 for (int i=0; environ[i] != null; ++i)
392 import std.string : indexOf;
394 immutable varDef = to!string(environ[i]);
395 immutable eq = indexOf(varDef, '=');
396 assert(eq >= 0);
398 immutable name = varDef[0 .. eq];
399 immutable value = varDef[eq+1 .. $];
401 // In POSIX, environment variables may be defined more
402 // than once. This is a security issue, which we avoid
403 // by checking whether the key already exists in the array.
404 // For more info:
405 // http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/environment-variables.html
406 if (name !in aa) aa[name] = value;
409 else version (Windows)
411 import std.exception : enforce;
412 import std.uni : toUpper;
413 auto envBlock = GetEnvironmentStringsW();
414 enforce(envBlock, "Failed to retrieve environment variables.");
415 scope(exit) FreeEnvironmentStringsW(envBlock);
417 for (int i=0; envBlock[i] != '\0'; ++i)
419 auto start = i;
420 while (envBlock[i] != '=') ++i;
421 immutable name = toUTF8(toUpper(envBlock[start .. i]));
423 start = i+1;
424 while (envBlock[i] != '\0') ++i;
426 // Ignore variables with empty names. These are used internally
427 // by Windows to keep track of each drive's individual current
428 // directory.
429 if (!name.length)
430 continue;
432 // Just like in POSIX systems, environment variables may be
433 // defined more than once in an environment block on Windows,
434 // and it is just as much of a security issue there. Moreso,
435 // in fact, due to the case insensensitivity of variable names,
436 // which is not handled correctly by all programs.
437 auto val = toUTF8(envBlock[start .. i]);
438 if (name !in aa) aa[name] = val is null ? "" : val;
441 else static assert(0);
442 return aa;
445 private:
446 version (Windows) alias OSChar = WCHAR;
447 else version (Posix) alias OSChar = char;
449 // Retrieves the environment variable. Calls `sink` with a
450 // temporary buffer of OS characters, or `null` if the variable
451 // doesn't exist.
452 void getImpl(scope const(char)[] name, scope void delegate(const(OSChar)[]) @safe sink) @trusted
454 version (Windows)
456 // first we ask windows how long the environment variable is,
457 // then we try to read it in to a buffer of that length. Lots
458 // of error conditions because the windows API is nasty.
460 import std.conv : to;
461 const namezTmp = name.tempCStringW();
462 WCHAR[] buf;
464 // clear error because GetEnvironmentVariable only says it sets it
465 // if the environment variable is missing, not on other errors.
466 SetLastError(NO_ERROR);
467 // len includes terminating null
468 immutable len = GetEnvironmentVariableW(namezTmp, null, 0);
469 if (len == 0)
471 immutable err = GetLastError();
472 if (err == ERROR_ENVVAR_NOT_FOUND)
473 return sink(null);
474 if (err != NO_ERROR) // Some other Windows error, throw.
475 throw new WindowsException(err);
477 if (len <= 1)
478 return sink("");
479 buf.length = len;
481 while (true)
483 // lenRead is either the number of bytes read w/o null - if buf was long enough - or
484 // the number of bytes necessary *including* null if buf wasn't long enough
485 immutable lenRead = GetEnvironmentVariableW(namezTmp, buf.ptr, to!DWORD(buf.length));
486 if (lenRead == 0)
488 immutable err = GetLastError();
489 if (err == NO_ERROR) // sucessfully read a 0-length variable
490 return sink("");
491 if (err == ERROR_ENVVAR_NOT_FOUND) // variable didn't exist
492 return sink(null);
493 // some other windows error
494 throw new WindowsException(err);
496 assert(lenRead != buf.length, "impossible according to msft docs");
497 if (lenRead < buf.length) // the buffer was long enough
498 return sink(buf[0 .. lenRead]);
499 // resize and go around again, because the environment variable grew
500 buf.length = lenRead;
503 else version (Posix)
505 import core.stdc.string : strlen;
507 const vz = core.sys.posix.stdlib.getenv(name.tempCString());
508 if (vz == null) return sink(null);
509 return sink(vz[0 .. strlen(vz)]);
511 else static assert(0);
514 string cachedToString(C)(scope const(C)[] v) @safe
516 import std.algorithm.comparison : equal;
518 // Cache the last call's result.
519 static string lastResult;
520 if (v.empty)
522 // Return non-null array for blank result to distinguish from
523 // not-present result.
524 lastResult = "";
526 else if (!v.equal(lastResult))
528 import std.conv : to;
529 lastResult = v.to!string;
531 return lastResult;
535 @safe unittest
537 import std.exception : assertThrown;
538 // New variable
539 environment["std_process"] = "foo";
540 assert(environment["std_process"] == "foo");
541 assert("std_process" in environment);
543 // Set variable again (also tests length 1 case)
544 environment["std_process"] = "b";
545 assert(environment["std_process"] == "b");
546 assert("std_process" in environment);
548 // Remove variable
549 environment.remove("std_process");
550 assert("std_process" !in environment);
552 // Remove again, should succeed
553 environment.remove("std_process");
554 assert("std_process" !in environment);
556 // Throw on not found.
557 assertThrown(environment["std_process"]);
559 // get() without default value
560 assert(environment.get("std_process") is null);
562 // get() with default value
563 assert(environment.get("std_process", "baz") == "baz");
565 // get() on an empty (but present) value
566 environment["std_process"] = "";
567 auto res = environment.get("std_process");
568 assert(res !is null);
569 assert(res == "");
570 assert("std_process" in environment);
572 // Important to do the following round-trip after the previous test
573 // because it tests toAA with an empty var
575 // Convert to associative array
576 auto aa = environment.toAA();
577 assert(aa.length > 0);
578 foreach (n, v; aa)
580 // Wine has some bugs related to environment variables:
581 // - Wine allows the existence of an env. variable with the name
582 // "\0", but GetEnvironmentVariable refuses to retrieve it.
583 // As of 2.067 we filter these out anyway (see comment in toAA).
585 assert(v == environment[n]);
588 // ... and back again.
589 foreach (n, v; aa)
590 environment[n] = v;
592 // Complete the roundtrip
593 auto aa2 = environment.toAA();
594 import std.conv : text;
595 assert(aa == aa2, text(aa, " != ", aa2));
596 assert("std_process" in environment);
598 // Setting null must have the same effect as remove
599 environment["std_process"] = null;
600 assert("std_process" !in environment);
603 // =============================================================================
604 // Functions and classes for process management.
605 // =============================================================================
608 * Returns the process ID of the current process,
609 * which is guaranteed to be unique on the system.
611 * Example:
612 * ---
613 * writefln("Current process ID: %d", thisProcessID);
614 * ---
616 @property int thisProcessID() @trusted nothrow @nogc //TODO: @safe
618 version (Windows) return GetCurrentProcessId();
619 else version (Posix) return core.sys.posix.unistd.getpid();
624 * Returns the process ID of the current thread,
625 * which is guaranteed to be unique within the current process.
627 * Returns:
628 * A $(REF ThreadID, core,thread) value for the calling thread.
630 * Example:
631 * ---
632 * writefln("Current thread ID: %s", thisThreadID);
633 * ---
635 @property ThreadID thisThreadID() @trusted nothrow @nogc //TODO: @safe
637 version (Windows)
638 return GetCurrentThreadId();
639 else
640 version (Posix)
642 import core.sys.posix.pthread : pthread_self;
643 return pthread_self();
648 @system unittest
650 int pidA, pidB;
651 ThreadID tidA, tidB;
652 pidA = thisProcessID;
653 tidA = thisThreadID;
655 import core.thread;
656 auto t = new Thread({
657 pidB = thisProcessID;
658 tidB = thisThreadID;
660 t.start();
661 t.join();
663 assert(pidA == pidB);
664 assert(tidA != tidB);
668 package(std) string uniqueTempPath() @safe
670 import std.file : tempDir;
671 import std.path : buildPath;
672 import std.uuid : randomUUID;
673 // Path should contain spaces to test escaping whitespace
674 return buildPath(tempDir(), "std.process temporary file " ~
675 randomUUID().toString());
679 version (iOSDerived) {}
680 else:
683 Spawns a new process, optionally assigning it an arbitrary set of standard
684 input, output, and error streams.
686 The function returns immediately, leaving the child process to execute
687 in parallel with its parent. It is recommended to always call $(LREF wait)
688 on the returned $(LREF Pid) unless the process was spawned with
689 `Config.detached` flag, as detailed in the documentation for `wait`.
691 Command_line:
692 There are four overloads of this function. The first two take an array
693 of strings, `args`, which should contain the program name as the
694 zeroth element and any command-line arguments in subsequent elements.
695 The third and fourth versions are included for convenience, and may be
696 used when there are no command-line arguments. They take a single string,
697 `program`, which specifies the program name.
699 Unless a directory is specified in `args[0]` or `program`,
700 `spawnProcess` will search for the program in a platform-dependent
701 manner. On POSIX systems, it will look for the executable in the
702 directories listed in the PATH environment variable, in the order
703 they are listed. On Windows, it will search for the executable in
704 the following sequence:
705 $(OL
706 $(LI The directory from which the application loaded.)
707 $(LI The current directory for the parent process.)
708 $(LI The 32-bit Windows system directory.)
709 $(LI The 16-bit Windows system directory.)
710 $(LI The Windows directory.)
711 $(LI The directories listed in the PATH environment variable.)
714 // Run an executable called "prog" located in the current working
715 // directory:
716 auto pid = spawnProcess("./prog");
717 scope(exit) wait(pid);
718 // We can do something else while the program runs. The scope guard
719 // ensures that the process is waited for at the end of the scope.
722 // Run DMD on the file "myprog.d", specifying a few compiler switches:
723 auto dmdPid = spawnProcess(["dmd", "-O", "-release", "-inline", "myprog.d" ]);
724 if (wait(dmdPid) != 0)
725 writeln("Compilation failed!");
728 Environment_variables:
729 By default, the child process inherits the environment of the parent
730 process, along with any additional variables specified in the `env`
731 parameter. If the same variable exists in both the parent's environment
732 and in `env`, the latter takes precedence.
734 If the $(LREF Config.newEnv) flag is set in `config`, the child
735 process will $(I not) inherit the parent's environment. Its entire
736 environment will then be determined by `env`.
738 wait(spawnProcess("myapp", ["foo" : "bar"], Config.newEnv));
741 Standard_streams:
742 The optional arguments `stdin`, `stdout` and `stderr` may
743 be used to assign arbitrary $(REF File, std,stdio) objects as the standard
744 input, output and error streams, respectively, of the child process. The
745 former must be opened for reading, while the latter two must be opened for
746 writing. The default is for the child process to inherit the standard
747 streams of its parent.
749 // Run DMD on the file myprog.d, logging any error messages to a
750 // file named errors.log.
751 auto logFile = File("errors.log", "w");
752 auto pid = spawnProcess(["dmd", "myprog.d"],
753 std.stdio.stdin,
754 std.stdio.stdout,
755 logFile);
756 if (wait(pid) != 0)
757 writeln("Compilation failed. See errors.log for details.");
760 Note that if you pass a `File` object that is $(I not)
761 one of the standard input/output/error streams of the parent process,
762 that stream will by default be $(I closed) in the parent process when
763 this function returns. See the $(LREF Config) documentation below for
764 information about how to disable this behaviour.
766 Beware of buffering issues when passing `File` objects to
767 `spawnProcess`. The child process will inherit the low-level raw
768 read/write offset associated with the underlying file descriptor, but
769 it will not be aware of any buffered data. In cases where this matters
770 (e.g. when a file should be aligned before being passed on to the
771 child process), it may be a good idea to use unbuffered streams, or at
772 least ensure all relevant buffers are flushed.
774 Params:
775 args = An array which contains the program name as the zeroth element
776 and any command-line arguments in the following elements.
777 stdin = The standard input stream of the child process.
778 This can be any $(REF File, std,stdio) that is opened for reading.
779 By default the child process inherits the parent's input
780 stream.
781 stdout = The standard output stream of the child process.
782 This can be any $(REF File, std,stdio) that is opened for writing.
783 By default the child process inherits the parent's output stream.
784 stderr = The standard error stream of the child process.
785 This can be any $(REF File, std,stdio) that is opened for writing.
786 By default the child process inherits the parent's error stream.
787 env = Additional environment variables for the child process.
788 config = Flags that control process creation. See $(LREF Config)
789 for an overview of available flags.
790 workDir = The working directory for the new process.
791 By default the child process inherits the parent's working
792 directory.
794 Returns:
795 A $(LREF Pid) object that corresponds to the spawned process.
797 Throws:
798 $(LREF ProcessException) on failure to start the process.$(BR)
799 $(REF StdioException, std,stdio) on failure to pass one of the streams
800 to the child process (Windows only).$(BR)
801 $(REF RangeError, core,exception) if `args` is empty.
803 Pid spawnProcess(scope const(char[])[] args,
804 File stdin = std.stdio.stdin,
805 File stdout = std.stdio.stdout,
806 File stderr = std.stdio.stderr,
807 const string[string] env = null,
808 Config config = Config.none,
809 scope const char[] workDir = null)
810 @safe
812 version (Windows)
814 const commandLine = escapeShellArguments(args);
815 const program = args.length ? args[0] : null;
816 return spawnProcessWin(commandLine, program, stdin, stdout, stderr, env, config, workDir);
818 else version (Posix)
820 return spawnProcessPosix(args, stdin, stdout, stderr, env, config, workDir);
822 else
823 static assert(0);
826 /// ditto
827 Pid spawnProcess(scope const(char[])[] args,
828 const string[string] env,
829 Config config = Config.none,
830 scope const(char)[] workDir = null)
831 @trusted // TODO: Should be @safe
833 return spawnProcess(args,
834 std.stdio.stdin,
835 std.stdio.stdout,
836 std.stdio.stderr,
837 env,
838 config,
839 workDir);
842 /// ditto
843 Pid spawnProcess(scope const(char)[] program,
844 File stdin = std.stdio.stdin,
845 File stdout = std.stdio.stdout,
846 File stderr = std.stdio.stderr,
847 const string[string] env = null,
848 Config config = Config.none,
849 scope const(char)[] workDir = null)
850 @trusted
852 return spawnProcess((&program)[0 .. 1],
853 stdin, stdout, stderr, env, config, workDir);
856 /// ditto
857 Pid spawnProcess(scope const(char)[] program,
858 const string[string] env,
859 Config config = Config.none,
860 scope const(char)[] workDir = null)
861 @trusted
863 return spawnProcess((&program)[0 .. 1], env, config, workDir);
866 version (Posix) private enum InternalError : ubyte
868 noerror,
869 exec,
870 chdir,
871 getrlimit,
872 doubleFork,
873 malloc,
874 preExec,
878 Implementation of spawnProcess() for POSIX.
880 envz should be a zero-terminated array of zero-terminated strings
881 on the form "var=value".
883 version (Posix)
884 private Pid spawnProcessPosix(scope const(char[])[] args,
885 File stdin,
886 File stdout,
887 File stderr,
888 scope const string[string] env,
889 Config config,
890 scope const(char)[] workDir)
891 @trusted // TODO: Should be @safe
893 import core.exception : RangeError;
894 import std.algorithm.searching : any;
895 import std.conv : text;
896 import std.path : isDirSeparator;
897 import std.string : toStringz;
899 if (args.empty) throw new RangeError();
900 const(char)[] name = args[0];
901 if (!any!isDirSeparator(name))
903 name = searchPathFor(name);
904 if (name is null)
905 throw new ProcessException(text("Executable file not found: ", args[0]));
908 // Convert program name and arguments to C-style strings.
909 auto argz = new const(char)*[args.length+1];
910 argz[0] = toStringz(name);
911 foreach (i; 1 .. args.length) argz[i] = toStringz(args[i]);
912 argz[$-1] = null;
914 // Prepare environment.
915 auto envz = createEnv(env, !(config.flags & Config.Flags.newEnv));
917 // Open the working directory.
918 // We use open in the parent and fchdir in the child
919 // so that most errors (directory doesn't exist, not a directory)
920 // can be propagated as exceptions before forking.
921 int workDirFD = -1;
922 scope(exit) if (workDirFD >= 0) close(workDirFD);
923 if (workDir.length)
925 import core.sys.posix.fcntl : open, O_RDONLY, stat_t, fstat, S_ISDIR;
926 workDirFD = open(workDir.tempCString(), O_RDONLY);
927 if (workDirFD < 0)
928 throw ProcessException.newFromErrno("Failed to open working directory");
929 stat_t s;
930 if (fstat(workDirFD, &s) < 0)
931 throw ProcessException.newFromErrno("Failed to stat working directory");
932 if (!S_ISDIR(s.st_mode))
933 throw new ProcessException("Not a directory: " ~ cast(string) workDir);
936 static int getFD(ref File f) { return core.stdc.stdio.fileno(f.getFP()); }
938 // Get the file descriptors of the streams.
939 // These could potentially be invalid, but that is OK. If so, later calls
940 // to dup2() and close() will just silently fail without causing any harm.
941 auto stdinFD = getFD(stdin);
942 auto stdoutFD = getFD(stdout);
943 auto stderrFD = getFD(stderr);
945 // We don't have direct access to the errors that may happen in a child process.
946 // So we use this pipe to deliver them.
947 int[2] forkPipe;
948 if (core.sys.posix.unistd.pipe(forkPipe) == 0)
949 setCLOEXEC(forkPipe[1], true);
950 else
951 throw ProcessException.newFromErrno("Could not create pipe to check startup of child");
952 scope(exit) close(forkPipe[0]);
955 To create detached process, we use double fork technique
956 but we don't have a direct access to the second fork pid from the caller side thus use a pipe.
957 We also can't reuse forkPipe for that purpose
958 because we can't predict the order in which pid and possible error will be written
959 since the first and the second forks will run in parallel.
961 int[2] pidPipe;
962 if (config.flags & Config.Flags.detached)
964 if (core.sys.posix.unistd.pipe(pidPipe) != 0)
965 throw ProcessException.newFromErrno("Could not create pipe to get process pid");
966 setCLOEXEC(pidPipe[1], true);
968 scope(exit) if (config.flags & Config.Flags.detached) close(pidPipe[0]);
970 static void abortOnError(int forkPipeOut, InternalError errorType, int error) nothrow
972 core.sys.posix.unistd.write(forkPipeOut, &errorType, errorType.sizeof);
973 core.sys.posix.unistd.write(forkPipeOut, &error, error.sizeof);
974 close(forkPipeOut);
975 core.sys.posix.unistd._exit(1);
976 assert(0);
979 void closePipeWriteEnds()
981 close(forkPipe[1]);
982 if (config.flags & Config.Flags.detached)
983 close(pidPipe[1]);
986 auto id = core.sys.posix.unistd.fork();
987 if (id < 0)
989 closePipeWriteEnds();
990 throw ProcessException.newFromErrno("Failed to spawn new process");
993 void forkChild() nothrow @nogc
995 static import core.sys.posix.stdio;
997 // Child process
999 // no need for the read end of pipe on child side
1000 if (config.flags & Config.Flags.detached)
1001 close(pidPipe[0]);
1002 close(forkPipe[0]);
1003 immutable forkPipeOut = forkPipe[1];
1004 immutable pidPipeOut = pidPipe[1];
1006 // Set the working directory.
1007 if (workDirFD >= 0)
1009 if (fchdir(workDirFD) < 0)
1011 // Fail. It is dangerous to run a program
1012 // in an unexpected working directory.
1013 abortOnError(forkPipeOut, InternalError.chdir, .errno);
1015 close(workDirFD);
1018 void execProcess()
1020 // Redirect streams and close the old file descriptors.
1021 // In the case that stderr is redirected to stdout, we need
1022 // to backup the file descriptor since stdout may be redirected
1023 // as well.
1024 if (stderrFD == STDOUT_FILENO) stderrFD = dup(stderrFD);
1025 dup2(stdinFD, STDIN_FILENO);
1026 dup2(stdoutFD, STDOUT_FILENO);
1027 dup2(stderrFD, STDERR_FILENO);
1029 // Ensure that the standard streams aren't closed on execute, and
1030 // optionally close all other file descriptors.
1031 setCLOEXEC(STDIN_FILENO, false);
1032 setCLOEXEC(STDOUT_FILENO, false);
1033 setCLOEXEC(STDERR_FILENO, false);
1035 if (!(config.flags & Config.Flags.inheritFDs))
1037 // NOTE: malloc() and getrlimit() are not on the POSIX async
1038 // signal safe functions list, but practically this should
1039 // not be a problem. Java VM and CPython also use malloc()
1040 // in its own implementation via opendir().
1041 import core.stdc.stdlib : malloc;
1042 import core.sys.posix.poll : pollfd, poll, POLLNVAL;
1043 import core.sys.posix.sys.resource : rlimit, getrlimit, RLIMIT_NOFILE;
1045 // Get the maximum number of file descriptors that could be open.
1046 rlimit r;
1047 if (getrlimit(RLIMIT_NOFILE, &r) != 0)
1049 abortOnError(forkPipeOut, InternalError.getrlimit, .errno);
1051 immutable maxDescriptors = cast(int) r.rlim_cur;
1053 // The above, less stdin, stdout, and stderr
1054 immutable maxToClose = maxDescriptors - 3;
1056 // Call poll() to see which ones are actually open:
1057 auto pfds = cast(pollfd*) malloc(pollfd.sizeof * maxToClose);
1058 if (pfds is null)
1060 abortOnError(forkPipeOut, InternalError.malloc, .errno);
1062 foreach (i; 0 .. maxToClose)
1064 pfds[i].fd = i + 3;
1065 pfds[i].events = 0;
1066 pfds[i].revents = 0;
1068 if (poll(pfds, maxToClose, 0) >= 0)
1070 foreach (i; 0 .. maxToClose)
1072 // don't close pipe write end
1073 if (pfds[i].fd == forkPipeOut) continue;
1074 // POLLNVAL will be set if the file descriptor is invalid.
1075 if (!(pfds[i].revents & POLLNVAL)) close(pfds[i].fd);
1078 else
1080 // Fall back to closing everything.
1081 foreach (i; 3 .. maxDescriptors)
1083 if (i == forkPipeOut) continue;
1084 close(i);
1088 else // This is already done if we don't inherit descriptors.
1090 // Close the old file descriptors, unless they are
1091 // either of the standard streams.
1092 if (stdinFD > STDERR_FILENO) close(stdinFD);
1093 if (stdoutFD > STDERR_FILENO) close(stdoutFD);
1094 if (stderrFD > STDERR_FILENO) close(stderrFD);
1097 if (config.preExecFunction !is null)
1099 if (config.preExecFunction() != true)
1101 abortOnError(forkPipeOut, InternalError.preExec, .errno);
1105 // Execute program.
1106 core.sys.posix.unistd.execve(argz[0], argz.ptr, envz);
1108 // If execution fails, exit as quickly as possible.
1109 abortOnError(forkPipeOut, InternalError.exec, .errno);
1112 if (config.flags & Config.Flags.detached)
1114 auto secondFork = core.sys.posix.unistd.fork();
1115 if (secondFork == 0)
1117 close(pidPipeOut);
1118 execProcess();
1120 else if (secondFork == -1)
1122 auto secondForkErrno = .errno;
1123 close(pidPipeOut);
1124 abortOnError(forkPipeOut, InternalError.doubleFork, secondForkErrno);
1126 else
1128 core.sys.posix.unistd.write(pidPipeOut, &secondFork, pid_t.sizeof);
1129 close(pidPipeOut);
1130 close(forkPipeOut);
1131 _exit(0);
1134 else
1136 execProcess();
1140 if (id == 0)
1142 forkChild();
1143 assert(0);
1145 else
1147 closePipeWriteEnds();
1148 auto status = InternalError.noerror;
1149 auto readExecResult = core.sys.posix.unistd.read(forkPipe[0], &status, status.sizeof);
1150 // Save error number just in case if subsequent "waitpid" fails and overrides errno
1151 immutable lastError = .errno;
1153 if (config.flags & Config.Flags.detached)
1155 // Forked child exits right after creating second fork. So it should be safe to wait here.
1156 import core.sys.posix.sys.wait : waitpid;
1157 int waitResult;
1158 waitpid(id, &waitResult, 0);
1161 if (readExecResult == -1)
1162 throw ProcessException.newFromErrno(lastError, "Could not read from pipe to get child status");
1164 bool owned = true;
1165 if (status != InternalError.noerror)
1167 int error;
1168 readExecResult = read(forkPipe[0], &error, error.sizeof);
1169 string errorMsg;
1170 final switch (status)
1172 case InternalError.chdir:
1173 errorMsg = "Failed to set working directory";
1174 break;
1175 case InternalError.getrlimit:
1176 errorMsg = "getrlimit failed";
1177 break;
1178 case InternalError.exec:
1179 errorMsg = "Failed to execute '" ~ cast(string) name ~ "'";
1180 break;
1181 case InternalError.doubleFork:
1182 // Can happen only when starting detached process
1183 assert(config.flags & Config.Flags.detached);
1184 errorMsg = "Failed to fork twice";
1185 break;
1186 case InternalError.malloc:
1187 errorMsg = "Failed to allocate memory";
1188 break;
1189 case InternalError.preExec:
1190 errorMsg = "Failed to execute preExecFunction";
1191 break;
1192 case InternalError.noerror:
1193 assert(false);
1195 if (readExecResult == error.sizeof)
1196 throw ProcessException.newFromErrno(error, errorMsg);
1197 throw new ProcessException(errorMsg);
1199 else if (config.flags & Config.Flags.detached)
1201 owned = false;
1202 if (read(pidPipe[0], &id, id.sizeof) != id.sizeof)
1203 throw ProcessException.newFromErrno("Could not read from pipe to get detached process id");
1206 // Parent process: Close streams and return.
1207 if (!(config.flags & Config.Flags.retainStdin ) && stdinFD > STDERR_FILENO
1208 && stdinFD != getFD(std.stdio.stdin ))
1209 stdin.close();
1210 if (!(config.flags & Config.Flags.retainStdout) && stdoutFD > STDERR_FILENO
1211 && stdoutFD != getFD(std.stdio.stdout))
1212 stdout.close();
1213 if (!(config.flags & Config.Flags.retainStderr) && stderrFD > STDERR_FILENO
1214 && stderrFD != getFD(std.stdio.stderr))
1215 stderr.close();
1216 return new Pid(id, owned);
1220 version (Posix)
1221 @system unittest
1223 import std.concurrency : ownerTid, receiveTimeout, send, spawn;
1224 import std.datetime : seconds;
1226 sigset_t ss;
1227 sigemptyset(&ss);
1228 sigaddset(&ss, SIGINT);
1229 pthread_sigmask(SIG_BLOCK, &ss, null);
1231 Config config = {
1232 preExecFunction: () @trusted @nogc nothrow {
1233 // Reset signal handlers
1234 sigset_t ss;
1235 if (sigfillset(&ss) != 0)
1237 return false;
1239 if (sigprocmask(SIG_UNBLOCK, &ss, null) != 0)
1241 return false;
1243 return true;
1247 auto pid = spawnProcess(["sleep", "10000"],
1248 std.stdio.stdin,
1249 std.stdio.stdout,
1250 std.stdio.stderr,
1251 null,
1252 config,
1253 null);
1254 scope(failure)
1256 kill(pid, SIGKILL);
1257 wait(pid);
1260 // kill the spawned process with SIGINT
1261 // and send its return code
1262 spawn((shared Pid pid) {
1263 auto p = cast() pid;
1264 kill(p, SIGINT);
1265 auto code = wait(p);
1266 assert(code < 0);
1267 send(ownerTid, code);
1268 }, cast(shared) pid);
1270 auto received = receiveTimeout(3.seconds, (int) {});
1271 assert(received);
1275 Implementation of spawnProcess() for Windows.
1277 commandLine must contain the entire command line, properly
1278 quoted/escaped as required by CreateProcessW().
1280 envz must be a pointer to a block of UTF-16 characters on the form
1281 "var1=value1\0var2=value2\0...varN=valueN\0\0".
1283 version (Windows)
1284 private Pid spawnProcessWin(scope const(char)[] commandLine,
1285 scope const(char)[] program,
1286 File stdin,
1287 File stdout,
1288 File stderr,
1289 scope const string[string] env,
1290 Config config,
1291 scope const(char)[] workDir)
1292 @trusted
1294 import core.exception : RangeError;
1295 import std.conv : text;
1297 if (commandLine.empty) throw new RangeError("Command line is empty");
1299 // Prepare environment.
1300 auto envz = createEnv(env, !(config.flags & Config.Flags.newEnv));
1302 // Startup info for CreateProcessW().
1303 STARTUPINFO_W startinfo;
1304 startinfo.cb = startinfo.sizeof;
1305 static int getFD(ref File f) { return f.isOpen ? f.fileno : -1; }
1307 // Extract file descriptors and HANDLEs from the streams and make the
1308 // handles inheritable.
1309 static void prepareStream(ref File file, DWORD stdHandle, string which,
1310 out int fileDescriptor, out HANDLE handle)
1312 enum _NO_CONSOLE_FILENO = cast(HANDLE)-2;
1313 fileDescriptor = getFD(file);
1314 handle = null;
1315 if (fileDescriptor >= 0)
1316 handle = file.windowsHandle;
1317 // Windows GUI applications have a fd but not a valid Windows HANDLE.
1318 if (handle is null || handle == INVALID_HANDLE_VALUE || handle == _NO_CONSOLE_FILENO)
1319 handle = GetStdHandle(stdHandle);
1321 DWORD dwFlags;
1322 if (GetHandleInformation(handle, &dwFlags))
1324 if (!(dwFlags & HANDLE_FLAG_INHERIT))
1326 if (!SetHandleInformation(handle,
1327 HANDLE_FLAG_INHERIT,
1328 HANDLE_FLAG_INHERIT))
1330 throw new StdioException(
1331 "Failed to make "~which~" stream inheritable by child process ("
1332 ~generateSysErrorMsg() ~ ')',
1338 int stdinFD = -1, stdoutFD = -1, stderrFD = -1;
1339 prepareStream(stdin, STD_INPUT_HANDLE, "stdin" , stdinFD, startinfo.hStdInput );
1340 prepareStream(stdout, STD_OUTPUT_HANDLE, "stdout", stdoutFD, startinfo.hStdOutput);
1341 prepareStream(stderr, STD_ERROR_HANDLE, "stderr", stderrFD, startinfo.hStdError );
1343 if ((startinfo.hStdInput != null && startinfo.hStdInput != INVALID_HANDLE_VALUE)
1344 || (startinfo.hStdOutput != null && startinfo.hStdOutput != INVALID_HANDLE_VALUE)
1345 || (startinfo.hStdError != null && startinfo.hStdError != INVALID_HANDLE_VALUE))
1346 startinfo.dwFlags = STARTF_USESTDHANDLES;
1348 // Create process.
1349 PROCESS_INFORMATION pi;
1350 DWORD dwCreationFlags =
1351 CREATE_UNICODE_ENVIRONMENT |
1352 ((config.flags & Config.Flags.suppressConsole) ? CREATE_NO_WINDOW : 0);
1353 // workaround until https://issues.dlang.org/show_bug.cgi?id=14696 is fixed
1354 auto pworkDir = workDir.tempCStringW();
1355 if (!CreateProcessW(null, commandLine.tempCStringW().buffPtr,
1356 null, null, true, dwCreationFlags,
1357 envz, workDir.length ? pworkDir : null, &startinfo, &pi))
1358 throw ProcessException.newFromLastError("Failed to spawn process \"" ~ cast(string) program ~ '"');
1360 // figure out if we should close any of the streams
1361 if (!(config.flags & Config.Flags.retainStdin ) && stdinFD > STDERR_FILENO
1362 && stdinFD != getFD(std.stdio.stdin ))
1363 stdin.close();
1364 if (!(config.flags & Config.Flags.retainStdout) && stdoutFD > STDERR_FILENO
1365 && stdoutFD != getFD(std.stdio.stdout))
1366 stdout.close();
1367 if (!(config.flags & Config.Flags.retainStderr) && stderrFD > STDERR_FILENO
1368 && stderrFD != getFD(std.stdio.stderr))
1369 stderr.close();
1371 // close the thread handle in the process info structure
1372 CloseHandle(pi.hThread);
1373 if (config.flags & Config.Flags.detached)
1375 CloseHandle(pi.hProcess);
1376 return new Pid(pi.dwProcessId);
1378 return new Pid(pi.dwProcessId, pi.hProcess);
1381 // Converts childEnv to a zero-terminated array of zero-terminated strings
1382 // on the form "name=value", optionally adding those of the current process'
1383 // environment strings that are not present in childEnv. If the parent's
1384 // environment should be inherited without modification, this function
1385 // returns environ directly.
1386 version (Posix)
1387 private const(char*)* createEnv(const string[string] childEnv,
1388 bool mergeWithParentEnv)
1390 // Determine the number of strings in the parent's environment.
1391 int parentEnvLength = 0;
1392 auto environ = getEnvironPtr;
1393 if (mergeWithParentEnv)
1395 if (childEnv.length == 0) return environ;
1396 while (environ[parentEnvLength] != null) ++parentEnvLength;
1399 // Convert the "new" variables to C-style strings.
1400 auto envz = new const(char)*[parentEnvLength + childEnv.length + 1];
1401 int pos = 0;
1402 foreach (var, val; childEnv)
1403 envz[pos++] = (var~'='~val~'\0').ptr;
1405 // Add the parent's environment.
1406 foreach (environStr; environ[0 .. parentEnvLength])
1408 int eqPos = 0;
1409 while (environStr[eqPos] != '=' && environStr[eqPos] != '\0') ++eqPos;
1410 if (environStr[eqPos] != '=') continue;
1411 auto var = environStr[0 .. eqPos];
1412 if (var in childEnv) continue;
1413 envz[pos++] = environStr;
1415 envz[pos] = null;
1416 return envz.ptr;
1419 version (Posix) @system unittest
1421 auto e1 = createEnv(null, false);
1422 assert(e1 != null && *e1 == null);
1424 auto e2 = createEnv(null, true);
1425 assert(e2 != null);
1426 int i = 0;
1427 auto environ = getEnvironPtr;
1428 for (; environ[i] != null; ++i)
1430 assert(e2[i] != null);
1431 import core.stdc.string : strcmp;
1432 assert(strcmp(e2[i], environ[i]) == 0);
1434 assert(e2[i] == null);
1436 auto e3 = createEnv(["foo" : "bar", "hello" : "world"], false);
1437 assert(e3 != null && e3[0] != null && e3[1] != null && e3[2] == null);
1438 assert((e3[0][0 .. 8] == "foo=bar\0" && e3[1][0 .. 12] == "hello=world\0")
1439 || (e3[0][0 .. 12] == "hello=world\0" && e3[1][0 .. 8] == "foo=bar\0"));
1443 // Converts childEnv to a Windows environment block, which is on the form
1444 // "name1=value1\0name2=value2\0...nameN=valueN\0\0", optionally adding
1445 // those of the current process' environment strings that are not present
1446 // in childEnv. Returns null if the parent's environment should be
1447 // inherited without modification, as this is what is expected by
1448 // CreateProcess().
1449 version (Windows)
1450 private LPVOID createEnv(const string[string] childEnv,
1451 bool mergeWithParentEnv)
1453 if (mergeWithParentEnv && childEnv.length == 0) return null;
1454 import std.array : appender;
1455 import std.uni : toUpper;
1456 auto envz = appender!(wchar[])();
1457 void put(string var, string val)
1459 envz.put(var);
1460 envz.put('=');
1461 envz.put(val);
1462 envz.put(cast(wchar) '\0');
1465 // Add the variables in childEnv, removing them from parentEnv
1466 // if they exist there too.
1467 auto parentEnv = mergeWithParentEnv ? environment.toAA() : null;
1468 foreach (k, v; childEnv)
1470 auto uk = toUpper(k);
1471 put(uk, v);
1472 if (uk in parentEnv) parentEnv.remove(uk);
1475 // Add remaining parent environment variables.
1476 foreach (k, v; parentEnv) put(k, v);
1478 // Two final zeros are needed in case there aren't any environment vars,
1479 // and the last one does no harm when there are.
1480 envz.put("\0\0"w);
1481 return envz.data.ptr;
1484 version (Windows) @system unittest
1486 assert(createEnv(null, true) == null);
1487 assert((cast(wchar*) createEnv(null, false))[0 .. 2] == "\0\0"w);
1488 auto e1 = (cast(wchar*) createEnv(["foo":"bar", "ab":"c"], false))[0 .. 14];
1489 assert(e1 == "FOO=bar\0AB=c\0\0"w || e1 == "AB=c\0FOO=bar\0\0"w);
1492 // Searches the PATH variable for the given executable file,
1493 // (checking that it is in fact executable).
1494 version (Posix)
1495 package(std) string searchPathFor(scope const(char)[] executable)
1496 @safe
1498 import std.algorithm.iteration : splitter;
1499 import std.conv : to;
1500 import std.path : chainPath;
1502 typeof(return) result;
1504 environment.getImpl("PATH",
1505 (scope const(char)[] path)
1507 if (!path)
1508 return;
1510 foreach (dir; splitter(path, ":"))
1512 auto execPath = chainPath(dir, executable);
1513 if (isExecutable(execPath))
1515 result = execPath.to!(typeof(result));
1516 return;
1521 return result;
1524 // Checks whether the file exists and can be executed by the
1525 // current user.
1526 version (Posix)
1527 private bool isExecutable(R)(R path) @trusted nothrow @nogc
1528 if (isSomeFiniteCharInputRange!R)
1530 return (access(path.tempCString(), X_OK) == 0);
1533 version (Posix) @safe unittest
1535 import std.algorithm;
1536 auto lsPath = searchPathFor("ls");
1537 assert(!lsPath.empty);
1538 assert(lsPath[0] == '/');
1539 assert(lsPath.endsWith("ls"));
1540 auto unlikely = searchPathFor("lkmqwpoialhggyaofijadsohufoiqezm");
1541 assert(unlikely is null, "Are you kidding me?");
1544 // Sets or unsets the FD_CLOEXEC flag on the given file descriptor.
1545 version (Posix)
1546 private void setCLOEXEC(int fd, bool on) nothrow @nogc
1548 import core.sys.posix.fcntl : fcntl, F_GETFD, FD_CLOEXEC, F_SETFD;
1549 auto flags = fcntl(fd, F_GETFD);
1550 if (flags >= 0)
1552 if (on) flags |= FD_CLOEXEC;
1553 else flags &= ~(cast(typeof(flags)) FD_CLOEXEC);
1554 flags = fcntl(fd, F_SETFD, flags);
1556 assert(flags != -1 || .errno == EBADF);
1559 @system unittest // Command line arguments in spawnProcess().
1561 version (Windows) TestScript prog =
1562 "if not [%~1]==[foo] ( exit 1 )
1563 if not [%~2]==[bar] ( exit 2 )
1564 exit 0";
1565 else version (Posix) TestScript prog =
1566 `if test "$1" != "foo"; then exit 1; fi
1567 if test "$2" != "bar"; then exit 2; fi
1568 exit 0`;
1569 assert(wait(spawnProcess(prog.path)) == 1);
1570 assert(wait(spawnProcess([prog.path])) == 1);
1571 assert(wait(spawnProcess([prog.path, "foo"])) == 2);
1572 assert(wait(spawnProcess([prog.path, "foo", "baz"])) == 2);
1573 assert(wait(spawnProcess([prog.path, "foo", "bar"])) == 0);
1576 // test that file descriptors are correctly closed / left open.
1577 // ideally this would be done by the child process making libc
1578 // calls, but we make do...
1579 version (Posix) @system unittest
1581 import core.stdc.errno : errno;
1582 import core.sys.posix.fcntl : open, O_RDONLY;
1583 import core.sys.posix.unistd : close;
1584 import std.algorithm.searching : canFind, findSplitBefore;
1585 import std.array : split;
1586 import std.conv : to;
1587 static import std.file;
1588 import std.functional : reverseArgs;
1589 import std.path : buildPath;
1591 auto directory = uniqueTempPath();
1592 std.file.mkdir(directory);
1593 scope(exit) std.file.rmdirRecurse(directory);
1594 auto path = buildPath(directory, "tmp");
1595 std.file.write(path, null);
1596 errno = 0;
1597 auto fd = open(path.tempCString, O_RDONLY);
1598 if (fd == -1)
1600 import core.stdc.string : strerror;
1601 import std.stdio : stderr;
1602 import std.string : fromStringz;
1604 // For the CI logs
1605 stderr.writefln("%s: could not open '%s': %s",
1606 __FUNCTION__, path, strerror(errno).fromStringz);
1607 // TODO: should we retry here instead?
1608 return;
1610 scope(exit) close(fd);
1612 // command >&2 (or any other number) checks whethether that number
1613 // file descriptor is open.
1614 // Can't use this for arbitrary descriptors as many shells only support
1615 // single digit fds.
1616 TestScript testDefaults = `command >&0 && command >&1 && command >&2`;
1617 assert(execute(testDefaults.path).status == 0);
1618 assert(execute(testDefaults.path, null, Config.inheritFDs).status == 0);
1620 // Try a few different methods to check whether there are any
1621 // incorrectly-open files.
1622 void testFDs()
1624 // try /proc/<pid>/fd/ on linux
1625 version (linux)
1627 TestScript proc = "ls /proc/$$/fd";
1628 auto procRes = execute(proc.path, null);
1629 if (procRes.status == 0)
1631 auto fdStr = fd.to!string;
1632 assert(!procRes.output.split.canFind(fdStr));
1633 assert(execute(proc.path, null, Config.inheritFDs)
1634 .output.split.canFind(fdStr));
1635 return;
1639 // try fuser (might sometimes need permissions)
1640 TestScript fuser = "echo $$ && fuser -f " ~ path;
1641 auto fuserRes = execute(fuser.path, null);
1642 if (fuserRes.status == 0)
1644 assert(!reverseArgs!canFind(fuserRes
1645 .output.findSplitBefore("\n").expand));
1646 assert(reverseArgs!canFind(execute(fuser.path, null, Config.inheritFDs)
1647 .output.findSplitBefore("\n").expand));
1648 return;
1651 // last resort, try lsof (not available on all Posix)
1652 TestScript lsof = "lsof -p$$";
1653 auto lsofRes = execute(lsof.path, null);
1654 if (lsofRes.status == 0)
1656 assert(!lsofRes.output.canFind(path));
1657 auto lsofOut = execute(lsof.path, null, Config.inheritFDs).output;
1658 if (!lsofOut.canFind(path))
1660 std.stdio.stderr.writeln(__FILE__, ':', __LINE__,
1661 ": Warning: unexpected lsof output:", lsofOut);
1663 return;
1666 std.stdio.stderr.writeln(__FILE__, ':', __LINE__,
1667 ": Warning: Couldn't find any way to check open files");
1669 testFDs();
1672 @system unittest // Environment variables in spawnProcess().
1674 // We really should use set /a on Windows, but Wine doesn't support it.
1675 version (Windows) TestScript envProg =
1676 `if [%STD_PROCESS_UNITTEST1%] == [1] (
1677 if [%STD_PROCESS_UNITTEST2%] == [2] (exit 3)
1678 exit 1
1680 if [%STD_PROCESS_UNITTEST1%] == [4] (
1681 if [%STD_PROCESS_UNITTEST2%] == [2] (exit 6)
1682 exit 4
1684 if [%STD_PROCESS_UNITTEST2%] == [2] (exit 2)
1685 exit 0`;
1686 version (Posix) TestScript envProg =
1687 `if test "$std_process_unittest1" = ""; then
1688 std_process_unittest1=0
1690 if test "$std_process_unittest2" = ""; then
1691 std_process_unittest2=0
1693 exit $(($std_process_unittest1+$std_process_unittest2))`;
1695 environment.remove("std_process_unittest1"); // Just in case.
1696 environment.remove("std_process_unittest2");
1697 assert(wait(spawnProcess(envProg.path)) == 0);
1698 assert(wait(spawnProcess(envProg.path, null, Config.newEnv)) == 0);
1700 environment["std_process_unittest1"] = "1";
1701 assert(wait(spawnProcess(envProg.path)) == 1);
1702 assert(wait(spawnProcess(envProg.path, null, Config.newEnv)) == 0);
1704 auto env = ["std_process_unittest2" : "2"];
1705 assert(wait(spawnProcess(envProg.path, env)) == 3);
1706 assert(wait(spawnProcess(envProg.path, env, Config.newEnv)) == 2);
1708 env["std_process_unittest1"] = "4";
1709 assert(wait(spawnProcess(envProg.path, env)) == 6);
1710 assert(wait(spawnProcess(envProg.path, env, Config.newEnv)) == 6);
1712 environment.remove("std_process_unittest1");
1713 assert(wait(spawnProcess(envProg.path, env)) == 6);
1714 assert(wait(spawnProcess(envProg.path, env, Config.newEnv)) == 6);
1717 @system unittest // Stream redirection in spawnProcess().
1719 import std.path : buildPath;
1720 import std.string;
1721 version (Windows) TestScript prog =
1722 "set /p INPUT=
1723 echo %INPUT% output %~1
1724 echo %INPUT% error %~2 1>&2
1725 echo done > %3";
1726 else version (Posix) TestScript prog =
1727 "read INPUT
1728 echo $INPUT output $1
1729 echo $INPUT error $2 >&2
1730 echo done > \"$3\"";
1732 // Pipes
1733 void testPipes(Config config)
1735 import std.file : tempDir, exists, remove;
1736 import std.uuid : randomUUID;
1737 import std.exception : collectException;
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 : newline;
1759 import std.file : tempDir, exists, remove, readText, write;
1760 import std.uuid : randomUUID;
1761 import std.exception : collectException;
1762 auto pathi = buildPath(tempDir(), randomUUID().toString());
1763 auto patho = buildPath(tempDir(), randomUUID().toString());
1764 auto pathe = buildPath(tempDir(), randomUUID().toString());
1765 write(pathi, "INPUT" ~ newline);
1766 auto filei = File(pathi, "r");
1767 auto fileo = File(patho, "w");
1768 auto filee = File(pathe, "w");
1769 auto done = buildPath(tempDir(), randomUUID().toString());
1770 auto pid = spawnProcess([prog.path, "bar", "baz", done], filei, fileo, filee, null, config);
1771 if (config.flags & Config.Flags.detached)
1772 while (!done.exists) Thread.sleep(10.msecs);
1773 else
1774 wait(pid);
1775 assert(readText(patho).chomp() == "INPUT output bar");
1776 assert(readText(pathe).chomp().stripRight() == "INPUT error baz");
1777 while (remove(pathi).collectException) Thread.sleep(10.msecs);
1778 while (remove(patho).collectException) Thread.sleep(10.msecs);
1779 while (remove(pathe).collectException) Thread.sleep(10.msecs);
1780 while (remove(done).collectException) Thread.sleep(10.msecs);
1783 testPipes(Config.none);
1784 testFiles(Config.none);
1785 testPipes(Config.detached);
1786 testFiles(Config.detached);
1789 @system unittest // Error handling in spawnProcess()
1791 import std.algorithm.searching : canFind;
1792 import std.exception : assertThrown, collectExceptionMsg;
1794 static void testNotFoundException(string program)
1796 assert(collectExceptionMsg!ProcessException(spawnProcess(program)).canFind(program));
1797 assert(collectExceptionMsg!ProcessException(spawnProcess(program, null, Config.detached)).canFind(program));
1799 testNotFoundException("ewrgiuhrifuheiohnmnvqweoijwf");
1800 testNotFoundException("./rgiuhrifuheiohnmnvqweoijwf");
1802 // can't execute malformed file with executable permissions
1803 version (Posix)
1805 import std.path : buildPath;
1806 import std.file : remove, write, setAttributes, tempDir;
1807 import core.sys.posix.sys.stat : S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IXGRP, S_IROTH, S_IXOTH;
1808 import std.conv : to;
1809 string deleteme = buildPath(tempDir(), "deleteme.std.process.unittest.pid") ~ to!string(thisProcessID);
1810 write(deleteme, "");
1811 scope(exit) remove(deleteme);
1812 setAttributes(deleteme, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
1813 assertThrown!ProcessException(spawnProcess(deleteme));
1814 assertThrown!ProcessException(spawnProcess(deleteme, null, Config.detached));
1818 @system unittest // Specifying a working directory.
1820 import std.path;
1821 import std.file;
1822 TestScript prog = "echo foo>bar";
1824 auto directory = uniqueTempPath();
1825 mkdir(directory);
1826 scope(exit) rmdirRecurse(directory);
1828 auto pid = spawnProcess([prog.path], null, Config.none, directory);
1829 wait(pid);
1830 assert(exists(buildPath(directory, "bar")));
1833 @system unittest // Specifying a bad working directory.
1835 import std.exception : assertThrown;
1836 import std.file;
1837 TestScript prog = "echo";
1839 auto directory = uniqueTempPath();
1840 assertThrown!ProcessException(spawnProcess([prog.path], null, Config.none, directory));
1841 assertThrown!ProcessException(spawnProcess([prog.path], null, Config.detached, directory));
1843 std.file.write(directory, "foo");
1844 scope(exit) remove(directory);
1845 assertThrown!ProcessException(spawnProcess([prog.path], null, Config.none, directory));
1846 assertThrown!ProcessException(spawnProcess([prog.path], null, Config.detached, directory));
1848 // can't run in directory if user does not have search permission on this directory
1849 version (Posix)
1851 if (core.sys.posix.unistd.getuid() != 0)
1853 import core.sys.posix.sys.stat : S_IRUSR;
1854 auto directoryNoSearch = uniqueTempPath();
1855 mkdir(directoryNoSearch);
1856 scope(exit) rmdirRecurse(directoryNoSearch);
1857 setAttributes(directoryNoSearch, S_IRUSR);
1858 assertThrown!ProcessException(spawnProcess(prog.path, null, Config.none, directoryNoSearch));
1859 assertThrown!ProcessException(spawnProcess(prog.path, null, Config.detached, directoryNoSearch));
1864 @system unittest // Specifying empty working directory.
1866 TestScript prog = "";
1868 string directory = "";
1869 assert(directory.ptr && !directory.length);
1870 spawnProcess([prog.path], null, Config.none, directory).wait();
1873 // Reopening the standard streams (https://issues.dlang.org/show_bug.cgi?id=13258)
1874 @system unittest
1876 import std.string;
1877 import std.file;
1878 void fun()
1880 spawnShell("echo foo").wait();
1881 spawnShell("echo bar").wait();
1884 auto tmpFile = uniqueTempPath();
1885 scope(exit) if (exists(tmpFile)) remove(tmpFile);
1888 auto oldOut = std.stdio.stdout;
1889 scope(exit) std.stdio.stdout = oldOut;
1891 std.stdio.stdout = File(tmpFile, "w");
1892 fun();
1893 std.stdio.stdout.close();
1896 auto lines = readText(tmpFile).splitLines();
1897 assert(lines == ["foo", "bar"]);
1900 // MSVCRT workaround (https://issues.dlang.org/show_bug.cgi?id=14422)
1901 version (Windows)
1902 @system unittest
1904 auto fn = uniqueTempPath();
1905 scope(exit) if (exists(fn)) remove(fn);
1906 std.file.write(fn, "AAAAAAAAAA");
1908 auto f = File(fn, "a");
1909 spawnProcess(["cmd", "/c", "echo BBBBB"], std.stdio.stdin, f).wait();
1911 auto data = readText(fn);
1912 assert(data == "AAAAAAAAAABBBBB\r\n", data);
1915 // https://issues.dlang.org/show_bug.cgi?id=20765
1916 // Test that running processes with relative path works in conjunction
1917 // with indicating a workDir.
1918 version (Posix) @system unittest
1920 import std.file : mkdir, write, setAttributes, rmdirRecurse;
1921 import std.conv : octal;
1923 auto dir = uniqueTempPath();
1924 mkdir(dir);
1925 scope(exit) rmdirRecurse(dir);
1926 write(dir ~ "/program", "#!/bin/sh\necho Hello");
1927 setAttributes(dir ~ "/program", octal!700);
1929 assert(execute(["./program"], null, Config.none, size_t.max, dir).output == "Hello\n");
1933 A variation on $(LREF spawnProcess) that runs the given _command through
1934 the current user's preferred _command interpreter (aka. shell).
1936 The string `command` is passed verbatim to the shell, and is therefore
1937 subject to its rules about _command structure, argument/filename quoting
1938 and escaping of special characters.
1939 The path to the shell executable defaults to $(LREF nativeShell).
1941 In all other respects this function works just like `spawnProcess`.
1942 Please refer to the $(LREF spawnProcess) documentation for descriptions
1943 of the other function parameters, the return value and any exceptions
1944 that may be thrown.
1946 // Run the command/program "foo" on the file named "my file.txt", and
1947 // redirect its output into foo.log.
1948 auto pid = spawnShell(`foo "my file.txt" > foo.log`);
1949 wait(pid);
1952 See_also:
1953 $(LREF escapeShellCommand), which may be helpful in constructing a
1954 properly quoted and escaped shell _command line for the current platform.
1956 Pid spawnShell(scope const(char)[] command,
1957 File stdin = std.stdio.stdin,
1958 File stdout = std.stdio.stdout,
1959 File stderr = std.stdio.stderr,
1960 scope const string[string] env = null,
1961 Config config = Config.none,
1962 scope const(char)[] workDir = null,
1963 scope string shellPath = nativeShell)
1964 @trusted // See reason below
1966 version (Windows)
1968 // CMD does not parse its arguments like other programs.
1969 // It does not use CommandLineToArgvW.
1970 // Instead, it treats the first and last quote specially.
1971 // See CMD.EXE /? for details.
1972 const commandLine = escapeShellFileName(shellPath)
1973 ~ ` ` ~ shellSwitch ~ ` "` ~ command ~ `"`;
1974 return spawnProcessWin(commandLine, shellPath, stdin, stdout, stderr, env, config, workDir);
1976 else version (Posix)
1978 const(char)[][3] args;
1979 args[0] = shellPath;
1980 args[1] = shellSwitch;
1981 args[2] = command;
1982 /* The passing of args converts the static array, which is initialized with `scope` pointers,
1983 * to a dynamic array, which is also a scope parameter. So, it is a scope pointer to a
1984 * scope pointer, which although is safely used here, D doesn't allow transitive scope.
1985 * See https://github.com/dlang/dmd/pull/10951
1987 return spawnProcessPosix(args, stdin, stdout, stderr, env, config, workDir);
1989 else
1990 static assert(0);
1993 /// ditto
1994 Pid spawnShell(scope const(char)[] command,
1995 scope const string[string] env,
1996 Config config = Config.none,
1997 scope const(char)[] workDir = null,
1998 scope string shellPath = nativeShell)
1999 @trusted // TODO: Should be @safe
2001 return spawnShell(command,
2002 std.stdio.stdin,
2003 std.stdio.stdout,
2004 std.stdio.stderr,
2005 env,
2006 config,
2007 workDir,
2008 shellPath);
2011 @system unittest
2013 version (Windows)
2014 auto cmd = "echo %FOO%";
2015 else version (Posix)
2016 auto cmd = "echo $foo";
2017 import std.file;
2018 auto tmpFile = uniqueTempPath();
2019 scope(exit) if (exists(tmpFile)) remove(tmpFile);
2020 auto redir = "> \""~tmpFile~'"';
2021 auto env = ["foo" : "bar"];
2022 assert(wait(spawnShell(cmd~redir, env)) == 0);
2023 auto f = File(tmpFile, "a");
2024 version (CRuntime_Microsoft) f.seek(0, SEEK_END); // MSVCRT probably seeks to the end when writing, not before
2025 assert(wait(spawnShell(cmd, std.stdio.stdin, f, std.stdio.stderr, env)) == 0);
2026 f.close();
2027 auto output = std.file.readText(tmpFile);
2028 assert(output == "bar\nbar\n" || output == "bar\r\nbar\r\n");
2031 version (Windows)
2032 @system unittest
2034 import std.string;
2035 import std.conv : text;
2036 TestScript prog = "echo %0 %*";
2037 auto outputFn = uniqueTempPath();
2038 scope(exit) if (exists(outputFn)) remove(outputFn);
2039 auto args = [`a b c`, `a\b\c\`, `a"b"c"`];
2040 auto result = executeShell(
2041 escapeShellCommand([prog.path] ~ args)
2042 ~ " > " ~
2043 escapeShellFileName(outputFn));
2044 assert(result.status == 0);
2045 auto args2 = outputFn.readText().strip().parseCommandLine()[1..$];
2046 assert(args == args2, text(args2));
2051 Options that control the behaviour of process creation functions in this
2052 module. Most options only apply to $(LREF spawnProcess) and
2053 $(LREF spawnShell).
2055 Example:
2057 auto logFile = File("myapp_error.log", "w");
2059 // Start program, suppressing the console window (Windows only),
2060 // redirect its error stream to logFile, and leave logFile open
2061 // in the parent process as well.
2062 auto pid = spawnProcess("myapp", stdin, stdout, logFile,
2063 Config.retainStderr | Config.suppressConsole);
2064 scope(exit)
2066 auto exitCode = wait(pid);
2067 logFile.writeln("myapp exited with code ", exitCode);
2068 logFile.close();
2072 struct Config
2075 Flag options.
2076 Use bitwise OR to combine flags.
2078 enum Flags
2080 none = 0,
2083 By default, the child process inherits the parent's environment,
2084 and any environment variables passed to $(LREF spawnProcess) will
2085 be added to it. If this flag is set, the only variables in the
2086 child process' environment will be those given to spawnProcess.
2088 newEnv = 1,
2091 Unless the child process inherits the standard input/output/error
2092 streams of its parent, one almost always wants the streams closed
2093 in the parent when $(LREF spawnProcess) returns. Therefore, by
2094 default, this is done. If this is not desirable, pass any of these
2095 options to spawnProcess.
2097 retainStdin = 2,
2098 retainStdout = 4, /// ditto
2099 retainStderr = 8, /// ditto
2102 On Windows, if the child process is a console application, this
2103 flag will prevent the creation of a console window. Otherwise,
2104 it will be ignored. On POSIX, `suppressConsole` has no effect.
2106 suppressConsole = 16,
2109 On POSIX, open $(LINK2 http://en.wikipedia.org/wiki/File_descriptor,file descriptors)
2110 are by default inherited by the child process. As this may lead
2111 to subtle bugs when pipes or multiple threads are involved,
2112 $(LREF spawnProcess) ensures that all file descriptors except the
2113 ones that correspond to standard input/output/error are closed
2114 in the child process when it starts. Use `inheritFDs` to prevent
2115 this.
2117 On Windows, this option has no effect, and any handles which have been
2118 explicitly marked as inheritable will always be inherited by the child
2119 process.
2121 inheritFDs = 32,
2124 Spawn process in detached state. This removes the need in calling
2125 $(LREF wait) to clean up the process resources.
2127 Note:
2128 Calling $(LREF wait) or $(LREF kill) with the resulting `Pid` is invalid.
2130 detached = 64,
2133 By default, the $(LREF execute) and $(LREF executeShell) functions
2134 will capture child processes' both stdout and stderr. This can be
2135 undesirable if the standard output is to be processed or otherwise
2136 used by the invoking program, as `execute`'s result would then
2137 contain a mix of output and warning/error messages.
2139 Specify this flag when calling `execute` or `executeShell` to
2140 cause invoked processes' stderr stream to be sent to $(REF stderr,
2141 std,stdio), and only capture and return standard output.
2143 This flag has no effect on $(LREF spawnProcess) or $(LREF spawnShell).
2145 stderrPassThrough = 128,
2147 Flags flags; /// ditto
2150 For backwards compatibility, and cases when only flags need to
2151 be specified in the `Config`, these allow building `Config`
2152 instances using flag names only.
2154 enum Config none = Config.init;
2155 enum Config newEnv = Config(Flags.newEnv); /// ditto
2156 enum Config retainStdin = Config(Flags.retainStdin); /// ditto
2157 enum Config retainStdout = Config(Flags.retainStdout); /// ditto
2158 enum Config retainStderr = Config(Flags.retainStderr); /// ditto
2159 enum Config suppressConsole = Config(Flags.suppressConsole); /// ditto
2160 enum Config inheritFDs = Config(Flags.inheritFDs); /// ditto
2161 enum Config detached = Config(Flags.detached); /// ditto
2162 enum Config stderrPassThrough = Config(Flags.stderrPassThrough); /// ditto
2163 Config opUnary(string op)()
2164 if (is(typeof(mixin(op ~ q{flags}))))
2166 return Config(mixin(op ~ q{flags}));
2167 } /// ditto
2168 Config opBinary(string op)(Config other)
2169 if (is(typeof(mixin(q{flags} ~ op ~ q{other.flags}))))
2171 return Config(mixin(q{flags} ~ op ~ q{other.flags}));
2172 } /// ditto
2173 Config opOpAssign(string op)(Config other)
2174 if (is(typeof(mixin(q{flags} ~ op ~ q{=other.flags}))))
2176 return Config(mixin(q{flags} ~ op ~ q{=other.flags}));
2177 } /// ditto
2179 version (StdDdoc)
2182 A function that is called before `exec` in $(LREF spawnProcess).
2183 It returns `true` if succeeded and otherwise returns `false`.
2185 $(RED Warning:
2186 Please note that the code in this function must only use
2187 async-signal-safe functions.)
2189 On Windows, this member is not available.
2191 bool function() nothrow @nogc @safe preExecFunction;
2193 else version (Posix)
2195 bool function() nothrow @nogc @safe preExecFunction;
2199 // https://issues.dlang.org/show_bug.cgi?id=22125
2200 @safe unittest
2202 Config c = Config.retainStdin;
2203 c |= Config.retainStdout;
2204 c |= Config.retainStderr;
2205 c &= ~Config.retainStderr;
2206 assert(c == (Config.retainStdin | Config.retainStdout));
2209 /// A handle that corresponds to a spawned process.
2210 final class Pid
2213 The process ID number.
2215 This is a number that uniquely identifies the process on the operating
2216 system, for at least as long as the process is running. Once $(LREF wait)
2217 has been called on the $(LREF Pid), this method will return an
2218 invalid (negative) process ID.
2220 @property int processID() const @safe pure nothrow
2222 return _processID;
2226 An operating system handle to the process.
2228 This handle is used to specify the process in OS-specific APIs.
2229 On POSIX, this function returns a `core.sys.posix.sys.types.pid_t`
2230 with the same value as $(LREF Pid.processID), while on Windows it returns
2231 a `core.sys.windows.windows.HANDLE`.
2233 Once $(LREF wait) has been called on the $(LREF Pid), this method
2234 will return an invalid handle.
2236 // Note: Since HANDLE is a reference, this function cannot be const.
2237 version (Windows)
2238 @property HANDLE osHandle() @nogc @safe pure nothrow
2240 return _handle;
2242 else version (Posix)
2243 @property pid_t osHandle() @nogc @safe pure nothrow
2245 return _processID;
2248 private:
2250 Pid.performWait() does the dirty work for wait() and nonBlockingWait().
2252 If block == true, this function blocks until the process terminates,
2253 sets _processID to terminated, and returns the exit code or terminating
2254 signal as described in the wait() documentation.
2256 If block == false, this function returns immediately, regardless
2257 of the status of the process. If the process has terminated, the
2258 function has the exact same effect as the blocking version. If not,
2259 it returns 0 and does not modify _processID.
2261 version (Posix)
2262 int performWait(bool block) @trusted
2264 import std.exception : enforce;
2265 enforce!ProcessException(owned, "Can't wait on a detached process");
2266 if (_processID == terminated) return _exitCode;
2267 int exitCode;
2268 while (true)
2270 int status;
2271 auto check = waitpid(_processID, &status, block ? 0 : WNOHANG);
2272 if (check == -1)
2274 if (errno == ECHILD)
2276 throw new ProcessException(
2277 "Process does not exist or is not a child process.");
2279 else
2281 // waitpid() was interrupted by a signal. We simply
2282 // restart it.
2283 assert(errno == EINTR);
2284 continue;
2287 if (!block && check == 0) return 0;
2288 if (WIFEXITED(status))
2290 exitCode = WEXITSTATUS(status);
2291 break;
2293 else if (WIFSIGNALED(status))
2295 exitCode = -WTERMSIG(status);
2296 break;
2298 // We check again whether the call should be blocking,
2299 // since we don't care about other status changes besides
2300 // "exited" and "terminated by signal".
2301 if (!block) return 0;
2303 // Process has stopped, but not terminated, so we continue waiting.
2305 // Mark Pid as terminated, and cache and return exit code.
2306 _processID = terminated;
2307 _exitCode = exitCode;
2308 return exitCode;
2310 else version (Windows)
2312 int performWait(const bool block, const DWORD timeout = INFINITE) @trusted
2314 import std.exception : enforce;
2315 enforce!ProcessException(owned, "Can't wait on a detached process");
2316 if (_processID == terminated) return _exitCode;
2317 assert(_handle != INVALID_HANDLE_VALUE);
2318 if (block)
2320 auto result = WaitForSingleObject(_handle, timeout);
2321 if (result != WAIT_OBJECT_0)
2323 // Wait time exceeded `timeout` milliseconds?
2324 if (result == WAIT_TIMEOUT && timeout != INFINITE)
2325 return 0;
2327 throw ProcessException.newFromLastError("Wait failed.");
2330 if (!GetExitCodeProcess(_handle, cast(LPDWORD)&_exitCode))
2331 throw ProcessException.newFromLastError();
2332 if (!block && _exitCode == STILL_ACTIVE) return 0;
2333 CloseHandle(_handle);
2334 _handle = INVALID_HANDLE_VALUE;
2335 _processID = terminated;
2336 return _exitCode;
2339 int performWait(Duration timeout) @safe
2341 import std.exception : enforce;
2342 const msecs = timeout.total!"msecs";
2344 // Limit this implementation the maximum wait time offered by
2345 // WaitForSingleObject. One could theoretically break up larger
2346 // durations into multiple waits but (DWORD.max - 1).msecs
2347 // (> 7 weeks, 17 hours) should be enough for the usual case.
2348 // DWORD.max is reserved for INFINITE
2349 enforce!ProcessException(msecs < DWORD.max, "Timeout exceeds maximum wait time!");
2350 return performWait(true, cast(DWORD) msecs);
2353 ~this()
2355 if (_handle != INVALID_HANDLE_VALUE)
2357 CloseHandle(_handle);
2358 _handle = INVALID_HANDLE_VALUE;
2363 // Special values for _processID.
2364 enum invalid = -1, terminated = -2;
2366 // OS process ID number. Only nonnegative IDs correspond to
2367 // running processes.
2368 int _processID = invalid;
2370 // Exit code cached by wait(). This is only expected to hold a
2371 // sensible value if _processID == terminated.
2372 int _exitCode;
2374 // Whether the process can be waited for by wait() for or killed by kill().
2375 // False if process was started as detached. True otherwise.
2376 bool owned;
2378 // Pids are only meant to be constructed inside this module, so
2379 // we make the constructor private.
2380 version (Windows)
2382 HANDLE _handle = INVALID_HANDLE_VALUE;
2383 this(int pid, HANDLE handle) @safe pure nothrow
2385 _processID = pid;
2386 _handle = handle;
2387 this.owned = true;
2389 this(int pid) @safe pure nothrow
2391 _processID = pid;
2392 this.owned = false;
2395 else
2397 this(int id, bool owned) @safe pure nothrow
2399 _processID = id;
2400 this.owned = owned;
2407 Waits for the process associated with `pid` to terminate, and returns
2408 its exit status.
2410 In general one should always _wait for child processes to terminate
2411 before exiting the parent process unless the process was spawned as detached
2412 (that was spawned with `Config.detached` flag).
2413 Otherwise, they may become "$(HTTP en.wikipedia.org/wiki/Zombie_process,zombies)"
2414 – processes that are defunct, yet still occupy a slot in the OS process table.
2415 You should not and must not wait for detached processes, since you don't own them.
2417 If the process has already terminated, this function returns directly.
2418 The exit code is cached, so that if wait() is called multiple times on
2419 the same $(LREF Pid) it will always return the same value.
2421 POSIX_specific:
2422 If the process is terminated by a signal, this function returns a
2423 negative number whose absolute value is the signal number.
2424 Since POSIX restricts normal exit codes to the range 0-255, a
2425 negative return value will always indicate termination by signal.
2426 Signal codes are defined in the `core.sys.posix.signal` module
2427 (which corresponds to the `signal.h` POSIX header).
2429 Throws:
2430 $(LREF ProcessException) on failure or on attempt to wait for detached process.
2432 Example:
2433 See the $(LREF spawnProcess) documentation.
2435 See_also:
2436 $(LREF tryWait), for a non-blocking function.
2438 int wait(Pid pid) @safe
2440 assert(pid !is null, "Called wait on a null Pid.");
2441 return pid.performWait(true);
2445 @system unittest // Pid and wait()
2447 version (Windows) TestScript prog = "exit %~1";
2448 else version (Posix) TestScript prog = "exit $1";
2449 assert(wait(spawnProcess([prog.path, "0"])) == 0);
2450 assert(wait(spawnProcess([prog.path, "123"])) == 123);
2451 auto pid = spawnProcess([prog.path, "10"]);
2452 assert(pid.processID > 0);
2453 version (Windows) assert(pid.osHandle != INVALID_HANDLE_VALUE);
2454 else version (Posix) assert(pid.osHandle == pid.processID);
2455 assert(wait(pid) == 10);
2456 assert(wait(pid) == 10); // cached exit code
2457 assert(pid.processID < 0);
2458 version (Windows) assert(pid.osHandle == INVALID_HANDLE_VALUE);
2459 else version (Posix) assert(pid.osHandle < 0);
2462 private import std.typecons : Tuple;
2465 Waits until either the process associated with `pid` terminates or the
2466 elapsed time exceeds the given timeout.
2468 If the process terminates within the given duration it behaves exactly like
2469 `wait`, except that it returns a tuple `(true, exit code)`.
2471 If the process does not terminate within the given duration it will stop
2472 waiting and return `(false, 0).`
2474 The timeout may not exceed `(uint.max - 1).msecs` (~ 7 weeks, 17 hours).
2476 $(BLUE This function is Windows-Only.)
2478 Returns:
2479 An $(D std.typecons.Tuple!(bool, "terminated", int, "status")).
2481 Throws:
2482 $(LREF ProcessException) on failure or on attempt to wait for detached process.
2484 Example:
2485 See the $(LREF spawnProcess) documentation.
2487 See_also:
2488 $(LREF wait), for a blocking function without timeout.
2489 $(LREF tryWait), for a non-blocking function without timeout.
2491 version (StdDdoc)
2492 Tuple!(bool, "terminated", int, "status") waitTimeout(Pid pid, Duration timeout) @safe;
2494 else version (Windows)
2495 Tuple!(bool, "terminated", int, "status") waitTimeout(Pid pid, Duration timeout) @safe
2497 assert(pid !is null, "Called wait on a null Pid.");
2498 auto code = pid.performWait(timeout);
2499 return typeof(return)(pid._processID == Pid.terminated, code);
2502 version (Windows)
2503 @system unittest // Pid and waitTimeout()
2505 import std.exception : collectException;
2506 import std.typecons : tuple;
2508 TestScript prog = ":Loop\r\n" ~ "goto Loop";
2509 auto pid = spawnProcess(prog.path);
2511 // Doesn't block longer than one second
2512 assert(waitTimeout(pid, 1.seconds) == tuple(false, 0));
2514 kill(pid);
2515 assert(waitTimeout(pid, 1.seconds) == tuple(true, 1)); // exit 1 because the process is killed
2517 // Rejects timeouts exceeding the Windows API capabilities
2518 const dur = DWORD.max.msecs;
2519 const ex = collectException!ProcessException(waitTimeout(pid, dur));
2520 assert(ex);
2521 assert(ex.msg == "Timeout exceeds maximum wait time!");
2525 A non-blocking version of $(LREF wait).
2527 If the process associated with `pid` has already terminated,
2528 `tryWait` has the exact same effect as `wait`.
2529 In this case, it returns a tuple where the `terminated` field
2530 is set to `true` and the `status` field has the same
2531 interpretation as the return value of `wait`.
2533 If the process has $(I not) yet terminated, this function differs
2534 from `wait` in that does not wait for this to happen, but instead
2535 returns immediately. The `terminated` field of the returned
2536 tuple will then be set to `false`, while the `status` field
2537 will always be 0 (zero). `wait` or `tryWait` should then be
2538 called again on the same `Pid` at some later time; not only to
2539 get the exit code, but also to avoid the process becoming a "zombie"
2540 when it finally terminates. (See $(LREF wait) for details).
2542 Returns:
2543 An $(D std.typecons.Tuple!(bool, "terminated", int, "status")).
2545 Throws:
2546 $(LREF ProcessException) on failure or on attempt to wait for detached process.
2548 Example:
2550 auto pid = spawnProcess("dmd myapp.d");
2551 scope(exit) wait(pid);
2553 auto dmd = tryWait(pid);
2554 if (dmd.terminated)
2556 if (dmd.status == 0) writeln("Compilation succeeded!");
2557 else writeln("Compilation failed");
2559 else writeln("Still compiling...");
2562 Note that in this example, the first `wait` call will have no
2563 effect if the process has already terminated by the time `tryWait`
2564 is called. In the opposite case, however, the `scope` statement
2565 ensures that we always wait for the process if it hasn't terminated
2566 by the time we reach the end of the scope.
2568 auto tryWait(Pid pid) @safe
2570 import std.typecons : Tuple;
2571 assert(pid !is null, "Called tryWait on a null Pid.");
2572 auto code = pid.performWait(false);
2573 return Tuple!(bool, "terminated", int, "status")(pid._processID == Pid.terminated, code);
2575 // unittest: This function is tested together with kill() below.
2579 Attempts to terminate the process associated with `pid`.
2581 The effect of this function, as well as the meaning of `codeOrSignal`,
2582 is highly platform dependent. Details are given below. Common to all
2583 platforms is that this function only $(I initiates) termination of the process,
2584 and returns immediately. It does not wait for the process to end,
2585 nor does it guarantee that the process does in fact get terminated.
2587 Always call $(LREF wait) to wait for a process to complete, even if `kill`
2588 has been called on it.
2590 Windows_specific:
2591 The process will be
2592 $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/ms686714%28v=vs.100%29.aspx,
2593 forcefully and abruptly terminated). If `codeOrSignal` is specified, it
2594 must be a nonnegative number which will be used as the exit code of the process.
2595 If not, the process wil exit with code 1. Do not use $(D codeOrSignal = 259),
2596 as this is a special value (aka. $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/ms683189.aspx,STILL_ACTIVE))
2597 used by Windows to signal that a process has in fact $(I not) terminated yet.
2599 auto pid = spawnProcess("some_app");
2600 kill(pid, 10);
2601 assert(wait(pid) == 10);
2604 POSIX_specific:
2605 A $(LINK2 http://en.wikipedia.org/wiki/Unix_signal,signal) will be sent to
2606 the process, whose value is given by `codeOrSignal`. Depending on the
2607 signal sent, this may or may not terminate the process. Symbolic constants
2608 for various $(LINK2 http://en.wikipedia.org/wiki/Unix_signal#POSIX_signals,
2609 POSIX signals) are defined in `core.sys.posix.signal`, which corresponds to the
2610 $(LINK2 http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html,
2611 `signal.h` POSIX header). If `codeOrSignal` is omitted, the
2612 `SIGTERM` signal will be sent. (This matches the behaviour of the
2613 $(LINK2 http://pubs.opengroup.org/onlinepubs/9699919799/utilities/kill.html,
2614 `_kill`) shell command.)
2616 import core.sys.posix.signal : SIGKILL;
2617 auto pid = spawnProcess("some_app");
2618 kill(pid, SIGKILL);
2619 assert(wait(pid) == -SIGKILL); // Negative return value on POSIX!
2622 Throws:
2623 $(LREF ProcessException) on error (e.g. if codeOrSignal is invalid).
2624 or on attempt to kill detached process.
2625 Note that failure to terminate the process is considered a "normal"
2626 outcome, not an error.$(BR)
2628 void kill(Pid pid)
2630 version (Windows) kill(pid, 1);
2631 else version (Posix)
2633 import core.sys.posix.signal : SIGTERM;
2634 kill(pid, SIGTERM);
2638 /// ditto
2639 void kill(Pid pid, int codeOrSignal)
2641 import std.exception : enforce;
2642 enforce!ProcessException(pid.owned, "Can't kill detached process");
2643 version (Windows)
2645 if (codeOrSignal < 0) throw new ProcessException("Invalid exit code");
2646 // On Windows, TerminateProcess() appears to terminate the
2647 // *current* process if it is passed an invalid handle...
2648 if (pid.osHandle == INVALID_HANDLE_VALUE)
2649 throw new ProcessException("Invalid process handle");
2650 if (!TerminateProcess(pid.osHandle, codeOrSignal))
2651 throw ProcessException.newFromLastError();
2653 else version (Posix)
2655 import core.sys.posix.signal : kill;
2656 if (kill(pid.osHandle, codeOrSignal) == -1)
2657 throw ProcessException.newFromErrno();
2661 @system unittest // tryWait() and kill()
2663 import core.thread;
2664 import std.exception : assertThrown;
2665 // The test script goes into an infinite loop.
2666 version (Windows)
2668 TestScript prog = ":loop
2669 goto loop";
2671 else version (Posix)
2673 import core.sys.posix.signal : SIGTERM, SIGKILL;
2674 TestScript prog = "while true; do sleep 1; done";
2676 auto pid = spawnProcess(prog.path);
2677 // Android appears to automatically kill sleeping processes very quickly,
2678 // so shorten the wait before killing here.
2679 version (Android)
2680 Thread.sleep(dur!"msecs"(5));
2681 else
2682 Thread.sleep(dur!"msecs"(500));
2683 kill(pid);
2684 version (Windows) assert(wait(pid) == 1);
2685 else version (Posix) assert(wait(pid) == -SIGTERM);
2687 pid = spawnProcess(prog.path);
2688 Thread.sleep(dur!"msecs"(500));
2689 auto s = tryWait(pid);
2690 assert(!s.terminated && s.status == 0);
2691 assertThrown!ProcessException(kill(pid, -123)); // Negative code not allowed.
2692 version (Windows) kill(pid, 123);
2693 else version (Posix) kill(pid, SIGKILL);
2694 do { s = tryWait(pid); } while (!s.terminated);
2695 version (Windows) assert(s.status == 123);
2696 else version (Posix) assert(s.status == -SIGKILL);
2697 assertThrown!ProcessException(kill(pid));
2700 @system unittest // wait() and kill() detached process
2702 import core.thread;
2703 import std.exception : assertThrown;
2704 TestScript prog = "exit 0";
2705 auto pid = spawnProcess([prog.path], null, Config.detached);
2707 This sleep is needed because we can't wait() for detached process to end
2708 and therefore TestScript destructor may run at the same time as /bin/sh tries to start the script.
2709 This leads to the annoying message like "/bin/sh: 0: Can't open /tmp/std.process temporary file" to appear when running tests.
2710 It does not happen in unittests with non-detached processes because we always wait() for them to finish.
2712 Thread.sleep(500.msecs);
2713 assert(!pid.owned);
2714 version (Windows) assert(pid.osHandle == INVALID_HANDLE_VALUE);
2715 assertThrown!ProcessException(wait(pid));
2716 assertThrown!ProcessException(kill(pid));
2721 Creates a unidirectional _pipe.
2723 Data is written to one end of the _pipe and read from the other.
2725 auto p = pipe();
2726 p.writeEnd.writeln("Hello World");
2727 p.writeEnd.flush();
2728 assert(p.readEnd.readln().chomp() == "Hello World");
2730 Pipes can, for example, be used for interprocess communication
2731 by spawning a new process and passing one end of the _pipe to
2732 the child, while the parent uses the other end.
2733 (See also $(LREF pipeProcess) and $(LREF pipeShell) for an easier
2734 way of doing this.)
2736 // Use cURL to download the dlang.org front page, pipe its
2737 // output to grep to extract a list of links to ZIP files,
2738 // and write the list to the file "D downloads.txt":
2739 auto p = pipe();
2740 auto outFile = File("D downloads.txt", "w");
2741 auto cpid = spawnProcess(["curl", "http://dlang.org/download.html"],
2742 std.stdio.stdin, p.writeEnd);
2743 scope(exit) wait(cpid);
2744 auto gpid = spawnProcess(["grep", "-o", `http://\S*\.zip`],
2745 p.readEnd, outFile);
2746 scope(exit) wait(gpid);
2749 Returns:
2750 A $(LREF Pipe) object that corresponds to the created _pipe.
2752 Throws:
2753 $(REF StdioException, std,stdio) on failure.
2755 version (Posix)
2756 Pipe pipe() @trusted //TODO: @safe
2758 import core.sys.posix.stdio : fdopen;
2759 int[2] fds;
2760 if (core.sys.posix.unistd.pipe(fds) != 0)
2761 throw new StdioException("Unable to create pipe");
2762 Pipe p;
2763 auto readFP = fdopen(fds[0], "r");
2764 if (readFP == null)
2765 throw new StdioException("Cannot open read end of pipe");
2766 p._read = File(readFP, null);
2767 auto writeFP = fdopen(fds[1], "w");
2768 if (writeFP == null)
2769 throw new StdioException("Cannot open write end of pipe");
2770 p._write = File(writeFP, null);
2771 return p;
2773 else version (Windows)
2774 Pipe pipe() @trusted //TODO: @safe
2776 // use CreatePipe to create an anonymous pipe
2777 HANDLE readHandle;
2778 HANDLE writeHandle;
2779 if (!CreatePipe(&readHandle, &writeHandle, null, 0))
2781 throw new StdioException(
2782 "Error creating pipe (" ~ generateSysErrorMsg() ~ ')',
2786 scope(failure)
2788 CloseHandle(readHandle);
2789 CloseHandle(writeHandle);
2794 Pipe p;
2795 p._read .windowsHandleOpen(readHandle , "r");
2796 p._write.windowsHandleOpen(writeHandle, "a");
2797 return p;
2799 catch (Exception e)
2801 throw new StdioException("Error attaching pipe (" ~ e.msg ~ ")",
2807 /// An interface to a pipe created by the $(LREF pipe) function.
2808 struct Pipe
2810 /// The read end of the pipe.
2811 @property File readEnd() @safe nothrow { return _read; }
2814 /// The write end of the pipe.
2815 @property File writeEnd() @safe nothrow { return _write; }
2819 Closes both ends of the pipe.
2821 Normally it is not necessary to do this manually, as $(REF File, std,stdio)
2822 objects are automatically closed when there are no more references
2823 to them.
2825 Note that if either end of the pipe has been passed to a child process,
2826 it will only be closed in the parent process. (What happens in the
2827 child process is platform dependent.)
2829 Throws:
2830 $(REF ErrnoException, std,exception) if an error occurs.
2832 void close() @safe
2834 _read.close();
2835 _write.close();
2838 private:
2839 File _read, _write;
2842 @system unittest
2844 import std.string;
2845 auto p = pipe();
2846 p.writeEnd.writeln("Hello World");
2847 p.writeEnd.flush();
2848 assert(p.readEnd.readln().chomp() == "Hello World");
2849 p.close();
2850 assert(!p.readEnd.isOpen);
2851 assert(!p.writeEnd.isOpen);
2856 Starts a new process, creating pipes to redirect its standard
2857 input, output and/or error streams.
2859 `pipeProcess` and `pipeShell` are convenient wrappers around
2860 $(LREF spawnProcess) and $(LREF spawnShell), respectively, and
2861 automate the task of redirecting one or more of the child process'
2862 standard streams through pipes. Like the functions they wrap,
2863 these functions return immediately, leaving the child process to
2864 execute in parallel with the invoking process. It is recommended
2865 to always call $(LREF wait) on the returned $(LREF ProcessPipes.pid),
2866 as detailed in the documentation for `wait`.
2868 The `args`/`program`/`command`, `env` and `config`
2869 parameters are forwarded straight to the underlying spawn functions,
2870 and we refer to their documentation for details.
2872 Params:
2873 args = An array which contains the program name as the zeroth element
2874 and any command-line arguments in the following elements.
2875 (See $(LREF spawnProcess) for details.)
2876 program = The program name, $(I without) command-line arguments.
2877 (See $(LREF spawnProcess) for details.)
2878 command = A shell command which is passed verbatim to the command
2879 interpreter. (See $(LREF spawnShell) for details.)
2880 redirect = Flags that determine which streams are redirected, and
2881 how. See $(LREF Redirect) for an overview of available
2882 flags.
2883 env = Additional environment variables for the child process.
2884 (See $(LREF spawnProcess) for details.)
2885 config = Flags that control process creation. See $(LREF Config)
2886 for an overview of available flags, and note that the
2887 `retainStd...` flags have no effect in this function.
2888 workDir = The working directory for the new process.
2889 By default the child process inherits the parent's working
2890 directory.
2891 shellPath = The path to the shell to use to run the specified program.
2892 By default this is $(LREF nativeShell).
2894 Returns:
2895 A $(LREF ProcessPipes) object which contains $(REF File, std,stdio)
2896 handles that communicate with the redirected streams of the child
2897 process, along with a $(LREF Pid) object that corresponds to the
2898 spawned process.
2900 Throws:
2901 $(LREF ProcessException) on failure to start the process.$(BR)
2902 $(REF StdioException, std,stdio) on failure to redirect any of the streams.$(BR)
2904 Example:
2906 // my_application writes to stdout and might write to stderr
2907 auto pipes = pipeProcess("my_application", Redirect.stdout | Redirect.stderr);
2908 scope(exit) wait(pipes.pid);
2910 // Store lines of output.
2911 string[] output;
2912 foreach (line; pipes.stdout.byLine) output ~= line.idup;
2914 // Store lines of errors.
2915 string[] errors;
2916 foreach (line; pipes.stderr.byLine) errors ~= line.idup;
2919 // sendmail expects to read from stdin
2920 pipes = pipeProcess(["/usr/bin/sendmail", "-t"], Redirect.stdin);
2921 pipes.stdin.writeln("To: you");
2922 pipes.stdin.writeln("From: me");
2923 pipes.stdin.writeln("Subject: dlang");
2924 pipes.stdin.writeln("");
2925 pipes.stdin.writeln(message);
2927 // a single period tells sendmail we are finished
2928 pipes.stdin.writeln(".");
2930 // but at this point sendmail might not see it, we need to flush
2931 pipes.stdin.flush();
2933 // sendmail happens to exit on ".", but some you have to close the file:
2934 pipes.stdin.close();
2936 // otherwise this wait will wait forever
2937 wait(pipes.pid);
2941 ProcessPipes pipeProcess(scope const(char[])[] args,
2942 Redirect redirect = Redirect.all,
2943 const string[string] env = null,
2944 Config config = Config.none,
2945 scope const(char)[] workDir = null)
2946 @safe
2948 return pipeProcessImpl!spawnProcess(args, redirect, env, config, workDir);
2951 /// ditto
2952 ProcessPipes pipeProcess(scope const(char)[] program,
2953 Redirect redirect = Redirect.all,
2954 const string[string] env = null,
2955 Config config = Config.none,
2956 scope const(char)[] workDir = null)
2957 @safe
2959 return pipeProcessImpl!spawnProcess(program, redirect, env, config, workDir);
2962 /// ditto
2963 ProcessPipes pipeShell(scope const(char)[] command,
2964 Redirect redirect = Redirect.all,
2965 const string[string] env = null,
2966 Config config = Config.none,
2967 scope const(char)[] workDir = null,
2968 string shellPath = nativeShell)
2969 @safe
2971 return pipeProcessImpl!spawnShell(command,
2972 redirect,
2973 env,
2974 config,
2975 workDir,
2976 shellPath);
2979 // Implementation of the pipeProcess() family of functions.
2980 private ProcessPipes pipeProcessImpl(alias spawnFunc, Cmd, ExtraSpawnFuncArgs...)
2981 (scope Cmd command,
2982 Redirect redirectFlags,
2983 const string[string] env = null,
2984 Config config = Config.none,
2985 scope const(char)[] workDir = null,
2986 ExtraSpawnFuncArgs extraArgs = ExtraSpawnFuncArgs.init)
2987 @trusted //TODO: @safe
2989 File childStdin, childStdout, childStderr;
2990 ProcessPipes pipes;
2991 pipes._redirectFlags = redirectFlags;
2993 if (redirectFlags & Redirect.stdin)
2995 auto p = pipe();
2996 childStdin = p.readEnd;
2997 pipes._stdin = p.writeEnd;
2999 else
3001 childStdin = std.stdio.stdin;
3004 if (redirectFlags & Redirect.stdout)
3006 if ((redirectFlags & Redirect.stdoutToStderr) != 0)
3007 throw new StdioException("Cannot create pipe for stdout AND "
3008 ~"redirect it to stderr", 0);
3009 auto p = pipe();
3010 childStdout = p.writeEnd;
3011 pipes._stdout = p.readEnd;
3013 else
3015 childStdout = std.stdio.stdout;
3018 if (redirectFlags & Redirect.stderr)
3020 if ((redirectFlags & Redirect.stderrToStdout) != 0)
3021 throw new StdioException("Cannot create pipe for stderr AND "
3022 ~"redirect it to stdout", 0);
3023 auto p = pipe();
3024 childStderr = p.writeEnd;
3025 pipes._stderr = p.readEnd;
3027 else
3029 childStderr = std.stdio.stderr;
3032 if (redirectFlags & Redirect.stdoutToStderr)
3034 if (redirectFlags & Redirect.stderrToStdout)
3036 // We know that neither of the other options have been
3037 // set, so we assign the std.stdio.std* streams directly.
3038 childStdout = std.stdio.stderr;
3039 childStderr = std.stdio.stdout;
3041 else
3043 childStdout = childStderr;
3046 else if (redirectFlags & Redirect.stderrToStdout)
3048 childStderr = childStdout;
3051 config.flags &= ~(Config.Flags.retainStdin | Config.Flags.retainStdout | Config.Flags.retainStderr);
3052 pipes._pid = spawnFunc(command, childStdin, childStdout, childStderr,
3053 env, config, workDir, extraArgs);
3054 return pipes;
3059 Flags that can be passed to $(LREF pipeProcess) and $(LREF pipeShell)
3060 to specify which of the child process' standard streams are redirected.
3061 Use bitwise OR to combine flags.
3063 enum Redirect
3065 /// Redirect the standard input, output or error streams, respectively.
3066 stdin = 1,
3067 stdout = 2, /// ditto
3068 stderr = 4, /// ditto
3071 Redirect _all three streams. This is equivalent to
3072 $(D Redirect.stdin | Redirect.stdout | Redirect.stderr).
3074 all = stdin | stdout | stderr,
3077 Redirect the standard error stream into the standard output stream.
3078 This can not be combined with `Redirect.stderr`.
3080 stderrToStdout = 8,
3083 Redirect the standard output stream into the standard error stream.
3084 This can not be combined with `Redirect.stdout`.
3086 stdoutToStderr = 16,
3089 @system unittest
3091 import std.string;
3092 version (Windows) TestScript prog =
3093 "call :sub %~1 %~2 0
3094 call :sub %~1 %~2 1
3095 call :sub %~1 %~2 2
3096 call :sub %~1 %~2 3
3097 exit 3
3099 :sub
3100 set /p INPUT=
3101 if -%INPUT%-==-stop- ( exit %~3 )
3102 echo %INPUT% %~1
3103 echo %INPUT% %~2 1>&2";
3104 else version (Posix) TestScript prog =
3105 `for EXITCODE in 0 1 2 3; do
3106 read INPUT
3107 if test "$INPUT" = stop; then break; fi
3108 echo "$INPUT $1"
3109 echo "$INPUT $2" >&2
3110 done
3111 exit $EXITCODE`;
3112 auto pp = pipeProcess([prog.path, "bar", "baz"]);
3113 pp.stdin.writeln("foo");
3114 pp.stdin.flush();
3115 assert(pp.stdout.readln().chomp() == "foo bar");
3116 assert(pp.stderr.readln().chomp().stripRight() == "foo baz");
3117 pp.stdin.writeln("1234567890");
3118 pp.stdin.flush();
3119 assert(pp.stdout.readln().chomp() == "1234567890 bar");
3120 assert(pp.stderr.readln().chomp().stripRight() == "1234567890 baz");
3121 pp.stdin.writeln("stop");
3122 pp.stdin.flush();
3123 assert(wait(pp.pid) == 2);
3125 pp = pipeProcess([prog.path, "12345", "67890"],
3126 Redirect.stdin | Redirect.stdout | Redirect.stderrToStdout);
3127 pp.stdin.writeln("xyz");
3128 pp.stdin.flush();
3129 assert(pp.stdout.readln().chomp() == "xyz 12345");
3130 assert(pp.stdout.readln().chomp().stripRight() == "xyz 67890");
3131 pp.stdin.writeln("stop");
3132 pp.stdin.flush();
3133 assert(wait(pp.pid) == 1);
3135 pp = pipeShell(escapeShellCommand(prog.path, "AAAAA", "BBB"),
3136 Redirect.stdin | Redirect.stdoutToStderr | Redirect.stderr);
3137 pp.stdin.writeln("ab");
3138 pp.stdin.flush();
3139 assert(pp.stderr.readln().chomp() == "ab AAAAA");
3140 assert(pp.stderr.readln().chomp().stripRight() == "ab BBB");
3141 pp.stdin.writeln("stop");
3142 pp.stdin.flush();
3143 assert(wait(pp.pid) == 1);
3146 @system unittest
3148 import std.exception : assertThrown;
3149 TestScript prog = "exit 0";
3150 assertThrown!StdioException(pipeProcess(
3151 prog.path,
3152 Redirect.stdout | Redirect.stdoutToStderr));
3153 assertThrown!StdioException(pipeProcess(
3154 prog.path,
3155 Redirect.stderr | Redirect.stderrToStdout));
3156 auto p = pipeProcess(prog.path, Redirect.stdin);
3157 assertThrown!Error(p.stdout);
3158 assertThrown!Error(p.stderr);
3159 wait(p.pid);
3160 p = pipeProcess(prog.path, Redirect.stderr);
3161 assertThrown!Error(p.stdin);
3162 assertThrown!Error(p.stdout);
3163 wait(p.pid);
3167 Object which contains $(REF File, std,stdio) handles that allow communication
3168 with a child process through its standard streams.
3170 struct ProcessPipes
3172 /// The $(LREF Pid) of the child process.
3173 @property Pid pid() @safe nothrow
3175 return _pid;
3179 An $(REF File, std,stdio) that allows writing to the child process'
3180 standard input stream.
3182 Throws:
3183 $(OBJECTREF Error) if the child process' standard input stream hasn't
3184 been redirected.
3186 @property File stdin() @safe nothrow
3188 if ((_redirectFlags & Redirect.stdin) == 0)
3189 throw new Error("Child process' standard input stream hasn't "
3190 ~"been redirected.");
3191 return _stdin;
3195 An $(REF File, std,stdio) that allows reading from the child process'
3196 standard output stream.
3198 Throws:
3199 $(OBJECTREF Error) if the child process' standard output stream hasn't
3200 been redirected.
3202 @property File stdout() @safe nothrow
3204 if ((_redirectFlags & Redirect.stdout) == 0)
3205 throw new Error("Child process' standard output stream hasn't "
3206 ~"been redirected.");
3207 return _stdout;
3211 An $(REF File, std,stdio) that allows reading from the child process'
3212 standard error stream.
3214 Throws:
3215 $(OBJECTREF Error) if the child process' standard error stream hasn't
3216 been redirected.
3218 @property File stderr() @safe nothrow
3220 if ((_redirectFlags & Redirect.stderr) == 0)
3221 throw new Error("Child process' standard error stream hasn't "
3222 ~"been redirected.");
3223 return _stderr;
3226 private:
3227 Redirect _redirectFlags;
3228 Pid _pid;
3229 File _stdin, _stdout, _stderr;
3235 Executes the given program or shell command and returns its exit
3236 code and output.
3238 `execute` and `executeShell` start a new process using
3239 $(LREF spawnProcess) and $(LREF spawnShell), respectively, and wait
3240 for the process to complete before returning. The functions capture
3241 what the child process prints to both its standard output and
3242 standard error streams, and return this together with its exit code.
3244 auto dmd = execute(["dmd", "myapp.d"]);
3245 if (dmd.status != 0) writeln("Compilation failed:\n", dmd.output);
3247 auto ls = executeShell("ls -l");
3248 if (ls.status != 0) writeln("Failed to retrieve file listing");
3249 else writeln(ls.output);
3252 The `args`/`program`/`command`, `env` and `config`
3253 parameters are forwarded straight to the underlying spawn functions,
3254 and we refer to their documentation for details.
3256 Params:
3257 args = An array which contains the program name as the zeroth element
3258 and any command-line arguments in the following elements.
3259 (See $(LREF spawnProcess) for details.)
3260 program = The program name, $(I without) command-line arguments.
3261 (See $(LREF spawnProcess) for details.)
3262 command = A shell command which is passed verbatim to the command
3263 interpreter. (See $(LREF spawnShell) for details.)
3264 env = Additional environment variables for the child process.
3265 (See $(LREF spawnProcess) for details.)
3266 config = Flags that control process creation. See $(LREF Config)
3267 for an overview of available flags, and note that the
3268 `retainStd...` flags have no effect in this function.
3269 maxOutput = The maximum number of bytes of output that should be
3270 captured.
3271 workDir = The working directory for the new process.
3272 By default the child process inherits the parent's working
3273 directory.
3274 shellPath = The path to the shell to use to run the specified program.
3275 By default this is $(LREF nativeShell).
3278 Returns:
3279 An $(D std.typecons.Tuple!(int, "status", string, "output")).
3281 POSIX_specific:
3282 If the process is terminated by a signal, the `status` field of
3283 the return value will contain a negative number whose absolute
3284 value is the signal number. (See $(LREF wait) for details.)
3286 Throws:
3287 $(LREF ProcessException) on failure to start the process.$(BR)
3288 $(REF StdioException, std,stdio) on failure to capture output.
3290 auto execute(scope const(char[])[] args,
3291 const string[string] env = null,
3292 Config config = Config.none,
3293 size_t maxOutput = size_t.max,
3294 scope const(char)[] workDir = null)
3295 @safe
3297 return executeImpl!pipeProcess(args, env, config, maxOutput, workDir);
3300 /// ditto
3301 auto execute(scope const(char)[] program,
3302 const string[string] env = null,
3303 Config config = Config.none,
3304 size_t maxOutput = size_t.max,
3305 scope const(char)[] workDir = null)
3306 @safe
3308 return executeImpl!pipeProcess(program, env, config, maxOutput, workDir);
3311 /// ditto
3312 auto executeShell(scope const(char)[] command,
3313 const string[string] env = null,
3314 Config config = Config.none,
3315 size_t maxOutput = size_t.max,
3316 scope const(char)[] workDir = null,
3317 string shellPath = nativeShell)
3318 @safe
3320 return executeImpl!pipeShell(command,
3321 env,
3322 config,
3323 maxOutput,
3324 workDir,
3325 shellPath);
3328 // Does the actual work for execute() and executeShell().
3329 private auto executeImpl(alias pipeFunc, Cmd, ExtraPipeFuncArgs...)(
3330 Cmd commandLine,
3331 const string[string] env = null,
3332 Config config = Config.none,
3333 size_t maxOutput = size_t.max,
3334 scope const(char)[] workDir = null,
3335 ExtraPipeFuncArgs extraArgs = ExtraPipeFuncArgs.init)
3336 @trusted //TODO: @safe
3338 import std.algorithm.comparison : min;
3339 import std.array : appender;
3340 import std.typecons : Tuple;
3342 auto redirect = (config.flags & Config.Flags.stderrPassThrough)
3343 ? Redirect.stdout
3344 : Redirect.stdout | Redirect.stderrToStdout;
3346 auto p = pipeFunc(commandLine, redirect,
3347 env, config, workDir, extraArgs);
3349 auto a = appender!string;
3350 enum size_t defaultChunkSize = 4096;
3351 immutable chunkSize = min(maxOutput, defaultChunkSize);
3353 // Store up to maxOutput bytes in a.
3354 foreach (ubyte[] chunk; p.stdout.byChunk(chunkSize))
3356 immutable size_t remain = maxOutput - a.data.length;
3358 if (chunk.length < remain) a.put(chunk);
3359 else
3361 a.put(chunk[0 .. remain]);
3362 break;
3365 // Exhaust the stream, if necessary.
3366 foreach (ubyte[] chunk; p.stdout.byChunk(defaultChunkSize)) { }
3368 return Tuple!(int, "status", string, "output")(wait(p.pid), a.data);
3371 @system unittest
3373 import std.string;
3374 // To avoid printing the newline characters, we use the echo|set trick on
3375 // Windows, and printf on POSIX (neither echo -n nor echo \c are portable).
3376 version (Windows) TestScript prog =
3377 "echo|set /p=%~1
3378 echo|set /p=%~2 1>&2
3379 exit 123";
3380 else version (Android) TestScript prog =
3381 `echo -n $1
3382 echo -n $2 >&2
3383 exit 123`;
3384 else version (Posix) TestScript prog =
3385 `printf '%s' $1
3386 printf '%s' $2 >&2
3387 exit 123`;
3388 auto r = execute([prog.path, "foo", "bar"]);
3389 assert(r.status == 123);
3390 assert(r.output.stripRight() == "foobar");
3391 auto s = execute([prog.path, "Hello", "World"]);
3392 assert(s.status == 123);
3393 assert(s.output.stripRight() == "HelloWorld");
3396 @safe unittest
3398 import std.string;
3399 auto r1 = executeShell("echo foo");
3400 assert(r1.status == 0);
3401 assert(r1.output.chomp() == "foo");
3402 auto r2 = executeShell("echo bar 1>&2");
3403 assert(r2.status == 0);
3404 assert(r2.output.chomp().stripRight() == "bar");
3405 auto r3 = executeShell("exit 123");
3406 assert(r3.status == 123);
3407 assert(r3.output.empty);
3410 @system unittest
3412 // Temporarily disable output to stderr so as to not spam the build log.
3413 import std.stdio : stderr;
3414 import std.typecons : Tuple;
3415 import std.file : readText, exists, remove;
3416 import std.traits : ReturnType;
3418 ReturnType!executeShell r;
3419 auto tmpname = uniqueTempPath;
3420 scope(exit) if (exists(tmpname)) remove(tmpname);
3421 auto t = stderr;
3422 // Open a new scope to minimize code ran with stderr redirected.
3424 stderr.open(tmpname, "w");
3425 scope(exit) stderr = t;
3426 r = executeShell("echo D rox>&2", null, Config.stderrPassThrough);
3428 assert(r.status == 0);
3429 assert(r.output.empty);
3430 auto witness = readText(tmpname);
3431 import std.ascii : newline;
3432 assert(witness == "D rox" ~ newline, "'" ~ witness ~ "'");
3435 @safe unittest
3437 import std.typecons : Tuple;
3438 void foo() //Just test the compilation
3440 auto ret1 = execute(["dummy", "arg"]);
3441 auto ret2 = executeShell("dummy arg");
3442 static assert(is(typeof(ret1) == typeof(ret2)));
3444 Tuple!(int, string) ret3 = execute(["dummy", "arg"]);
3448 /// An exception that signals a problem with starting or waiting for a process.
3449 class ProcessException : Exception
3451 import std.exception : basicExceptionCtors;
3452 mixin basicExceptionCtors;
3454 // Creates a new ProcessException based on errno.
3455 static ProcessException newFromErrno(string customMsg = null,
3456 string file = __FILE__,
3457 size_t line = __LINE__)
3459 import core.stdc.errno : errno;
3460 return newFromErrno(errno, customMsg, file, line);
3463 // ditto, but error number is provided by caller
3464 static ProcessException newFromErrno(int error,
3465 string customMsg = null,
3466 string file = __FILE__,
3467 size_t line = __LINE__)
3469 import std.exception : errnoString;
3470 auto errnoMsg = errnoString(error);
3471 auto msg = customMsg.empty ? errnoMsg
3472 : customMsg ~ " (" ~ errnoMsg ~ ')';
3473 return new ProcessException(msg, file, line);
3476 // Creates a new ProcessException based on GetLastError() (Windows only).
3477 version (Windows)
3478 static ProcessException newFromLastError(string customMsg = null,
3479 string file = __FILE__,
3480 size_t line = __LINE__)
3482 auto lastMsg = generateSysErrorMsg();
3483 auto msg = customMsg.empty ? lastMsg
3484 : customMsg ~ " (" ~ lastMsg ~ ')';
3485 return new ProcessException(msg, file, line);
3491 Determines the path to the current user's preferred command interpreter.
3493 On Windows, this function returns the contents of the COMSPEC environment
3494 variable, if it exists. Otherwise, it returns the result of $(LREF nativeShell).
3496 On POSIX, `userShell` returns the contents of the SHELL environment
3497 variable, if it exists and is non-empty. Otherwise, it returns the result of
3498 $(LREF nativeShell).
3500 @property string userShell() @safe
3502 version (Windows) return environment.get("COMSPEC", nativeShell);
3503 else version (Posix) return environment.get("SHELL", nativeShell);
3507 The platform-specific native shell path.
3509 This function returns `"cmd.exe"` on Windows, `"/bin/sh"` on POSIX, and
3510 `"/system/bin/sh"` on Android.
3512 @property string nativeShell() @safe @nogc pure nothrow
3514 version (Windows) return "cmd.exe";
3515 else version (Android) return "/system/bin/sh";
3516 else version (Posix) return "/bin/sh";
3519 // A command-line switch that indicates to the shell that it should
3520 // interpret the following argument as a command to be executed.
3521 version (Posix) private immutable string shellSwitch = "-c";
3522 version (Windows) private immutable string shellSwitch = "/C";
3524 // Unittest support code: TestScript takes a string that contains a
3525 // shell script for the current platform, and writes it to a temporary
3526 // file. On Windows the file name gets a .cmd extension, while on
3527 // POSIX its executable permission bit is set. The file is
3528 // automatically deleted when the object goes out of scope.
3529 version (StdUnittest)
3530 private struct TestScript
3532 this(string code) @system
3534 // @system due to chmod
3535 import std.ascii : newline;
3536 import std.file : write;
3537 version (Windows)
3539 auto ext = ".cmd";
3540 auto firstLine = "@echo off";
3542 else version (Posix)
3544 auto ext = "";
3545 auto firstLine = "#!" ~ nativeShell;
3547 path = uniqueTempPath()~ext;
3548 write(path, firstLine ~ newline ~ code ~ newline);
3549 version (Posix)
3551 import core.sys.posix.sys.stat : chmod;
3552 import std.conv : octal;
3553 chmod(path.tempCString(), octal!777);
3557 ~this()
3559 import std.file : remove, exists;
3560 if (!path.empty && exists(path))
3562 try { remove(path); }
3563 catch (Exception e)
3565 debug std.stdio.stderr.writeln(e.msg);
3570 string path;
3574 // =============================================================================
3575 // Functions for shell command quoting/escaping.
3576 // =============================================================================
3580 Command line arguments exist in three forms:
3581 1) string or char* array, as received by main.
3582 Also used internally on POSIX systems.
3583 2) Command line string, as used in Windows'
3584 CreateProcess and CommandLineToArgvW functions.
3585 A specific quoting and escaping algorithm is used
3586 to distinguish individual arguments.
3587 3) Shell command string, as written at a shell prompt
3588 or passed to cmd /C - this one may contain shell
3589 control characters, e.g. > or | for redirection /
3590 piping - thus, yet another layer of escaping is
3591 used to distinguish them from program arguments.
3593 Except for escapeWindowsArgument, the intermediary
3594 format (2) is hidden away from the user in this module.
3598 Escapes an argv-style argument array to be used with $(LREF spawnShell),
3599 $(LREF pipeShell) or $(LREF executeShell).
3601 string url = "http://dlang.org/";
3602 executeShell(escapeShellCommand("wget", url, "-O", "dlang-index.html"));
3605 Concatenate multiple `escapeShellCommand` and
3606 $(LREF escapeShellFileName) results to use shell redirection or
3607 piping operators.
3609 executeShell(
3610 escapeShellCommand("curl", "http://dlang.org/download.html") ~
3611 "|" ~
3612 escapeShellCommand("grep", "-o", `http://\S*\.zip`) ~
3613 ">" ~
3614 escapeShellFileName("D download links.txt"));
3617 Throws:
3618 $(OBJECTREF Exception) if any part of the command line contains unescapable
3619 characters (NUL on all platforms, as well as CR and LF on Windows).
3621 string escapeShellCommand(scope const(char[])[] args...) @safe pure
3623 if (args.empty)
3624 return null;
3625 version (Windows)
3627 // Do not ^-escape the first argument (the program path),
3628 // as the shell parses it differently from parameters.
3629 // ^-escaping a program path that contains spaces will fail.
3630 string result = escapeShellFileName(args[0]);
3631 if (args.length > 1)
3633 result ~= " " ~ escapeShellCommandString(
3634 escapeShellArguments(args[1..$]));
3636 return result;
3638 version (Posix)
3640 return escapeShellCommandString(escapeShellArguments(args));
3644 @safe unittest
3646 // This is a simple unit test without any special requirements,
3647 // in addition to the unittest_burnin one below which requires
3648 // special preparation.
3650 struct TestVector { string[] args; string windows, posix; }
3651 TestVector[] tests =
3654 args : ["foo bar"],
3655 windows : `"foo bar"`,
3656 posix : `'foo bar'`
3659 args : ["foo bar", "hello"],
3660 windows : `"foo bar" hello`,
3661 posix : `'foo bar' hello`
3664 args : ["foo bar", "hello world"],
3665 windows : `"foo bar" ^"hello world^"`,
3666 posix : `'foo bar' 'hello world'`
3669 args : ["foo bar", "hello", "world"],
3670 windows : `"foo bar" hello world`,
3671 posix : `'foo bar' hello world`
3674 args : ["foo bar", `'"^\`],
3675 windows : `"foo bar" ^"'\^"^^\\^"`,
3676 posix : `'foo bar' ''\''"^\'`
3679 args : ["foo bar", ""],
3680 windows : `"foo bar" ^"^"`,
3681 posix : `'foo bar' ''`
3684 args : ["foo bar", "2"],
3685 windows : `"foo bar" ^"2^"`,
3686 posix : `'foo bar' '2'`
3690 foreach (test; tests)
3692 auto actual = escapeShellCommand(test.args);
3693 version (Windows)
3694 string expected = test.windows;
3695 else
3696 string expected = test.posix;
3697 assert(actual == expected, "\nExpected: " ~ expected ~ "\nGot: " ~ actual);
3701 private string escapeShellCommandString(return scope string command) @safe pure
3703 version (Windows)
3704 return escapeWindowsShellCommand(command);
3705 else
3706 return command;
3709 private string escapeWindowsShellCommand(scope const(char)[] command) @safe pure
3711 import std.array : appender;
3712 auto result = appender!string();
3713 result.reserve(command.length);
3715 foreach (c; command)
3716 switch (c)
3718 case '\0':
3719 throw new Exception("Cannot put NUL in command line");
3720 case '\r':
3721 case '\n':
3722 throw new Exception("CR/LF are not escapable");
3723 case '\x01': .. case '\x09':
3724 case '\x0B': .. case '\x0C':
3725 case '\x0E': .. case '\x1F':
3726 case '"':
3727 case '^':
3728 case '&':
3729 case '<':
3730 case '>':
3731 case '|':
3732 result.put('^');
3733 goto default;
3734 default:
3735 result.put(c);
3737 return result.data;
3740 private string escapeShellArguments(scope const(char[])[] args...)
3741 @trusted pure nothrow
3743 import std.exception : assumeUnique;
3744 char[] buf;
3746 @safe nothrow
3747 char[] allocator(size_t size)
3749 if (buf.length == 0)
3750 return buf = new char[size];
3751 else
3753 auto p = buf.length;
3754 buf.length = buf.length + 1 + size;
3755 buf[p++] = ' ';
3756 return buf[p .. p+size];
3760 foreach (arg; args)
3761 escapeShellArgument!allocator(arg);
3762 return assumeUnique(buf);
3765 private auto escapeShellArgument(alias allocator)(scope const(char)[] arg) @safe nothrow
3767 // The unittest for this function requires special
3768 // preparation - see below.
3770 version (Windows)
3771 return escapeWindowsArgumentImpl!allocator(arg);
3772 else
3773 return escapePosixArgumentImpl!allocator(arg);
3777 Quotes a command-line argument in a manner conforming to the behavior of
3778 $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx,
3779 CommandLineToArgvW).
3781 string escapeWindowsArgument(scope const(char)[] arg) @trusted pure nothrow
3783 // Rationale for leaving this function as public:
3784 // this algorithm of escaping paths is also used in other software,
3785 // e.g. DMD's response files.
3786 import std.exception : assumeUnique;
3787 auto buf = escapeWindowsArgumentImpl!charAllocator(arg);
3788 return assumeUnique(buf);
3792 private char[] charAllocator(size_t size) @safe pure nothrow
3794 return new char[size];
3798 private char[] escapeWindowsArgumentImpl(alias allocator)(scope const(char)[] arg)
3799 @safe nothrow
3800 if (is(typeof(allocator(size_t.init)[0] = char.init)))
3802 // References:
3803 // * http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx
3804 // * http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx
3806 // Check if the string needs to be escaped,
3807 // and calculate the total string size.
3809 // Trailing backslashes must be escaped
3810 bool escaping = true;
3811 bool needEscape = false;
3812 // Result size = input size + 2 for surrounding quotes + 1 for the
3813 // backslash for each escaped character.
3814 size_t size = 1 + arg.length + 1;
3816 foreach_reverse (char c; arg)
3818 if (c == '"')
3820 needEscape = true;
3821 escaping = true;
3822 size++;
3824 else
3825 if (c == '\\')
3827 if (escaping)
3828 size++;
3830 else
3832 if (c == ' ' || c == '\t')
3833 needEscape = true;
3834 escaping = false;
3838 import std.ascii : isDigit;
3839 // Empty arguments need to be specified as ""
3840 if (!arg.length)
3841 needEscape = true;
3842 else
3843 // Arguments ending with digits need to be escaped,
3844 // to disambiguate with 1>file redirection syntax
3845 if (isDigit(arg[$-1]))
3846 needEscape = true;
3848 if (!needEscape)
3849 return allocator(arg.length)[] = arg;
3851 // Construct result string.
3853 auto buf = allocator(size);
3854 size_t p = size;
3855 buf[--p] = '"';
3856 escaping = true;
3857 foreach_reverse (char c; arg)
3859 if (c == '"')
3860 escaping = true;
3861 else
3862 if (c != '\\')
3863 escaping = false;
3865 buf[--p] = c;
3866 if (escaping)
3867 buf[--p] = '\\';
3869 buf[--p] = '"';
3870 assert(p == 0);
3872 return buf;
3875 version (Windows) version (StdUnittest)
3877 private:
3878 import core.stdc.stddef;
3879 import core.stdc.wchar_ : wcslen;
3880 import core.sys.windows.shellapi : CommandLineToArgvW;
3881 import core.sys.windows.winbase;
3882 import core.sys.windows.winnt;
3883 import std.array;
3885 string[] parseCommandLine(string line)
3887 import std.algorithm.iteration : map;
3888 import std.array : array;
3889 import std.conv : to;
3890 auto lpCommandLine = (to!(WCHAR[])(line) ~ '\0').ptr;
3891 int numArgs;
3892 auto args = CommandLineToArgvW(lpCommandLine, &numArgs);
3893 scope(exit) LocalFree(args);
3894 return args[0 .. numArgs]
3895 .map!(arg => to!string(arg[0 .. wcslen(arg)]))
3896 .array();
3899 @system unittest
3901 import std.conv : text;
3902 string[] testStrings = [
3903 `Hello`,
3904 `Hello, world`,
3905 `Hello, "world"`,
3906 `C:\`,
3907 `C:\dmd`,
3908 `C:\Program Files\`,
3911 enum CHARS = `_x\" *&^` ~ "\t"; // _ is placeholder for nothing
3912 foreach (c1; CHARS)
3913 foreach (c2; CHARS)
3914 foreach (c3; CHARS)
3915 foreach (c4; CHARS)
3916 testStrings ~= [c1, c2, c3, c4].replace("_", "");
3918 foreach (s; testStrings)
3920 auto q = escapeWindowsArgument(s);
3921 auto args = parseCommandLine("Dummy.exe " ~ q);
3922 assert(args.length == 2, s ~ " => " ~ q ~ " #" ~ text(args.length-1));
3923 assert(args[1] == s, s ~ " => " ~ q ~ " => " ~ args[1]);
3928 private string escapePosixArgument(scope const(char)[] arg) @trusted pure nothrow
3930 import std.exception : assumeUnique;
3931 auto buf = escapePosixArgumentImpl!charAllocator(arg);
3932 return assumeUnique(buf);
3935 private char[] escapePosixArgumentImpl(alias allocator)(scope const(char)[] arg)
3936 @safe nothrow
3937 if (is(typeof(allocator(size_t.init)[0] = char.init)))
3939 bool needQuoting = {
3940 import std.ascii : isAlphaNum, isDigit;
3941 import std.algorithm.comparison : among;
3943 // Empty arguments need to be specified as ''
3944 if (arg.length == 0)
3945 return true;
3946 // Arguments ending with digits need to be escaped,
3947 // to disambiguate with 1>file redirection syntax
3948 if (isDigit(arg[$-1]))
3949 return true;
3951 // Obtained using:
3952 // for n in $(seq 1 255) ; do
3953 // c=$(printf \\$(printf "%o" $n))
3954 // q=$(/bin/printf '%q' "$c")
3955 // if [[ "$q" == "$c" ]] ; then printf "%s, " "'$c'" ; fi
3956 // done
3957 // printf '\n'
3958 foreach (char c; arg)
3959 if (!isAlphaNum(c) && !c.among('%', '+', ',', '-', '.', '/', ':', '@', ']', '_'))
3960 return true;
3961 return false;
3962 }();
3963 if (!needQuoting)
3965 auto buf = allocator(arg.length);
3966 buf[] = arg;
3967 return buf;
3970 // '\'' means: close quoted part of argument, append an escaped
3971 // single quote, and reopen quotes
3973 // Below code is equivalent to:
3974 // return `'` ~ std.array.replace(arg, `'`, `'\''`) ~ `'`;
3976 size_t size = 1 + arg.length + 1;
3977 foreach (char c; arg)
3978 if (c == '\'')
3979 size += 3;
3981 auto buf = allocator(size);
3982 size_t p = 0;
3983 buf[p++] = '\'';
3984 foreach (char c; arg)
3985 if (c == '\'')
3987 buf[p .. p+4] = `'\''`;
3988 p += 4;
3990 else
3991 buf[p++] = c;
3992 buf[p++] = '\'';
3993 assert(p == size);
3995 return buf;
3999 Escapes a filename to be used for shell redirection with $(LREF spawnShell),
4000 $(LREF pipeShell) or $(LREF executeShell).
4002 string escapeShellFileName(scope const(char)[] fileName) @trusted pure nothrow
4004 // The unittest for this function requires special
4005 // preparation - see below.
4007 version (Windows)
4009 // If a file starts with &, it can cause cmd.exe to misinterpret
4010 // the file name as the stream redirection syntax:
4011 // command > "&foo.txt"
4012 // gets interpreted as
4013 // command >&foo.txt
4014 // Prepend .\ to disambiguate.
4016 if (fileName.length && fileName[0] == '&')
4017 return cast(string)(`".\` ~ fileName ~ '"');
4019 return cast(string)('"' ~ fileName ~ '"');
4021 else
4022 return escapePosixArgument(fileName);
4025 // Loop generating strings with random characters
4026 //version = unittest_burnin;
4028 version (unittest_burnin)
4029 @system unittest
4031 // There are no readily-available commands on all platforms suitable
4032 // for properly testing command escaping. The behavior of CMD's "echo"
4033 // built-in differs from the POSIX program, and Windows ports of POSIX
4034 // environments (Cygwin, msys, gnuwin32) may interfere with their own
4035 // "echo" ports.
4037 // To run this unit test, create std_process_unittest_helper.d with the
4038 // following content and compile it:
4039 // import std.stdio, std.array; void main(string[] args) { write(args.join("\0")); }
4040 // Then, test this module with:
4041 // rdmd --main -unittest -version=unittest_burnin process.d
4043 import std.file : readText, remove;
4044 import std.format : format;
4045 import std.path : absolutePath;
4046 import std.random : uniform;
4048 auto helper = absolutePath("std_process_unittest_helper");
4049 assert(executeShell(helper ~ " hello").output.split("\0")[1..$] == ["hello"], "Helper malfunction");
4051 void test(string[] s, string fn)
4053 string e;
4054 string[] g;
4056 e = escapeShellCommand(helper ~ s);
4058 scope(failure) writefln("executeShell() failed.\nExpected:\t%s\nEncoded:\t%s", s, [e]);
4059 auto result = executeShell(e);
4060 assert(result.status == 0, "std_process_unittest_helper failed");
4061 g = result.output.split("\0")[1..$];
4063 assert(s == g, format("executeShell() test failed.\nExpected:\t%s\nGot:\t\t%s\nEncoded:\t%s", s, g, [e]));
4065 e = escapeShellCommand(helper ~ s) ~ ">" ~ escapeShellFileName(fn);
4067 scope(failure) writefln(
4068 "executeShell() with redirect failed.\nExpected:\t%s\nFilename:\t%s\nEncoded:\t%s", s, [fn], [e]);
4069 auto result = executeShell(e);
4070 assert(result.status == 0, "std_process_unittest_helper failed");
4071 assert(!result.output.length, "No output expected, got:\n" ~ result.output);
4072 g = readText(fn).split("\0")[1..$];
4074 remove(fn);
4075 assert(s == g,
4076 format("executeShell() with redirect test failed.\nExpected:\t%s\nGot:\t\t%s\nEncoded:\t%s", s, g, [e]));
4079 while (true)
4081 string[] args;
4082 foreach (n; 0 .. uniform(1, 4))
4084 string arg;
4085 foreach (l; 0 .. uniform(0, 10))
4087 dchar c;
4088 while (true)
4090 version (Windows)
4092 // As long as DMD's system() uses CreateProcessA,
4093 // we can't reliably pass Unicode
4094 c = uniform(0, 128);
4096 else
4097 c = uniform!ubyte();
4099 if (c == 0)
4100 continue; // argv-strings are zero-terminated
4101 version (Windows)
4102 if (c == '\r' || c == '\n')
4103 continue; // newlines are unescapable on Windows
4104 break;
4106 arg ~= c;
4108 args ~= arg;
4111 // generate filename
4112 string fn;
4113 foreach (l; 0 .. uniform(1, 10))
4115 dchar c;
4116 while (true)
4118 version (Windows)
4119 c = uniform(0, 128); // as above
4120 else
4121 c = uniform!ubyte();
4123 if (c == 0 || c == '/')
4124 continue; // NUL and / are the only characters
4125 // forbidden in POSIX filenames
4126 version (Windows)
4127 if (c < '\x20' || c == '<' || c == '>' || c == ':' ||
4128 c == '"' || c == '\\' || c == '|' || c == '?' || c == '*')
4129 continue; // http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx
4130 break;
4133 fn ~= c;
4135 fn = fn[0..$/2] ~ "_testfile_" ~ fn[$/2..$];
4137 test(args, fn);
4141 // =============================================================================
4142 // Everything below this line was part of the old std.process, and most of
4143 // it will be deprecated and removed.
4144 // =============================================================================
4148 Copyright: Copyright The D Language Foundation 2007 - 2009.
4149 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
4150 Authors: $(HTTP digitalmars.com, Walter Bright),
4151 $(HTTP erdani.org, Andrei Alexandrescu),
4152 $(HTTP thecybershadow.net, Vladimir Panteleev)
4153 Source: $(PHOBOSSRC std/_process.d)
4156 Copyright The D Language Foundation 2007 - 2009.
4157 Distributed under the Boost Software License, Version 1.0.
4158 (See accompanying file LICENSE_1_0.txt or copy at
4159 http://www.boost.org/LICENSE_1_0.txt)
4163 import core.stdc.errno;
4164 import core.stdc.stdlib;
4165 import core.stdc.string;
4166 import core.thread;
4168 version (Windows)
4170 import std.file, std.format, std.random;
4172 version (Posix)
4174 import core.sys.posix.stdlib;
4177 private void toAStringz(in string[] a, const(char)**az)
4179 import std.string : toStringz;
4180 foreach (string s; a)
4182 *az++ = toStringz(s);
4184 *az = null;
4188 /* ========================================================== */
4190 //version (Windows)
4192 // int spawnvp(int mode, string pathname, string[] argv)
4193 // {
4194 // char** argv_ = cast(char**) core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length));
4195 // scope(exit) core.stdc.stdlib.free(argv_);
4197 // toAStringz(argv, argv_);
4199 // return spawnvp(mode, pathname.tempCString(), argv_);
4200 // }
4203 // Incorporating idea (for spawnvp() on Posix) from Dave Fladebo
4205 enum { _P_WAIT, _P_NOWAIT, _P_OVERLAY }
4206 version (Windows) extern(C) int spawnvp(int, scope const(char) *, scope const(char*)*);
4207 alias P_WAIT = _P_WAIT;
4208 alias P_NOWAIT = _P_NOWAIT;
4210 /* ========================================================== */
4212 version (StdDdoc)
4215 Replaces the current process by executing a command, `pathname`, with
4216 the arguments in `argv`.
4218 $(BLUE This function is Posix-Only.)
4220 Typically, the first element of `argv` is
4221 the command being executed, i.e. $(D argv[0] == pathname). The 'p'
4222 versions of `exec` search the PATH environment variable for $(D
4223 pathname). The 'e' versions additionally take the new process'
4224 environment variables as an array of strings of the form key=value.
4226 Does not return on success (the current process will have been
4227 replaced). Returns -1 on failure with no indication of the
4228 underlying error.
4230 Windows_specific:
4231 These functions are only supported on POSIX platforms, as the Windows
4232 operating systems do not provide the ability to overwrite the current
4233 process image with another. In single-threaded programs it is possible
4234 to approximate the effect of `execv*` by using $(LREF spawnProcess)
4235 and terminating the current process once the child process has returned.
4236 For example:
4238 auto commandLine = [ "program", "arg1", "arg2" ];
4239 version (Posix)
4241 execv(commandLine[0], commandLine);
4242 throw new Exception("Failed to execute program");
4244 else version (Windows)
4246 import core.stdc.stdlib : _Exit;
4247 _Exit(wait(spawnProcess(commandLine)));
4250 This is, however, NOT equivalent to POSIX' `execv*`. For one thing, the
4251 executed program is started as a separate process, with all this entails.
4252 Secondly, in a multithreaded program, other threads will continue to do
4253 work while the current thread is waiting for the child process to complete.
4255 A better option may sometimes be to terminate the current program immediately
4256 after spawning the child process. This is the behaviour exhibited by the
4257 $(LINK2 http://msdn.microsoft.com/en-us/library/431x4c1w.aspx,`__exec`)
4258 functions in Microsoft's C runtime library, and it is how D's now-deprecated
4259 Windows `execv*` functions work. Example:
4261 auto commandLine = [ "program", "arg1", "arg2" ];
4262 version (Posix)
4264 execv(commandLine[0], commandLine);
4265 throw new Exception("Failed to execute program");
4267 else version (Windows)
4269 spawnProcess(commandLine);
4270 import core.stdc.stdlib : _exit;
4271 _exit(0);
4275 int execv(in string pathname, in string[] argv);
4276 ///ditto
4277 int execve(in string pathname, in string[] argv, in string[] envp);
4278 /// ditto
4279 int execvp(in string pathname, in string[] argv);
4280 /// ditto
4281 int execvpe(in string pathname, in string[] argv, in string[] envp);
4283 else version (Posix)
4285 int execv(in string pathname, in string[] argv)
4287 return execv_(pathname, argv);
4289 int execve(in string pathname, in string[] argv, in string[] envp)
4291 return execve_(pathname, argv, envp);
4293 int execvp(in string pathname, in string[] argv)
4295 return execvp_(pathname, argv);
4297 int execvpe(in string pathname, in string[] argv, in string[] envp)
4299 return execvpe_(pathname, argv, envp);
4303 // Move these C declarations to druntime if we decide to keep the D wrappers
4304 extern(C)
4306 int execv(scope const(char) *, scope const(char *)*);
4307 int execve(scope const(char)*, scope const(char*)*, scope const(char*)*);
4308 int execvp(scope const(char)*, scope const(char*)*);
4309 version (Windows) int execvpe(scope const(char)*, scope const(char*)*, scope const(char*)*);
4312 private int execv_(in string pathname, in string[] argv)
4314 import core.exception : OutOfMemoryError;
4315 import std.exception : enforce;
4316 auto argv_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length));
4317 enforce!OutOfMemoryError(argv_ !is null, "Out of memory in std.process.");
4318 scope(exit) core.stdc.stdlib.free(argv_);
4320 toAStringz(argv, argv_);
4322 return execv(pathname.tempCString(), argv_);
4325 private int execve_(in string pathname, in string[] argv, in string[] envp)
4327 import core.exception : OutOfMemoryError;
4328 import std.exception : enforce;
4329 auto argv_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length));
4330 enforce!OutOfMemoryError(argv_ !is null, "Out of memory in std.process.");
4331 scope(exit) core.stdc.stdlib.free(argv_);
4332 auto envp_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + envp.length));
4333 enforce!OutOfMemoryError(envp_ !is null, "Out of memory in std.process.");
4334 scope(exit) core.stdc.stdlib.free(envp_);
4336 toAStringz(argv, argv_);
4337 toAStringz(envp, envp_);
4339 return execve(pathname.tempCString(), argv_, envp_);
4342 private int execvp_(in string pathname, in string[] argv)
4344 import core.exception : OutOfMemoryError;
4345 import std.exception : enforce;
4346 auto argv_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length));
4347 enforce!OutOfMemoryError(argv_ !is null, "Out of memory in std.process.");
4348 scope(exit) core.stdc.stdlib.free(argv_);
4350 toAStringz(argv, argv_);
4352 return execvp(pathname.tempCString(), argv_);
4355 private int execvpe_(in string pathname, in string[] argv, in string[] envp)
4357 version (Posix)
4359 import std.array : split;
4360 import std.conv : to;
4361 // Is pathname rooted?
4362 if (pathname[0] == '/')
4364 // Yes, so just call execve()
4365 return execve(pathname, argv, envp);
4367 else
4369 // No, so must traverse PATHs, looking for first match
4370 string[] envPaths = split(
4371 to!string(core.stdc.stdlib.getenv("PATH")), ":");
4372 int iRet = 0;
4374 // Note: if any call to execve() succeeds, this process will cease
4375 // execution, so there's no need to check the execve() result through
4376 // the loop.
4378 foreach (string pathDir; envPaths)
4380 string composite = cast(string) (pathDir ~ "/" ~ pathname);
4382 iRet = execve(composite, argv, envp);
4384 if (0 != iRet)
4386 iRet = execve(pathname, argv, envp);
4389 return iRet;
4392 else version (Windows)
4394 import core.exception : OutOfMemoryError;
4395 import std.exception : enforce;
4396 auto argv_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + argv.length));
4397 enforce!OutOfMemoryError(argv_ !is null, "Out of memory in std.process.");
4398 scope(exit) core.stdc.stdlib.free(argv_);
4399 auto envp_ = cast(const(char)**)core.stdc.stdlib.malloc((char*).sizeof * (1 + envp.length));
4400 enforce!OutOfMemoryError(envp_ !is null, "Out of memory in std.process.");
4401 scope(exit) core.stdc.stdlib.free(envp_);
4403 toAStringz(argv, argv_);
4404 toAStringz(envp, envp_);
4406 return execvpe(pathname.tempCString(), argv_, envp_);
4408 else
4410 static assert(0);
4411 } // version
4414 version (StdDdoc)
4416 /****************************************
4417 * Start up the browser and set it to viewing the page at url.
4419 void browse(scope const(char)[] url);
4421 else
4422 version (Windows)
4424 import core.sys.windows.shellapi, core.sys.windows.winuser;
4426 pragma(lib,"shell32.lib");
4428 void browse(scope const(char)[] url) nothrow @nogc @trusted
4430 ShellExecuteW(null, "open", url.tempCStringW(), null, null, SW_SHOWNORMAL);
4433 else version (Posix)
4435 import core.stdc.stdio;
4436 import core.stdc.string;
4437 import core.sys.posix.unistd;
4439 void browse(scope const(char)[] url) nothrow @nogc @safe
4441 const buffer = url.tempCString(); // Retain buffer until end of scope
4442 const(char)*[3] args;
4444 // Trusted because it's called with a zero-terminated literal
4445 const(char)* browser = (() @trusted => core.stdc.stdlib.getenv("BROWSER"))();
4446 if (browser)
4448 // String already zero-terminated
4449 browser = (() @trusted => strdup(browser))();
4450 args[0] = browser;
4452 else
4454 version (OSX)
4456 args[0] = "open";
4458 else
4460 //args[0] = "x-www-browser"; // doesn't work on some systems
4461 args[0] = "xdg-open";
4465 args[1] = buffer;
4466 args[2] = null;
4468 auto childpid = core.sys.posix.unistd.fork();
4469 if (childpid == 0)
4471 // Trusted because args and all entries are always zero-terminated
4472 (() @trusted =>
4473 core.sys.posix.unistd.execvp(args[0], &args[0]) ||
4474 perror(args[0]) // failed to execute
4475 )();
4476 return;
4478 if (browser)
4479 // Trusted because it's allocated via strdup above
4480 (() @trusted => free(cast(void*) browser))();
4482 version (StdUnittest)
4484 // Verify that the test script actually suceeds
4485 int status;
4486 const check = (() @trusted => waitpid(childpid, &status, 0))();
4487 assert(check != -1);
4488 assert(status == 0);
4492 else
4493 static assert(0, "os not supported");
4495 // Verify attributes are consistent between all implementations
4496 @safe @nogc nothrow unittest
4498 if (false)
4499 browse("");
4502 version (Windows) { /* Doesn't use BROWSER */ }
4503 else
4504 @system unittest
4506 import std.conv : text;
4507 import std.range : repeat;
4508 immutable string url = text("http://", repeat('x', 249));
4510 TestScript prog = `if [ "$1" != "` ~ url ~ `" ]; then exit 1; fi`;
4511 environment["BROWSER"] = prog.path;
4512 browse(url);