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