< prev index next >

src/java.base/share/classes/java/lang/ProcessBuilder.java

Print this page
imported patch ProcessEnvironment-race


   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>


 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      *


 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 =


1280                     }
1281                     redirects[1] = new RedirectPipeImpl();  // placeholder for new output
1282                 }
1283                 processes.add(builder.start(redirects));
1284                 prevOutput = redirects[1];
1285             }
1286         } catch (Exception ex) {
1287             // Cleanup processes already started
1288             processes.forEach(Process::destroyForcibly);
1289             processes.forEach(p -> {
1290                 try {
1291                     p.waitFor();        // Wait for it to exit
1292                 } catch (InterruptedException ie) {
1293                     // If interrupted; continue with next Process
1294                     Thread.currentThread().interrupt();
1295                 }
1296             });
1297             throw ex;
1298         }
1299         return processes;















1300     }
1301 }


   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.lang.invoke.MethodHandles;
  29 import java.lang.invoke.VarHandle;
  30 import java.io.File;
  31 import java.io.FileDescriptor;
  32 import java.io.IOException;
  33 import java.io.InputStream;
  34 import java.io.OutputStream;
  35 import java.util.Arrays;
  36 import java.util.ArrayList;
  37 import java.util.List;
  38 import java.util.Map;
  39 import sun.security.action.GetPropertyAction;
  40 
  41 /**
  42  * This class is used to create operating system processes.
  43  *
  44  * <p>Each {@code ProcessBuilder} instance manages a collection
  45  * of process attributes.  The {@link #start()} method creates a new
  46  * {@link Process} instance with those attributes.  The {@link
  47  * #start()} method can be invoked repeatedly from the same instance
  48  * to create new subprocesses with identical or related attributes.
  49  * <p>


 194     private List<String> command;
 195     private File directory;
 196     private Map<String,String> environment;
 197     private boolean redirectErrorStream;
 198     private Redirect[] redirects;
 199 
 200     /**
 201      * Constructs a process builder with the specified operating
 202      * system program and arguments.  This constructor does <i>not</i>
 203      * make a copy of the {@code command} list.  Subsequent
 204      * updates to the list will be reflected in the state of the
 205      * process builder.  It is not checked whether
 206      * {@code command} corresponds to a valid operating system
 207      * command.
 208      *
 209      * @param  command the list containing the program and its arguments
 210      */
 211     public ProcessBuilder(List<String> command) {
 212         if (command == null)
 213             throw new NullPointerException();
 214         COMMAND.setRelease(this, command);
 215     }
 216 
 217     /**
 218      * Constructs a process builder with the specified operating
 219      * system program and arguments.  This is a convenience
 220      * constructor that sets the process builder's command to a string
 221      * list containing the same strings as the {@code command}
 222      * array, in the same order.  It is not checked whether
 223      * {@code command} corresponds to a valid operating system
 224      * command.
 225      *
 226      * @param command a string array containing the program and its arguments
 227      */
 228     public ProcessBuilder(String... command) {
 229         List<String> commandList = new ArrayList<>(command.length);
 230         for (String arg : command)
 231             commandList.add(arg);
 232         COMMAND.setRelease(this, commandList);
 233     }
 234 
 235     /**
 236      * Sets this process builder's operating system program and
 237      * arguments.  This method does <i>not</i> make a copy of the
 238      * {@code command} list.  Subsequent updates to the list will
 239      * be reflected in the state of the process builder.  It is not
 240      * checked whether {@code command} corresponds to a valid
 241      * operating system command.
 242      *
 243      * @param  command the list containing the program and its arguments
 244      * @return this process builder
 245      */
 246     public ProcessBuilder command(List<String> command) {
 247         if (command == null)
 248             throw new NullPointerException();
 249         COMMAND.setRelease(this, command);
 250         return this;
 251     }
 252 
 253     /**
 254      * Sets this process builder's operating system program and
 255      * arguments.  This is a convenience method that sets the command
 256      * to a string list containing the same strings as the
 257      * {@code command} array, in the same order.  It is not
 258      * checked whether {@code command} corresponds to a valid
 259      * operating system command.
 260      *
 261      * @param  command a string array containing the program and its arguments
 262      * @return this process builder
 263      */
 264     public ProcessBuilder command(String... command) {
 265         this.command = new ArrayList<>(command.length);
 266         for (String arg : command)
 267             this.command.add(arg);
 268         return this;
 269     }
 270 
 271     /**
 272      * Returns this process builder's operating system program and
 273      * arguments.  The returned list is <i>not</i> a copy.  Subsequent
 274      * updates to the list will be reflected in the state of this
 275      * process builder.
 276      *
 277      * @return this process builder's program and its arguments
 278      */
 279     public List<String> command() {
 280         return (List<String>) COMMAND.getAcquire(this);
 281     }
 282 
 283     /**
 284      * Returns a string map view of this process builder's environment.
 285      *
 286      * Whenever a process builder is created, the environment is
 287      * initialized to a copy of the current process environment (see
 288      * {@link System#getenv()}).  Subprocesses subsequently started by
 289      * this object's {@link #start()} method will use this map as
 290      * their environment.
 291      *
 292      * <p>The returned object may be modified using ordinary {@link
 293      * java.util.Map Map} operations.  These modifications will be
 294      * visible to subprocesses started via the {@link #start()}
 295      * method.  Two {@code ProcessBuilder} instances always
 296      * contain independent process environments, so changes to the
 297      * returned map will never be reflected in any other
 298      * {@code ProcessBuilder} instance or the values returned by
 299      * {@link System#getenv System.getenv}.
 300      *


 336      *
 337      * <p>When passing information to a Java subprocess,
 338      * <a href=System.html#EnvironmentVSSystemProperties>system properties</a>
 339      * are generally preferred over environment variables.
 340      *
 341      * @return this process builder's environment
 342      *
 343      * @throws SecurityException
 344      *         if a security manager exists and its
 345      *         {@link SecurityManager#checkPermission checkPermission}
 346      *         method doesn't allow access to the process environment
 347      *
 348      * @see    Runtime#exec(String[],String[],java.io.File)
 349      * @see    System#getenv()
 350      */
 351     public Map<String,String> environment() {
 352         SecurityManager security = System.getSecurityManager();
 353         if (security != null)
 354             security.checkPermission(new RuntimePermission("getenv.*"));
 355 
 356         // Multiple threads may call this method without synchronization
 357         for (;;) {
 358             Map<String,String> environment = (Map<String,String>)
 359                 ENVIRONMENT.getAcquire(this);
 360             if (environment != null)
 361                 return environment;
 362             ENVIRONMENT.compareAndSet(this, null,
 363                                       ProcessEnvironment.environment());
 364         }
 365     }
 366 
 367     // Only for use by Runtime.exec(...envp...)
 368     ProcessBuilder environment(String[] envp) {
 369         assert environment == null;
 370         if (envp != null) {
 371             environment = ProcessEnvironment.emptyEnvironment(envp.length);
 372             assert environment != null;
 373 
 374             for (String envstring : envp) {
 375                 // Before 1.5, we blindly passed invalid envstrings
 376                 // to the child process.
 377                 // We would like to throw an exception, but do not,
 378                 // for compatibility with old broken code.
 379 
 380                 // Silently discard any trailing junk.
 381                 if (envstring.indexOf((int) '\u0000') != -1)
 382                     envstring = envstring.replaceFirst("\u0000.*", "");
 383 
 384                 int eqlsign =


1286                     }
1287                     redirects[1] = new RedirectPipeImpl();  // placeholder for new output
1288                 }
1289                 processes.add(builder.start(redirects));
1290                 prevOutput = redirects[1];
1291             }
1292         } catch (Exception ex) {
1293             // Cleanup processes already started
1294             processes.forEach(Process::destroyForcibly);
1295             processes.forEach(p -> {
1296                 try {
1297                     p.waitFor();        // Wait for it to exit
1298                 } catch (InterruptedException ie) {
1299                     // If interrupted; continue with next Process
1300                     Thread.currentThread().interrupt();
1301                 }
1302             });
1303             throw ex;
1304         }
1305         return processes;
1306     }
1307 
1308     // VarHandle mechanics
1309     private static final VarHandle COMMAND;
1310     private static final VarHandle ENVIRONMENT;
1311     static {
1312         try {
1313             MethodHandles.Lookup l = MethodHandles.lookup();
1314             COMMAND = l.findVarHandle(
1315                     ProcessBuilder.class, "command", List.class);
1316             ENVIRONMENT = l.findVarHandle(
1317                     ProcessBuilder.class, "environment", Map.class);
1318         } catch (ReflectiveOperationException e) {
1319             throw new ExceptionInInitializerError(e);
1320         }
1321     }
1322 }
< prev index next >