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