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() {
|