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

1254      */
1255     public static List<Process> startPipeline(List<ProcessBuilder> builders) throws IOException {
1256         // Accumulate and check the builders
1257         final int numBuilders = builders.size();
1258         List<Process> processes = new ArrayList<>(numBuilders);
1259         try {
1260             Redirect prevOutput = null;
1261             for (int index = 0; index < builders.size(); index++) {
1262                 ProcessBuilder builder = builders.get(index);
1263                 Redirect[] redirects = builder.redirects();
1264                 if (index > 0) {
1265                     // check the current Builder to see if it can take input from the previous
1266                     if (builder.redirectInput() != Redirect.PIPE) {
1267                         throw new IllegalArgumentException("builder redirectInput()" +
1268                                 " must be PIPE except for the first builder: "
1269                                 + builder.redirectInput());
1270                     }
1271                     redirects[0] = prevOutput;
1272                 }
1273                 if (index < numBuilders - 1) {
1274                     // check all but the last stage has output = PIPE
1275                     if (builder.redirectOutput() != Redirect.PIPE) {
1276                         throw new IllegalArgumentException("builder redirectOutput()" +
1277                                 " must be PIPE except for the last builder: "
1278                                 + builder.redirectOutput());
1279                     }
1280                     redirects[1] = new RedirectPipeImpl();  // placeholder for new output
1281                 }
1282                 processes.add(builder.start(redirects));
1283                 prevOutput = redirects[1];
1284             }
1285         } catch (Exception ex) {
1286             // Cleanup processes already started
1287             processes.forEach(Process::destroyForcibly);
1288             processes.forEach(p -> {
1289                 try {
1290                     p.waitFor();        // Wait for it to exit
1291                 } catch (InterruptedException ie) {
1292                     // If interrupted; continue with next Process
1293                     Thread.currentThread().interrupt();
1294                 }
1295             });
1296             throw ex;
1297         }
1298         return processes;
1299     }
1300 }
--- EOF ---