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