1/*
2 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package java.lang;
27
28import java.io.File;
29import java.io.IOException;
30import java.io.InputStream;
31import java.io.OutputStream;
32import java.security.AccessControlException;
33import java.util.Arrays;
34import java.util.ArrayList;
35import java.util.List;
36import java.util.Map;
37
38/**
39 * This class is used to create operating system processes.
40 *
41 * <p>Each {@code ProcessBuilder} instance manages a collection
42 * of process attributes.  The {@link #start()} method creates a new
43 * {@link Process} instance with those attributes.  The {@link
44 * #start()} method can be invoked repeatedly from the same instance
45 * to create new subprocesses with identical or related attributes.
46 *
47 * <p>Each process builder manages these process attributes:
48 *
49 * <ul>
50 *
51 * <li>a <i>command</i>, a list of strings which signifies the
52 * external program file to be invoked and its arguments, if any.
53 * Which string lists represent a valid operating system command is
54 * system-dependent.  For example, it is common for each conceptual
55 * argument to be an element in this list, but there are operating
56 * systems where programs are expected to tokenize command line
57 * strings themselves - on such a system a Java implementation might
58 * require commands to contain exactly two elements.
59 *
60 * <li>an <i>environment</i>, which is a system-dependent mapping from
61 * <i>variables</i> to <i>values</i>.  The initial value is a copy of
62 * the environment of the current process (see {@link System#getenv()}).
63 *
64 * <li>a <i>working directory</i>.  The default value is the current
65 * working directory of the current process, usually the directory
66 * named by the system property {@code user.dir}.
67 *
68 * <p>Modifying a process builder's attributes will affect processes
69 * subsequently started by that object's {@link #start()} method, but
70 * will never affect previously started processes or the Java process
71 * itself.
72 *
73 * <p>Most error checking is performed by the {@link #start()} method.
74 * It is possible to modify the state of an object so that {@link
75 * #start()} will fail.  For example, setting the command attribute to
76 * an empty list will not throw an exception unless {@link #start()}
77 * is invoked.
78 *
79 * <p><strong>Note that this class is not synchronized.</strong>
80 * If multiple threads access a {@code ProcessBuilder} instance
81 * concurrently, and at least one of the threads modifies one of the
82 * attributes structurally, it <i>must</i> be synchronized externally.
83 *
84 * <p>Starting a new process which uses the default working directory
85 * and environment is easy:
86 *
87 * <pre> {@code
88 * Process p = new ProcessBuilder("myCommand", "myArg").start();
89 * }</pre>
90 *
91 * <p>Here is an example that starts a process with a modified working
92 * directory and environment:
93 *
94 * <pre> {@code
95 * ProcessBuilder pb =
96 *   new ProcessBuilder("myCommand", "myArg1", "myArg2");
97 * Map<String, String> env = pb.environment();
98 * env.put("VAR1", "myValue");
99 * env.remove("OTHERVAR");
100 * env.put("VAR2", env.get("VAR1") + "suffix");
101 * pb.directory(new File("myDir"));
102 * Process p = pb.start();
103 * }</pre>
104 *
105 * <p>To start a process with an explicit set of environment
106 * variables, first call {@link java.util.Map#clear() Map.clear()}
107 * before adding environment variables.
108 *
109 * @author Martin Buchholz
110 * @since 1.5
111 */
112
113public final class ProcessBuilder
114{
115    private List<String> command;
116    private File directory;
117    private Map<String,String> environment;
118    private boolean redirectErrorStream;
119    private Redirect[] redirects;
120
121    /**
122     * Constructs a process builder with the specified operating
123     * system program and arguments.  This constructor does <i>not</i>
124     * make a copy of the {@code command} list.  Subsequent
125     * updates to the list will be reflected in the state of the
126     * process builder.  It is not checked whether
127     * {@code command} corresponds to a valid operating system
128     * command.
129     *
130     * @param  command the list containing the program and its arguments
131     * @throws NullPointerException if the argument is null
132     */
133    public ProcessBuilder(List<String> command) {
134        if (command == null)
135            throw new NullPointerException();
136        this.command = command;
137    }
138
139    /**
140     * Constructs a process builder with the specified operating
141     * system program and arguments.  This is a convenience
142     * constructor that sets the process builder's command to a string
143     * list containing the same strings as the {@code command}
144     * array, in the same order.  It is not checked whether
145     * {@code command} corresponds to a valid operating system
146     * command.
147     *
148     * @param command a string array containing the program and its arguments
149     */
150    public ProcessBuilder(String... command) {
151        this.command = new ArrayList<>(command.length);
152        for (String arg : command)
153            this.command.add(arg);
154    }
155
156    /**
157     * Sets this process builder's operating system program and
158     * arguments.  This method does <i>not</i> make a copy of the
159     * {@code command} list.  Subsequent updates to the list will
160     * be reflected in the state of the process builder.  It is not
161     * checked whether {@code command} corresponds to a valid
162     * operating system command.
163     *
164     * @param  command the list containing the program and its arguments
165     * @return this process builder
166     *
167     * @throws NullPointerException if the argument is null
168     */
169    public ProcessBuilder command(List<String> command) {
170        if (command == null)
171            throw new NullPointerException();
172        this.command = command;
173        return this;
174    }
175
176    /**
177     * Sets this process builder's operating system program and
178     * arguments.  This is a convenience method that sets the command
179     * to a string list containing the same strings as the
180     * {@code command} array, in the same order.  It is not
181     * checked whether {@code command} corresponds to a valid
182     * operating system command.
183     *
184     * @param  command a string array containing the program and its arguments
185     * @return this process builder
186     */
187    public ProcessBuilder command(String... command) {
188        this.command = new ArrayList<>(command.length);
189        for (String arg : command)
190            this.command.add(arg);
191        return this;
192    }
193
194    /**
195     * Returns this process builder's operating system program and
196     * arguments.  The returned list is <i>not</i> a copy.  Subsequent
197     * updates to the list will be reflected in the state of this
198     * process builder.
199     *
200     * @return this process builder's program and its arguments
201     */
202    public List<String> command() {
203        return command;
204    }
205
206    /**
207     * Returns a string map view of this process builder's environment.
208     *
209     * Whenever a process builder is created, the environment is
210     * initialized to a copy of the current process environment (see
211     * {@link System#getenv()}).  Subprocesses subsequently started by
212     * this object's {@link #start()} method will use this map as
213     * their environment.
214     *
215     * <p>The returned object may be modified using ordinary {@link
216     * java.util.Map Map} operations.  These modifications will be
217     * visible to subprocesses started via the {@link #start()}
218     * method.  Two {@code ProcessBuilder} instances always
219     * contain independent process environments, so changes to the
220     * returned map will never be reflected in any other
221     * {@code ProcessBuilder} instance or the values returned by
222     * {@link System#getenv System.getenv}.
223     *
224     * <p>If the system does not support environment variables, an
225     * empty map is returned.
226     *
227     * <p>The returned map does not permit null keys or values.
228     * Attempting to insert or query the presence of a null key or
229     * value will throw a {@link NullPointerException}.
230     * Attempting to query the presence of a key or value which is not
231     * of type {@link String} will throw a {@link ClassCastException}.
232     *
233     * <p>The behavior of the returned map is system-dependent.  A
234     * system may not allow modifications to environment variables or
235     * may forbid certain variable names or values.  For this reason,
236     * attempts to modify the map may fail with
237     * {@link UnsupportedOperationException} or
238     * {@link IllegalArgumentException}
239     * if the modification is not permitted by the operating system.
240     *
241     * <p>Since the external format of environment variable names and
242     * values is system-dependent, there may not be a one-to-one
243     * mapping between them and Java's Unicode strings.  Nevertheless,
244     * the map is implemented in such a way that environment variables
245     * which are not modified by Java code will have an unmodified
246     * native representation in the subprocess.
247     *
248     * <p>The returned map and its collection views may not obey the
249     * general contract of the {@link Object#equals} and
250     * {@link Object#hashCode} methods.
251     *
252     * <p>The returned map is typically case-sensitive on all platforms.
253     *
254     * <p>If a security manager exists, its
255     * {@link SecurityManager#checkPermission checkPermission} method
256     * is called with a
257     * {@link RuntimePermission}{@code ("getenv.*")} permission.
258     * This may result in a {@link SecurityException} being thrown.
259     *
260     * <p>When passing information to a Java subprocess,
261     * <a href=System.html#EnvironmentVSSystemProperties>system properties</a>
262     * are generally preferred over environment variables.
263     *
264     * @return this process builder's environment
265     *
266     * @throws SecurityException
267     *         if a security manager exists and its
268     *         {@link SecurityManager#checkPermission checkPermission}
269     *         method doesn't allow access to the process environment
270     *
271     * @see    Runtime#exec(String[],String[],java.io.File)
272     * @see    System#getenv()
273     */
274    public Map<String,String> environment() {
275        SecurityManager security = System.getSecurityManager();
276        if (security != null)
277            security.checkPermission(new RuntimePermission("getenv.*"));
278
279        if (environment == null)
280            environment = ProcessEnvironment.environment();
281
282        assert environment != null;
283
284        return environment;
285    }
286
287    // Only for use by Runtime.exec(...envp...)
288    ProcessBuilder environment(String[] envp) {
289        assert environment == null;
290        if (envp != null) {
291            environment = ProcessEnvironment.emptyEnvironment(envp.length);
292            assert environment != null;
293
294            for (String envstring : envp) {
295                // Before 1.5, we blindly passed invalid envstrings
296                // to the child process.
297                // We would like to throw an exception, but do not,
298                // for compatibility with old broken code.
299
300                // Silently discard any trailing junk.
301                if (envstring.indexOf((int) '\u0000') != -1)
302                    envstring = envstring.replaceFirst("\u0000.*", "");
303
304                int eqlsign =
305                    envstring.indexOf('=', ProcessEnvironment.MIN_NAME_LENGTH);
306                // Silently ignore envstrings lacking the required `='.
307                if (eqlsign != -1)
308                    environment.put(envstring.substring(0,eqlsign),
309                                    envstring.substring(eqlsign+1));
310            }
311        }
312        return this;
313    }
314
315    /**
316     * Returns this process builder's working directory.
317     *
318     * Subprocesses subsequently started by this object's {@link
319     * #start()} method will use this as their working directory.
320     * The returned value may be {@code null} -- this means to use
321     * the working directory of the current Java process, usually the
322     * directory named by the system property {@code user.dir},
323     * as the working directory of the child process.
324     *
325     * @return this process builder's working directory
326     */
327    public File directory() {
328        return directory;
329    }
330
331    /**
332     * Sets this process builder's working directory.
333     *
334     * Subprocesses subsequently started by this object's {@link
335     * #start()} method will use this as their working directory.
336     * The argument may be {@code null} -- this means to use the
337     * working directory of the current Java process, usually the
338     * directory named by the system property {@code user.dir},
339     * as the working directory of the child process.
340     *
341     * @param  directory the new working directory
342     * @return this process builder
343     */
344    public ProcessBuilder directory(File directory) {
345        this.directory = directory;
346        return this;
347    }
348
349    // ---------------- I/O Redirection ----------------
350
351    /**
352     * Implements a <a href="#redirect-output">null input stream</a>.
353     */
354    static class NullInputStream extends InputStream {
355        static final NullInputStream INSTANCE = new NullInputStream();
356        private NullInputStream() {}
357        public int read()      { return -1; }
358        public int available() { return 0; }
359    }
360
361    /**
362     * Implements a <a href="#redirect-input">null output stream</a>.
363     */
364    static class NullOutputStream extends OutputStream {
365        static final NullOutputStream INSTANCE = new NullOutputStream();
366        private NullOutputStream() {}
367        public void write(int b) throws IOException {
368            throw new IOException("Stream closed");
369        }
370    }
371
372    /**
373     * Represents a source of subprocess input or a destination of
374     * subprocess output.
375     *
376     * Each {@code Redirect} instance is one of the following:
377     *
378     * <ul>
379     * <li>the special value {@link #PIPE Redirect.PIPE}
380     * <li>the special value {@link #INHERIT Redirect.INHERIT}
381     * <li>a redirection to read from a file, created by an invocation of
382     *     {@link Redirect#from Redirect.from(File)}
383     * <li>a redirection to write to a file,  created by an invocation of
384     *     {@link Redirect#to Redirect.to(File)}
385     * <li>a redirection to append to a file, created by an invocation of
386     *     {@link Redirect#appendTo Redirect.appendTo(File)}
387     * </ul>
388     *
389     * <p>Each of the above categories has an associated unique
390     * {@link Type Type}.
391     *
392     * @since 1.7
393     *
394     * @hide
395     */
396    public static abstract class Redirect {
397        /**
398         * The type of a {@link Redirect}.
399         */
400        public enum Type {
401            /**
402             * The type of {@link Redirect#PIPE Redirect.PIPE}.
403             */
404            PIPE,
405
406            /**
407             * The type of {@link Redirect#INHERIT Redirect.INHERIT}.
408             */
409            INHERIT,
410
411            /**
412             * The type of redirects returned from
413             * {@link Redirect#from Redirect.from(File)}.
414             */
415            READ,
416
417            /**
418             * The type of redirects returned from
419             * {@link Redirect#to Redirect.to(File)}.
420             */
421            WRITE,
422
423            /**
424             * The type of redirects returned from
425             * {@link Redirect#appendTo Redirect.appendTo(File)}.
426             */
427            APPEND
428        };
429
430        /**
431         * Returns the type of this {@code Redirect}.
432         * @return the type of this {@code Redirect}
433         */
434        public abstract Type type();
435
436        /**
437         * Indicates that subprocess I/O will be connected to the
438         * current Java process over a pipe.
439         *
440         * This is the default handling of subprocess standard I/O.
441         *
442         * <p>It will always be true that
443         *  <pre> {@code
444         * Redirect.PIPE.file() == null &&
445         * Redirect.PIPE.type() == Redirect.Type.PIPE
446         * }</pre>
447         */
448        public static final Redirect PIPE = new Redirect() {
449                public Type type() { return Type.PIPE; }
450                public String toString() { return type().toString(); }};
451
452        /**
453         * Indicates that subprocess I/O source or destination will be the
454         * same as those of the current process.  This is the normal
455         * behavior of most operating system command interpreters (shells).
456         *
457         * <p>It will always be true that
458         *  <pre> {@code
459         * Redirect.INHERIT.file() == null &&
460         * Redirect.INHERIT.type() == Redirect.Type.INHERIT
461         * }</pre>
462         */
463        public static final Redirect INHERIT = new Redirect() {
464                public Type type() { return Type.INHERIT; }
465                public String toString() { return type().toString(); }};
466
467        /**
468         * Returns the {@link File} source or destination associated
469         * with this redirect, or {@code null} if there is no such file.
470         *
471         * @return the file associated with this redirect,
472         *         or {@code null} if there is no such file
473         */
474        public File file() { return null; }
475
476        /**
477         * When redirected to a destination file, indicates if the output
478         * is to be written to the end of the file.
479         */
480        boolean append() {
481            throw new UnsupportedOperationException();
482        }
483
484        /**
485         * Returns a redirect to read from the specified file.
486         *
487         * <p>It will always be true that
488         *  <pre> {@code
489         * Redirect.from(file).file() == file &&
490         * Redirect.from(file).type() == Redirect.Type.READ
491         * }</pre>
492         *
493         * @throws NullPointerException if the specified file is null
494         * @return a redirect to read from the specified file
495         */
496        public static Redirect from(final File file) {
497            if (file == null)
498                throw new NullPointerException();
499            return new Redirect() {
500                    public Type type() { return Type.READ; }
501                    public File file() { return file; }
502                    public String toString() {
503                        return "redirect to read from file \"" + file + "\"";
504                    }
505                };
506        }
507
508        /**
509         * Returns a redirect to write to the specified file.
510         * If the specified file exists when the subprocess is started,
511         * its previous contents will be discarded.
512         *
513         * <p>It will always be true that
514         *  <pre> {@code
515         * Redirect.to(file).file() == file &&
516         * Redirect.to(file).type() == Redirect.Type.WRITE
517         * }</pre>
518         *
519         * @throws NullPointerException if the specified file is null
520         * @return a redirect to write to the specified file
521         */
522        public static Redirect to(final File file) {
523            if (file == null)
524                throw new NullPointerException();
525            return new Redirect() {
526                    public Type type() { return Type.WRITE; }
527                    public File file() { return file; }
528                    public String toString() {
529                        return "redirect to write to file \"" + file + "\"";
530                    }
531                    boolean append() { return false; }
532                };
533        }
534
535        /**
536         * Returns a redirect to append to the specified file.
537         * Each write operation first advances the position to the
538         * end of the file and then writes the requested data.
539         * Whether the advancement of the position and the writing
540         * of the data are done in a single atomic operation is
541         * system-dependent and therefore unspecified.
542         *
543         * <p>It will always be true that
544         *  <pre> {@code
545         * Redirect.appendTo(file).file() == file &&
546         * Redirect.appendTo(file).type() == Redirect.Type.APPEND
547         * }</pre>
548         *
549         * @throws NullPointerException if the specified file is null
550         * @return a redirect to append to the specified file
551         */
552        public static Redirect appendTo(final File file) {
553            if (file == null)
554                throw new NullPointerException();
555            return new Redirect() {
556                    public Type type() { return Type.APPEND; }
557                    public File file() { return file; }
558                    public String toString() {
559                        return "redirect to append to file \"" + file + "\"";
560                    }
561                    boolean append() { return true; }
562                };
563        }
564
565        /**
566         * Compares the specified object with this {@code Redirect} for
567         * equality.  Returns {@code true} if and only if the two
568         * objects are identical or both objects are {@code Redirect}
569         * instances of the same type associated with non-null equal
570         * {@code File} instances.
571         */
572        public boolean equals(Object obj) {
573            if (obj == this)
574                return true;
575            if (! (obj instanceof Redirect))
576                return false;
577            Redirect r = (Redirect) obj;
578            if (r.type() != this.type())
579                return false;
580            assert this.file() != null;
581            return this.file().equals(r.file());
582        }
583
584        /**
585         * Returns a hash code value for this {@code Redirect}.
586         * @return a hash code value for this {@code Redirect}
587         */
588        public int hashCode() {
589            File file = file();
590            if (file == null)
591                return super.hashCode();
592            else
593                return file.hashCode();
594        }
595
596        /**
597         * No public constructors.  Clients must use predefined
598         * static {@code Redirect} instances or factory methods.
599         */
600        private Redirect() {}
601    }
602
603    private Redirect[] redirects() {
604        if (redirects == null)
605            redirects = new Redirect[] {
606                Redirect.PIPE, Redirect.PIPE, Redirect.PIPE
607            };
608        return redirects;
609    }
610
611    /**
612     * Sets this process builder's standard input source.
613     *
614     * Subprocesses subsequently started by this object's {@link #start()}
615     * method obtain their standard input from this source.
616     *
617     * <p>If the source is {@link Redirect#PIPE Redirect.PIPE}
618     * (the initial value), then the standard input of a
619     * subprocess can be written to using the output stream
620     * returned by {@link Process#getOutputStream()}.
621     * If the source is set to any other value, then
622     * {@link Process#getOutputStream()} will return a
623     * <a href="#redirect-input">null output stream</a>.
624     *
625     * @param  source the new standard input source
626     * @return this process builder
627     * @throws IllegalArgumentException
628     *         if the redirect does not correspond to a valid source
629     *         of data, that is, has type
630     *         {@link Redirect.Type#WRITE WRITE} or
631     *         {@link Redirect.Type#APPEND APPEND}
632     * @since  1.7
633     *
634     * @hide
635     */
636    public ProcessBuilder redirectInput(Redirect source) {
637        if (source.type() == Redirect.Type.WRITE ||
638            source.type() == Redirect.Type.APPEND)
639            throw new IllegalArgumentException(
640                "Redirect invalid for reading: " + source);
641        redirects()[0] = source;
642        return this;
643    }
644
645    /**
646     * Sets this process builder's standard output destination.
647     *
648     * Subprocesses subsequently started by this object's {@link #start()}
649     * method send their standard output to this destination.
650     *
651     * <p>If the destination is {@link Redirect#PIPE Redirect.PIPE}
652     * (the initial value), then the standard output of a subprocess
653     * can be read using the input stream returned by {@link
654     * Process#getInputStream()}.
655     * If the destination is set to any other value, then
656     * {@link Process#getInputStream()} will return a
657     * <a href="#redirect-output">null input stream</a>.
658     *
659     * @param  destination the new standard output destination
660     * @return this process builder
661     * @throws IllegalArgumentException
662     *         if the redirect does not correspond to a valid
663     *         destination of data, that is, has type
664     *         {@link Redirect.Type#READ READ}
665     * @since  1.7
666     *
667     * @hide
668     */
669    public ProcessBuilder redirectOutput(Redirect destination) {
670        if (destination.type() == Redirect.Type.READ)
671            throw new IllegalArgumentException(
672                "Redirect invalid for writing: " + destination);
673        redirects()[1] = destination;
674        return this;
675    }
676
677    /**
678     * Sets this process builder's standard error destination.
679     *
680     * Subprocesses subsequently started by this object's {@link #start()}
681     * method send their standard error to this destination.
682     *
683     * <p>If the destination is {@link Redirect#PIPE Redirect.PIPE}
684     * (the initial value), then the error output of a subprocess
685     * can be read using the input stream returned by {@link
686     * Process#getErrorStream()}.
687     * If the destination is set to any other value, then
688     * {@link Process#getErrorStream()} will return a
689     * <a href="#redirect-output">null input stream</a>.
690     *
691     * <p>If the {@link #redirectErrorStream redirectErrorStream}
692     * attribute has been set {@code true}, then the redirection set
693     * by this method has no effect.
694     *
695     * @param  destination the new standard error destination
696     * @return this process builder
697     * @throws IllegalArgumentException
698     *         if the redirect does not correspond to a valid
699     *         destination of data, that is, has type
700     *         {@link Redirect.Type#READ READ}
701     * @since  1.7
702     *
703     * @hide
704     */
705    public ProcessBuilder redirectError(Redirect destination) {
706        if (destination.type() == Redirect.Type.READ)
707            throw new IllegalArgumentException(
708                "Redirect invalid for writing: " + destination);
709        redirects()[2] = destination;
710        return this;
711    }
712
713    /**
714     * Sets this process builder's standard input source to a file.
715     *
716     * <p>This is a convenience method.  An invocation of the form
717     * {@code redirectInput(file)}
718     * behaves in exactly the same way as the invocation
719     * {@link #redirectInput(Redirect) redirectInput}
720     * {@code (Redirect.from(file))}.
721     *
722     * @param  file the new standard input source
723     * @return this process builder
724     * @since  1.7
725     *
726     * @hide
727     */
728    public ProcessBuilder redirectInput(File file) {
729        return redirectInput(Redirect.from(file));
730    }
731
732    /**
733     * Sets this process builder's standard output destination to a file.
734     *
735     * <p>This is a convenience method.  An invocation of the form
736     * {@code redirectOutput(file)}
737     * behaves in exactly the same way as the invocation
738     * {@link #redirectOutput(Redirect) redirectOutput}
739     * {@code (Redirect.to(file))}.
740     *
741     * @param  file the new standard output destination
742     * @return this process builder
743     * @since  1.7
744     *
745     * @hide
746     */
747    public ProcessBuilder redirectOutput(File file) {
748        return redirectOutput(Redirect.to(file));
749    }
750
751    /**
752     * Sets this process builder's standard error destination to a file.
753     *
754     * <p>This is a convenience method.  An invocation of the form
755     * {@code redirectError(file)}
756     * behaves in exactly the same way as the invocation
757     * {@link #redirectError(Redirect) redirectError}
758     * {@code (Redirect.to(file))}.
759     *
760     * @param  file the new standard error destination
761     * @return this process builder
762     * @since  1.7
763     *
764     * @hide
765     */
766    public ProcessBuilder redirectError(File file) {
767        return redirectError(Redirect.to(file));
768    }
769
770    /**
771     * Returns this process builder's standard input source.
772     *
773     * Subprocesses subsequently started by this object's {@link #start()}
774     * method obtain their standard input from this source.
775     * The initial value is {@link Redirect#PIPE Redirect.PIPE}.
776     *
777     * @return this process builder's standard input source
778     * @since  1.7
779     *
780     * @hide
781     */
782    public Redirect redirectInput() {
783        return (redirects == null) ? Redirect.PIPE : redirects[0];
784    }
785
786    /**
787     * Returns this process builder's standard output destination.
788     *
789     * Subprocesses subsequently started by this object's {@link #start()}
790     * method redirect their standard output to this destination.
791     * The initial value is {@link Redirect#PIPE Redirect.PIPE}.
792     *
793     * @return this process builder's standard output destination
794     * @since  1.7
795     *
796     * @hide
797     */
798    public Redirect redirectOutput() {
799        return (redirects == null) ? Redirect.PIPE : redirects[1];
800    }
801
802    /**
803     * Returns this process builder's standard error destination.
804     *
805     * Subprocesses subsequently started by this object's {@link #start()}
806     * method redirect their standard error to this destination.
807     * The initial value is {@link Redirect#PIPE Redirect.PIPE}.
808     *
809     * @return this process builder's standard error destination
810     * @since  1.7
811     *
812     * @hide
813     */
814    public Redirect redirectError() {
815        return (redirects == null) ? Redirect.PIPE : redirects[2];
816    }
817
818    /**
819     * Sets the source and destination for subprocess standard I/O
820     * to be the same as those of the current Java process.
821     *
822     * <p>This is a convenience method.  An invocation of the form
823     *  <pre> {@code
824     * pb.inheritIO()
825     * }</pre>
826     * behaves in exactly the same way as the invocation
827     *  <pre> {@code
828     * pb.redirectInput(Redirect.INHERIT)
829     *   .redirectOutput(Redirect.INHERIT)
830     *   .redirectError(Redirect.INHERIT)
831     * }</pre>
832     *
833     * This gives behavior equivalent to most operating system
834     * command interpreters, or the standard C library function
835     * {@code system()}.
836     *
837     * @return this process builder
838     * @since  1.7
839     *
840     * @hide
841     */
842    public ProcessBuilder inheritIO() {
843        Arrays.fill(redirects(), Redirect.INHERIT);
844        return this;
845    }
846
847    /**
848     * Tells whether this process builder merges standard error and
849     * standard output.
850     *
851     * <p>If this property is {@code true}, then any error output
852     * generated by subprocesses subsequently started by this object's
853     * {@link #start()} method will be merged with the standard
854     * output, so that both can be read using the
855     * {@link Process#getInputStream()} method.  This makes it easier
856     * to correlate error messages with the corresponding output.
857     * The initial value is {@code false}.
858     *
859     * @return this process builder's {@code redirectErrorStream} property
860     */
861    public boolean redirectErrorStream() {
862        return redirectErrorStream;
863    }
864
865    /**
866     * Sets this process builder's {@code redirectErrorStream} property.
867     *
868     * <p>If this property is {@code true}, then any error output
869     * generated by subprocesses subsequently started by this object's
870     * {@link #start()} method will be merged with the standard
871     * output, so that both can be read using the
872     * {@link Process#getInputStream()} method.  This makes it easier
873     * to correlate error messages with the corresponding output.
874     * The initial value is {@code false}.
875     *
876     * @param  redirectErrorStream the new property value
877     * @return this process builder
878     */
879    public ProcessBuilder redirectErrorStream(boolean redirectErrorStream) {
880        this.redirectErrorStream = redirectErrorStream;
881        return this;
882    }
883
884    /**
885     * Starts a new process using the attributes of this process builder.
886     *
887     * <p>The new process will
888     * invoke the command and arguments given by {@link #command()},
889     * in a working directory as given by {@link #directory()},
890     * with a process environment as given by {@link #environment()}.
891     *
892     * <p>This method checks that the command is a valid operating
893     * system command.  Which commands are valid is system-dependent,
894     * but at the very least the command must be a non-empty list of
895     * non-null strings.
896     *
897     * <p>A minimal set of system dependent environment variables may
898     * be required to start a process on some operating systems.
899     * As a result, the subprocess may inherit additional environment variable
900     * settings beyond those in the process builder's {@link #environment()}.
901     *
902     * <p>If there is a security manager, its
903     * {@link SecurityManager#checkExec checkExec}
904     * method is called with the first component of this object's
905     * {@code command} array as its argument. This may result in
906     * a {@link SecurityException} being thrown.
907     *
908     * <p>Starting an operating system process is highly system-dependent.
909     * Among the many things that can go wrong are:
910     * <ul>
911     * <li>The operating system program file was not found.
912     * <li>Access to the program file was denied.
913     * <li>The working directory does not exist.
914     * </ul>
915     *
916     * <p>In such cases an exception will be thrown.  The exact nature
917     * of the exception is system-dependent, but it will always be a
918     * subclass of {@link IOException}.
919     *
920     * <p>Subsequent modifications to this process builder will not
921     * affect the returned {@link Process}.
922     *
923     * @return a new {@link Process} object for managing the subprocess
924     *
925     * @throws NullPointerException
926     *         if an element of the command list is null
927     *
928     * @throws IndexOutOfBoundsException
929     *         if the command is an empty list (has size {@code 0})
930     *
931     * @throws SecurityException
932     *         if a security manager exists and
933     *         <ul>
934     *
935     *         <li>its
936     *         {@link SecurityManager#checkExec checkExec}
937     *         method doesn't allow creation of the subprocess, or
938     *         </ul>
939     *
940     * @throws IOException if an I/O error occurs
941     *
942     * @see Runtime#exec(String[], String[], java.io.File)
943     */
944    public Process start() throws IOException {
945        // Must convert to array first -- a malicious user-supplied
946        // list might try to circumvent the security check.
947        String[] cmdarray = command.toArray(new String[command.size()]);
948        cmdarray = cmdarray.clone();
949
950        for (String arg : cmdarray)
951            if (arg == null)
952                throw new NullPointerException();
953        // Throws IndexOutOfBoundsException if command is empty
954        String prog = cmdarray[0];
955
956        SecurityManager security = System.getSecurityManager();
957        if (security != null) {
958            security.checkExec(prog);
959        }
960
961        String dir = directory == null ? null : directory.toString();
962
963        try {
964            return ProcessImpl.start(cmdarray,
965                                     environment,
966                                     dir,
967                                     redirects,
968                                     redirectErrorStream);
969        } catch (IOException | IllegalArgumentException e) {
970            String exceptionInfo = ": " + e.getMessage();
971            Throwable cause = e;
972            if ((e instanceof IOException) && security != null) {
973                // Can not disclose the fail reason for read-protected files.
974                try {
975                    security.checkRead(prog);
976                } catch (AccessControlException ace) {
977                    exceptionInfo = "";
978                    cause = ace;
979                }
980            }
981            // It's much easier for us to create a high-quality error
982            // message than the low-level C code which found the problem.
983            throw new IOException(
984                "Cannot run program \"" + prog + "\""
985                + (dir == null ? "" : " (in directory \"" + dir + "\")")
986                + exceptionInfo,
987                cause);
988        }
989    }
990}
991