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