1 /*******************************************************************************
2   copyright:   Copyright (c) 2006 Juan Jose Comellas. All rights reserved
3   license:     BSD style: $(LICENSE)
4   author:      Juan Jose Comellas <juanjo@comellas.com.ar>
5 *******************************************************************************/
6 
7 module tango.sys.Process;
8 
9 private import tango.io.model.IFile;
10 private import tango.io.Console;
11 private import tango.sys.Common;
12 private import tango.sys.Pipe;
13 private import tango.core.Exception;
14 private import tango.text.Util;
15 private import Integer = tango.text.convert.Integer;
16 
17 private import tango.stdc.stdlib;
18 private import tango.stdc.string;
19 private import tango.stdc.stringz;
20 
21 version (Posix)
22 {
23     private import tango.stdc.errno;
24     private import tango.stdc.posix.fcntl;
25     private import tango.stdc.posix.unistd;
26     private import tango.stdc.posix.sys.wait;
27 
28     version(OSX)
29     {
30         extern (C) char*** _NSGetEnviron();
31         private __gshared char** environ;
32 
33         shared static this ()
34         {
35             environ = *_NSGetEnviron();
36         }
37     }
38 
39     else
40         private extern (C) extern __gshared char** environ;
41 }
42 
43 version (Windows)
44 {
45   version (Win32SansUnicode)
46   {
47   }
48   else
49   {
50     private import tango.text.convert.Utf : toString16;
51   }
52 }
53 
54 debug (Process)
55 {
56     private import tango.io.Stdout;
57 }
58 
59 
60 /**
61  * Redirect flags for processes.  Defined outside process class to cut down on
62  * verbosity.
63  */
64 enum Redirect
65 {
66     /**
67      * Redirect none of the standard handles
68      */
69     None = 0,
70 
71     /**
72      * Redirect the stdout handle to a pipe.
73      */
74     Output = 1,
75 
76     /**
77      * Redirect the stderr handle to a pipe.
78      */
79     Error = 2,
80 
81     /**
82      * Redirect the stdin handle to a pipe.
83      */
84     Input = 4,
85 
86     /**
87      * Redirect all three handles to pipes (default).
88      */
89     All = Output | Error | Input,
90 
91     /**
92      * Send stderr to stdout's handle.  Note that the stderr PipeConduit will
93      * be null.
94      */
95     ErrorToOutput = 0x10,
96 
97     /**
98      * Send stdout to stderr's handle.  Note that the stdout PipeConduit will
99      * be null.
100      */
101     OutputToError = 0x20,
102 }
103 
104 /**
105  * The Process class is used to start external programs and communicate with
106  * them via their standard input, output and error streams.
107  *
108  * You can pass either the command line or an array of arguments to execute,
109  * either in the constructor or to the args property. The environment
110  * variables can be set in a similar way using the env property and you can
111  * set the program's working directory via the workDir property.
112  *
113  * To actually start a process you need to use the execute() method. Once the
114  * program is running you will be able to write to its standard input via the
115  * stdin OutputStream and you will be able to read from its standard output and
116  * error through the stdout and stderr InputStream respectively.
117  *
118  * You can check whether the process is running or not with the isRunning()
119  * method and you can get its process ID via the pid property.
120  *
121  * After you are done with the process, or if you just want to wait for it to
122  * end, you need to call the wait() method which will return once the process
123  * is no longer running.
124  *
125  * To stop a running process you must use kill() method. If you do this you
126  * cannot call the wait() method. Once the kill() method returns the process
127  * will be already dead.
128  *
129  * After calling either wait() or kill(), and no more data is expected on the
130  * pipes, you should call close() as this will clean the pipes. Not doing this
131  * may lead to a depletion of the available file descriptors for the main
132  * process if many processes are created.
133  *
134  * Examples:
135  * ---
136  * try
137  * {
138  *     auto p = new Process ("ls -al", null);
139  *     p.execute;
140  *
141  *     Stdout.formatln ("Output from {}:", p.programName);
142  *     Stdout.copy (p.stdout).flush;
143  *     auto result = p.wait;
144  *
145  *     Stdout.formatln ("Process '{}' ({}) exited with reason {}, status {}",
146  *                      p.programName, p.pid, cast(int) result.reason, result.status);
147  * }
148  * catch (ProcessException e)
149  *        Stdout.formatln ("Process execution failed: {}", e);
150  * ---
151  */
152 class Process
153 {
154     /**
155      * Result returned by wait().
156      */
157     public struct Result
158     {
159         /**
160          * Reasons returned by wait() indicating why the process is no
161          * longer running.
162          */
163         public enum
164         {
165             Exit,
166             Signal,
167             Stop,
168             Continue,
169             Error
170         }
171 
172         public int reason;
173         public int status;
174 
175         /**
176          * Returns a string with a description of the process execution result.
177          */
178         public immutable(char)[] toString()
179         {
180             const(char)[] str;
181 
182             switch (reason)
183             {
184                 case Exit:
185                     str = format("Process exited normally with return code ", status);
186                     break;
187 
188                 case Signal:
189                     str = format("Process was killed with signal ", status);
190                     break;
191 
192                 case Stop:
193                     str = format("Process was stopped with signal ", status);
194                     break;
195 
196                 case Continue:
197                     str = format("Process was resumed with signal ", status);
198                     break;
199 
200                 case Error:
201                     str = format("Process failed with error code ", reason) ~
202                                  " : " ~ SysError.lookup(status);
203                     break;
204 
205                 default:
206                     str = format("Unknown process result ", reason);
207                     break;
208             }
209             return cast(immutable(char)[])str;
210         }
211     }
212 
213     enum uint DefaultStdinBufferSize    = 512;
214     enum uint DefaultStdoutBufferSize   = 8192;
215     enum uint DefaultStderrBufferSize   = 512;
216     enum Redirect DefaultRedirectFlags  = Redirect.All;
217 
218     private const(char[])[]        _args;
219     private const(char)[]          _program;
220     private const(char[])[char[]]  _env;
221     private const(char)[]          _workDir;
222     private PipeConduit            _stdin;
223     private PipeConduit            _stdout;
224     private PipeConduit            _stderr;
225     private bool                   _running = false;
226     private bool                   _copyEnv = false;
227     private Redirect               _redirect = DefaultRedirectFlags;
228 
229     version (Windows)
230     {
231         private PROCESS_INFORMATION *_info = null;
232         private bool                 _gui = false;
233     }
234     else
235     {
236         private pid_t _pid = cast(pid_t) -1;
237     }
238 
239     /**
240      * Constructor (variadic version).  Note that by default, the environment
241      * will not be copied.
242      *
243      * Params:
244      * args     = array of strings with the process' arguments.  If there is
245      *            exactly one argument, it is considered to contain the entire
246      *            command line including parameters.  If you pass only one
247      *            argument, spaces that are not intended to separate
248      *            parameters should be embedded in quotes.  The arguments can
249      *            also be empty.
250      *            Note: The class will use only slices, .dup when necessary. 
251      *
252      * Examples:
253      * ---
254      * auto p = new Process("myprogram", "first argument", "second", "third");
255      * auto p = new Process("myprogram \"first argument\" second third");
256      * ---
257      */
258     public this(const(char[])[] args ...)
259     {
260         if(args.length == 1)
261             _args = splitArgs(args[0]);
262         else
263             _args = args;
264         if(_args.length > 0)
265         {
266             _program = _args[0];
267             _args = _args[1..$];
268         }
269     }
270 
271     /**
272      * Constructor (variadic version, with environment copy).
273      *
274      * Params:
275      * copyEnv  = if true, the environment is copied from the current process.
276      * args     = array of strings with the process' arguments.  If there is
277      *            exactly one argument, it is considered to contain the entire
278      *            command line including parameters.  If you pass only one
279      *            argument, spaces that are not intended to separate
280      *            parameters should be embedded in quotes.  The arguments can
281      *            also be empty.
282      *            Note: The class will use only slices, .dup when necessary. 
283      *
284      * Examples:
285      * ---
286      * auto p = new Process(true, "myprogram", "first argument", "second", "third");
287      * auto p = new Process(true, "myprogram \"first argument\" second third");
288      * ---
289      */
290     public this(bool copyEnv, const(char[])[] args ...)
291     {
292         _copyEnv = copyEnv;
293         this(args);
294     }
295 
296     /**
297      * Constructor.
298      *
299      * Params:
300      * command  = string with the process' command line; arguments that have
301      *            embedded whitespace must be enclosed in inside double-quotes (").
302      *            Note: The class will use only slices, .dup when necessary. 
303      * env      = associative array of strings with the process' environment
304      *            variables; the variable name must be the key of each entry.
305      *
306      * Examples:
307      * ---
308      * char[] command = "myprogram \"first argument\" second third";
309      * char[][char[]] env;
310      *
311      * // Environment variables
312      * env["MYVAR1"] = "first";
313      * env["MYVAR2"] = "second";
314      *
315      * auto p = new Process(command, env)
316      * ---
317      */
318     public this(const(char)[] command, const(char[])[char[]] env)
319     in
320     {
321         assert(command.length > 0);
322     }
323     body
324     {
325         _args = splitArgs(command);
326         _env = env;
327         if(_args.length > 0)
328         {
329             _program = _args[0];
330             _args = _args[1..$];
331         }
332     }
333 
334     /**
335      * Constructor.
336      *
337      * Params:
338      * args     = array of strings with the process' arguments; the first
339      *            argument must be the process' name; the arguments can be
340      *            empty.
341      *            Note: The class will use only slices, .dup when necessary. 
342      * env      = associative array of strings with the process' environment
343      *            variables; the variable name must be the key of each entry.
344      *
345      * Examples:
346      * ---
347      * char[][] args;
348      * char[][char[]] env;
349      *
350      * // Process name
351      * args ~= "myprogram";
352      * // Process arguments
353      * args ~= "first argument";
354      * args ~= "second";
355      * args ~= "third";
356      *
357      * // Environment variables
358      * env["MYVAR1"] = "first";
359      * env["MYVAR2"] = "second";
360      *
361      * auto p = new Process(args, env)
362      * ---
363      */
364     public this(const(char[])[] args, const(char[])[char[]] env)
365     in
366     {
367         assert(args.length > 0);
368         assert(args[0].length > 0);
369     }
370     body
371     {
372         _args = args;
373         _env = env;
374         if(_args.length > 0)
375         {
376             _program = _args[0];
377             _args = _args[1..$];
378         }
379     }
380 
381     /**
382      * Indicate whether the process is running or not.
383      */
384     public const bool isRunning()
385     {
386         return _running;
387     }
388 
389     /**
390      * Return the running process' ID.
391      *
392      * Returns: an int with the process ID if the process is running;
393      *          -1 if not.
394      */
395     @property
396     public const int pid()
397     {
398         version (Windows)
399         {
400             return (_info !is null ? cast(int) _info.dwProcessId : -1);
401         }
402         else // version (Posix)
403         {
404             return cast(int) _pid;
405         }
406     }
407 
408     /**
409      * Return the process' executable filename.
410      */
411     @property
412     public const const(char)[] programName()
413     {
414         return _program;
415     }
416 
417     /**
418      * Set the process' executable filename.
419      */
420     @property
421     public const(char)[] programName(const(char)[] name)
422     {
423         return _program = name;
424     }
425 
426     /**
427      * Set the process' executable filename, return 'this' for chaining
428      */
429     public Process setProgramName(const(char)[] name)
430     {
431         programName = name;
432         return this;
433     }
434 
435     /**
436      * Return an array with the process' arguments. This does not include the actual program name.
437      */
438     public 
439     const(char[])[] args() const
440     {
441         return _args;
442     }
443 
444     /**
445      * Set the process' arguments from the arguments received by the method.
446      *
447      * Remarks:
448      * The first element of the array must be the name of the process'
449      * executable.
450      *
451      * Returns: the arguments that were set. This doesn't include the progname.
452      *
453      * Examples:
454      * ---
455      * p.args("myprogram", "first", "second argument", "third");
456      * ---
457      */
458     public const(char[])[] args(const(char)[] progname, const(char[])[] args ...)
459     {
460         _program = progname;
461         return _args = args.dup;
462     }
463 
464     /**
465      * Set the process' arguments from the arguments received by the method.
466      *
467      * Remarks:
468      * The first element of the array must be the name of the process'
469      * executable.
470      *
471      * Returns: a reference to this for chaining
472      *
473      * Examples:
474      * ---
475      * p.setArgs("myprogram", "first", "second argument", "third").execute();
476      * ---
477      */
478     public Process setArgs(const(char)[] progname, const(char[])[] args ...)
479     {
480         this.args(progname, args);
481         return this;
482     }
483 
484     /**
485      * If true, the environment from the current process will be copied to the
486      * child process.
487      */
488     @property
489     public const bool copyEnv()
490     {
491         return _copyEnv;
492     }
493 
494     /**
495      * Set the copyEnv flag.  If set to true, then the environment will be
496      * copied from the current process.  If set to false, then the environment
497      * is set from the env field.
498      */
499     @property
500     public bool copyEnv(bool b)
501     {
502         return _copyEnv = b;
503     }
504 
505     /**
506      * Set the copyEnv flag.  If set to true, then the environment will be
507      * copied from the current process.  If set to false, then the environment
508      * is set from the env field.
509      *
510      * Returns:
511      *   A reference to this for chaining
512      */
513     public Process setCopyEnv(bool b)
514     {
515         _copyEnv = b;
516         return this;
517     }
518 
519     /**
520      * Return an associative array with the process' environment variables.
521      *
522      * Note that if copyEnv is set to true, this value is ignored.
523      */
524     @property
525     public const(const(char[])[char[]]) env() const
526     {
527         return _env;
528     }
529 
530     /**
531      * Set the process' environment variables from the associative array
532      * received by the method.
533      *
534      * This also clears the copyEnv flag.
535      *
536      * Params:
537      * env  = associative array of strings containing the environment
538      *        variables for the process. The variable name should be the key
539      *        used for each entry.
540      *
541      * Returns: the env set.
542      * Examples:
543      * ---
544      * char[][char[]] env;
545      *
546      * env["MYVAR1"] = "first";
547      * env["MYVAR2"] = "second";
548      *
549      * p.env = env;
550      * ---
551      */
552     @property
553     public const(char[])[char[]] env(const(char[])[char[]] env)
554     {
555         _copyEnv = false;
556         return _env = env;
557     }
558 
559     /**
560      * Set the process' environment variables from the associative array
561      * received by the method.  Returns a 'this' reference for chaining.
562      *
563      * This also clears the copyEnv flag.
564      *
565      * Params:
566      * env  = associative array of strings containing the environment
567      *        variables for the process. The variable name should be the key
568      *        used for each entry.
569      *
570      * Returns: A reference to this process object
571      * Examples:
572      * ---
573      * char[][char[]] env;
574      *
575      * env["MYVAR1"] = "first";
576      * env["MYVAR2"] = "second";
577      *
578      * p.setEnv(env).execute();
579      * ---
580      */
581     public Process setEnv(const(char[])[char[]] env)
582     {
583         _copyEnv = false;
584         _env = env;
585         return this;
586     }
587 
588     /**
589      * Return an UTF-8 string with the process' command line.
590      */
591     public override 
592     string toString()
593     {
594         immutable(char)[] command;
595         
596         command ~= _program.substitute("\\", "\\\\").substitute(`"`, `\"`);
597 
598         for (size_t i = 0; i < _args.length; ++i)
599         {
600             if (i > 0)
601             {
602                 command ~= ' ';
603             }
604             if (contains(_args[i], ' ') || _args[i].length == 0)
605             {
606                 command ~= '"';
607                 command ~= _args[i].substitute("\\", "\\\\").substitute(`"`, `\"`);
608                 command ~= '"';
609             }
610             else
611             {
612                 command ~= _args[i].substitute("\\", "\\\\").substitute(`"`, `\"`);
613             }
614         }
615         return command;
616     }
617 
618     /**
619      * Return the working directory for the process.
620      *
621      * Returns: a string with the working directory; null if the working
622      *          directory is the current directory.
623      */
624     @property
625     public const(char)[] workDir() const
626     {
627         return _workDir;
628     }
629 
630     /**
631      * Set the working directory for the process.
632      *
633      * Params:
634      * dir  = a string with the working directory; null if the working
635      *         directory is the current directory.
636      *
637      * Returns: the directory set.
638      */
639     @property
640     public const(char)[] workDir(const(char)[] dir)
641     {
642         return _workDir = dir;
643     }
644 
645     /**
646      * Set the working directory for the process.  Returns a 'this' reference
647      * for chaining
648      *
649      * Params:
650      * dir  = a string with the working directory; null if the working
651      *         directory is the current directory.
652      *
653      * Returns: a reference to this process.
654      */
655     public Process setWorkDir(const(char)[] dir)
656     {
657         _workDir = dir;
658         return this;
659     }
660 
661     /**
662      * Get the redirect flags for the process.
663      *
664      * The redirect flags are used to determine whether stdout, stderr, or
665      * stdin are redirected.  The flags are an or'd combination of which
666      * standard handles to redirect.  A redirected handle creates a pipe,
667      * whereas a non-redirected handle simply points to the same handle this
668      * process is pointing to.
669      *
670      * You can also redirect stdout or stderr to each other.  The flags to
671      * redirect a handle to a pipe and to redirect it to another handle are
672      * mutually exclusive.  In the case both are specified, the redirect to
673      * the other handle takes precedent.  It is illegal to specify both
674      * redirection from stdout to stderr and from stderr to stdout.  If both
675      * of these are specified, an exception is thrown.
676      *
677      * If redirected to a pipe, once the process is executed successfully, its
678      * input and output can be manipulated through the stdin, stdout and
679      * stderr member PipeConduit's.  Note that if you redirect for example
680      * stderr to stdout, and you redirect stdout to a pipe, only stdout will
681      * be non-null.
682      */
683     @property public const Redirect redirect()
684     {
685         return _redirect;
686     }
687 
688     /**
689      * Set the redirect flags for the process.
690      */
691     @property public Redirect redirect(Redirect flags)
692     {
693         return _redirect = flags;
694     }
695 
696     /**
697      * Set the redirect flags for the process.  Return a reference to this
698      * process for chaining.
699      */
700     public Process setRedirect(Redirect flags)
701     {
702         _redirect = flags;
703         return this;
704     }
705 
706     /**
707      * Get the GUI flag.
708      *
709      * This flag indicates on Windows systems that the CREATE_NO_WINDOW flag
710      * should be set on CreateProcess.  Although this is a specific windows
711      * flag, it is present on posix systems as a noop for compatibility.
712      *
713      * Without this flag, a console window will be allocated if it doesn't
714      * already exist.
715      */
716     @property
717     public bool gui() const
718     {
719         version(Windows)
720             return _gui;
721         else
722             return false;
723     }
724 
725     /**
726      * Set the GUI flag.
727      *
728      * This flag indicates on Windows systems that the CREATE_NO_WINDOW flag
729      * should be set on CreateProcess.  Although this is a specific windows
730      * flag, it is present on posix systems as a noop for compatibility.
731      *
732      * Without this flag, a console window will be allocated if it doesn't
733      * already exist.
734      */
735     @property
736     public bool gui(bool value)
737     {
738         version(Windows)
739             return _gui = value;
740         else
741             return false;
742     }
743 
744     /**
745      * Set the GUI flag.  Returns a reference to this process for chaining.
746      *
747      * This flag indicates on Windows systems that the CREATE_NO_WINDOW flag
748      * should be set on CreateProcess.  Although this is a specific windows
749      * flag, it is present on posix systems as a noop for compatibility.
750      *
751      * Without this flag, a console window will be allocated if it doesn't
752      * already exist.
753      */
754     public Process setGui(bool value)
755     {
756         version(Windows)
757         {
758             _gui = value;
759         }
760         return this;
761     }
762 
763     /**
764      * Return the running process' standard input pipe.
765      *
766      * Returns: a write-only PipeConduit connected to the child
767      *          process' stdin.
768      *
769      * Remarks:
770      * The stream will be null if no child process has been executed, or the
771      * standard input stream was not redirected.
772      */
773     @property public PipeConduit stdin()
774     {
775         return _stdin;
776     }
777 
778     /**
779      * Return the running process' standard output pipe.
780      *
781      * Returns: a read-only PipeConduit connected to the child
782      *          process' stdout.
783      *
784      * Remarks:
785      * The stream will be null if no child process has been executed, or the
786      * standard output stream was not redirected.
787      */
788     @property public PipeConduit stdout()
789     {
790         return _stdout;
791     }
792 
793     /**
794      * Return the running process' standard error pipe.
795      *
796      * Returns: a read-only PipeConduit connected to the child
797      *          process' stderr.
798      *
799      * Remarks:
800      * The stream will be null if no child process has been executed, or the
801      * standard error stream was not redirected.
802      */
803     @property public PipeConduit stderr()
804     {
805         return _stderr;
806     }
807 
808     /**
809      * Execute a process using the arguments as parameters to this method.
810      *
811      * Once the process is executed successfully, its input and output can be
812      * manipulated through the stdin, stdout and
813      * stderr member PipeConduit's.
814      *
815      * Throws:
816      * ProcessCreateException if the process could not be created
817      * successfully; ProcessForkException if the call to the fork()
818      * system call failed (on POSIX-compatible platforms).
819      *
820      * Remarks:
821      * The process must not be running and the provided list of arguments must
822      * not be empty. If there was any argument already present in the args
823      * member, they will be replaced by the arguments supplied to the method.
824      *
825      * Deprecated: Use constructor or properties to set up process for
826      * execution.
827      */
828     deprecated public void execute(const(char)[] arg1, const(char[])[] args ...)
829     in
830     {
831         assert(!_running);
832     }
833     body
834     {
835         this._program = arg1;
836         this._args = args;
837         execute();
838     }
839 
840     /**
841      * Execute a process using the command line arguments as parameters to
842      * this method.
843      *
844      * Once the process is executed successfully, its input and output can be
845      * manipulated through the stdin, stdout and
846      * stderr member PipeConduit's.
847      *
848      * This also clears the copyEnv flag
849      *
850      * Params:
851      * command  = string with the process' command line; arguments that have
852      *            embedded whitespace must be enclosed in inside double-quotes (").
853      * env      = associative array of strings with the process' environment
854      *            variables; the variable name must be the key of each entry.
855      *
856      * Throws:
857      * ProcessCreateException if the process could not be created
858      * successfully; ProcessForkException if the call to the fork()
859      * system call failed (on POSIX-compatible platforms).
860      *
861      * Remarks:
862      * The process must not be running and the provided list of arguments must
863      * not be empty. If there was any argument already present in the args
864      * member, they will be replaced by the arguments supplied to the method.
865      *
866      * Deprecated: use properties or the constructor to set these parameters
867      * instead.
868      */
869     deprecated public void execute(const(char)[] command, const(char[])[const(char)[]] env)
870     in
871     {
872         assert(!_running);
873         assert(command.length > 0);
874     }
875     body
876     {
877         _args = splitArgs(command);
878         if (_args.length > 0)
879         {
880             _program = _args[0];
881             _args = _args[1..$];
882         }
883         _copyEnv = false;
884         _env = env;
885         execute();
886     }
887 
888     /**
889      * Execute a process using the command line arguments as parameters to
890      * this method.
891      *
892      * Once the process is executed successfully, its input and output can be
893      * manipulated through the stdin, stdout and
894      * stderr member PipeConduit's.
895      *
896      * This also clears the copyEnv flag
897      *
898      * Params:
899      * args     = array of strings with the process' arguments; the first
900      *            argument must be the process' name; the arguments can be
901      *            empty.
902      * env      = associative array of strings with the process' environment
903      *            variables; the variable name must be the key of each entry.
904      *
905      * Throws:
906      * ProcessCreateException if the process could not be created
907      * successfully; ProcessForkException if the call to the fork()
908      * system call failed (on POSIX-compatible platforms).
909      *
910      * Remarks:
911      * The process must not be running and the provided list of arguments must
912      * not be empty. If there was any argument already present in the args
913      * member, they will be replaced by the arguments supplied to the method.
914      *
915      * Deprecated:
916      * Use properties or the constructor to set these parameters instead.
917      *
918      * Examples:
919      * ---
920      * auto p = new Process();
921      * char[][] args;
922      *
923      * args ~= "ls";
924      * args ~= "-l";
925      *
926      * p.execute(args, null);
927      * ---
928      */
929     deprecated public void execute(const(char[])[] args, const(char[])[char[]] env)
930     in
931     {
932         assert(!_running);
933         assert(args.length > 0);
934     }
935     body
936     {
937         _args = args;
938         if (_args.length > 0)
939         {
940             _program = _args[0];
941             _args = _args[1..$];
942         }
943         _env = env;
944         _copyEnv = false;
945 
946         execute();
947     }
948 
949     /**
950      * Execute a process using the arguments that were supplied to the
951      * constructor or to the args property.
952      *
953      * Once the process is executed successfully, its input and output can be
954      * manipulated through the stdin, stdout and
955      * stderr member PipeConduit's.
956      *
957      * Returns:
958      * A reference to this process object for chaining.
959      *
960      * Throws:
961      * ProcessCreateException if the process could not be created
962      * successfully; ProcessForkException if the call to the fork()
963      * system call failed (on POSIX-compatible platforms).
964      *
965      * Remarks:
966      * The process must not be running and the list of arguments must
967      * not be empty before calling this method.
968      */
969     public Process execute()
970     in
971     {
972         assert(!_running);
973         assert(_program !is null);
974     }
975     body
976     {
977         version (Windows)
978         {
979             SECURITY_ATTRIBUTES sa;
980             STARTUPINFO         startup;
981 
982             // We close and delete the pipes that could have been left open
983             // from a previous execution.
984             cleanPipes();
985 
986             // Set up the security attributes struct.
987             sa.nLength = SECURITY_ATTRIBUTES.sizeof;
988             sa.lpSecurityDescriptor = null;
989             sa.bInheritHandle = true;
990 
991             // Set up members of the STARTUPINFO structure.
992             memset(&startup, '\0', STARTUPINFO.sizeof);
993             startup.cb = STARTUPINFO.sizeof;
994 
995             Pipe pin, pout, perr;
996             if(_redirect != Redirect.None)
997             {
998                 if((_redirect & (Redirect.OutputToError | Redirect.ErrorToOutput)) == (Redirect.OutputToError | Redirect.ErrorToOutput))
999                     throw new ProcessCreateException(_program, "Illegal redirection flags", __FILE__, __LINE__);
1000                 //
1001                 // some redirection is specified, set the flag that indicates
1002                 startup.dwFlags |= STARTF_USESTDHANDLES;
1003 
1004                 // Create the pipes used to communicate with the child process.
1005                 if(_redirect & Redirect.Input)
1006                 {
1007                     pin = new Pipe(DefaultStdinBufferSize, &sa);
1008                     // Replace stdin with the "read" pipe
1009                     _stdin = pin.sink;
1010                     startup.hStdInput = cast(HANDLE) pin.source.fileHandle();
1011                     // Ensure the write handle to the pipe for STDIN is not inherited.
1012                     SetHandleInformation(cast(HANDLE) pin.sink.fileHandle(), HANDLE_FLAG_INHERIT, 0);
1013                 }
1014                 else
1015                 {
1016                     // need to get the local process stdin handle
1017                     startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1018                 }
1019 
1020                 if((_redirect & (Redirect.Output | Redirect.OutputToError)) == Redirect.Output)
1021                 {
1022                     pout = new Pipe(DefaultStdoutBufferSize, &sa);
1023                     // Replace stdout with the "write" pipe
1024                     _stdout = pout.source;
1025                     startup.hStdOutput = cast(HANDLE) pout.sink.fileHandle();
1026                     // Ensure the read handle to the pipe for STDOUT is not inherited.
1027                     SetHandleInformation(cast(HANDLE) pout.source.fileHandle(), HANDLE_FLAG_INHERIT, 0);
1028                 }
1029                 else
1030                 {
1031                     // need to get the local process stdout handle
1032                     startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1033                 }
1034 
1035                 if((_redirect & (Redirect.Error | Redirect.ErrorToOutput)) == Redirect.Error)
1036                 {
1037                     perr = new Pipe(DefaultStderrBufferSize, &sa);
1038                     // Replace stderr with the "write" pipe
1039                     _stderr = perr.source;
1040                     startup.hStdError = cast(HANDLE) perr.sink.fileHandle();
1041                     // Ensure the read handle to the pipe for STDOUT is not inherited.
1042                     SetHandleInformation(cast(HANDLE) perr.source.fileHandle(), HANDLE_FLAG_INHERIT, 0);
1043                 }
1044                 else
1045                 {
1046                     // need to get the local process stderr handle
1047                     startup.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1048                 }
1049 
1050                 // do redirection from one handle to another
1051                 if(_redirect & Redirect.ErrorToOutput)
1052                 {
1053                     startup.hStdError = startup.hStdOutput;
1054                 }
1055 
1056                 if(_redirect & Redirect.OutputToError)
1057                 {
1058                     startup.hStdOutput = startup.hStdError;
1059                 }
1060             }
1061 
1062             // close the unused end of the pipes on scope exit
1063             scope(exit)
1064             {
1065                 if(pin !is null)
1066                     pin.source.close();
1067                 if(pout !is null)
1068                     pout.sink.close();
1069                 if(perr !is null)
1070                     perr.sink.close();
1071             }
1072 
1073             _info = new PROCESS_INFORMATION;
1074             // Set up members of the PROCESS_INFORMATION structure.
1075             memset(_info, '\0', PROCESS_INFORMATION.sizeof);
1076 
1077            /*
1078             * quotes and backslashes in the command line are handled very
1079             * strangely by Windows.  Through trial and error, I believe that
1080             * these are the rules:
1081             *
1082             * inside or outside quote mode:
1083             * 1. if 2 or more backslashes are followed by a quote, the first
1084             *    2 backslashes are reduced to 1 backslash which does not
1085             *    affect anything after it.
1086             * 2. one backslash followed by a quote is interpreted as a
1087             *    literal quote, which cannot be used to close quote mode, and
1088             *    does not affect anything after it.
1089             *
1090             * outside quote mode:
1091             * 3. a quote enters quote mode
1092             * 4. whitespace delineates an argument
1093             *
1094             * inside quote mode:
1095             * 5. 2 quotes sequentially are interpreted as a literal quote and
1096             *    an exit from quote mode.
1097             * 6. a quote at the end of the string, or one that is followed by
1098             *    anything other than a quote exits quote mode, but does not
1099             *    affect the character after the quote.
1100             * 7. end of line exits quote mode
1101             *
1102             * In our 'reverse' routine, we will only utilize the first 2 rules
1103             * for escapes.
1104             */
1105             char[] command;
1106             
1107             void append_arg(const(char)[] arg)
1108             {
1109               const(char)[] nextarg = arg.substitute(`"`, `\"`);
1110               //
1111               // find all instances where \\" occurs, and double all the
1112               // backslashes.  Otherwise, it will fall under rule 1, and those
1113               // backslashes will be halved.
1114               //
1115               uint pos = 0;
1116               while((pos = nextarg.locatePattern(`\\"`, pos)) < nextarg.length)
1117               {
1118                 //
1119                 // move back until we have all the backslashes
1120                 //
1121                 uint afterback = pos+1;
1122                 while(pos > 0 && nextarg[pos - 1] == '\\')
1123                   pos--;
1124 
1125                 //
1126                 // double the number of backslashes that do not escape the
1127                 // quote
1128                 //
1129                 nextarg = nextarg[0..afterback] ~ nextarg[pos..$];
1130                 pos = afterback + afterback - pos + 2;
1131               }
1132 
1133               //
1134               // check to see if we need to surround the arg with quotes.
1135               //
1136               if(nextarg.length == 0)
1137               {
1138                 nextarg = `""`;
1139               }
1140               else if(nextarg.contains(' '))
1141               {
1142                 //
1143                 // surround with quotes, but if the arg ends in backslashes,
1144                 // we must double all the backslashes, or they will fall under
1145                 // rule 1 and be halved.
1146                 //
1147 
1148                 if(nextarg[$-1] == '\\')
1149                 {
1150                   //
1151                   // ends in a backslash.  count all the \'s at the end of the
1152                   // string, and repeat them
1153                   //
1154                   pos = nextarg.length - 1;
1155                   while(pos > 0 && nextarg[pos-1] == '\\')
1156                     pos--;
1157                   nextarg ~= nextarg[pos..$];
1158                 }
1159 
1160                 // surround the argument with quotes
1161                 nextarg = '"' ~ nextarg ~ '"';
1162               }
1163 
1164               command ~= ' ';
1165               command ~= nextarg;
1166 			}
1167 			
1168 			append_arg(_program);
1169             
1170             foreach(a; _args)
1171 				append_arg(a);
1172 
1173             command ~= '\0';
1174             command = command[1..$];
1175 
1176             // old way
1177             //char[] command = toString();
1178             //command ~= '\0';
1179 
1180             version(Win32SansUnicode)
1181             {
1182               //
1183               // ASCII version of CreateProcess
1184               //
1185 
1186               // Convert the working directory to a null-ended string if
1187               // necessary.
1188               //
1189               // Note, this used to contain DETACHED_PROCESS, but
1190               // this causes problems with redirection if the program being
1191               // started decides to allocate a console (i.e. if you run a batch
1192               // file)
1193               if (CreateProcessA(null, command.ptr, null, null, true,
1194                     _gui ? CREATE_NO_WINDOW : 0,
1195                     (_copyEnv ? null : toNullEndedBuffer(_env).ptr),
1196                     toStringz(_workDir), &startup, _info))
1197               {
1198                 CloseHandle(_info.hThread);
1199                 _running = true;
1200               }
1201               else
1202               {
1203                 throw new ProcessCreateException(_program, __FILE__, __LINE__);
1204               }
1205             }
1206             else
1207             {
1208               // Convert the working directory to a null-ended string if
1209               // necessary.
1210               //
1211               // Note, this used to contain DETACHED_PROCESS, but
1212               // this causes problems with redirection if the program being
1213               // started decides to allocate a console (i.e. if you run a batch
1214               // file)
1215               if (CreateProcessW(null, toString16(command).ptr, null, null, true,
1216                     _gui ? CREATE_NO_WINDOW : 0,
1217                     (_copyEnv ? null : toNullEndedBuffer(_env).ptr),
1218                     toString16z(toString16(_workDir)), &startup, _info))
1219               {
1220                 CloseHandle(_info.hThread);
1221                 _running = true;
1222               }
1223               else
1224               {
1225                 throw new ProcessCreateException(_program, __FILE__, __LINE__);
1226               }
1227             }
1228         }
1229         else version (Posix)
1230         {
1231             // We close and delete the pipes that could have been left open
1232             // from a previous execution.
1233             cleanPipes();
1234 
1235             // validate the redirection flags
1236             if((_redirect & (Redirect.OutputToError | Redirect.ErrorToOutput)) == (Redirect.OutputToError | Redirect.ErrorToOutput))
1237                 throw new ProcessCreateException(_program, "Illegal redirection flags", __FILE__, __LINE__);
1238 
1239 
1240             Pipe pin, pout, perr;
1241             if(_redirect & Redirect.Input)
1242                 pin = new Pipe(DefaultStdinBufferSize);
1243             if((_redirect & (Redirect.Output | Redirect.OutputToError)) == Redirect.Output)
1244                 pout = new Pipe(DefaultStdoutBufferSize);
1245 
1246             if((_redirect & (Redirect.Error | Redirect.ErrorToOutput)) == Redirect.Error)
1247                 perr = new Pipe(DefaultStderrBufferSize);
1248 
1249             // This pipe is used to propagate the result of the call to
1250             // execv*() from the child process to the parent process.
1251             Pipe pexec = new Pipe(8);
1252             int status = 0;
1253 
1254             _pid = fork();
1255             if (_pid >= 0)
1256             {
1257                 if (_pid != 0)
1258                 {
1259                     // Parent process
1260                     if(pin !is null)
1261                     {
1262                         _stdin = pin.sink;
1263                         pin.source.close();
1264                     }
1265 
1266                     if(pout !is null)
1267                     {
1268                         _stdout = pout.source;
1269                         pout.sink.close();
1270                     }
1271 
1272                     if(perr !is null)
1273                     {
1274                         _stderr = perr.source;
1275                         perr.sink.close();
1276                     }
1277 
1278                     pexec.sink.close();
1279                     scope(exit)
1280                         pexec.source.close();
1281 
1282                     try
1283                     {
1284                         pexec.source.input.read((cast(byte*) &status)[0 .. status.sizeof]);
1285                     }
1286                     catch (Exception e)
1287                     {
1288                         // Everything's OK, the pipe was closed after the call to execv*()
1289                     }
1290 
1291                     if (status == 0)
1292                     {
1293                         _running = true;
1294                     }
1295                     else
1296                     {
1297                         // We set errno to the value that was sent through
1298                         // the pipe from the child process
1299                         errno = status;
1300                         _running = false;
1301 
1302                         throw new ProcessCreateException(_program, __FILE__, __LINE__);
1303                     }
1304                 }
1305                 else
1306                 {
1307                     // Child process
1308                     int rc;
1309                     const(char)*[] argptr;
1310                     const(char)*[] envptr;
1311 
1312                     // Note that for all the pipes, we can close both ends
1313                     // because dup2 opens a duplicate file descriptor to the
1314                     // same resource.
1315 
1316                     // Replace stdin with the "read" pipe
1317                     if(pin !is null)
1318                     {
1319                         if (dup2(pin.source.fileHandle(), STDIN_FILENO) < 0)
1320                             throw new Exception("dup2 < 0");
1321                         pin.sink().close();
1322                         pin.source.close();
1323                     }
1324 
1325                     // Replace stdout with the "write" pipe
1326                     if(pout !is null)
1327                     {
1328                         if (dup2(pout.sink.fileHandle(), STDOUT_FILENO) < 0)
1329                             throw new Exception("dup2 < 0");
1330                         pout.source.close();
1331                         pout.sink.close();
1332                     }
1333 
1334                     // Replace stderr with the "write" pipe
1335                     if(perr !is null)
1336                     {
1337                         if (dup2(perr.sink.fileHandle(), STDERR_FILENO) < 0)
1338                             throw new Exception("dup2 < 0");
1339                         perr.source.close();
1340                         perr.sink.close();
1341                     }
1342 
1343                     // Check for redirection from stdout to stderr or vice
1344                     // versa
1345                     if(_redirect & Redirect.OutputToError)
1346                     {
1347                         if(dup2(STDERR_FILENO, STDOUT_FILENO) < 0)
1348                             throw new Exception("dup2 < 0");
1349                     }
1350 
1351                     if(_redirect & Redirect.ErrorToOutput)
1352                     {
1353                         if(dup2(STDOUT_FILENO, STDERR_FILENO) < 0)
1354                             throw new Exception("dup2 < 0");
1355                     }
1356 
1357                     // We close the unneeded part of the execv*() notification pipe
1358                     pexec.source.close();
1359 
1360                     // Set the "write" pipe so that it closes upon a successful
1361                     // call to execv*()
1362                     if (fcntl(cast(int) pexec.sink.fileHandle(), F_SETFD, FD_CLOEXEC) == 0)
1363                     {
1364                         // Convert the arguments and the environment variables to
1365                         // the format expected by the execv() family of functions.
1366                         argptr = toNullEndedArray(_program, _args);
1367                         envptr = (_copyEnv ? null : toNullEndedArray(_env));
1368 
1369                         // Switch to the working directory if it has been set.
1370                         if (_workDir.length > 0)
1371                         {
1372                             chdir(toStringz(_workDir));
1373                         }
1374 
1375                         // Replace the child fork with a new process. We always use the
1376                         // system PATH to look for executables that don't specify
1377                         // directories in their names.
1378                         rc = execvpe(_program, argptr, envptr);
1379                         if (rc == -1)
1380                         {
1381                             Cerr("Failed to exec ")(_program)(": ")(SysError.lastMsg).newline;
1382 
1383                             try
1384                             {
1385                                 status = errno;
1386 
1387                                 // Propagate the child process' errno value to
1388                                 // the parent process.
1389                                 pexec.sink.output.write((cast(byte*) &status)[0 .. status.sizeof]);
1390                             }
1391                             catch (Exception e)
1392                             {
1393                             }
1394                             exit(errno);
1395                         }
1396                         exit(errno);
1397                     }
1398                     else
1399                     {
1400                         Cerr("Failed to set notification pipe to close-on-exec for ")
1401                             (_program)(": ")(SysError.lastMsg).newline;
1402                         exit(errno);
1403                     }
1404                 }
1405             }
1406             else
1407             {
1408                 throw new ProcessForkException(_pid, __FILE__, __LINE__);
1409             }
1410         }
1411         else
1412         {
1413             assert(false, "tango.sys.Process: Unsupported platform");
1414         }
1415         return this;
1416     }
1417 
1418 
1419     /**
1420      * Unconditionally wait for a process to end and return the reason and
1421      * status code why the process ended.
1422      *
1423      * Returns:
1424      * The return value is a Result struct, which has two members:
1425      * reason and status. The reason can take the
1426      * following values:
1427      *
1428      * Process.Result.Exit: the child process exited normally;
1429      *                      status has the process' return
1430      *                      code.
1431      *
1432      * Process.Result.Signal: the child process was killed by a signal;
1433      *                        status has the signal number
1434      *                        that killed the process.
1435      *
1436      * Process.Result.Stop: the process was stopped; status
1437      *                      has the signal number that was used to stop
1438      *                      the process.
1439      *
1440      * Process.Result.Continue: the process had been previously stopped
1441      *                          and has now been restarted;
1442      *                          status has the signal number
1443      *                          that was used to continue the process.
1444      *
1445      * Process.Result.Error: We could not properly wait on the child
1446      *                       process; status has the
1447      *                       errno value if the process was
1448      *                       running and -1 if not.
1449      *
1450      * Remarks:
1451      * You can only call wait() on a running process once. The Signal, Stop
1452      * and Continue reasons will only be returned on POSIX-compatible
1453      * platforms.
1454      * Calling wait() will not clean the pipes as the parent process may still
1455      * want the remaining output. It is however recommended to call close()
1456      * when no more content is expected, as this will close the pipes.
1457      */
1458     public Result wait()
1459     {
1460         version (Windows)
1461         {
1462             Result result;
1463 
1464             if (_running)
1465             {
1466                 DWORD rc;
1467                 DWORD exitCode;
1468 
1469                 assert(_info !is null);
1470 
1471                 // We clean up the process related data and set the _running
1472                 // flag to false once we're done waiting for the process to
1473                 // finish.
1474                 //
1475                 // IMPORTANT: we don't delete the open pipes so that the parent
1476                 //            process can get whatever the child process left on
1477                 //            these pipes before dying.
1478                 scope(exit)
1479                 {
1480                     CloseHandle(_info.hProcess);
1481                     _running = false;
1482                 }
1483 
1484                 rc = WaitForSingleObject(_info.hProcess, INFINITE);
1485                 if (rc == WAIT_OBJECT_0)
1486                 {
1487                     GetExitCodeProcess(_info.hProcess, &exitCode);
1488 
1489                     result.reason = Result.Exit;
1490                     result.status = cast(typeof(result.status)) exitCode;
1491 
1492                     debug (Process)
1493                         Stdout.formatln("Child process '{0}' ({1}) returned with code {2}\n",
1494                                         _program, pid, result.status);
1495                 }
1496                 else if (rc == WAIT_FAILED)
1497                 {
1498                     result.reason = Result.Error;
1499                     result.status = cast(short) GetLastError();
1500 
1501                     debug (Process)
1502                         Stdout.formatln("Child process '{0}' ({1}) failed " ~
1503                                         "with unknown exit status {2}\n",
1504                                         _program, pid, result.status);
1505                 }
1506             }
1507             else
1508             {
1509                 result.reason = Result.Error;
1510                 result.status = -1;
1511 
1512                 debug (Process)
1513                     Stdout.formatln("Child process '{0}' is not running", _program);
1514             }
1515             return result;
1516         }
1517         else version (Posix)
1518         {
1519             Result result;
1520 
1521             if (_running)
1522             {
1523                 int rc;
1524 
1525                 // We clean up the process related data and set the _running
1526                 // flag to false once we're done waiting for the process to
1527                 // finish.
1528                 //
1529                 // IMPORTANT: we don't delete the open pipes so that the parent
1530                 //            process can get whatever the child process left on
1531                 //            these pipes before dying.
1532                 scope(exit)
1533                 {
1534                     _running = false;
1535                 }
1536 
1537                 // Wait for child process to end.
1538                 if (waitpid(_pid, &rc, 0) != -1)
1539                 {
1540                     if (WIFEXITED(rc))
1541                     {
1542                         result.reason = Result.Exit;
1543                         result.status = WEXITSTATUS(rc);
1544                         if (result.status != 0)
1545                         {
1546                             debug (Process)
1547                                 Stdout.formatln("Child process '{0}' ({1}) returned with code {2}\n",
1548                                                 _program, _pid, result.status);
1549                         }
1550                     }
1551                     else
1552                     {
1553                         if (WIFSIGNALED(rc))
1554                         {
1555                             result.reason = Result.Signal;
1556                             result.status = WTERMSIG(rc);
1557 
1558                             debug (Process)
1559                                 Stdout.formatln("Child process '{0}' ({1}) was killed prematurely " ~
1560                                                 "with signal {2}",
1561                                                 _program, _pid, result.status);
1562                         }
1563                         else if (WIFSTOPPED(rc))
1564                         {
1565                             result.reason = Result.Stop;
1566                             result.status = WSTOPSIG(rc);
1567 
1568                             debug (Process)
1569                                 Stdout.formatln("Child process '{0}' ({1}) was stopped " ~
1570                                                 "with signal {2}",
1571                                                 _program, _pid, result.status);
1572                         }
1573                         else if (WIFCONTINUED(rc))
1574                         {
1575                             result.reason = Result.Stop;
1576                             result.status = WSTOPSIG(rc);
1577 
1578                             debug (Process)
1579                                 Stdout.formatln("Child process '{0}' ({1}) was continued " ~
1580                                                 "with signal {2}",
1581                                                 _program, _pid, result.status);
1582                         }
1583                         else
1584                         {
1585                             result.reason = Result.Error;
1586                             result.status = rc;
1587 
1588                             debug (Process)
1589                                 Stdout.formatln("Child process '{0}' ({1}) failed " ~
1590                                                 "with unknown exit status {2}\n",
1591                                                 _program, _pid, result.status);
1592                         }
1593                     }
1594                 }
1595                 else
1596                 {
1597                     result.reason = Result.Error;
1598                     result.status = errno;
1599 
1600                     debug (Process)
1601                         Stdout.formatln("Could not wait on child process '{0}' ({1}): ({2}) {3}",
1602                                         _program, _pid, result.status, SysError.lastMsg);
1603                 }
1604             }
1605             else
1606             {
1607                 result.reason = Result.Error;
1608                 result.status = -1;
1609 
1610                 debug (Process)
1611                     Stdout.formatln("Child process '{0}' is not running", _program);
1612             }
1613             return result;
1614         }
1615         else
1616         {
1617             assert(false, "tango.sys.Process: Unsupported platform");
1618         }
1619     }
1620 
1621     /**
1622      * Kill a running process. This method will not return until the process
1623      * has been killed.
1624      *
1625      * Throws:
1626      * ProcessKillException if the process could not be killed;
1627      * ProcessWaitException if we could not wait on the process after
1628      * killing it.
1629      *
1630      * Remarks:
1631      * After calling this method you will not be able to call wait() on the
1632      * process.
1633      * Killing the process does not clean the attached pipes as the parent
1634      * process may still want/need the remaining content. However, it is
1635      * recommended to call close() on the process when it is no longer needed
1636      * as this will clean the pipes.
1637      */
1638     public void kill()
1639     {
1640         version (Windows)
1641         {
1642             if (_running)
1643             {
1644                 assert(_info !is null);
1645 
1646                 if (TerminateProcess(_info.hProcess, cast(UINT) -1))
1647                 {
1648                     assert(_info !is null);
1649 
1650                     // We clean up the process related data and set the _running
1651                     // flag to false once we're done waiting for the process to
1652                     // finish.
1653                     //
1654                     // IMPORTANT: we don't delete the open pipes so that the parent
1655                     //            process can get whatever the child process left on
1656                     //            these pipes before dying.
1657                     scope(exit)
1658                     {
1659                         CloseHandle(_info.hProcess);
1660                         _running = false;
1661                     }
1662 
1663                     // FIXME: We should probably use a timeout here
1664                     if (WaitForSingleObject(_info.hProcess, INFINITE) == WAIT_FAILED)
1665                     {
1666                         throw new ProcessWaitException(cast(int) _info.dwProcessId,
1667                                                        __FILE__, __LINE__);
1668                     }
1669                 }
1670                 else
1671                 {
1672                     throw new ProcessKillException(cast(int) _info.dwProcessId,
1673                                                    __FILE__, __LINE__);
1674                 }
1675             }
1676             else
1677             {
1678                 debug (Process)
1679                     Stdout.print("Tried to kill an invalid process");
1680             }
1681         }
1682         else version (Posix)
1683         {
1684             if (_running)
1685             {
1686                 int rc;
1687 
1688                 assert(_pid > 0);
1689 
1690                 if (.kill(_pid, SIGTERM) != -1)
1691                 {
1692                     // We clean up the process related data and set the _running
1693                     // flag to false once we're done waiting for the process to
1694                     // finish.
1695                     //
1696                     // IMPORTANT: we don't delete the open pipes so that the parent
1697                     //            process can get whatever the child process left on
1698                     //            these pipes before dying.
1699                     scope(exit)
1700                     {
1701                         _running = false;
1702                     }
1703 
1704                     // FIXME: is this loop really needed?
1705                     for (uint i = 0; i < 100; i++)
1706                     {
1707                         rc = waitpid(pid, null, WNOHANG | WUNTRACED);
1708                         if (rc == _pid)
1709                         {
1710                             break;
1711                         }
1712                         else if (rc == -1)
1713                         {
1714                             throw new ProcessWaitException(cast(int) _pid, __FILE__, __LINE__);
1715                         }
1716                         usleep(50000);
1717                     }
1718                 }
1719                 else
1720                 {
1721                     throw new ProcessKillException(_pid, __FILE__, __LINE__);
1722                 }
1723             }
1724             else
1725             {
1726                 debug (Process)
1727                     Stdout.print("Tried to kill an invalid process");
1728             }
1729         }
1730         else
1731         {
1732             assert(false, "tango.sys.Process: Unsupported platform");
1733         }
1734     }
1735 
1736     /**
1737      * Split a string containing the command line used to invoke a program
1738      * and return and array with the parsed arguments. The double-quotes (")
1739      * character can be used to specify arguments with embedded spaces.
1740      * e.g. first "second param" third
1741      */
1742     protected static const(char)[][] splitArgs(const(char)[] command, const(char)[] delims = " \t\r\n")
1743     in
1744     {
1745         assert(!contains(delims, '"'),
1746                "The argument delimiter string cannot contain a double quotes ('\"') character");
1747     }
1748     body
1749     {
1750         enum State
1751         {
1752             Start,
1753             FindDelimiter,
1754             InsideQuotes
1755         }
1756 
1757         const(char)[][]    args = null;
1758         const(char)[][]    chunks = null;
1759         int         start = -1;
1760         char        c;
1761         int         i;
1762         State       state = State.Start;
1763 
1764         // Append an argument to the 'args' array using the 'chunks' array
1765         // and the current position in the 'command' string as the source.
1766         void appendChunksAsArg()
1767         {
1768             size_t argPos;
1769 
1770             if (chunks.length > 0)
1771             {
1772                 // Create the array element corresponding to the argument by
1773                 // appending the first chunk.
1774                 args   ~= chunks[0];
1775                 argPos  = args.length - 1;
1776 
1777                 for (uint chunkPos = 1; chunkPos < chunks.length; ++chunkPos)
1778                 {
1779                     args[argPos] ~= chunks[chunkPos];
1780                 }
1781 
1782                 if (start != -1)
1783                 {
1784                     args[argPos] ~= command[start .. i];
1785                 }
1786                 chunks.length = 0;
1787             }
1788             else
1789             {
1790                 if (start != -1)
1791                 {
1792                     args ~= command[start .. i];
1793                 }
1794             }
1795             start = -1;
1796         }
1797 
1798         for (i = 0; i < command.length; i++)
1799         {
1800             c = command[i];
1801 
1802             switch (state)
1803             {
1804                 // Start looking for an argument.
1805                 case State.Start:
1806                     if (c == '"')
1807                     {
1808                         state = State.InsideQuotes;
1809                     }
1810                     else if (!contains(delims, c))
1811                     {
1812                         start = i;
1813                         state = State.FindDelimiter;
1814                     }
1815                     else
1816                     {
1817                         appendChunksAsArg();
1818                     }
1819                     break;
1820 
1821                 // Find the ending delimiter for an argument.
1822                 case State.FindDelimiter:
1823                     if (c == '"')
1824                     {
1825                         // If we find a quotes character this means that we've
1826                         // found a quoted section of an argument. (e.g.
1827                         // abc"def"ghi). The quoted section will be appended
1828                         // to the preceding part of the argument. This is also
1829                         // what Unix shells do (i.e. a"b"c becomes abc).
1830                         if (start != -1)
1831                         {
1832                             chunks ~= command[start .. i];
1833                             start = -1;
1834                         }
1835                         state = State.InsideQuotes;
1836                     }
1837                     else if (contains(delims, c))
1838                     {
1839                         appendChunksAsArg();
1840                         state = State.Start;
1841                     }
1842                     break;
1843 
1844                 // Inside a quoted argument or section of an argument.
1845                 case State.InsideQuotes:
1846                     if (start == -1)
1847                     {
1848                         start = i;
1849                     }
1850 
1851                     if (c == '"')
1852                     {
1853                         chunks ~= command[start .. i];
1854                         start = -1;
1855                         state = State.Start;
1856                     }
1857                     break;
1858 
1859                 default:
1860                     assert(false, "Invalid state in Process.splitArgs");
1861             }
1862         }
1863 
1864         // Add the last argument (if there is one)
1865         appendChunksAsArg();
1866 
1867         return args;
1868     }
1869 
1870     /**
1871      * Close and delete any pipe that may have been left open in a previous
1872      * execution of a child process.
1873      */
1874     protected void cleanPipes()
1875     {
1876         _stdin.destroy;
1877         _stdout.destroy;
1878         _stderr.destroy;
1879     }
1880 
1881     /**
1882      * Explicitly close any resources held by this process object. It is recommended
1883      * to always call this when you are done with the process.
1884      */
1885     public void close()
1886     {
1887         this.cleanPipes();
1888     }
1889 
1890     version (Windows)
1891     {
1892         /**
1893          * Convert an associative array of strings to a buffer containing a
1894          * concatenation of "<name>=<value>" strings separated by a null
1895          * character and with an additional null character at the end of it.
1896          * This is the format expected by the CreateProcess() Windows API for
1897          * the environment variables.
1898          */
1899         protected static char[] toNullEndedBuffer(const(char[])[char[]] src)
1900         {
1901             char[] dest;
1902 
1903             foreach (key, value; src)
1904             {
1905                 dest ~= key ~ '=' ~ value ~ '\0';
1906             }
1907 
1908             dest ~= "\0\0";
1909             return dest;
1910         }
1911     }
1912     else version (Posix)
1913     {
1914         /**
1915          * Convert an array of strings to an array of pointers to char with
1916          * a terminating null character (C strings). The resulting array
1917          * has a null pointer at the end. This is the format expected by
1918          * the execv*() family of POSIX functions.
1919          */
1920         protected static const(char)*[] toNullEndedArray(const(char)[] elem0, const(char[])[] src)
1921         {
1922             if (src !is null && elem0 !is null)
1923             {
1924                 const(char)*[] dest = new const(char)*[src.length + 2];
1925                 auto i = src.length;
1926 
1927                 // Add terminating null pointer to the array
1928                 dest[i + 1] = null;
1929 
1930                 while (i > 0)
1931                 {
1932                     --i;
1933                     // Add a terminating null character to each string
1934                     dest[i + 1] = toStringz(src[i]);
1935                 }
1936                 
1937                 dest[0] = toStringz(elem0);
1938                 return dest;
1939             }
1940             else
1941             {
1942                 return null;
1943             }
1944         }
1945 
1946         /**
1947          * Convert an associative array of strings to an array of pointers to
1948          * char with a terminating null character (C strings). The resulting
1949          * array has a null pointer at the end. This is the format expected by
1950          * the execv*() family of POSIX functions for environment variables.
1951          */
1952         protected static const(char)*[] toNullEndedArray(const(char[])[char[]] src)
1953         {
1954             const(char)*[] dest;
1955 
1956             foreach (key, value; src)
1957             {
1958                 dest ~= (key ~ '=' ~ value ~ '\0').ptr;
1959             }
1960 
1961             dest ~= null;
1962             return dest;
1963         }
1964 
1965         /**
1966          * Execute a process by looking up a file in the system path, passing
1967          * the array of arguments and the the environment variables. This
1968          * method is a combination of the execve() and execvp() POSIX system
1969          * calls.
1970          */
1971         protected static int execvpe(const(char)[] filename, const(char)*[] argv, const(char)*[] envp)
1972         in
1973         {
1974             assert(filename.length > 0);
1975         }
1976         body
1977         {
1978             int rc = -1;
1979             char* str;
1980 
1981             if (!contains(filename, FileConst.PathSeparatorChar) &&
1982                 (str = getenv("PATH")) !is null)
1983             {
1984                 auto pathList = delimit(str[0 .. strlen(str)], ":");
1985 
1986                 char[] path_buf;
1987 
1988                 foreach (path; pathList)
1989                 {
1990                     if (path[$-1] != FileConst.PathSeparatorChar)
1991                     {
1992                         path_buf.length = path.length + 1 + filename.length + 1;
1993                         path_buf[] = (path ~ FileConst.PathSeparatorChar ~ filename ~ '\0')[];
1994                     }
1995                     else
1996                     {
1997                         path_buf.length = path.length +filename.length + 1;
1998                         path_buf[] = (path ~ filename ~ '\0')[];
1999                     }
2000 
2001                     rc = execve(path_buf.ptr, argv.ptr, (envp.length == 0 ? cast(const(char)**)environ : envp.ptr));
2002 
2003                     // If the process execution failed because of an error
2004                     // other than ENOENT (No such file or directory) we
2005                     // abort the loop.
2006                     if (rc == -1 && SysError.lastCode !is ENOENT)
2007                     {
2008                         break;
2009                     }
2010                 }
2011             }
2012             else
2013             {
2014                 debug (Process)
2015                     Stdout.formatln("Calling execve('{0}', argv[{1}], {2})",
2016                                     (argv[0])[0 .. strlen(argv[0])],
2017                                     argv.length, (envp.length > 0 ? "envp" : "null"));
2018 
2019                 rc = execve(argv[0], argv.ptr, (envp.length == 0 ? cast(const(char)**)environ : envp.ptr));
2020             }
2021             return rc;
2022         }
2023     }
2024 }
2025 
2026 
2027 /**
2028  * Exception thrown when the process cannot be created.
2029  */
2030 class ProcessCreateException: ProcessException
2031 {
2032     public this(const(char)[] command, const(char)[] file, uint line)
2033     {
2034         this(command, SysError.lastMsg, file, line);
2035     }
2036 
2037     public this(const(char)[] command, const(char)[] message, const(char)[] file, uint line)
2038     {
2039         super("Could not create process for " ~ command.idup ~ " : " ~ message.idup);
2040     }
2041 }
2042 
2043 /**
2044  * Exception thrown when the parent process cannot be forked.
2045  *
2046  * This exception will only be thrown on POSIX-compatible platforms.
2047  */
2048 class ProcessForkException: ProcessException
2049 {
2050     public this(int pid, const(char)[] file, uint line)
2051     {
2052         super(format("Could not fork process ", pid).idup ~ " : " ~ SysError.lastMsg.idup);
2053     }
2054 }
2055 
2056 /**
2057  * Exception thrown when the process cannot be killed.
2058  */
2059 class ProcessKillException: ProcessException
2060 {
2061     public this(int pid, const(char)[] file, uint line)
2062     {
2063         super(format("Could not kill process ", pid).idup ~ " : " ~ SysError.lastMsg.idup);
2064     }
2065 }
2066 
2067 /**
2068  * Exception thrown when the parent process tries to wait on the child
2069  * process and fails.
2070  */
2071 class ProcessWaitException: ProcessException
2072 {
2073     public this(int pid, const(char)[] file, uint line)
2074     {
2075         super(format("Could not wait on process ", pid).idup ~ " : " ~ SysError.lastMsg.idup);
2076     }
2077 }
2078 
2079 
2080 
2081 
2082 /**
2083  *  append an int argument to a message
2084 */
2085 private char[] format (const(char)[] msg, int value)
2086 {
2087     char[10] tmp;
2088 
2089     return msg ~ Integer.format (tmp, value);
2090 }
2091 
2092 extern (C) uint sleep (uint s);
2093 debug (UnitTest)
2094 {
2095     import tango.io.Stdout;
2096     import tango.stdc.stdio : printf, fflush, stdout;
2097 
2098     unittest
2099     {
2100         const(char)[] message = "hello world";
2101         version(Windows)
2102         {
2103             const(char)[] command = "cmd.exe /c echo " ~ message;
2104         }
2105         else
2106             const(char)[] command = "echo " ~ message;
2107 
2108 
2109         try
2110         {
2111             auto p = new Process(command, null);
2112             Stdout.flush();
2113             p.execute();
2114             char[255] buffer;
2115 
2116             auto nread = p.stdout.read(buffer);
2117 
2118             assert(nread != p.stdout.Eof);
2119 
2120             version(Windows)
2121                 assert(buffer[0..nread] == message ~ "\r\n");
2122             else
2123                 assert(buffer[0..nread] == message ~ "\n");
2124 
2125             nread = p.stdout.read(buffer);
2126             assert(nread == p.stdout.Eof);
2127 
2128             auto result = p.wait();
2129 
2130             assert(result.reason == Process.Result.Exit && result.status == 0);
2131         }
2132         catch (ProcessException e)
2133         {
2134             Cerr("Program execution failed: ")(e.toString()).newline();
2135         }
2136     }
2137 }
2138