src/windows/classes/java/lang/ProcessImpl.java

Print this page




  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.IOException;
  29 import java.io.File;
  30 import java.io.InputStream;
  31 import java.io.OutputStream;
  32 import java.io.FileInputStream;
  33 import java.io.FileOutputStream;
  34 import java.io.FileDescriptor;
  35 import java.io.BufferedInputStream;
  36 import java.io.BufferedOutputStream;
  37 import java.lang.ProcessBuilder.Redirect;
  38 import java.security.AccessController;
  39 import java.security.PrivilegedAction;

  40 
  41 /* This class is for the exclusive use of ProcessBuilder.start() to
  42  * create new processes.
  43  *
  44  * @author Martin Buchholz
  45  * @since   1.5
  46  */
  47 
  48 final class ProcessImpl extends Process {
  49     private static final sun.misc.JavaIOFileDescriptorAccess fdAccess
  50         = sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess();
  51 
  52     /**
  53      * Open a file for writing. If {@code append} is {@code true} then the file
  54      * is opened for atomic append directly and a FileOutputStream constructed
  55      * with the resulting handle. This is because a FileOutputStream created
  56      * to append to a file does not open the file in a manner that guarantees
  57      * that writes by the child process will be atomic.
  58      */
  59     private static FileOutputStream newFileOutputStream(File f, boolean append)


 138             finally {
 139                 try { if (f1 != null) f1.close(); }
 140                 finally { if (f2 != null) f2.close(); }
 141             }
 142         }
 143 
 144     }
 145 
 146     private long handle = 0;
 147     private OutputStream stdin_stream;
 148     private InputStream stdout_stream;
 149     private InputStream stderr_stream;
 150 
 151     private ProcessImpl(final String cmd[],
 152                         final String envblock,
 153                         final String path,
 154                         final long[] stdHandles,
 155                         final boolean redirectErrorStream)
 156         throws IOException
 157     {



 158         // Win32 CreateProcess requires cmd[0] to be normalized
 159         cmd[0] = new File(cmd[0]).getPath();
 160 
 161         StringBuilder cmdbuf = new StringBuilder(80);
 162         for (int i = 0; i < cmd.length; i++) {
 163             if (i > 0) {
 164                 cmdbuf.append(' ');
 165             }
 166             String s = cmd[i];
 167             if (s.indexOf(' ') >= 0 || s.indexOf('\t') >= 0) {
 168                 if (s.charAt(0) != '"') {
 169                     cmdbuf.append('"');
 170                     cmdbuf.append(s);
 171                     if (s.endsWith("\\")) {
 172                         cmdbuf.append("\\");
 173                     }
 174                     cmdbuf.append('"');
 175                 } else if (s.endsWith("\"")) {
 176                     /* The argument has already been quoted. */
 177                     cmdbuf.append(s);
 178                 } else {
 179                     /* Unmatched quote for the argument. */
 180                     throw new IllegalArgumentException();
 181                 }
 182             } else {
 183                 cmdbuf.append(s);
 184             }
 185         }
 186         String cmdstr = cmdbuf.toString();
 187 































 188         handle = create(cmdstr, envblock, path,
 189                         stdHandles, redirectErrorStream);
 190 
 191         java.security.AccessController.doPrivileged(
 192         new java.security.PrivilegedAction<Void>() {
 193         public Void run() {
 194             if (stdHandles[0] == -1L)
 195                 stdin_stream = ProcessBuilder.NullOutputStream.INSTANCE;
 196             else {
 197                 FileDescriptor stdin_fd = new FileDescriptor();
 198                 fdAccess.setHandle(stdin_fd, stdHandles[0]);
 199                 stdin_stream = new BufferedOutputStream(
 200                     new FileOutputStream(stdin_fd));
 201             }
 202 
 203             if (stdHandles[1] == -1L)
 204                 stdout_stream = ProcessBuilder.NullInputStream.INSTANCE;
 205             else {
 206                 FileDescriptor stdout_fd = new FileDescriptor();
 207                 fdAccess.setHandle(stdout_fd, stdHandles[1]);
 208                 stdout_stream = new BufferedInputStream(
 209                     new FileInputStream(stdout_fd));
 210             }
 211 
 212             if (stdHandles[2] == -1L)
 213                 stderr_stream = ProcessBuilder.NullInputStream.INSTANCE;
 214             else {
 215                 FileDescriptor stderr_fd = new FileDescriptor();
 216                 fdAccess.setHandle(stderr_fd, stdHandles[2]);
 217                 stderr_stream = new FileInputStream(stderr_fd);
 218             }
 219 
 220             return null; }});






 221     }

 222 






























































 223     public OutputStream getOutputStream() {
 224         return stdin_stream;
 225     }
 226 
 227     public InputStream getInputStream() {
 228         return stdout_stream;
 229     }
 230 
 231     public InputStream getErrorStream() {
 232         return stderr_stream;
 233     }
 234 
 235     public void finalize() {
 236         closeHandle(handle);
 237     }
 238 
 239     private static final int STILL_ACTIVE = getStillActive();
 240     private static native int getStillActive();
 241 
 242     public int exitValue() {




  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.IOException;
  29 import java.io.File;
  30 import java.io.InputStream;
  31 import java.io.OutputStream;
  32 import java.io.FileInputStream;
  33 import java.io.FileOutputStream;
  34 import java.io.FileDescriptor;
  35 import java.io.BufferedInputStream;
  36 import java.io.BufferedOutputStream;
  37 import java.lang.ProcessBuilder.Redirect;
  38 import java.security.AccessController;
  39 import java.security.PrivilegedAction;
  40 import java.util.StringTokenizer;
  41 
  42 /* This class is for the exclusive use of ProcessBuilder.start() to
  43  * create new processes.
  44  *
  45  * @author Martin Buchholz
  46  * @since   1.5
  47  */
  48 
  49 final class ProcessImpl extends Process {
  50     private static final sun.misc.JavaIOFileDescriptorAccess fdAccess
  51         = sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess();
  52 
  53     /**
  54      * Open a file for writing. If {@code append} is {@code true} then the file
  55      * is opened for atomic append directly and a FileOutputStream constructed
  56      * with the resulting handle. This is because a FileOutputStream created
  57      * to append to a file does not open the file in a manner that guarantees
  58      * that writes by the child process will be atomic.
  59      */
  60     private static FileOutputStream newFileOutputStream(File f, boolean append)


 139             finally {
 140                 try { if (f1 != null) f1.close(); }
 141                 finally { if (f2 != null) f2.close(); }
 142             }
 143         }
 144 
 145     }
 146 
 147     private long handle = 0;
 148     private OutputStream stdin_stream;
 149     private InputStream stdout_stream;
 150     private InputStream stderr_stream;
 151 
 152     private ProcessImpl(final String cmd[],
 153                         final String envblock,
 154                         final String path,
 155                         final long[] stdHandles,
 156                         final boolean redirectErrorStream)
 157         throws IOException
 158     {
 159         String prog = "";
 160 
 161         try {
 162             // Win32 CreateProcess requires cmd[0] to be normalized
 163             cmd[0] = new File(cmd[0]).getPath();
 164 
 165             StringBuilder cmdbuf = new StringBuilder(80);
 166             for (int i = 0; i < cmd.length; i++) {
 167                 if (i > 0) {
 168                     cmdbuf.append(' ');
 169                 }
 170                 String s = cmd[i];
 171                 if (s.indexOf(' ') >= 0 || s.indexOf('\t') >= 0) {
 172                     if (s.charAt(0) != '"') {
 173                         cmdbuf.append('"');
 174                         cmdbuf.append(s);
 175                         if (s.endsWith("\\")) {
 176                             cmdbuf.append("\\");
 177                         }
 178                         cmdbuf.append('"');
 179                     } else if (s.endsWith("\"")) {
 180                         /* The argument has already been quoted. */
 181                         cmdbuf.append(s);
 182                     } else {
 183                         /* Unmatched quote for the argument. */
 184                         throw new IllegalArgumentException();
 185                     }
 186                 } else {
 187                     cmdbuf.append(s);
 188                 }
 189             }
 190             String cmdstr = cmdbuf.toString();
 191 
 192             if (cmdstr.length() > 0 && cmdstr.charAt(0) == '"') {
 193                 // quoted string must contain the prog name
 194                 int end = cmdstr.indexOf('"', 1);
 195                 if (end == -1 || cmdstr.indexOf('"', end+1) != -1) {
 196                     // either unterminated string or has embedded string
 197                     throw new IllegalArgumentException("Invalid string");
 198                 }
 199                 prog = cmdstr.substring(1, end);
 200             } else {
 201                 prog = getProgramPath(cmdstr);
 202             }
 203 
 204             SecurityManager security = System.getSecurityManager();
 205             if (security != null) {
 206                 try {
 207                     security.checkExec(prog);
 208                 } catch (SecurityException e) {
 209                     // We support invocation of "foo" or "foo.exe" assuming "foo.exe" exists.
 210                     // So, the security check should allow the same latitude.
 211                     String lprog = prog.toLowerCase();
 212                     if (lprog.endsWith(".exe")) {
 213                         // check without the .exe extension
 214                         int len = lprog.length();
 215                         String mprog = prog.substring(0, len-4);
 216                         security.checkExec(mprog);
 217                     } else {
 218                         throw e;
 219                     }
 220                 }
 221             }
 222 
 223             handle = create(cmdstr, envblock, path,
 224                             stdHandles, redirectErrorStream);
 225 
 226             java.security.AccessController.doPrivileged(
 227             new java.security.PrivilegedAction<Void>() {
 228                 public Void run() {
 229                 if (stdHandles[0] == -1L)
 230                     stdin_stream = ProcessBuilder.NullOutputStream.INSTANCE;
 231                 else {
 232                     FileDescriptor stdin_fd = new FileDescriptor();
 233                     fdAccess.setHandle(stdin_fd, stdHandles[0]);
 234                     stdin_stream = new BufferedOutputStream(
 235                         new FileOutputStream(stdin_fd));
 236                 }
 237 
 238                 if (stdHandles[1] == -1L)
 239                     stdout_stream = ProcessBuilder.NullInputStream.INSTANCE;
 240                 else {
 241                     FileDescriptor stdout_fd = new FileDescriptor();
 242                     fdAccess.setHandle(stdout_fd, stdHandles[1]);
 243                     stdout_stream = new BufferedInputStream(
 244                         new FileInputStream(stdout_fd));
 245                 }
 246     
 247                 if (stdHandles[2] == -1L)
 248                     stderr_stream = ProcessBuilder.NullInputStream.INSTANCE;
 249                 else {
 250                     FileDescriptor stderr_fd = new FileDescriptor();
 251                     fdAccess.setHandle(stderr_fd, stdHandles[2]);
 252                     stderr_stream = new FileInputStream(stderr_fd);
 253                 }
 254     
 255                 return null; }
 256             });
 257         } catch (IOException e) {
 258             throw new IOException (
 259                 "Cannot run program \"" + prog + "\""
 260                 + (path == null ? "" : " (in directory \"" + path + "\")")
 261                 + ": " + e.getMessage(), e);
 262         }
 263     }
 264 
 265     /**
 266      * Use the same algorithm as Windows CreateProcess to determine the pathname to
 267      * the given command. Is complicated by the presence of whitespace in the pathname,
 268      * which makes it hard(er) to distinguish between command line parameters and
 269      * whitespace in the command path. We have to check for the existence of files
 270      * to disambiguate. Note, this means when the target does *not* exist, the path
 271      * remains ambiguous, and security checks in particular, will probably fail
 272      * because the whole command string (including args) will be passed to the security
 273      * check.
 274      *
 275      * C:\A B\C D\E F G 
 276      * 
 277      * We check in the following order (for files existing)
 278      * 1. C:\A.exe
 279      * 2. C:\A
 280      * 3. C:\A B\C.exe
 281      * 4. C:\A B\C
 282      * 5. C:\A B\C D\E.exe
 283      * 6. C:\A B\C D\E (and so on)
 284      * Any token ending in '\\' can't be a valid filename. So it isn't checked.
 285      * If no file is found, then the entire original string is returned.
 286      */
 287     static String getProgramPath(final String command) {
 288         return java.security.AccessController.doPrivileged(
 289         new java.security.PrivilegedAction<String>() {
 290             public String run() {
 291                 StringBuilder sb = new StringBuilder();
 292                 StringTokenizer tokenizer = new StringTokenizer(command, " \t", true);
 293                 while (tokenizer.hasMoreTokens()) {
 294                     String t = tokenizer.nextToken();
 295                     sb.append(t);
 296                     if (t.equals(" ") || t.equals("\t") || t.endsWith("\\")) {
 297                         continue;
 298                     }
 299                     t = sb.toString();
 300                     if (fileHasNoDot(t)) {
 301                         // try appending .exe
 302                         String t1 = t + ".exe";
 303                         if (exists(t1)) {
 304                             return t1;
 305                         }
 306                     }
 307                     if (exists(t)) {
 308                         return t;
 309                     }
 310                 }
 311                 return command; 
 312             }
 313         });
 314     }
 315 
 316     // final component of path has no '.' in it
 317     private static boolean fileHasNoDot(String name) {
 318         int n = name.lastIndexOf('\\') + 1;
 319         return name.length() > n ? name.indexOf('.', n) == -1 : false;
 320     }
 321 
 322     private static boolean exists(String name) {
 323         File f = new File (name);
 324         return f.exists();
 325     }
 326 
 327     public OutputStream getOutputStream() {
 328         return stdin_stream;
 329     }
 330 
 331     public InputStream getInputStream() {
 332         return stdout_stream;
 333     }
 334 
 335     public InputStream getErrorStream() {
 336         return stderr_stream;
 337     }
 338 
 339     public void finalize() {
 340         closeHandle(handle);
 341     }
 342 
 343     private static final int STILL_ACTIVE = getStillActive();
 344     private static native int getStillActive();
 345 
 346     public int exitValue() {