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