PageRenderTime 140ms CodeModel.GetById 3ms app.highlight 121ms RepoModel.GetById 1ms app.codeStats 1ms

/std/process.d

http://github.com/jcd/phobos
D | 3445 lines | 2043 code | 295 blank | 1107 comment | 385 complexity | c9ae7d4412c9f60edf2d104d11570b7e MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1// Written in the D programming language.
   2
   3/**
   4Functions for starting and interacting with other processes, and for
   5working with the current _process' execution environment.
   6
   7Process_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 $(D 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 $(D 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 $(D 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    $(D spawnProcess), $(D pipeProcess) and $(D execute), respectively,
  36    except that they take a single command string and run it through
  37    the current user's default command interpreter.
  38    $(D executeShell) corresponds roughly to C's $(D system) function.)
  39$(LI
  40    $(LREF kill) attempts to terminate a running _process.)
  41)
  42
  43The following table compactly summarises the different _process creation
  44functions 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
  60Other_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
  72Authors:
  73    $(LINK2 https://github.com/kyllingstad, Lars Tandle Kyllingstad),
  74    $(LINK2 https://github.com/schveiguy, Steven Schveighoffer),
  75    $(WEB thecybershadow.net, Vladimir Panteleev)
  76Copyright:
  77    Copyright (c) 2013, the authors. All rights reserved.
  78Source:
  79    $(PHOBOSSRC std/_process.d)
  80Macros:
  81    WIKI=Phobos/StdProcess
  82    OBJECTREF=$(D $(LINK2 object.html#$0,$0))
  83    LREF=$(D $(LINK2 #.$0,$0))
  84*/
  85module std.process;
  86
  87version (Posix)
  88{
  89    import core.stdc.errno;
  90    import core.stdc.string;
  91    import core.sys.posix.stdio;
  92    import core.sys.posix.unistd;
  93    import core.sys.posix.sys.wait;
  94}
  95version (Windows)
  96{
  97    import core.stdc.stdio;
  98    import core.sys.windows.windows;
  99    import std.utf;
 100    import std.windows.syserror;
 101}
 102import std.algorithm;
 103import std.array;
 104import std.conv;
 105import std.exception;
 106import std.path;
 107import std.stdio;
 108import std.string;
 109import std.internal.processinit;
 110
 111
 112// When the DMC runtime is used, we have to use some custom functions
 113// to convert between Windows file handles and FILE*s.
 114version (Win32) version (DigitalMars) version = DMC_RUNTIME;
 115
 116
 117// Some of the following should be moved to druntime.
 118private
 119{
 120
 121// Microsoft Visual C Runtime (MSVCRT) declarations.
 122version (Windows)
 123{
 124    version (DMC_RUNTIME) { } else
 125    {
 126        import core.stdc.stdint;
 127        extern(C)
 128        {
 129            int _fileno(FILE* stream);
 130            HANDLE _get_osfhandle(int fd);
 131            int _open_osfhandle(HANDLE osfhandle, int flags);
 132            FILE* _fdopen(int fd, const (char)* mode);
 133            int _close(int fd);
 134        }
 135        enum
 136        {
 137            STDIN_FILENO  = 0,
 138            STDOUT_FILENO = 1,
 139            STDERR_FILENO = 2,
 140        }
 141        enum
 142        {
 143            _O_RDONLY = 0x0000,
 144            _O_APPEND = 0x0004,
 145            _O_TEXT   = 0x4000,
 146        }
 147    }
 148}
 149
 150// POSIX API declarations.
 151version (Posix)
 152{
 153    version (OSX)
 154    {
 155        extern(C) char*** _NSGetEnviron() nothrow;
 156        private __gshared const(char**)* environPtr;
 157        extern(C) void std_process_shared_static_this() { environPtr = _NSGetEnviron(); }
 158        const(char**) environ() @property @trusted nothrow { return *environPtr; }
 159    }
 160    else
 161    {
 162        // Made available by the C runtime:
 163        extern(C) extern __gshared const char** environ;
 164    }
 165
 166    unittest
 167    {
 168        new Thread({assert(environ !is null);}).start();
 169    }
 170}
 171
 172
 173} // private
 174
 175
 176// =============================================================================
 177// Functions and classes for process management.
 178// =============================================================================
 179
 180
 181/**
 182Spawns a new _process, optionally assigning it an arbitrary set of standard
 183input, output, and error streams.
 184
 185The function returns immediately, leaving the child _process to execute
 186in parallel with its parent.  It is recommended to always call $(LREF wait)
 187on the returned $(LREF Pid), as detailed in the documentation for $(D wait).
 188
 189Command_line:
 190There are four overloads of this function.  The first two take an array
 191of strings, $(D args), which should contain the program name as the
 192zeroth element and any command-line arguments in subsequent elements.
 193The third and fourth versions are included for convenience, and may be
 194used when there are no command-line arguments.  They take a single string,
 195$(D program), which specifies the program name.
 196
 197Unless a directory is specified in $(D args[0]) or $(D program),
 198$(D spawnProcess) will search for the program in a platform-dependent
 199manner.  On POSIX systems, it will look for the executable in the
 200directories listed in the PATH environment variable, in the order
 201they are listed.  On Windows, it will search for the executable in
 202the following sequence:
 203$(OL
 204    $(LI The directory from which the application loaded.)
 205    $(LI The current directory for the parent process.)
 206    $(LI The 32-bit Windows system directory.)
 207    $(LI The 16-bit Windows system directory.)
 208    $(LI The Windows directory.)
 209    $(LI The directories listed in the PATH environment variable.)
 210)
 211---
 212// Run an executable called "prog" located in the current working
 213// directory:
 214auto pid = spawnProcess("./prog");
 215scope(exit) wait(pid);
 216// We can do something else while the program runs.  The scope guard
 217// ensures that the process is waited for at the end of the scope.
 218...
 219
 220// Run DMD on the file "myprog.d", specifying a few compiler switches:
 221auto dmdPid = spawnProcess(["dmd", "-O", "-release", "-inline", "myprog.d" ]);
 222if (wait(dmdPid) != 0)
 223    writeln("Compilation failed!");
 224---
 225
 226Environment_variables:
 227By default, the child process inherits the environment of the parent
 228process, along with any additional variables specified in the $(D env)
 229parameter.  If the same variable exists in both the parent's environment
 230and in $(D env), the latter takes precedence.
 231
 232If the $(LREF Config.newEnv) flag is set in $(D config), the child
 233process will $(I not) inherit the parent's environment.  Its entire
 234environment will then be determined by $(D env).
 235---
 236wait(spawnProcess("myapp", ["foo" : "bar"], Config.newEnv));
 237---
 238
 239Standard_streams:
 240The optional arguments $(D stdin), $(D stdout) and $(D stderr) may
 241be used to assign arbitrary $(XREF stdio,File) objects as the standard
 242input, output and error streams, respectively, of the child process.  The
 243former must be opened for reading, while the latter two must be opened for
 244writing.  The default is for the child process to inherit the standard
 245streams of its parent.
 246---
 247// Run DMD on the file myprog.d, logging any error messages to a
 248// file named errors.log.
 249auto logFile = File("errors.log", "w");
 250auto pid = spawnProcess(["dmd", "myprog.d"],
 251                        std.stdio.stdin,
 252                        std.stdio.stdout,
 253                        logFile);
 254if (wait(pid) != 0)
 255    writeln("Compilation failed. See errors.log for details.");
 256---
 257
 258Note that if you pass a $(D File) object that is $(I not)
 259one of the standard input/output/error streams of the parent process,
 260that stream will by default be $(I closed) in the parent process when
 261this function returns.  See the $(LREF Config) documentation below for
 262information about how to disable this behaviour.
 263
 264Beware of buffering issues when passing $(D File) objects to
 265$(D spawnProcess).  The child process will inherit the low-level raw
 266read/write offset associated with the underlying file descriptor, but
 267it will not be aware of any buffered data.  In cases where this matters
 268(e.g. when a file should be aligned before being passed on to the
 269child process), it may be a good idea to use unbuffered streams, or at
 270least ensure all relevant buffers are flushed.
 271
 272Params:
 273args    = An array which contains the program name as the zeroth element
 274          and any command-line arguments in the following elements.
 275stdin   = The standard input stream of the child process.
 276          This can be any $(XREF stdio,File) that is opened for reading.
 277          By default the child process inherits the parent's input
 278          stream.
 279stdout  = The standard output stream of the child process.
 280          This can be any $(XREF stdio,File) that is opened for writing.
 281          By default the child process inherits the parent's output stream.
 282stderr  = The standard error stream of the child process.
 283          This can be any $(XREF stdio,File) that is opened for writing.
 284          By default the child process inherits the parent's error stream.
 285env     = Additional environment variables for the child process.
 286config  = Flags that control process creation. See $(LREF Config)
 287          for an overview of available flags.
 288
 289Returns:
 290A $(LREF Pid) object that corresponds to the spawned process.
 291
 292Throws:
 293$(LREF ProcessException) on failure to start the process.$(BR)
 294$(XREF stdio,StdioException) on failure to pass one of the streams
 295    to the child process (Windows only).$(BR)
 296$(CXREF exception,RangeError) if $(D args) is empty.
 297*/
 298Pid spawnProcess(in char[][] args,
 299                 File stdin = std.stdio.stdin,
 300                 File stdout = std.stdio.stdout,
 301                 File stderr = std.stdio.stderr,
 302                 const string[string] env = null,
 303                 Config config = Config.none)
 304    @trusted // TODO: Should be @safe
 305{
 306    version (Windows)    auto  args2 = escapeShellArguments(args);
 307    else version (Posix) alias args2 = args;
 308    return spawnProcessImpl(args2, stdin, stdout, stderr, env, config);
 309}
 310
 311/// ditto
 312Pid spawnProcess(in char[][] args,
 313                 const string[string] env,
 314                 Config config = Config.none)
 315    @trusted // TODO: Should be @safe
 316{
 317    return spawnProcess(args,
 318                        std.stdio.stdin,
 319                        std.stdio.stdout,
 320                        std.stdio.stderr,
 321                        env,
 322                        config);
 323}
 324
 325/// ditto
 326Pid spawnProcess(in char[] program,
 327                 File stdin = std.stdio.stdin,
 328                 File stdout = std.stdio.stdout,
 329                 File stderr = std.stdio.stderr,
 330                 const string[string] env = null,
 331                 Config config = Config.none)
 332    @trusted
 333{
 334    return spawnProcess((&program)[0 .. 1],
 335                        stdin, stdout, stderr, env, config);
 336}
 337
 338/// ditto
 339Pid spawnProcess(in char[] program,
 340                 const string[string] env,
 341                 Config config = Config.none)
 342    @trusted
 343{
 344    return spawnProcess((&program)[0 .. 1], env, config);
 345}
 346
 347/*
 348Implementation of spawnProcess() for POSIX.
 349
 350envz should be a zero-terminated array of zero-terminated strings
 351on the form "var=value".
 352*/
 353version (Posix)
 354private Pid spawnProcessImpl(in char[][] args,
 355                             File stdin,
 356                             File stdout,
 357                             File stderr,
 358                             const string[string] env,
 359                             Config config)
 360    @trusted // TODO: Should be @safe
 361{
 362    import core.exception: RangeError;
 363
 364    if (args.empty) throw new RangeError();
 365    const(char)[] name = args[0];
 366    if (any!isDirSeparator(name))
 367    {
 368        if (!isExecutable(name))
 369            throw new ProcessException(text("Not an executable file: ", name));
 370    }
 371    else
 372    {
 373        name = searchPathFor(name);
 374        if (name is null)
 375            throw new ProcessException(text("Executable file not found: ", name));
 376    }
 377
 378    // Convert program name and arguments to C-style strings.
 379    auto argz = new const(char)*[args.length+1];
 380    argz[0] = toStringz(name);
 381    foreach (i; 1 .. args.length) argz[i] = toStringz(args[i]);
 382    argz[$-1] = null;
 383
 384    // Prepare environment.
 385    auto envz = createEnv(env, !(config & Config.newEnv));
 386
 387    // Get the file descriptors of the streams.
 388    // These could potentially be invalid, but that is OK.  If so, later calls
 389    // to dup2() and close() will just silently fail without causing any harm.
 390    auto stdinFD  = core.stdc.stdio.fileno(stdin.getFP());
 391    auto stdoutFD = core.stdc.stdio.fileno(stdout.getFP());
 392    auto stderrFD = core.stdc.stdio.fileno(stderr.getFP());
 393
 394    auto id = fork();
 395    if (id < 0)
 396        throw ProcessException.newFromErrno("Failed to spawn new process");
 397    if (id == 0)
 398    {
 399        // Child process
 400
 401        // Redirect streams and close the old file descriptors.
 402        // In the case that stderr is redirected to stdout, we need
 403        // to backup the file descriptor since stdout may be redirected
 404        // as well.
 405        if (stderrFD == STDOUT_FILENO)  stderrFD = dup(stderrFD);
 406        dup2(stdinFD,  STDIN_FILENO);
 407        dup2(stdoutFD, STDOUT_FILENO);
 408        dup2(stderrFD, STDERR_FILENO);
 409
 410        // Ensure that the standard streams aren't closed on execute, and
 411        // optionally close all other file descriptors.
 412        setCLOEXEC(STDIN_FILENO, false);
 413        setCLOEXEC(STDOUT_FILENO, false);
 414        setCLOEXEC(STDERR_FILENO, false);
 415        if (!(config & Config.inheritFDs))
 416        {
 417            import core.sys.posix.sys.resource;
 418            rlimit r;
 419            getrlimit(RLIMIT_NOFILE, &r);
 420            foreach (i; 3 .. cast(int) r.rlim_cur) close(i);
 421        }
 422
 423        // Close the old file descriptors, unless they are
 424        // either of the standard streams.
 425        if (stdinFD  > STDERR_FILENO)  close(stdinFD);
 426        if (stdoutFD > STDERR_FILENO)  close(stdoutFD);
 427        if (stderrFD > STDERR_FILENO)  close(stderrFD);
 428
 429        // Execute program.
 430        core.sys.posix.unistd.execve(argz[0], argz.ptr, envz);
 431
 432        // If execution fails, exit as quickly as possible.
 433        core.sys.posix.stdio.perror("spawnProcess(): Failed to execute program");
 434        core.sys.posix.unistd._exit(1);
 435        assert (0);
 436    }
 437    else
 438    {
 439        // Parent process:  Close streams and return.
 440        if (stdinFD  > STDERR_FILENO && !(config & Config.retainStdin))
 441            stdin.close();
 442        if (stdoutFD > STDERR_FILENO && !(config & Config.retainStdout))
 443            stdout.close();
 444        if (stderrFD > STDERR_FILENO && !(config & Config.retainStderr))
 445            stderr.close();
 446        return new Pid(id);
 447    }
 448}
 449
 450/*
 451Implementation of spawnProcess() for Windows.
 452
 453commandLine must contain the entire command line, properly
 454quoted/escaped as required by CreateProcessW().
 455
 456envz must be a pointer to a block of UTF-16 characters on the form
 457"var1=value1\0var2=value2\0...varN=valueN\0\0".
 458*/
 459version (Windows)
 460private Pid spawnProcessImpl(in char[] commandLine,
 461                             File stdin,
 462                             File stdout,
 463                             File stderr,
 464                             const string[string] env,
 465                             Config config)
 466    @trusted
 467{
 468    import core.exception: RangeError;
 469
 470    if (commandLine.empty) throw new RangeError("Command line is empty");
 471    auto commandz = toUTFz!(wchar*)(commandLine);
 472
 473    // Prepare environment.
 474    auto envz = createEnv(env, !(config & Config.newEnv));
 475
 476    // Startup info for CreateProcessW().
 477    STARTUPINFO_W startinfo;
 478    startinfo.cb = startinfo.sizeof;
 479    startinfo.dwFlags = STARTF_USESTDHANDLES;
 480
 481    // Extract file descriptors and HANDLEs from the streams and make the
 482    // handles inheritable.
 483    static void prepareStream(ref File file, DWORD stdHandle, string which,
 484                              out int fileDescriptor, out HANDLE handle)
 485    {
 486        fileDescriptor = _fileno(file.getFP());
 487        if (fileDescriptor < 0)   handle = GetStdHandle(stdHandle);
 488        else
 489        {
 490            version (DMC_RUNTIME) handle = _fdToHandle(fileDescriptor);
 491            else    /* MSVCRT */  handle = _get_osfhandle(fileDescriptor);
 492        }
 493
 494        DWORD dwFlags;
 495        if (GetHandleInformation(handle, &dwFlags))
 496        {
 497            if (!(dwFlags & HANDLE_FLAG_INHERIT))
 498            {
 499                if (!SetHandleInformation(handle,
 500                                          HANDLE_FLAG_INHERIT,
 501                                          HANDLE_FLAG_INHERIT))
 502                {
 503                    throw new StdioException(
 504                        "Failed to make "~which~" stream inheritable by child process ("
 505                        ~sysErrorString(GetLastError()) ~ ')',
 506                        0);
 507                }
 508            }
 509        }
 510    }
 511    int stdinFD = -1, stdoutFD = -1, stderrFD = -1;
 512    prepareStream(stdin,  STD_INPUT_HANDLE,  "stdin" , stdinFD,  startinfo.hStdInput );
 513    prepareStream(stdout, STD_OUTPUT_HANDLE, "stdout", stdoutFD, startinfo.hStdOutput);
 514    prepareStream(stderr, STD_ERROR_HANDLE,  "stderr", stderrFD, startinfo.hStdError );
 515
 516    // Create process.
 517    PROCESS_INFORMATION pi;
 518    DWORD dwCreationFlags =
 519        CREATE_UNICODE_ENVIRONMENT |
 520        ((config & Config.suppressConsole) ? CREATE_NO_WINDOW : 0);
 521    if (!CreateProcessW(null, commandz, null, null, true, dwCreationFlags,
 522                        envz, null, &startinfo, &pi))
 523        throw ProcessException.newFromLastError("Failed to spawn new process");
 524
 525    // figure out if we should close any of the streams
 526    if (stdinFD  > STDERR_FILENO && !(config & Config.retainStdin))
 527        stdin.close();
 528    if (stdoutFD > STDERR_FILENO && !(config & Config.retainStdout))
 529        stdout.close();
 530    if (stderrFD > STDERR_FILENO && !(config & Config.retainStderr))
 531        stderr.close();
 532
 533    // close the thread handle in the process info structure
 534    CloseHandle(pi.hThread);
 535
 536    return new Pid(pi.dwProcessId, pi.hProcess);
 537}
 538
 539// Converts childEnv to a zero-terminated array of zero-terminated strings
 540// on the form "name=value", optionally adding those of the current process'
 541// environment strings that are not present in childEnv.  If the parent's
 542// environment should be inherited without modification, this function
 543// returns environ directly.
 544version (Posix)
 545private const(char*)* createEnv(const string[string] childEnv,
 546                                bool mergeWithParentEnv)
 547{
 548    // Determine the number of strings in the parent's environment.
 549    int parentEnvLength = 0;
 550    if (mergeWithParentEnv)
 551    {
 552        if (childEnv.length == 0) return environ;
 553        while (environ[parentEnvLength] != null) ++parentEnvLength;
 554    }
 555
 556    // Convert the "new" variables to C-style strings.
 557    auto envz = new const(char)*[parentEnvLength + childEnv.length + 1];
 558    int pos = 0;
 559    foreach (var, val; childEnv)
 560        envz[pos++] = (var~'='~val~'\0').ptr;
 561
 562    // Add the parent's environment.
 563    foreach (environStr; environ[0 .. parentEnvLength])
 564    {
 565        int eqPos = 0;
 566        while (environStr[eqPos] != '=' && environStr[eqPos] != '\0') ++eqPos;
 567        if (environStr[eqPos] != '=') continue;
 568        auto var = environStr[0 .. eqPos];
 569        if (var in childEnv) continue;
 570        envz[pos++] = environStr;
 571    }
 572    envz[pos] = null;
 573    return envz.ptr;
 574}
 575
 576version (Posix) unittest
 577{
 578    auto e1 = createEnv(null, false);
 579    assert (e1 != null && *e1 == null);
 580
 581    auto e2 = createEnv(null, true);
 582    assert (e2 != null);
 583    int i = 0;
 584    for (; environ[i] != null; ++i)
 585    {
 586        assert (e2[i] != null);
 587        import core.stdc.string;
 588        assert (strcmp(e2[i], environ[i]) == 0);
 589    }
 590    assert (e2[i] == null);
 591
 592    auto e3 = createEnv(["foo" : "bar", "hello" : "world"], false);
 593    assert (e3 != null && e3[0] != null && e3[1] != null && e3[2] == null);
 594    assert ((e3[0][0 .. 8] == "foo=bar\0" && e3[1][0 .. 12] == "hello=world\0")
 595         || (e3[0][0 .. 12] == "hello=world\0" && e3[1][0 .. 8] == "foo=bar\0"));
 596}
 597
 598
 599// Converts childEnv to a Windows environment block, which is on the form
 600// "name1=value1\0name2=value2\0...nameN=valueN\0\0", optionally adding
 601// those of the current process' environment strings that are not present
 602// in childEnv.  Returns null if the parent's environment should be
 603// inherited without modification, as this is what is expected by
 604// CreateProcess().
 605version (Windows)
 606private LPVOID createEnv(const string[string] childEnv,
 607                         bool mergeWithParentEnv)
 608{
 609    if (mergeWithParentEnv && childEnv.length == 0) return null;
 610
 611    auto envz = appender!(wchar[])();
 612    void put(string var, string val)
 613    {
 614        envz.put(var);
 615        envz.put('=');
 616        envz.put(val);
 617        envz.put(cast(wchar) '\0');
 618    }
 619
 620    // Add the variables in childEnv, removing them from parentEnv
 621    // if they exist there too.
 622    auto parentEnv = mergeWithParentEnv ? environment.toAA() : null;
 623    foreach (k, v; childEnv)
 624    {
 625        auto uk = toUpper(k);
 626        put(uk, v);
 627        if (uk in parentEnv) parentEnv.remove(uk);
 628    }
 629
 630    // Add remaining parent environment variables.
 631    foreach (k, v; parentEnv) put(k, v);
 632
 633    // Two final zeros are needed in case there aren't any environment vars,
 634    // and the last one does no harm when there are.
 635    envz.put("\0\0"w);
 636    return envz.data.ptr;
 637}
 638
 639version (Windows) unittest
 640{
 641    assert (createEnv(null, true) == null);
 642    assert ((cast(wchar*) createEnv(null, false))[0 .. 2] == "\0\0"w);
 643    auto e1 = (cast(wchar*) createEnv(["foo":"bar", "ab":"c"], false))[0 .. 14];
 644    assert (e1 == "FOO=bar\0AB=c\0\0"w || e1 == "AB=c\0FOO=bar\0\0"w);
 645}
 646
 647// Searches the PATH variable for the given executable file,
 648// (checking that it is in fact executable).
 649version (Posix)
 650private string searchPathFor(in char[] executable)
 651    @trusted //TODO: @safe nothrow
 652{
 653    auto pathz = core.stdc.stdlib.getenv("PATH");
 654    if (pathz == null)  return null;
 655
 656    foreach (dir; splitter(to!string(pathz), ':'))
 657    {
 658        auto execPath = buildPath(dir, executable);
 659        if (isExecutable(execPath))  return execPath;
 660    }
 661
 662    return null;
 663}
 664
 665// Checks whether the file exists and can be executed by the
 666// current user.
 667version (Posix)
 668private bool isExecutable(in char[] path) @trusted //TODO: @safe nothrow
 669{
 670    return (access(toStringz(path), X_OK) == 0);
 671}
 672
 673version (Posix) unittest
 674{
 675    auto unamePath = searchPathFor("uname");
 676    assert (!unamePath.empty);
 677    assert (unamePath[0] == '/');
 678    assert (unamePath.endsWith("uname"));
 679    auto unlikely = searchPathFor("lkmqwpoialhggyaofijadsohufoiqezm");
 680    assert (unlikely is null, "Are you kidding me?");
 681}
 682
 683// Sets or unsets the FD_CLOEXEC flag on the given file descriptor.
 684version (Posix)
 685private void setCLOEXEC(int fd, bool on)
 686{
 687    import core.sys.posix.fcntl;
 688    auto flags = fcntl(fd, F_GETFD);
 689    if (flags >= 0)
 690    {
 691        if (on) flags |= FD_CLOEXEC;
 692        else    flags &= ~(cast(typeof(flags)) FD_CLOEXEC);
 693        flags = fcntl(fd, F_SETFD, flags);
 694    }
 695    if (flags == -1)
 696    {
 697        throw new StdioException("Failed to "~(on ? "" : "un")
 698                                 ~"set close-on-exec flag on file descriptor");
 699    }
 700}
 701
 702unittest // Command line arguments in spawnProcess().
 703{
 704    version (Windows) TestScript prog =
 705       "if not [%~1]==[foo] ( exit 1 )
 706        if not [%~2]==[bar] ( exit 2 )
 707        exit 0";
 708    else version (Posix) TestScript prog =
 709       `if test "$1" != "foo"; then exit 1; fi
 710        if test "$2" != "bar"; then exit 2; fi
 711        exit 0`;
 712    assert (wait(spawnProcess(prog.path)) == 1);
 713    assert (wait(spawnProcess([prog.path])) == 1);
 714    assert (wait(spawnProcess([prog.path, "foo"])) == 2);
 715    assert (wait(spawnProcess([prog.path, "foo", "baz"])) == 2);
 716    assert (wait(spawnProcess([prog.path, "foo", "bar"])) == 0);
 717}
 718
 719unittest // Environment variables in spawnProcess().
 720{
 721    // We really should use set /a on Windows, but Wine doesn't support it.
 722    version (Windows) TestScript envProg =
 723       `if [%STD_PROCESS_UNITTEST1%] == [1] (
 724            if [%STD_PROCESS_UNITTEST2%] == [2] (exit 3)
 725            exit 1
 726        )
 727        if [%STD_PROCESS_UNITTEST1%] == [4] (
 728            if [%STD_PROCESS_UNITTEST2%] == [2] (exit 6)
 729            exit 4
 730        )
 731        if [%STD_PROCESS_UNITTEST2%] == [2] (exit 2)
 732        exit 0`;
 733    version (Posix) TestScript envProg =
 734       `if test "$std_process_unittest1" = ""; then
 735            std_process_unittest1=0
 736        fi
 737        if test "$std_process_unittest2" = ""; then
 738            std_process_unittest2=0
 739        fi
 740        exit $(($std_process_unittest1+$std_process_unittest2))`;
 741
 742    environment.remove("std_process_unittest1"); // Just in case.
 743    environment.remove("std_process_unittest2");
 744    assert (wait(spawnProcess(envProg.path)) == 0);
 745    assert (wait(spawnProcess(envProg.path, null, Config.newEnv)) == 0);
 746
 747    environment["std_process_unittest1"] = "1";
 748    assert (wait(spawnProcess(envProg.path)) == 1);
 749    assert (wait(spawnProcess(envProg.path, null, Config.newEnv)) == 0);
 750
 751    auto env = ["std_process_unittest2" : "2"];
 752    assert (wait(spawnProcess(envProg.path, env)) == 3);
 753    assert (wait(spawnProcess(envProg.path, env, Config.newEnv)) == 2);
 754
 755    env["std_process_unittest1"] = "4";
 756    assert (wait(spawnProcess(envProg.path, env)) == 6);
 757    assert (wait(spawnProcess(envProg.path, env, Config.newEnv)) == 6);
 758
 759    environment.remove("std_process_unittest1");
 760    assert (wait(spawnProcess(envProg.path, env)) == 6);
 761    assert (wait(spawnProcess(envProg.path, env, Config.newEnv)) == 6);
 762}
 763
 764unittest // Stream redirection in spawnProcess().
 765{
 766    version (Windows) TestScript prog =
 767       "set /p INPUT=
 768        echo %INPUT% output %~1
 769        echo %INPUT% error %~2 1>&2";
 770    else version (Posix) TestScript prog =
 771       "read INPUT
 772        echo $INPUT output $1
 773        echo $INPUT error $2 >&2";
 774
 775    // Pipes
 776    auto pipei = pipe();
 777    auto pipeo = pipe();
 778    auto pipee = pipe();
 779    auto pid = spawnProcess([prog.path, "foo", "bar"],
 780                             pipei.readEnd, pipeo.writeEnd, pipee.writeEnd);
 781    pipei.writeEnd.writeln("input");
 782    pipei.writeEnd.flush();
 783    assert (pipeo.readEnd.readln().chomp() == "input output foo");
 784    assert (pipee.readEnd.readln().chomp().stripRight() == "input error bar");
 785    wait(pid);
 786
 787    // Files
 788    import std.ascii, std.file, std.uuid;
 789    auto pathi = buildPath(tempDir(), randomUUID().toString());
 790    auto patho = buildPath(tempDir(), randomUUID().toString());
 791    auto pathe = buildPath(tempDir(), randomUUID().toString());
 792    std.file.write(pathi, "INPUT"~std.ascii.newline);
 793    auto filei = File(pathi, "r");
 794    auto fileo = File(patho, "w");
 795    auto filee = File(pathe, "w");
 796    pid = spawnProcess([prog.path, "bar", "baz" ], filei, fileo, filee);
 797    wait(pid);
 798    assert (readText(patho).chomp() == "INPUT output bar");
 799    assert (readText(pathe).chomp().stripRight() == "INPUT error baz");
 800    remove(pathi);
 801    remove(patho);
 802    remove(pathe);
 803}
 804
 805unittest // Error handling in spawnProcess()
 806{
 807    assertThrown!ProcessException(spawnProcess("ewrgiuhrifuheiohnmnvqweoijwf"));
 808    assertThrown!ProcessException(spawnProcess("./rgiuhrifuheiohnmnvqweoijwf"));
 809}
 810
 811
 812/**
 813A variation on $(LREF spawnProcess) that runs the given _command through
 814the current user's preferred _command interpreter (aka. shell).
 815
 816The string $(D command) is passed verbatim to the shell, and is therefore
 817subject to its rules about _command structure, argument/filename quoting
 818and escaping of special characters.
 819The path to the shell executable is determined by the $(LREF userShell)
 820function.
 821
 822In all other respects this function works just like $(D spawnProcess).
 823Please refer to the $(LREF spawnProcess) documentation for descriptions
 824of the other function parameters, the return value and any exceptions
 825that may be thrown.
 826---
 827// Run the command/program "foo" on the file named "my file.txt", and
 828// redirect its output into foo.log.
 829auto pid = spawnShell(`foo "my file.txt" > foo.log`);
 830wait(pid);
 831---
 832
 833See_also:
 834$(LREF escapeShellCommand), which may be helpful in constructing a
 835properly quoted and escaped shell _command line for the current platform.
 836*/
 837Pid spawnShell(in char[] command,
 838               File stdin = std.stdio.stdin,
 839               File stdout = std.stdio.stdout,
 840               File stderr = std.stdio.stderr,
 841               const string[string] env = null,
 842               Config config = Config.none)
 843    @trusted // TODO: Should be @safe
 844{
 845    version (Windows)
 846    {
 847        auto args = escapeShellArguments(userShell, shellSwitch)
 848                    ~ " " ~ command;
 849    }
 850    else version (Posix)
 851    {
 852        const(char)[][3] args;
 853        args[0] = userShell;
 854        args[1] = shellSwitch;
 855        args[2] = command;
 856    }
 857    return spawnProcessImpl(args, stdin, stdout, stderr, env, config);
 858}
 859
 860/// ditto
 861Pid spawnShell(in char[] command,
 862               const string[string] env,
 863               Config config = Config.none)
 864    @trusted // TODO: Should be @safe
 865{
 866    return spawnShell(command,
 867                      std.stdio.stdin,
 868                      std.stdio.stdout,
 869                      std.stdio.stderr,
 870                      env,
 871                      config);
 872}
 873
 874unittest
 875{
 876    version (Windows)
 877        auto cmd = "echo %FOO%";
 878    else version (Posix)
 879        auto cmd = "echo $foo";
 880    import std.file;
 881    auto tmpFile = uniqueTempPath();
 882    scope(exit) if (exists(tmpFile)) remove(tmpFile);
 883    auto redir = "> \""~tmpFile~'"';
 884    auto env = ["foo" : "bar"];
 885    assert (wait(spawnShell(cmd~redir, env)) == 0);
 886    auto f = File(tmpFile, "a");
 887    assert (wait(spawnShell(cmd, std.stdio.stdin, f, std.stdio.stderr, env)) == 0);
 888    f.close();
 889    auto output = std.file.readText(tmpFile);
 890    assert (output == "bar\nbar\n" || output == "bar\r\nbar\r\n");
 891}
 892
 893
 894/**
 895Flags that control the behaviour of $(LREF spawnProcess) and
 896$(LREF spawnShell).
 897
 898Use bitwise OR to combine flags.
 899
 900Example:
 901---
 902auto logFile = File("myapp_error.log", "w");
 903
 904// Start program, suppressing the console window (Windows only),
 905// redirect its error stream to logFile, and leave logFile open
 906// in the parent process as well.
 907auto pid = spawnProcess("myapp", stdin, stdout, logFile,
 908                        Config.retainStderr | Config.suppressConsole);
 909scope(exit)
 910{
 911    auto exitCode = wait(pid);
 912    logFile.writeln("myapp exited with code ", exitCode);
 913    logFile.close();
 914}
 915---
 916*/
 917enum Config
 918{
 919    none = 0,
 920
 921    /**
 922    By default, the child process inherits the parent's environment,
 923    and any environment variables passed to $(LREF spawnProcess) will
 924    be added to it.  If this flag is set, the only variables in the
 925    child process' environment will be those given to spawnProcess.
 926    */
 927    newEnv = 1,
 928
 929    /**
 930    Unless the child process inherits the standard input/output/error
 931    streams of its parent, one almost always wants the streams closed
 932    in the parent when $(LREF spawnProcess) returns.  Therefore, by
 933    default, this is done.  If this is not desirable, pass any of these
 934    options to spawnProcess.
 935    */
 936    retainStdin  = 2,
 937    retainStdout = 4,                                  /// ditto
 938    retainStderr = 8,                                  /// ditto
 939
 940    /**
 941    On Windows, if the child process is a console application, this
 942    flag will prevent the creation of a console window.  Otherwise,
 943    it will be ignored. On POSIX, $(D suppressConsole) has no effect.
 944    */
 945    suppressConsole = 16,
 946
 947    /**
 948    On POSIX, open $(LINK2 http://en.wikipedia.org/wiki/File_descriptor,file descriptors)
 949    are by default inherited by the child process.  As this may lead
 950    to subtle bugs when pipes or multiple threads are involved,
 951    $(LREF spawnProcess) ensures that all file descriptors except the
 952    ones that correspond to standard input/output/error are closed
 953    in the child process when it starts.  Use $(D inheritFDs) to prevent
 954    this.
 955
 956    On Windows, this option has no effect, and any handles which have been
 957    explicitly marked as inheritable will always be inherited by the child
 958    process.
 959    */
 960    inheritFDs = 32,
 961}
 962
 963
 964/// A handle that corresponds to a spawned process.
 965final class Pid
 966{
 967    /**
 968    The process ID number.
 969
 970    This is a number that uniquely identifies the process on the operating
 971    system, for at least as long as the process is running.  Once $(LREF wait)
 972    has been called on the $(LREF Pid), this method will return an
 973    invalid process ID.
 974    */
 975    @property int processID() const @safe pure nothrow
 976    {
 977        return _processID;
 978    }
 979
 980    /**
 981    An operating system handle to the process.
 982
 983    This handle is used to specify the process in OS-specific APIs.
 984    On POSIX, this function returns a $(D core.sys.posix.sys.types.pid_t)
 985    with the same value as $(LREF Pid.processID), while on Windows it returns
 986    a $(D core.sys.windows.windows.HANDLE).
 987
 988    Once $(LREF wait) has been called on the $(LREF Pid), this method
 989    will return an invalid handle.
 990    */
 991    // Note: Since HANDLE is a reference, this function cannot be const.
 992    version (Windows)
 993    @property HANDLE osHandle() @safe pure nothrow
 994    {
 995        return _handle;
 996    }
 997    else version (Posix)
 998    @property pid_t osHandle() @safe pure nothrow
 999    {
1000        return _processID;
1001    }
1002
1003private:
1004    /*
1005    Pid.performWait() does the dirty work for wait() and nonBlockingWait().
1006
1007    If block == true, this function blocks until the process terminates,
1008    sets _processID to terminated, and returns the exit code or terminating
1009    signal as described in the wait() documentation.
1010
1011    If block == false, this function returns immediately, regardless
1012    of the status of the process.  If the process has terminated, the
1013    function has the exact same effect as the blocking version.  If not,
1014    it returns 0 and does not modify _processID.
1015    */
1016    version (Posix)
1017    int performWait(bool block) @trusted
1018    {
1019        if (_processID == terminated) return _exitCode;
1020        int exitCode;
1021        while(true)
1022        {
1023            int status;
1024            auto check = waitpid(_processID, &status, block ? 0 : WNOHANG);
1025            if (check == -1)
1026            {
1027                if (errno == ECHILD)
1028                {
1029                    throw new ProcessException(
1030                        "Process does not exist or is not a child process.");
1031                }
1032                else
1033                {
1034                    // waitpid() was interrupted by a signal.  We simply
1035                    // restart it.
1036                    assert (errno == EINTR);
1037                    continue;
1038                }
1039            }
1040            if (!block && check == 0) return 0;
1041            if (WIFEXITED(status))
1042            {
1043                exitCode = WEXITSTATUS(status);
1044                break;
1045            }
1046            else if (WIFSIGNALED(status))
1047            {
1048                exitCode = -WTERMSIG(status);
1049                break;
1050            }
1051            // We check again whether the call should be blocking,
1052            // since we don't care about other status changes besides
1053            // "exited" and "terminated by signal".
1054            if (!block) return 0;
1055
1056            // Process has stopped, but not terminated, so we continue waiting.
1057        }
1058        // Mark Pid as terminated, and cache and return exit code.
1059        _processID = terminated;
1060        _exitCode = exitCode;
1061        return exitCode;
1062    }
1063    else version (Windows)
1064    {
1065        int performWait(bool block) @trusted
1066        {
1067            if (_processID == terminated) return _exitCode;
1068            assert (_handle != INVALID_HANDLE_VALUE);
1069            if (block)
1070            {
1071                auto result = WaitForSingleObject(_handle, INFINITE);
1072                if (result != WAIT_OBJECT_0)
1073                    throw ProcessException.newFromLastError("Wait failed.");
1074            }
1075            if (!GetExitCodeProcess(_handle, cast(LPDWORD)&_exitCode))
1076                throw ProcessException.newFromLastError();
1077            if (!block && _exitCode == STILL_ACTIVE) return 0;
1078            CloseHandle(_handle);
1079            _handle = INVALID_HANDLE_VALUE;
1080            _processID = terminated;
1081            return _exitCode;
1082        }
1083
1084        ~this()
1085        {
1086            if(_handle != INVALID_HANDLE_VALUE)
1087            {
1088                CloseHandle(_handle);
1089                _handle = INVALID_HANDLE_VALUE;
1090            }
1091        }
1092    }
1093
1094    // Special values for _processID.
1095    enum invalid = -1, terminated = -2;
1096
1097    // OS process ID number.  Only nonnegative IDs correspond to
1098    // running processes.
1099    int _processID = invalid;
1100
1101    // Exit code cached by wait().  This is only expected to hold a
1102    // sensible value if _processID == terminated.
1103    int _exitCode;
1104
1105    // Pids are only meant to be constructed inside this module, so
1106    // we make the constructor private.
1107    version (Windows)
1108    {
1109        HANDLE _handle = INVALID_HANDLE_VALUE;
1110        this(int pid, HANDLE handle) @safe pure nothrow
1111        {
1112            _processID = pid;
1113            _handle = handle;
1114        }
1115    }
1116    else
1117    {
1118        this(int id) @safe pure nothrow
1119        {
1120            _processID = id;
1121        }
1122    }
1123}
1124
1125
1126/**
1127Waits for the process associated with $(D pid) to terminate, and returns
1128its exit status.
1129
1130In general one should always _wait for child processes to terminate
1131before exiting the parent process.  Otherwise, they may become
1132"$(WEB en.wikipedia.org/wiki/Zombie_process,zombies)"  processes
1133that are defunct, yet still occupy a slot in the OS process table.
1134
1135If the process has already terminated, this function returns directly.
1136The exit code is cached, so that if wait() is called multiple times on
1137the same $(LREF Pid) it will always return the same value.
1138
1139POSIX_specific:
1140If the process is terminated by a signal, this function returns a
1141negative number whose absolute value is the signal number.
1142Since POSIX restricts normal exit codes to the range 0-255, a
1143negative return value will always indicate termination by signal.
1144Signal codes are defined in the $(D core.sys.posix.signal) module
1145(which corresponds to the $(D signal.h) POSIX header).
1146
1147Throws:
1148$(LREF ProcessException) on failure.
1149
1150Examples:
1151See the $(LREF spawnProcess) documentation.
1152
1153See_also:
1154$(LREF tryWait), for a non-blocking function.
1155*/
1156int wait(Pid pid) @safe
1157{
1158    assert(pid !is null, "Called wait on a null Pid.");
1159    return pid.performWait(true);
1160}
1161
1162
1163unittest // Pid and wait()
1164{
1165    version (Windows)    TestScript prog = "exit %~1";
1166    else version (Posix) TestScript prog = "exit $1";
1167    assert (wait(spawnProcess([prog.path, "0"])) == 0);
1168    assert (wait(spawnProcess([prog.path, "123"])) == 123);
1169    auto pid = spawnProcess([prog.path, "10"]);
1170    assert (pid.processID > 0);
1171    version (Windows)    assert (pid.osHandle != INVALID_HANDLE_VALUE);
1172    else version (Posix) assert (pid.osHandle == pid.processID);
1173    assert (wait(pid) == 10);
1174    assert (wait(pid) == 10); // cached exit code
1175    assert (pid.processID < 0);
1176    version (Windows)    assert (pid.osHandle == INVALID_HANDLE_VALUE);
1177    else version (Posix) assert (pid.osHandle < 0);
1178}
1179
1180
1181/**
1182A non-blocking version of $(LREF wait).
1183
1184If the process associated with $(D pid) has already terminated,
1185$(D tryWait) has the exact same effect as $(D wait).
1186In this case, it returns a struct where the $(D terminated) field
1187is set to $(D true) and the $(D status) field has the same
1188interpretation as the return value of $(D wait).
1189
1190If the process has $(I not) yet terminated, this function differs
1191from $(D wait) in that does not wait for this to happen, but instead
1192returns immediately.  The $(D terminated) field of the returned
1193tuple will then be set to $(D false), while the $(D status) field
1194will always be 0 (zero).  $(D wait) or $(D tryWait) should then be
1195called again on the same $(D Pid) at some later time; not only to
1196get the exit code, but also to avoid the process becoming a "zombie"
1197when it finally terminates.  (See $(LREF wait) for details).
1198
1199Returns:
1200A $(D struct) which contains the fields $(D bool terminated)
1201and $(D int status).  (This will most likely change to become a
1202$(D std.typecons.Tuple!(bool,"terminated",int,"status")) in the future,
1203but a compiler bug currently prevents this.)
1204
1205Throws:
1206$(LREF ProcessException) on failure.
1207
1208Example:
1209---
1210auto pid = spawnProcess("dmd myapp.d");
1211scope(exit) wait(pid);
1212...
1213auto dmd = tryWait(pid);
1214if (dmd.terminated)
1215{
1216    if (dmd.status == 0) writeln("Compilation succeeded!");
1217    else writeln("Compilation failed");
1218}
1219else writeln("Still compiling...");
1220...
1221---
1222Note that in this example, the first $(D wait) call will have no
1223effect if the process has already terminated by the time $(D tryWait)
1224is called.  In the opposite case, however, the $(D scope) statement
1225ensures that we always wait for the process if it hasn't terminated
1226by the time we reach the end of the scope.
1227*/
1228auto tryWait(Pid pid) @safe
1229{
1230    struct TryWaitResult
1231    {
1232        bool terminated;
1233        int status;
1234    }
1235    assert(pid !is null, "Called tryWait on a null Pid.");
1236    auto code = pid.performWait(false);
1237    return TryWaitResult(pid._processID == Pid.terminated, code);
1238}
1239// unittest: This function is tested together with kill() below.
1240
1241
1242/**
1243Attempts to terminate the process associated with $(D pid).
1244
1245The effect of this function, as well as the meaning of $(D codeOrSignal),
1246is highly platform dependent.  Details are given below.  Common to all
1247platforms is that this function only $(I initiates) termination of the process,
1248and returns immediately.  It does not wait for the process to end,
1249nor does it guarantee that the process does in fact get terminated.
1250
1251Always call $(LREF wait) to wait for a process to complete, even if $(D kill)
1252has been called on it.
1253
1254Windows_specific:
1255The process will be
1256$(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/ms686714%28v=vs.100%29.aspx,
1257forcefully and abruptly terminated).  If $(D codeOrSignal) is specified, it
1258must be a nonnegative number which will be used as the exit code of the process.
1259If not, the process wil exit with code 1.  Do not use $(D codeOrSignal = 259),
1260as this is a special value (aka. $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/ms683189.aspx,STILL_ACTIVE))
1261used by Windows to signal that a process has in fact $(I not) terminated yet.
1262---
1263auto pid = spawnProcess("some_app");
1264kill(pid, 10);
1265assert (wait(pid) == 10);
1266---
1267
1268POSIX_specific:
1269A $(LINK2 http://en.wikipedia.org/wiki/Unix_signal,signal) will be sent to
1270the process, whose value is given by $(D codeOrSignal).  Depending on the
1271signal sent, this may or may not terminate the process.  Symbolic constants
1272for various $(LINK2 http://en.wikipedia.org/wiki/Unix_signal#POSIX_signals,
1273POSIX signals) are defined in $(D core.sys.posix.signal), which corresponds to the
1274$(LINK2 http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html,
1275$(D signal.h) POSIX header).  If $(D codeOrSignal) is omitted, the
1276$(D SIGTERM) signal will be sent.  (This matches the behaviour of the
1277$(LINK2 http://pubs.opengroup.org/onlinepubs/9699919799/utilities/kill.html,
1278$(D _kill)) shell command.)
1279---
1280import core.sys.posix.signal: SIGKILL;
1281auto pid = spawnProcess("some_app");
1282kill(pid, SIGKILL);
1283assert (wait(pid) == -SIGKILL); // Negative return value on POSIX!
1284---
1285
1286Throws:
1287$(LREF ProcessException) on error (e.g. if codeOrSignal is invalid).
1288    Note that failure to terminate the process is considered a "normal"
1289    outcome, not an error.$(BR)
1290*/
1291void kill(Pid pid)
1292{
1293    version (Windows) kill(pid, 1);
1294    else version (Posix)
1295    {
1296        import core.sys.posix.signal: SIGTERM;
1297        kill(pid, SIGTERM);
1298    }
1299}
1300
1301/// ditto
1302void kill(Pid pid, int codeOrSignal)
1303{
1304    version (Windows)
1305    {
1306        if (codeOrSignal < 0) throw new ProcessException("Invalid exit code");
1307        version (Win32)
1308        {
1309            // On Windows XP, TerminateProcess() appears to terminate the
1310            // *current* process if it is passed an invalid handle...
1311            if (pid.osHandle == INVALID_HANDLE_VALUE)
1312                throw new ProcessException("Invalid process handle");
1313        }
1314        if (!TerminateProcess(pid.osHandle, codeOrSignal))
1315            throw ProcessException.newFromLastError();
1316    }
1317    else version (Posix)
1318    {
1319        import core.sys.posix.signal;
1320        if (kill(pid.osHandle, codeOrSignal) == -1)
1321            throw ProcessException.newFromErrno();
1322    }
1323}
1324
1325unittest // tryWait() and kill()
1326{
1327    import core.thread;
1328    // The test script goes into an infinite loop.
1329    version (Windows)
1330    {
1331        TestScript prog = ":loop
1332                           goto loop";
1333    }
1334    else version (Posix)
1335    {
1336        import core.sys.posix.signal: SIGTERM, SIGKILL;
1337        TestScript prog = "while true; do sleep 1; done";
1338    }
1339    auto pid = spawnProcess(prog.path);
1340    Thread.sleep(dur!"seconds"(1));
1341    kill(pid);
1342    version (Windows)    assert (wait(pid) == 1);
1343    else version (Posix) assert (wait(pid) == -SIGTERM);
1344
1345    pid = spawnProcess(prog.path);
1346    Thread.sleep(dur!"seconds"(1));
1347    auto s = tryWait(pid);
1348    assert (!s.terminated && s.status == 0);
1349    assertThrown!ProcessException(kill(pid, -123)); // Negative code not allowed.
1350    version (Windows)    kill(pid, 123);
1351    else version (Posix) kill(pid, SIGKILL);
1352    do { s = tryWait(pid); } while (!s.terminated);
1353    version (Windows)    assert (s.status == 123);
1354    else version (Posix) assert (s.status == -SIGKILL);
1355    assertThrown!ProcessException(kill(pid));
1356}
1357
1358
1359/**
1360Creates a unidirectional _pipe.
1361
1362Data is written to one end of the _pipe and read from the other.
1363---
1364auto p = pipe();
1365p.writeEnd.writeln("Hello World");
1366assert (p.readEnd.readln().chomp() == "Hello World");
1367---
1368Pipes can, for example, be used for interprocess communication
1369by spawning a new process and passing one end of the _pipe to
1370the child, while the parent uses the other end.
1371(See also $(LREF pipeProcess) and $(LREF pipeShell) for an easier
1372way of doing this.)
1373---
1374// Use cURL to download the dlang.org front page, pipe its
1375// output to grep to extract a list of links to ZIP files,
1376// and write the list to the file "D downloads.txt":
1377auto p = pipe();
1378auto outFile = File("D downloads.txt", "w");
1379auto cpid = spawnProcess(["curl", "http://dlang.org/download.html"],
1380                         std.stdio.stdin, p.writeEnd);
1381scope(exit) wait(cpid);
1382auto gpid = spawnProcess(["grep", "-o", `http://\S*\.zip`],
1383                         p.readEnd, outFile);
1384scope(exit) wait(gpid);
1385---
1386
1387Returns:
1388A $(LREF Pipe) object that corresponds to the created _pipe.
1389
1390Throws:
1391$(XREF stdio,StdioException) on failure.
1392*/
1393version (Posix)
1394Pipe pipe() @trusted //TODO: @safe
1395{
1396    int[2] fds;
1397    if (core.sys.posix.unistd.pipe(fds) != 0)
1398        throw new StdioException("Unable to create pipe");
1399    Pipe p;
1400    auto readFP = fdopen(fds[0], "r");
1401    if (readFP == null)
1402        throw new StdioException("Cannot open read end of pipe");
1403    p._read = File(readFP, null);
1404    auto writeFP = fdopen(fds[1], "w");
1405    if (writeFP == null)
1406        throw new StdioException("Cannot open write end of pipe");
1407    p._write = File(writeFP, null);
1408    return p;
1409}
1410else version (Windows)
1411Pipe pipe() @trusted //TODO: @safe
1412{
1413    // use CreatePipe to create an anonymous pipe
1414    HANDLE readHandle;
1415    HANDLE writeHandle;
1416    if (!CreatePipe(&readHandle, &writeHandle, null, 0))
1417    {
1418        throw new StdioException(
1419            "Error creating pipe (" ~ sysErrorString(GetLastError()) ~ ')',
1420            0);
1421    }
1422
1423    // Create file descriptors from the handles
1424    version (DMC_RUNTIME)
1425    {
1426        auto readFD  = _handleToFD(readHandle, FHND_DEVICE);
1427        auto writeFD = _handleToFD(writeHandle, FHND_DEVICE);
1428    }
1429    else // MSVCRT
1430    {
1431        auto readFD  = _open_osfhandle(readHandle, _O_RDONLY);
1432        auto writeFD = _open_osfhandle(writeHandle, _O_APPEND);
1433    }
1434    version (DMC_RUNTIME) alias .close _close;
1435    if (readFD == -1 || writeFD == -1)
1436    {
1437        // Close file descriptors, then throw.
1438        if (readFD >= 0) _close(readFD);
1439        else CloseHandle(readHandle);
1440        if (writeFD >= 0) _close(writeFD);
1441        else CloseHandle(writeHandle);
1442        throw new StdioException("Error creating pipe");
1443    }
1444
1445    // Create FILE pointers from the file descriptors
1446    Pipe p;
1447    version (DMC_RUNTIME)
1448    {
1449        // This is a re-implementation of DMC's fdop…

Large files files are truncated, but you can click here to view the full file