1 /*******************************************************************************
2 3 Copyright:
4 Copyright (c) 2006 Juan Jose Comellas.
5 Some parts copyright (c) 2009-2016 dunnhumby Germany GmbH.
6 All rights reserved.
7 8 License:
9 Tango Dual License: 3-Clause BSD License / Academic Free License v3.0.
10 See LICENSE_TANGO.txt for details.
11 12 Authors: Juan Jose Comellas <juanjo@comellas.com.ar>
13 14 *******************************************************************************/15 16 moduleocean.sys.Process;
17 18 importocean.meta.types.Qualifiers;
19 importocean.core.Verify;
20 importocean.core.Array : copy;
21 importocean.io.model.IFile;
22 importocean.io.Console;
23 importocean.sys.Common;
24 importocean.sys.Pipe;
25 importocean.core.ExceptionDefinitions;
26 importocean.text.convert.Formatter;
27 importocean.text.Util;
28 29 version (unittest) importocean.core.Test;
30 31 importcore.stdc.stdlib;
32 importcore.stdc.string;
33 34 importcore.stdc.errno;
35 importocean.stdc.posix.fcntl;
36 importcore.sys.posix.unistd;
37 importcore.sys.posix.sys.wait;
38 39 private40 {
41 __gsharedextern (C) externchar** environ;
42 }
43 44 debug (Process)
45 {
46 importocean.io.Stdout;
47 }
48 49 50 /**
51 * Redirect flags for processes. Defined outside process class to cut down on
52 * verbosity.
53 */54 enumRedirect55 {
56 /**
57 * Redirect none of the standard handles
58 */59 None = 0,
60 61 /**
62 * Redirect the stdout handle to a pipe.
63 */64 Output = 1,
65 66 /**
67 * Redirect the stderr handle to a pipe.
68 */69 Error = 2,
70 71 /**
72 * Redirect the stdin handle to a pipe.
73 */74 Input = 4,
75 76 /**
77 * Redirect all three handles to pipes (default).
78 */79 All = Output | Error | Input,
80 81 /**
82 * Send stderr to stdout's handle. Note that the stderr PipeConduit will
83 * be null.
84 */85 ErrorToOutput = 0x10,
86 87 /**
88 * Send stdout to stderr's handle. Note that the stdout PipeConduit will
89 * be null.
90 */91 OutputToError = 0x20,
92 }
93 94 /**
95 * The Process class is used to start external programs and communicate with
96 * them via their standard input, output and error streams.
97 *
98 * You can pass either the command line or an array of arguments to execute,
99 * either in the constructor or to the args property. The environment
100 * variables can be set in a similar way using the env property and you can
101 * set the program's working directory via the workDir property.
102 *
103 * To actually start a process you need to use the execute() method. Once the
104 * program is running you will be able to write to its standard input via the
105 * stdin OutputStream and you will be able to read from its standard output and
106 * error through the stdout and stderr InputStream respectively.
107 *
108 * You can check whether the process is running or not with the isRunning()
109 * method and you can get its process ID via the pid property.
110 *
111 * After you are done with the process, or if you just want to wait for it to
112 * end, you need to call the wait() method which will return once the process
113 * is no longer running.
114 *
115 * To stop a running process you must use kill() method. If you do this you
116 * cannot call the wait() method. Once the kill() method returns the process
117 * will be already dead.
118 *
119 * After calling either wait() or kill(), and no more data is expected on the
120 * pipes, you should call close() as this will clean the pipes. Not doing this
121 * may lead to a depletion of the available file descriptors for the main
122 * process if many processes are created.
123 *
124 * Examples:
125 * ---
126 * try
127 * {
128 * auto p = new Process ("ls -al", null);
129 * p.execute;
130 *
131 * Stdout.formatln ("Output from {}:", p.programName);
132 * Stdout.copy (p.stdout).flush;
133 * auto result = p.wait;
134 *
135 * Stdout.formatln ("Process '{}' ({}) exited with reason {}, status {}",
136 * p.programName, p.pid, cast(int) result.reason, result.status);
137 * }
138 * catch (ProcessException e)
139 * Stdout.formatln ("Process execution failed: {}", e);
140 * ---
141 *
142 * ---
143 * // Example how to pipe two processes together:
144 * auto p1 = new Process("ls");
145 * auto p2 = new Process("head");
146 *
147 * p1.execute();
148 * p2.execute();
149 *
150 * p2.stdin.copy(p1.stdout);
151 *
152 * p2.wait();
153 * Stdout.copy(p2.stdout);
154 *
155 * ---
156 */157 classProcess158 {
159 /**
160 * Result returned by wait().
161 */162 publicstructResult163 {
164 /**
165 * Reasons returned by wait() indicating why the process is no
166 * longer running.
167 */168 publicenum169 {
170 Exit,
171 Signal,
172 Stop,
173 Continue,
174 Error175 }
176 177 publicintreason;
178 publicintstatus;
179 180 /// Formatter-compatible string formatting function181 publicvoidtoString (scopeFormatterSinksink)
182 {
183 switch (reason)
184 {
185 caseExit:
186 sformat(sink,
187 "Process exited normally with return code {}", status);
188 break;
189 190 caseSignal:
191 sformat(sink, "Process was killed with signal {}", status);
192 break;
193 194 caseStop:
195 sformat(sink, "Process was stopped with signal {}", status);
196 break;
197 198 caseContinue:
199 sformat(sink, "Process was resumed with signal {}", status);
200 break;
201 202 caseError:
203 sformat(sink, "Process failed with error code {}: {}",
204 reason, SysError.lookup(status));
205 break;
206 207 default:
208 sformat(sink, "Unknown process result {}", reason);
209 break;
210 }
211 }
212 213 /// Convenience overload that format this as a string214 publicistringtoString ()
215 {
216 returnformat("{}", &this);
217 }
218 }
219 220 staticimmutableuintDefaultStdinBufferSize = 512;
221 staticimmutableuintDefaultStdoutBufferSize = 8192;
222 staticimmutableuintDefaultStderrBufferSize = 512;
223 staticimmutableRedirectDefaultRedirectFlags = Redirect.All;
224 225 privatecstring[] _args;
226 privateistring[istring] _env;
227 privatecstring_workDir;
228 privatePipeConduit_stdin;
229 privatePipeConduit_stdout;
230 privatePipeConduit_stderr;
231 privatebool_running = false;
232 privatebool_copyEnv = false;
233 privateRedirect_redirect = DefaultRedirectFlags;
234 235 privatepid_t_pid = cast(pid_t) -1;
236 237 /**
238 * Constructor (variadic version). Note that by default, the environment
239 * will not be copied.
240 *
241 * Params:
242 * args = array of strings with the process' arguments. If there is
243 * exactly one argument, it is considered to contain the entire
244 * command line including parameters. If you pass only one
245 * argument, spaces that are not intended to separate
246 * parameters should be embedded in quotes. The arguments can
247 * also be empty.
248 * Note: The class will use only slices, .dup when necessary.
249 *
250 */251 publicthis(const(mstring)[] args ...)
252 {
253 if(args.length == 1)
254 _args = splitArgs(args[0]);
255 else256 _args.copy(args);
257 }
258 259 ///260 unittest261 {
262 voidexample ( )
263 {
264 autop1 = newProcess("myprogram", "first argument", "second", "third");
265 autop2 = newProcess("myprogram \"first argument\" second third");
266 }
267 }
268 269 /**
270 * Constructor (variadic version, with environment copy).
271 *
272 * Params:
273 * copyEnv = if true, the environment is copied from the current process.
274 * args = array of strings with the process' arguments. If there is
275 * exactly one argument, it is considered to contain the entire
276 * command line including parameters. If you pass only one
277 * argument, spaces that are not intended to separate
278 * parameters should be embedded in quotes. The arguments can
279 * also be empty.
280 * Note: The class will use only slices, .dup when necessary.
281 */282 publicthis(boolcopyEnv, const(mstring)[] args ...)
283 {
284 _copyEnv = copyEnv;
285 this(args);
286 }
287 288 ///289 unittest290 {
291 voidexample ( )
292 {
293 autop1 = newProcess(true, "myprogram", "first argument", "second", "third");
294 autop2 = newProcess(true, "myprogram \"first argument\" second third");
295 }
296 }
297 298 /**
299 * Constructor.
300 *
301 * Params:
302 * command = string with the process' command line; arguments that have
303 * embedded whitespace must be enclosed in inside double-quotes (").
304 * Note: The class will use only slices, .dup when necessary.
305 * env = associative array of strings with the process' environment
306 * variables; the variable name must be the key of each entry.
307 */308 publicthis(cstringcommand, istring[istring] env)
309 {
310 verify(command.length > 0);
311 _args = splitArgs(command);
312 _env = env;
313 }
314 315 ///316 unittest317 {
318 voidexample ( )
319 {
320 cstringcommand = "myprogram \"first argument\" second third";
321 istring[istring] env;
322 323 // Environment variables324 env["MYVAR1"] = "first";
325 env["MYVAR2"] = "second";
326 327 autop = newProcess(command, env);
328 }
329 }
330 331 /**
332 * Constructor.
333 *
334 * Params:
335 * args = array of strings with the process' arguments; the first
336 * argument must be the process' name; the arguments can be
337 * empty.
338 * Note: The class will use only slices, .dup when necessary.
339 * env = associative array of strings with the process' environment
340 * variables; the variable name must be the key of each entry.
341 */342 publicthis(const(mstring)[] args, istring[istring] env)
343 {
344 verify(args.length > 0);
345 verify(args[0].length > 0);
346 _args.copy(args);
347 _env = env;
348 }
349 350 ///351 unittest352 {
353 voidexample ( )
354 {
355 istring[] args;
356 istring[istring] env;
357 358 // Process name359 args ~= "myprogram";
360 // Process arguments361 args ~= "first argument";
362 args ~= "second";
363 args ~= "third";
364 365 // Environment variables366 env["MYVAR1"] = "first";
367 env["MYVAR2"] = "second";
368 369 autop = newProcess(args, env);
370 }
371 }
372 373 /**
374 * Indicate whether the process is running or not.
375 */376 publicboolisRunning()
377 {
378 return_running;
379 }
380 381 /**
382 * Return the running process' ID.
383 *
384 * Returns: an int with the process ID if the process is running;
385 * -1 if not.
386 */387 publicintpid()
388 {
389 returncast(int) _pid;
390 }
391 392 /**
393 * Return the process' executable filename.
394 */395 publiccstringprogramName()
396 {
397 return (_args !isnull ? _args[0] : null);
398 }
399 400 /**
401 * Set the process' executable filename.
402 */403 publiccstringprogramName(cstringname)
404 {
405 if (_args.length == 0)
406 {
407 _args.length = 1;
408 }
409 return_args[0] = name;
410 }
411 412 /**
413 * Set the process' executable filename, return 'this' for chaining
414 */415 publicProcesssetProgramName(cstringname)
416 {
417 programName = name;
418 returnthis;
419 }
420 421 /**
422 * Return an array with the process' arguments.
423 */424 publiccstring[] args()
425 {
426 return_args;
427 }
428 429 /**
430 * Set the process' arguments from the arguments received by the method.
431 *
432 * Remarks:
433 * The first element of the array must be the name of the process'
434 * executable.
435 *
436 * Returns: the arguments that were set.
437 */438 publiccstring[] args(cstringprogname, const(mstring)[] args ...)
439 {
440 return_args.copy(progname ~ args);
441 }
442 443 ///444 unittest445 {
446 voidexample ( )
447 {
448 autop = newProcess;
449 p.args("myprogram", "first", "second argument", "third");
450 }
451 }
452 453 /**
454 * Set the process' command and arguments from an array.
455 *
456 * Remarks:
457 * The first element of the array must be the name of the process'
458 * executable.
459 *
460 * Returns: the arguments that were set.
461 *
462 */463 464 publicvoidargsWithCommand(const(mstring)[] args)
465 {
466 _args.copy(args);
467 }
468 469 ///470 unittest471 {
472 voidexample ( )
473 {
474 autop = newProcess;
475 p.argsWithCommand(["myprogram", "first", "second argument", "third"]);
476 }
477 }
478 479 /**
480 * Set the process' arguments from the arguments received by the method.
481 *
482 * Remarks:
483 * The first element of the array must be the name of the process'
484 * executable.
485 *
486 * Returns: a reference to this for chaining
487 *
488 */489 publicProcesssetArgs(cstringprogname, const(mstring)[] args ...)
490 {
491 this.args(progname, args);
492 returnthis;
493 }
494 495 ///496 unittest497 {
498 voidexample ( )
499 {
500 autop = newProcess;
501 p.setArgs("myprogram", "first", "second argument", "third").execute();
502 }
503 }
504 505 /**
506 * If true, the environment from the current process will be copied to the
507 * child process.
508 */509 publicboolcopyEnv()
510 {
511 return_copyEnv;
512 }
513 514 /**
515 * Set the copyEnv flag. If set to true, then the environment will be
516 * copied from the current process. If set to false, then the environment
517 * is set from the env field.
518 */519 publicboolcopyEnv(boolb)
520 {
521 return_copyEnv = b;
522 }
523 524 /**
525 * Set the copyEnv flag. If set to true, then the environment will be
526 * copied from the current process. If set to false, then the environment
527 * is set from the env field.
528 *
529 * Returns:
530 * A reference to this for chaining
531 */532 publicProcesssetCopyEnv(boolb)
533 {
534 _copyEnv = b;
535 returnthis;
536 }
537 538 /**
539 * Return an associative array with the process' environment variables.
540 *
541 * Note that if copyEnv is set to true, this value is ignored.
542 */543 publicistring[istring] env()
544 {
545 return_env;
546 }
547 548 /**
549 * Set the process' environment variables from the associative array
550 * received by the method.
551 *
552 * This also clears the copyEnv flag.
553 *
554 * Params:
555 * env = associative array of strings containing the environment
556 * variables for the process. The variable name should be the key
557 * used for each entry.
558 *
559 * Returns: the env set.
560 * Examples:
561 * ---
562 * istring[istring] env;
563 *
564 * env["MYVAR1"] = "first";
565 * env["MYVAR2"] = "second";
566 *
567 * p.env = env;
568 * ---
569 */570 publicistring[istring] env(istring[istring] env)
571 {
572 _copyEnv = false;
573 return_env = env;
574 }
575 576 /**
577 * Set the process' environment variables from the associative array
578 * received by the method. Returns a 'this' reference for chaining.
579 *
580 * This also clears the copyEnv flag.
581 *
582 * Params:
583 * env = associative array of strings containing the environment
584 * variables for the process. The variable name should be the key
585 * used for each entry.
586 *
587 * Returns: A reference to this process object
588 */589 publicProcesssetEnv(istring[istring] env)
590 {
591 _copyEnv = false;
592 _env = env;
593 returnthis;
594 }
595 596 ///597 unittest598 {
599 voidexample ( )
600 {
601 autop = newProcess;
602 istring[istring] env;
603 env["MYVAR1"] = "first";
604 env["MYVAR2"] = "second";
605 p.setEnv(env).execute();
606 }
607 }
608 609 /**
610 * Return an UTF-8 string with the process' command line.
611 */612 publicoverrideistringtoString()
613 {
614 istringcommand;
615 616 for (uinti = 0; i < _args.length; ++i)
617 {
618 if (i > 0)
619 {
620 command ~= ' ';
621 }
622 if (contains(_args[i], ' ') || _args[i].length == 0)
623 {
624 command ~= '"';
625 command ~= _args[i].substitute("\\", "\\\\").substitute(`"`, `\"`);
626 command ~= '"';
627 }
628 else629 {
630 command ~= _args[i].substitute("\\", "\\\\").substitute(`"`, `\"`);
631 }
632 }
633 returncommand;
634 }
635 636 /**
637 * Return the working directory for the process.
638 *
639 * Returns: a string with the working directory; null if the working
640 * directory is the current directory.
641 */642 publiccstringworkDir()
643 {
644 return_workDir;
645 }
646 647 /**
648 * Set the working directory for the process.
649 *
650 * Params:
651 * dir = a string with the working directory; null if the working
652 * directory is the current directory.
653 *
654 * Returns: the directory set.
655 */656 publiccstringworkDir(cstringdir)
657 {
658 return_workDir = dir;
659 }
660 661 /**
662 * Set the working directory for the process. Returns a 'this' reference
663 * for chaining
664 *
665 * Params:
666 * dir = a string with the working directory; null if the working
667 * directory is the current directory.
668 *
669 * Returns: a reference to this process.
670 */671 publicProcesssetWorkDir(cstringdir)
672 {
673 _workDir = dir;
674 returnthis;
675 }
676 677 /**
678 * Get the redirect flags for the process.
679 *
680 * The redirect flags are used to determine whether stdout, stderr, or
681 * stdin are redirected. The flags are an or'd combination of which
682 * standard handles to redirect. A redirected handle creates a pipe,
683 * whereas a non-redirected handle simply points to the same handle this
684 * process is pointing to.
685 *
686 * You can also redirect stdout or stderr to each other. The flags to
687 * redirect a handle to a pipe and to redirect it to another handle are
688 * mutually exclusive. In the case both are specified, the redirect to
689 * the other handle takes precedent. It is illegal to specify both
690 * redirection from stdout to stderr and from stderr to stdout. If both
691 * of these are specified, an exception is thrown.
692 *
693 * If redirected to a pipe, once the process is executed successfully, its
694 * input and output can be manipulated through the stdin, stdout and
695 * stderr member PipeConduit's. Note that if you redirect for example
696 * stderr to stdout, and you redirect stdout to a pipe, only stdout will
697 * be non-null.
698 */699 publicRedirectredirect()
700 {
701 return_redirect;
702 }
703 704 /**
705 * Set the redirect flags for the process.
706 */707 publicRedirectredirect(Redirectflags)
708 {
709 return_redirect = flags;
710 }
711 712 /**
713 * Set the redirect flags for the process. Return a reference to this
714 * process for chaining.
715 */716 publicProcesssetRedirect(Redirectflags)
717 {
718 _redirect = flags;
719 returnthis;
720 }
721 722 /**
723 * Get the GUI flag.
724 *
725 * This flag indicates on Windows systems that the CREATE_NO_WINDOW flag
726 * should be set on CreateProcess. Although this is a specific windows
727 * flag, it is present on posix systems as a noop for compatibility.
728 *
729 * Without this flag, a console window will be allocated if it doesn't
730 * already exist.
731 */732 publicboolgui()
733 {
734 returnfalse;
735 }
736 737 /**
738 * Set the GUI flag.
739 *
740 * This flag indicates on Windows systems that the CREATE_NO_WINDOW flag
741 * should be set on CreateProcess. Although this is a specific windows
742 * flag, it is present on posix systems as a noop for compatibility.
743 *
744 * Without this flag, a console window will be allocated if it doesn't
745 * already exist.
746 */747 publicboolgui(boolvalue)
748 {
749 returnfalse;
750 }
751 752 /**
753 * Set the GUI flag. Returns a reference to this process for chaining.
754 *
755 * This flag indicates on Windows systems that the CREATE_NO_WINDOW flag
756 * should be set on CreateProcess. Although this is a specific windows
757 * flag, it is present on posix systems as a noop for compatibility.
758 *
759 * Without this flag, a console window will be allocated if it doesn't
760 * already exist.
761 */762 publicProcesssetGui(boolvalue)
763 {
764 returnthis;
765 }
766 767 /**
768 * Return the running process' standard input pipe.
769 *
770 * Returns: a write-only PipeConduit connected to the child
771 * process' stdin.
772 *
773 * Remarks:
774 * The stream will be null if no child process has been executed, or the
775 * standard input stream was not redirected.
776 */777 publicPipeConduitstdin()
778 {
779 return_stdin;
780 }
781 782 /**
783 * Return the running process' standard output pipe.
784 *
785 * Returns: a read-only PipeConduit connected to the child
786 * process' stdout.
787 *
788 * Remarks:
789 * The stream will be null if no child process has been executed, or the
790 * standard output stream was not redirected.
791 */792 publicPipeConduitstdout()
793 {
794 return_stdout;
795 }
796 797 /**
798 * Return the running process' standard error pipe.
799 *
800 * Returns: a read-only PipeConduit connected to the child
801 * process' stderr.
802 *
803 * Remarks:
804 * The stream will be null if no child process has been executed, or the
805 * standard error stream was not redirected.
806 */807 publicPipeConduitstderr()
808 {
809 return_stderr;
810 }
811 812 /**
813 * Pipes used during execute(). They are member variables so that they
814 * can be reused by later calls to execute().
815 * Note that any file handles created during execute() will remain open
816 * and stored in these pipes, unless they are explicitly closed.
817 */818 Pipepin, pout, perr, pexec;
819 820 /**
821 * Execute a process using the arguments that were supplied to the
822 * constructor or to the args property.
823 *
824 * Once the process is executed successfully, its input and output can be
825 * manipulated through the stdin, stdout and
826 * stderr member PipeConduit's.
827 *
828 * Returns:
829 * A reference to this process object for chaining.
830 *
831 * Throws:
832 * ProcessCreateException if the process could not be created
833 * successfully; ProcessForkException if the call to the fork()
834 * system call failed (on POSIX-compatible platforms).
835 *
836 * Remarks:
837 * The process must not be running and the list of arguments must
838 * not be empty before calling this method.
839 */840 publicProcessexecute()
841 {
842 verify(!_running);
843 verify(_args.length > 0 && _args[0] !isnull);
844 845 // We close the pipes that could have been left open from a previous846 // execution.847 cleanPipes();
848 849 // validate the redirection flags850 if((_redirect & (Redirect.OutputToError | Redirect.ErrorToOutput)) == (Redirect.OutputToError | Redirect.ErrorToOutput))
851 thrownewProcessCreateException(_args[0], "Illegal redirection flags");
852 853 // Are we redirecting stdout and stderr?854 boolredirected_output = (_redirect & (Redirect.Output | Redirect.OutputToError)) == Redirect.Output;
855 boolredirected_error = (_redirect & (Redirect.Error | Redirect.ErrorToOutput)) == Redirect.Error;
856 857 if(_redirect & Redirect.Input)
858 {
859 if ( ! pin )
860 {
861 pin = newPipe(DefaultStdinBufferSize);
862 }
863 else864 {
865 pin.recreate(DefaultStdinBufferSize);
866 }
867 }
868 869 if( redirected_output )
870 {
871 if ( ! pout )
872 {
873 pout = newPipe(DefaultStdoutBufferSize);
874 }
875 else876 {
877 pout.recreate(DefaultStdoutBufferSize);
878 }
879 }
880 881 if( redirected_error )
882 {
883 if ( ! perr)
884 {
885 perr = newPipe(DefaultStderrBufferSize);
886 }
887 else888 {
889 perr.recreate(DefaultStderrBufferSize);
890 }
891 }
892 893 // This pipe is used to propagate the result of the call to894 // execv*() from the child process to the parent process.895 if (! pexec)
896 {
897 pexec = newPipe(8);
898 }
899 else900 {
901 pexec.recreate(8);
902 }
903 904 intstatus = 0;
905 906 _pid = fork();
907 if (_pid >= 0)
908 {
909 if (_pid != 0)
910 {
911 // Parent process912 if(_redirect & Redirect.Input)
913 {
914 _stdin = pin.sink;
915 pin.source.close();
916 }
917 918 if( redirected_output )
919 {
920 _stdout = pout.source;
921 pout.sink.close();
922 }
923 924 if(redirected_error)
925 {
926 _stderr = perr.source;
927 perr.sink.close();
928 }
929 930 pexec.sink.close();
931 932 try933 {
934 pexec.source.input.read((cast(byte*) &status)[0 .. status.sizeof]);
935 }
936 catch (Exceptione)
937 {
938 // Everything's OK, the pipe was closed after the call to execv*()939 }
940 941 pexec.source.close();
942 943 if (status == 0)
944 {
945 _running = true;
946 }
947 else948 {
949 // We set errno to the value that was sent through950 // the pipe from the child process951 errno = status;
952 _running = false;
953 954 thrownewProcessCreateException(_args[0]);
955 }
956 }
957 else958 {
959 // Child process960 intrc;
961 char*[] argptr;
962 char*[] envptr;
963 964 // Note that for all the pipes, we can close both ends965 // because dup2 opens a duplicate file descriptor to the966 // same resource.967 968 // Replace stdin with the "read" pipe969 if(_redirect & Redirect.Input)
970 {
971 if (dup2(pin.source.fileHandle(), STDIN_FILENO) < 0)
972 thrownewException("dup2 < 0");
973 pin.sink.close();
974 pin.source.close();
975 }
976 977 // Replace stdout with the "write" pipe978 if( redirected_output )
979 {
980 if (dup2(pout.sink.fileHandle(), STDOUT_FILENO) < 0)
981 thrownewException("dup2 < 0");
982 pout.source.close();
983 pout.sink.close();
984 }
985 986 // Replace stderr with the "write" pipe987 if( redirected_error )
988 {
989 if (dup2(perr.sink.fileHandle(), STDERR_FILENO) < 0)
990 thrownewException("dup2 < 0");
991 perr.source.close();
992 perr.sink.close();
993 }
994 995 // Check for redirection from stdout to stderr or vice996 // versa997 if(_redirect & Redirect.OutputToError)
998 {
999 if(dup2(STDERR_FILENO, STDOUT_FILENO) < 0)
1000 thrownewException("dup2 < 0");
1001 }
1002 1003 if(_redirect & Redirect.ErrorToOutput)
1004 {
1005 if(dup2(STDOUT_FILENO, STDERR_FILENO) < 0)
1006 thrownewException("dup2 < 0");
1007 }
1008 1009 // We close the unneeded part of the execv*() notification pipe1010 pexec.source.close();
1011 1012 // Set the "write" pipe so that it closes upon a successful1013 // call to execv*()1014 if (fcntl(cast(int) pexec.sink.fileHandle(), F_SETFD, FD_CLOEXEC) == 0)
1015 {
1016 // Convert the arguments and the environment variables to1017 // the format expected by the execv() family of functions.1018 argptr = toNullEndedArray(_args);
1019 envptr = (_copyEnv ? null : toNullEndedArray(_env));
1020 1021 // Switch to the working directory if it has been set.1022 if (_workDir.length > 0)
1023 {
1024 chdir((_workDir ~ "\0").ptr);
1025 }
1026 1027 // Replace the child fork with a new process. We always use the1028 // system PATH to look for executables that don't specify1029 // directories in their names.1030 rc = execvpe(_args[0], argptr, envptr);
1031 if (rc == -1)
1032 {
1033 Cerr("Failed to exec ")(_args[0])(": ")(SysError.lastMsg).newline;
1034 1035 try1036 {
1037 status = errno;
1038 1039 // Propagate the child process' errno value to1040 // the parent process.1041 pexec.sink.output.write((cast(byte*) &status)[0 .. status.sizeof]);
1042 }
1043 catch (Exceptione)
1044 {
1045 }
1046 exit(errno);
1047 }
1048 exit(errno);
1049 }
1050 else1051 {
1052 Cerr("Failed to set notification pipe to close-on-exec for ")
1053 (_args[0])(": ")(SysError.lastMsg).newline;
1054 exit(errno);
1055 }
1056 }
1057 }
1058 else1059 {
1060 thrownewProcessForkException(_pid);
1061 }
1062 returnthis;
1063 }
1064 1065 1066 /**
1067 * Unconditionally wait for a process to end and return the reason and
1068 * status code why the process ended.
1069 *
1070 * Returns:
1071 * The return value is a Result struct, which has two members:
1072 * reason and status. The reason can take the
1073 * following values:
1074 *
1075 * Process.Result.Exit: the child process exited normally;
1076 * status has the process' return
1077 * code.
1078 *
1079 * Process.Result.Signal: the child process was killed by a signal;
1080 * status has the signal number
1081 * that killed the process.
1082 *
1083 * Process.Result.Stop: the process was stopped; status
1084 * has the signal number that was used to stop
1085 * the process.
1086 *
1087 * Process.Result.Continue: the process had been previously stopped
1088 * and has now been restarted;
1089 * status has the signal number
1090 * that was used to continue the process.
1091 *
1092 * Process.Result.Error: We could not properly wait on the child
1093 * process; status has the
1094 * errno value if the process was
1095 * running and -1 if not.
1096 *
1097 * Remarks:
1098 * You can only call wait() on a running process once. The Signal, Stop
1099 * and Continue reasons will only be returned on POSIX-compatible
1100 * platforms.
1101 * Calling wait() will not clean the pipes as the parent process may still
1102 * want the remaining output. It is however recommended to call close()
1103 * when no more content is expected, as this will close the pipes.
1104 */1105 publicResultwait()
1106 {
1107 Resultresult;
1108 1109 if (_running)
1110 {
1111 intrc;
1112 1113 // We clean up the process related data and set the _running1114 // flag to false once we're done waiting for the process to1115 // finish.1116 //1117 // IMPORTANT: we don't delete the open pipes so that the parent1118 // process can get whatever the child process left on1119 // these pipes before dying.1120 scope(exit)
1121 {
1122 _running = false;
1123 }
1124 1125 // Wait for child process to end.1126 if (waitpid(_pid, &rc, 0) != -1)
1127 {
1128 if (WIFEXITED(rc))
1129 {
1130 result.reason = Result.Exit;
1131 result.status = WEXITSTATUS(rc);
1132 if (result.status != 0)
1133 {
1134 debug (Process)
1135 Stdout.formatln("Child process '{0}' ({1}) returned with code {2}\n",
1136 _args[0], _pid, result.status);
1137 }
1138 }
1139 else1140 {
1141 if (WIFSIGNALED(rc))
1142 {
1143 result.reason = Result.Signal;
1144 result.status = WTERMSIG(rc);
1145 1146 debug (Process)
1147 Stdout.formatln("Child process '{0}' ({1}) was killed prematurely "1148 ~ "with signal {2}",
1149 _args[0], _pid, result.status);
1150 }
1151 elseif (WIFSTOPPED(rc))
1152 {
1153 result.reason = Result.Stop;
1154 result.status = WSTOPSIG(rc);
1155 1156 debug (Process)
1157 Stdout.formatln("Child process '{0}' ({1}) was stopped "1158 ~ "with signal {2}",
1159 _args[0], _pid, result.status);
1160 }
1161 elseif (WIFCONTINUED(rc))
1162 {
1163 result.reason = Result.Stop;
1164 result.status = WSTOPSIG(rc);
1165 1166 debug (Process)
1167 Stdout.formatln("Child process '{0}' ({1}) was continued "1168 ~ "with signal {2}",
1169 _args[0], _pid, result.status);
1170 }
1171 else1172 {
1173 result.reason = Result.Error;
1174 result.status = rc;
1175 1176 debug (Process)
1177 Stdout.formatln("Child process '{0}' ({1}) failed "1178 ~ "with unknown exit status {2}\n",
1179 _args[0], _pid, result.status);
1180 }
1181 }
1182 }
1183 else1184 {
1185 result.reason = Result.Error;
1186 result.status = errno;
1187 1188 debug (Process)
1189 Stdout.formatln("Could not wait on child process '{0}' ({1}): ({2}) {3}",
1190 _args[0], _pid, result.status, SysError.lastMsg);
1191 }
1192 }
1193 else1194 {
1195 result.reason = Result.Error;
1196 result.status = -1;
1197 1198 debug (Process)
1199 Stdout.formatln("Child process '{0}' is not running", _args[0]);
1200 }
1201 returnresult;
1202 }
1203 1204 /**
1205 * Kill a running process. This method will not return until the process
1206 * has been killed.
1207 *
1208 * Throws:
1209 * ProcessKillException if the process could not be killed;
1210 * ProcessWaitException if we could not wait on the process after
1211 * killing it.
1212 *
1213 * Remarks:
1214 * After calling this method you will not be able to call wait() on the
1215 * process.
1216 * Killing the process does not clean the attached pipes as the parent
1217 * process may still want/need the remaining content. However, it is
1218 * recommended to call close() on the process when it is no longer needed
1219 * as this will clean the pipes.
1220 */1221 publicvoidkill()
1222 {
1223 if (_running)
1224 {
1225 intrc;
1226 1227 verify(_pid > 0);
1228 1229 if (.kill(_pid, SIGTERM) != -1)
1230 {
1231 // We clean up the process related data and set the _running1232 // flag to false once we're done waiting for the process to1233 // finish.1234 //1235 // IMPORTANT: we don't delete the open pipes so that the parent1236 // process can get whatever the child process left on1237 // these pipes before dying.1238 scope(exit)
1239 {
1240 _running = false;
1241 }
1242 1243 // FIXME: is this loop really needed?1244 for (uinti = 0; i < 100; i++)
1245 {
1246 rc = waitpid(pid, null, WNOHANG | WUNTRACED);
1247 if (rc == _pid)
1248 {
1249 break;
1250 }
1251 elseif (rc == -1)
1252 {
1253 thrownewProcessWaitException(cast(int) _pid);
1254 }
1255 usleep(50000);
1256 }
1257 }
1258 else1259 {
1260 thrownewProcessKillException(_pid);
1261 }
1262 }
1263 else1264 {
1265 debug (Process)
1266 Stdout.print("Tried to kill an invalid process");
1267 }
1268 }
1269 1270 /**
1271 * Split a string containing the command line used to invoke a program
1272 * and return and array with the parsed arguments. The double-quotes (")
1273 * character can be used to specify arguments with embedded spaces.
1274 * e.g. first "second param" third
1275 */1276 protectedstaticcstring[] splitArgs(cstringcommand, cstringdelims = " \t\r\n")
1277 {
1278 verify(
1279 !contains(delims, '"'),
1280 "The argument delimiter string cannot contain a double "1281 ~ "quotes ('\"') character"1282 );
1283 1284 enumState1285 {
1286 Start,
1287 FindDelimiter,
1288 InsideQuotes1289 }
1290 1291 cstring[] args = null;
1292 cstring[] chunks = null;
1293 intstart = -1;
1294 charc;
1295 inti;
1296 Statestate = State.Start;
1297 1298 // Append an argument to the 'args' array using the 'chunks' array1299 // and the current position in the 'command' string as the source.1300 voidappendChunksAsArg()
1301 {
1302 size_targPos;
1303 1304 if (chunks.length > 0)
1305 {
1306 // Create the array element corresponding to the argument by1307 // appending the first chunk.1308 args ~= chunks[0];
1309 argPos = args.length - 1;
1310 1311 for (uintchunkPos = 1; chunkPos < chunks.length; ++chunkPos)
1312 {
1313 args[argPos] ~= chunks[chunkPos];
1314 }
1315 1316 if (start != -1)
1317 {
1318 args[argPos] ~= command[start .. i];
1319 }
1320 chunks.length = 0;
1321 }
1322 else1323 {
1324 if (start != -1)
1325 {
1326 args ~= command[start .. i];
1327 }
1328 }
1329 start = -1;
1330 }
1331 1332 for (i = 0; i < command.length; i++)
1333 {
1334 c = command[i];
1335 1336 switch (state)
1337 {
1338 // Start looking for an argument.1339 caseState.Start:
1340 if (c == '"')
1341 {
1342 state = State.InsideQuotes;
1343 }
1344 elseif (!contains(delims, c))
1345 {
1346 start = i;
1347 state = State.FindDelimiter;
1348 }
1349 else1350 {
1351 appendChunksAsArg();
1352 }
1353 break;
1354 1355 // Find the ending delimiter for an argument.1356 caseState.FindDelimiter:
1357 if (c == '"')
1358 {
1359 // If we find a quotes character this means that we've1360 // found a quoted section of an argument. (e.g.1361 // abc"def"ghi). The quoted section will be appended1362 // to the preceding part of the argument. This is also1363 // what Unix shells do (i.e. a"b"c becomes abc).1364 if (start != -1)
1365 {
1366 chunks ~= command[start .. i];
1367 start = -1;
1368 }
1369 state = State.InsideQuotes;
1370 }
1371 elseif (contains(delims, c))
1372 {
1373 appendChunksAsArg();
1374 state = State.Start;
1375 }
1376 break;
1377 1378 // Inside a quoted argument or section of an argument.1379 caseState.InsideQuotes:
1380 if (start == -1)
1381 {
1382 start = i;
1383 }
1384 1385 if (c == '"')
1386 {
1387 chunks ~= command[start .. i];
1388 start = -1;
1389 state = State.Start;
1390 }
1391 break;
1392 1393 default:
1394 assert(false, "Invalid state in Process.splitArgs");
1395 }
1396 }
1397 1398 // Add the last argument (if there is one)1399 appendChunksAsArg();
1400 1401 returnargs;
1402 }
1403 1404 /**
1405 * Close and delete any pipe that may have been left open in a previous
1406 * execution of a child process.
1407 */1408 protectedvoidcleanPipes()
1409 {
1410 // We re-uses Pipe objects, so simply close them, if they1411 // have been used before1412 if ( pin !isnull ) pin.close();
1413 if ( pout !isnull ) pout.close();
1414 if ( perr !isnull ) perr.close();
1415 if ( pexec !isnull ) pexec.close();
1416 }
1417 1418 /**
1419 * Explicitly close any resources held by this process object. It is recommended
1420 * to always call this when you are done with the process.
1421 */1422 publicvoidclose()
1423 {
1424 this.cleanPipes;
1425 }
1426 1427 /**
1428 * Convert an array of strings to an array of pointers to char with
1429 * a terminating null character (C strings). The resulting array
1430 * has a null pointer at the end. This is the format expected by
1431 * the execv*() family of POSIX functions.
1432 */1433 protectedstaticchar*[] toNullEndedArray(cstring[] src)
1434 {
1435 if (src !isnull)
1436 {
1437 char*[] dest = newchar*[src.length + 1];
1438 autoi = src.length;
1439 1440 // Add terminating null pointer to the array1441 dest[i] = null;
1442 1443 while (i > 0)
1444 {
1445 --i;
1446 // Add a terminating null character to each string1447 autocstr = src[i];
1448 if (cstr.length == 0)
1449 dest[i] = "\0".dup.ptr;
1450 elseif (cstr[$ - 1] == '\0')
1451 dest[i] = cstr.dup.ptr;
1452 else1453 dest[i] = (cstr ~ "\0").ptr;
1454 }
1455 returndest;
1456 }
1457 else1458 {
1459 returnnull;
1460 }
1461 }
1462 1463 /**
1464 * Convert an associative array of strings to an array of pointers to
1465 * char with a terminating null character (C strings). The resulting
1466 * array has a null pointer at the end. This is the format expected by
1467 * the execv*() family of POSIX functions for environment variables.
1468 */1469 protectedstaticchar*[] toNullEndedArray(istring[istring] src)
1470 {
1471 char*[] dest;
1472 1473 foreach (key, value; src)
1474 {
1475 dest ~= (key.dup ~ '=' ~ value ~ '\0').ptr;
1476 }
1477 1478 dest ~= null;
1479 returndest;
1480 }
1481 1482 /**
1483 * Execute a process by looking up a file in the system path, passing
1484 * the array of arguments and the the environment variables. This
1485 * method is a combination of the execve() and execvp() POSIX system
1486 * calls.
1487 */1488 protectedstaticintexecvpe(cstringfilename, char*[] argv, char*[] envp)
1489 {
1490 verify(filename.length > 0);
1491 1492 intrc = -1;
1493 char* str;
1494 1495 if (!contains(filename, FileConst.PathSeparatorChar) &&
1496 (str = getenv("PATH".ptr)) !isnull)
1497 {
1498 autopathList = delimit(str[0 .. strlen(str)], ":");
1499 1500 mstringpath_buf;
1501 1502 foreach (path; pathList)
1503 {
1504 if (path[$-1] != FileConst.PathSeparatorChar)
1505 {
1506 path_buf.length = path.length + 1 + filename.length + 1;
1507 assumeSafeAppend(path_buf);
1508 1509 path_buf[] = path ~ FileConst.PathSeparatorChar ~ filename ~ '\0';
1510 }
1511 else1512 {
1513 path_buf.length = path.length +filename.length + 1;
1514 assumeSafeAppend(path_buf);
1515 1516 path_buf[] = path ~ filename ~ '\0';
1517 }
1518 1519 rc = execve(path_buf.ptr, argv.ptr, (envp.length == 0 ? environ : envp.ptr));
1520 1521 // If the process execution failed because of an error1522 // other than ENOENT (No such file or directory) we1523 // abort the loop.1524 if (rc == -1 && SysError.lastCode !isENOENT)
1525 {
1526 break;
1527 }
1528 }
1529 }
1530 else1531 {
1532 debug (Process)
1533 Stdout.formatln("Calling execve('{0}', argv[{1}], {2})",
1534 (argv[0])[0 .. strlen(argv[0])],
1535 argv.length, (envp.length > 0 ? "envp" : "null"));
1536 1537 rc = execve(argv[0], argv.ptr, (envp.length == 0 ? environ : envp.ptr));
1538 }
1539 returnrc;
1540 }
1541 }
1542 1543 1544 /**
1545 * Exception thrown when the process cannot be created.
1546 */1547 classProcessCreateException: ProcessException1548 {
1549 publicthis (cstringcommand, istringmessage = SysError.lastMsg,
1550 istringfile = __FILE__, uintline = __LINE__)
1551 {
1552 super(
1553 format("Could not create process for '{}': {}", command, message),
1554 file, line);
1555 }
1556 }
1557 1558 /**
1559 * Exception thrown when the parent process cannot be forked.
1560 *
1561 * This exception will only be thrown on POSIX-compatible platforms.
1562 */1563 classProcessForkException: ProcessException1564 {
1565 publicthis (intpid, istringfile = __FILE__, uintline = __LINE__)
1566 {
1567 super(
1568 format("Could not fork process {}: {}", pid, SysError.lastMsg),
1569 file, line);
1570 }
1571 }
1572 1573 /**
1574 * Exception thrown when the process cannot be killed.
1575 */1576 classProcessKillException: ProcessException1577 {
1578 publicthis (intpid, istringfile = __FILE__, uintline = __LINE__)
1579 {
1580 super(
1581 format("Could not kill process {}: {}", pid, SysError.lastMsg),
1582 file, line);
1583 }
1584 }
1585 1586 /**
1587 * Exception thrown when the parent process tries to wait on the child
1588 * process and fails.
1589 */1590 classProcessWaitException: ProcessException1591 {
1592 publicthis (intpid, istringfile = __FILE__, uintline = __LINE__)
1593 {
1594 super(
1595 format("Could not wait on process {}: {}", pid, SysError.lastMsg),
1596 file, line);
1597 }
1598 }
1599 1600 extern (C) uintsleep (uints);
1601 1602 unittest1603 {
1604 istringmessage = "hello world";
1605 istringcommand = "echo " ~ message;
1606 1607 try1608 {
1609 autop = newProcess(command, null);
1610 p.execute();
1611 char[255] buffer;
1612 1613 autonread = p.stdout.read(buffer);
1614 test(nread != p.stdout.Eof);
1615 test(buffer[0..nread] == message ~ "\n");
1616 1617 nread = p.stdout.read(buffer);
1618 test(nread == p.stdout.Eof);
1619 1620 autoresult = p.wait();
1621 1622 test(result.reason == Process.Result.Exit && result.status == 0);
1623 }
1624 catch (ProcessExceptione)
1625 {
1626 test(false, e.message());
1627 }
1628 }
1629 1630 // check differently qualified argument calls1631 unittest1632 {
1633 autop = newProcess("aaa", "bbb", "ccc");
1634 mstrings = "xxxx".dup;
1635 p.argsWithCommand([ s, "aaa", "bbb"]);
1636 p.programName("huh");
1637 }
1638 1639 // check non-literals arguments1640 unittest1641 {
1642 istring[] args = [ "aaa", "bbb" ];
1643 autop = newProcess(args);
1644 p.argsWithCommand(args);
1645 }