Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
095ce48d
D
dragonwell8_jdk
项目概览
openanolis
/
dragonwell8_jdk
通知
4
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell8_jdk
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
095ce48d
编写于
3月 10, 2008
作者:
M
martin
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
4960438: (process) Need IO redirection API for subprocesses
Reviewed-by: alanb, iris
上级
6d73e05f
变更
12
隐藏空白更改
内联
并排
Showing
12 changed file
with
1680 addition
and
476 deletion
+1680
-476
src/share/classes/java/lang/Process.java
src/share/classes/java/lang/Process.java
+50
-21
src/share/classes/java/lang/ProcessBuilder.java
src/share/classes/java/lang/ProcessBuilder.java
+635
-91
src/share/classes/sun/misc/JavaIOFileDescriptorAccess.java
src/share/classes/sun/misc/JavaIOFileDescriptorAccess.java
+4
-0
src/solaris/classes/java/io/FileDescriptor.java
src/solaris/classes/java/io/FileDescriptor.java
+9
-1
src/solaris/classes/java/lang/ProcessImpl.java
src/solaris/classes/java/lang/ProcessImpl.java
+58
-1
src/solaris/classes/java/lang/UNIXProcess.java.linux
src/solaris/classes/java/lang/UNIXProcess.java.linux
+105
-79
src/solaris/classes/java/lang/UNIXProcess.java.solaris
src/solaris/classes/java/lang/UNIXProcess.java.solaris
+209
-183
src/solaris/native/java/lang/UNIXProcess_md.c
src/solaris/native/java/lang/UNIXProcess_md.c
+30
-21
src/windows/classes/java/io/FileDescriptor.java
src/windows/classes/java/io/FileDescriptor.java
+19
-14
src/windows/classes/java/lang/ProcessImpl.java
src/windows/classes/java/lang/ProcessImpl.java
+121
-29
src/windows/native/java/lang/ProcessImpl_md.c
src/windows/native/java/lang/ProcessImpl_md.c
+64
-33
test/java/lang/ProcessBuilder/Basic.java
test/java/lang/ProcessBuilder/Basic.java
+376
-3
未找到文件。
src/share/classes/java/lang/Process.java
浏览文件 @
095ce48d
...
@@ -41,18 +41,24 @@ import java.io.*;
...
@@ -41,18 +41,24 @@ import java.io.*;
* <p>The methods that create processes may not work well for special
* <p>The methods that create processes may not work well for special
* processes on certain native platforms, such as native windowing
* processes on certain native platforms, such as native windowing
* processes, daemon processes, Win16/DOS processes on Microsoft
* processes, daemon processes, Win16/DOS processes on Microsoft
* Windows, or shell scripts. The created subprocess does not have
* Windows, or shell scripts.
* its own terminal or console. All its standard I/O (i.e. stdin,
*
* stdout, stderr) operations will be redirected to the parent process
* <p>By default, the created subprocess does not have its own terminal
* through three streams
* or console. All its standard I/O (i.e. stdin, stdout, stderr)
* ({@link #getOutputStream()},
* operations will be redirected to the parent process, where they can
* {@link #getInputStream()},
* be accessed via the streams obtained using the methods
* {@link #getErrorStream()}).
* {@link #getOutputStream()},
* {@link #getInputStream()}, and
* {@link #getErrorStream()}.
* The parent process uses these streams to feed input to and get output
* The parent process uses these streams to feed input to and get output
* from the subprocess. Because some native platforms only provide
* from the subprocess. Because some native platforms only provide
* limited buffer size for standard input and output streams, failure
* limited buffer size for standard input and output streams, failure
* to promptly write the input stream or read the output stream of
* to promptly write the input stream or read the output stream of
* the subprocess may cause the subprocess to block, and even deadlock.
* the subprocess may cause the subprocess to block, or even deadlock.
*
* <p>Where desired, <a href="ProcessBuilder.html#redirect-input">
* subprocess I/O can also be redirected</a>
* using methods of the {@link ProcessBuilder} class.
*
*
* <p>The subprocess is not killed when there are no more references to
* <p>The subprocess is not killed when there are no more references to
* the {@code Process} object, but rather the subprocess
* the {@code Process} object, but rather the subprocess
...
@@ -62,16 +68,22 @@ import java.io.*;
...
@@ -62,16 +68,22 @@ import java.io.*;
* Process} object execute asynchronously or concurrently with respect
* Process} object execute asynchronously or concurrently with respect
* to the Java process that owns the {@code Process} object.
* to the Java process that owns the {@code Process} object.
*
*
* @author unascribed
* <p>As of 1.5, {@link ProcessBuilder#start()} is the preferred way
* @see ProcessBuilder
* to create a {@code Process}.
*
* @since JDK1.0
* @since JDK1.0
*/
*/
public
abstract
class
Process
{
public
abstract
class
Process
{
/**
/**
* Returns the output stream connected to the normal input of the
* Returns the output stream connected to the normal input of the
* subprocess. Output to the stream is piped into the standard
* subprocess. Output to the stream is piped into the standard
* input stream of the process represented by this {@code Process}
* input of the process represented by this {@code Process} object.
* object.
*
* <p>If the standard input of the subprocess has been redirected using
* {@link ProcessBuilder#redirectInput(Redirect)
* ProcessBuilder.redirectInput}
* then this method will return a
* <a href="ProcessBuilder.html#redirect-input">null output stream</a>.
*
*
* <p>Implementation note: It is a good idea for the returned
* <p>Implementation note: It is a good idea for the returned
* output stream to be buffered.
* output stream to be buffered.
...
@@ -84,30 +96,47 @@ public abstract class Process {
...
@@ -84,30 +96,47 @@ public abstract class Process {
/**
/**
* Returns the input stream connected to the normal output of the
* Returns the input stream connected to the normal output of the
* subprocess. The stream obtains data piped from the standard
* subprocess. The stream obtains data piped from the standard
* output stream of the process represented by this {@code
* output of the process represented by this {@code Process} object.
* Process} object.
*
* <p>If the standard output of the subprocess has been redirected using
* {@link ProcessBuilder#redirectOutput(Redirect)
* ProcessBuilder.redirectOutput}
* then this method will return a
* <a href="ProcessBuilder.html#redirect-output">null input stream</a>.
*
* <p>Otherwise, if the standard error of the subprocess has been
* redirected using
* {@link ProcessBuilder#redirectErrorStream(boolean)
* ProcessBuilder.redirectErrorStream}
* then the input stream returned by this method will receive the
* merged standard output and the standard error of the subprocess.
*
*
* <p>Implementation note: It is a good idea for the returned
* <p>Implementation note: It is a good idea for the returned
* input stream to be buffered.
* input stream to be buffered.
*
*
* @return the input stream connected to the normal output of the
* @return the input stream connected to the normal output of the
* subprocess
* subprocess
* @see ProcessBuilder#redirectErrorStream()
*/
*/
abstract
public
InputStream
getInputStream
();
abstract
public
InputStream
getInputStream
();
/**
/**
* Returns the input stream connected to the error output stream of
* Returns the input stream connected to the error output of the
* the subprocess. The stream obtains data piped from the error
* subprocess. The stream obtains data piped from the error output
* output stream of the process represented by this {@code Process}
* of the process represented by this {@code Process} object.
* object.
*
* <p>If the standard error of the subprocess has been redirected using
* {@link ProcessBuilder#redirectError(Redirect)
* ProcessBuilder.redirectError} or
* {@link ProcessBuilder#redirectErrorStream(boolean)
* ProcessBuilder.redirectErrorStream}
* then this method will return a
* <a href="ProcessBuilder.html#redirect-output">null input stream</a>.
*
*
* <p>Implementation note: It is a good idea for the returned
* <p>Implementation note: It is a good idea for the returned
* input stream to be buffered.
* input stream to be buffered.
*
*
* @return the input stream connected to the error output
stream
of
* @return the input stream connected to the error output of
* the subprocess
* the subprocess
* @see ProcessBuilder#redirectErrorStream()
*/
*/
abstract
public
InputStream
getErrorStream
();
abstract
public
InputStream
getErrorStream
();
...
...
src/share/classes/java/lang/ProcessBuilder.java
浏览文件 @
095ce48d
/*
/*
* Copyright 2003-200
6
Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2003-200
8
Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*
* This code is free software; you can redistribute it and/or modify it
* This code is free software; you can redistribute it and/or modify it
...
@@ -27,6 +27,10 @@ package java.lang;
...
@@ -27,6 +27,10 @@ package java.lang;
import
java.io.File
;
import
java.io.File
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.io.FileOutputStream
;
import
java.util.Arrays
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Map
;
...
@@ -34,7 +38,7 @@ import java.util.Map;
...
@@ -34,7 +38,7 @@ import java.util.Map;
/**
/**
* This class is used to create operating system processes.
* This class is used to create operating system processes.
*
*
* <p>Each
<code>ProcessBuilder</code>
instance manages a collection
* <p>Each
{@code ProcessBuilder}
instance manages a collection
* of process attributes. The {@link #start()} method creates a new
* of process attributes. The {@link #start()} method creates a new
* {@link Process} instance with those attributes. The {@link
* {@link Process} instance with those attributes. The {@link
* #start()} method can be invoked repeatedly from the same instance
* #start()} method can be invoked repeatedly from the same instance
...
@@ -59,19 +63,64 @@ import java.util.Map;
...
@@ -59,19 +63,64 @@ import java.util.Map;
*
*
* <li>a <i>working directory</i>. The default value is the current
* <li>a <i>working directory</i>. The default value is the current
* working directory of the current process, usually the directory
* working directory of the current process, usually the directory
* named by the system property <code>user.dir</code>.
* named by the system property {@code user.dir}.
*
* <li><a name="redirect-input">a source of <i>standard input</i>.
* By default, the subprocess reads input from a pipe. Java code
* can access this pipe via the output stream returned by
* {@link Process#getOutputStream()}. However, standard input may
* be redirected to another source using
* {@link #redirectInput(Redirect) redirectInput}.
* In this case, {@link Process#getOutputStream()} will return a
* <i>null output stream</i>, for which:
*
* <ul>
* <li>the {@link OutputStream#write(int) write} methods always
* throw {@code IOException}
* <li>the {@link OutputStream#close() close} method does nothing
* </ul>
*
* <li><a name="redirect-output">a destination for <i>standard output</i>
* and <i>standard error</i>. By default, the subprocess writes standard
* output and standard error to pipes. Java code can access these pipes
* via the input streams returned by {@link Process#getInputStream()} and
* {@link Process#getErrorStream()}. However, standard output and
* standard error may be redirected to other destinations using
* {@link #redirectOutput(Redirect) redirectOutput} and
* {@link #redirectError(Redirect) redirectError}.
* In this case, {@link Process#getInputStream()} and/or
* {@link Process#getErrorStream()} will return a <i>null input
* stream</i>, for which:
*
* <ul>
* <li>the {@link InputStream#read() read} methods always return
* {@code -1}
* <li>the {@link InputStream#available() available} method always returns
* {@code 0}
* <li>the {@link InputStream#close() close} method does nothing
* </ul>
*
*
* <li>a <i>redirectErrorStream</i> property. Initially, this property
* <li>a <i>redirectErrorStream</i> property. Initially, this property
* is
<code>false</code>
, meaning that the standard output and error
* is
{@code false}
, meaning that the standard output and error
* output of a subprocess are sent to two separate streams, which can
* output of a subprocess are sent to two separate streams, which can
* be accessed using the {@link Process#getInputStream()} and {@link
* be accessed using the {@link Process#getInputStream()} and {@link
* Process#getErrorStream()} methods. If the value is set to
* Process#getErrorStream()} methods.
* <code>true</code>, the standard error is merged with the standard
*
* output. This makes it easier to correlate error messages with the
* <p>If the value is set to {@code true}, then:
* corresponding output. In this case, the merged data can be read
*
* from the stream returned by {@link Process#getInputStream()}, while
* <ul>
* reading from the stream returned by {@link
* <li>standard error is merged with the standard output and always sent
* Process#getErrorStream()} will get an immediate end of file.
* to the same destination (this makes it easier to correlate error
* messages with the corresponding output)
* <li>the common destination of standard error and standard output can be
* redirected using
* {@link #redirectOutput(Redirect) redirectOutput}
* <li>any redirection set by the
* {@link #redirectError(Redirect) redirectError}
* method is ignored when creating a subprocess
* <li>the stream returned from {@link Process#getErrorStream()} will
* always be a <a href="#redirect-output">null input stream</a>
* </ul>
*
*
* </ul>
* </ul>
*
*
...
@@ -87,34 +136,43 @@ import java.util.Map;
...
@@ -87,34 +136,43 @@ import java.util.Map;
* is invoked.
* is invoked.
*
*
* <p><strong>Note that this class is not synchronized.</strong>
* <p><strong>Note that this class is not synchronized.</strong>
* If multiple threads access a
<code>ProcessBuilder</code>
instance
* If multiple threads access a
{@code ProcessBuilder}
instance
* concurrently, and at least one of the threads modifies one of the
* concurrently, and at least one of the threads modifies one of the
* attributes structurally, it <i>must</i> be synchronized externally.
* attributes structurally, it <i>must</i> be synchronized externally.
*
*
* <p>Starting a new process which uses the default working directory
* <p>Starting a new process which uses the default working directory
* and environment is easy:
* and environment is easy:
*
*
* <
blockquote><pre>
* <
pre> {@code
* Process p = new ProcessBuilder("myCommand", "myArg").start();
* Process p = new ProcessBuilder("myCommand", "myArg").start();
*
</pre></blockquot
e>
*
}</pr
e>
*
*
* <p>Here is an example that starts a process with a modified working
* <p>Here is an example that starts a process with a modified working
* directory and environment:
* directory and environment, and redirects standard output and error
* to be appended to a log file:
*
*
* <blockquote><pre>
* <pre> {@code
* ProcessBuilder pb = new ProcessBuilder("myCommand", "myArg1", "myArg2");
* ProcessBuilder pb =
* Map<String, String> env = pb.environment();
* new ProcessBuilder("myCommand", "myArg1", "myArg2");
* Map<String, String> env = pb.environment();
* env.put("VAR1", "myValue");
* env.put("VAR1", "myValue");
* env.remove("OTHERVAR");
* env.remove("OTHERVAR");
* env.put("VAR2", env.get("VAR1") + "suffix");
* env.put("VAR2", env.get("VAR1") + "suffix");
* pb.directory(new File("myDir"));
* pb.directory(new File("myDir"));
* File log = new File("log");
* pb.redirectErrorStream(true);
* pb.redirectOutput(Redirect.appendTo(log));
* Process p = pb.start();
* Process p = pb.start();
* </pre></blockquote>
* assert pb.redirectInput() == Redirect.PIPE;
* assert pb.redirectOutput().file() == log;
* assert p.getInputStream().read() == -1;
* }</pre>
*
*
* <p>To start a process with an explicit set of environment
* <p>To start a process with an explicit set of environment
* variables, first call {@link java.util.Map#clear() Map.clear()}
* variables, first call {@link java.util.Map#clear() Map.clear()}
* before adding environment variables.
* before adding environment variables.
*
*
* @author Martin Buchholz
* @since 1.5
* @since 1.5
*/
*/
...
@@ -124,20 +182,19 @@ public final class ProcessBuilder
...
@@ -124,20 +182,19 @@ public final class ProcessBuilder
private
File
directory
;
private
File
directory
;
private
Map
<
String
,
String
>
environment
;
private
Map
<
String
,
String
>
environment
;
private
boolean
redirectErrorStream
;
private
boolean
redirectErrorStream
;
private
Redirect
[]
redirects
;
/**
/**
* Constructs a process builder with the specified operating
* Constructs a process builder with the specified operating
* system program and arguments. This constructor does <i>not</i>
* system program and arguments. This constructor does <i>not</i>
* make a copy of the
<code>command</code>
list. Subsequent
* make a copy of the
{@code command}
list. Subsequent
* updates to the list will be reflected in the state of the
* updates to the list will be reflected in the state of the
* process builder. It is not checked whether
* process builder. It is not checked whether
* <code>command</code> corresponds to a valid operating system
* {@code command} corresponds to a valid operating system
* command.</p>
* command.
*
* @param command The list containing the program and its arguments
*
*
* @
throws NullPointerException
* @
param command the list containing the program and its arguments
*
If the argument is <code>null</code>
*
@throws NullPointerException if the argument is null
*/
*/
public
ProcessBuilder
(
List
<
String
>
command
)
{
public
ProcessBuilder
(
List
<
String
>
command
)
{
if
(
command
==
null
)
if
(
command
==
null
)
...
@@ -149,12 +206,12 @@ public final class ProcessBuilder
...
@@ -149,12 +206,12 @@ public final class ProcessBuilder
* Constructs a process builder with the specified operating
* Constructs a process builder with the specified operating
* system program and arguments. This is a convenience
* system program and arguments. This is a convenience
* constructor that sets the process builder's command to a string
* constructor that sets the process builder's command to a string
* list containing the same strings as the
<code>command</code>
* list containing the same strings as the
{@code command}
* array, in the same order. It is not checked whether
* array, in the same order. It is not checked whether
*
<code>command</code>
corresponds to a valid operating system
*
{@code command}
corresponds to a valid operating system
* command.
</p>
* command.
*
*
* @param
command A
string array containing the program and its arguments
* @param
command a
string array containing the program and its arguments
*/
*/
public
ProcessBuilder
(
String
...
command
)
{
public
ProcessBuilder
(
String
...
command
)
{
this
.
command
=
new
ArrayList
<
String
>(
command
.
length
);
this
.
command
=
new
ArrayList
<
String
>(
command
.
length
);
...
@@ -165,16 +222,15 @@ public final class ProcessBuilder
...
@@ -165,16 +222,15 @@ public final class ProcessBuilder
/**
/**
* Sets this process builder's operating system program and
* Sets this process builder's operating system program and
* arguments. This method does <i>not</i> make a copy of the
* arguments. This method does <i>not</i> make a copy of the
*
<code>command</code>
list. Subsequent updates to the list will
*
{@code command}
list. Subsequent updates to the list will
* be reflected in the state of the process builder. It is not
* be reflected in the state of the process builder. It is not
* checked whether
<code>command</code>
corresponds to a valid
* checked whether
{@code command}
corresponds to a valid
* operating system command.
</p>
* operating system command.
*
*
* @param
command T
he list containing the program and its arguments
* @param
command t
he list containing the program and its arguments
* @return
T
his process builder
* @return
t
his process builder
*
*
* @throws NullPointerException
* @throws NullPointerException if the argument is null
* If the argument is <code>null</code>
*/
*/
public
ProcessBuilder
command
(
List
<
String
>
command
)
{
public
ProcessBuilder
command
(
List
<
String
>
command
)
{
if
(
command
==
null
)
if
(
command
==
null
)
...
@@ -187,12 +243,12 @@ public final class ProcessBuilder
...
@@ -187,12 +243,12 @@ public final class ProcessBuilder
* Sets this process builder's operating system program and
* Sets this process builder's operating system program and
* arguments. This is a convenience method that sets the command
* arguments. This is a convenience method that sets the command
* to a string list containing the same strings as the
* to a string list containing the same strings as the
*
<code>command</code>
array, in the same order. It is not
*
{@code command}
array, in the same order. It is not
* checked whether
<code>command</code>
corresponds to a valid
* checked whether
{@code command}
corresponds to a valid
* operating system command.
</p>
* operating system command.
*
*
* @param
command A
string array containing the program and its arguments
* @param
command a
string array containing the program and its arguments
* @return
T
his process builder
* @return
t
his process builder
*/
*/
public
ProcessBuilder
command
(
String
...
command
)
{
public
ProcessBuilder
command
(
String
...
command
)
{
this
.
command
=
new
ArrayList
<
String
>(
command
.
length
);
this
.
command
=
new
ArrayList
<
String
>(
command
.
length
);
...
@@ -205,9 +261,9 @@ public final class ProcessBuilder
...
@@ -205,9 +261,9 @@ public final class ProcessBuilder
* Returns this process builder's operating system program and
* Returns this process builder's operating system program and
* arguments. The returned list is <i>not</i> a copy. Subsequent
* arguments. The returned list is <i>not</i> a copy. Subsequent
* updates to the list will be reflected in the state of this
* updates to the list will be reflected in the state of this
* process builder.
</p>
* process builder.
*
*
* @return
T
his process builder's program and its arguments
* @return
t
his process builder's program and its arguments
*/
*/
public
List
<
String
>
command
()
{
public
List
<
String
>
command
()
{
return
command
;
return
command
;
...
@@ -225,10 +281,10 @@ public final class ProcessBuilder
...
@@ -225,10 +281,10 @@ public final class ProcessBuilder
* <p>The returned object may be modified using ordinary {@link
* <p>The returned object may be modified using ordinary {@link
* java.util.Map Map} operations. These modifications will be
* java.util.Map Map} operations. These modifications will be
* visible to subprocesses started via the {@link #start()}
* visible to subprocesses started via the {@link #start()}
* method. Two
<code>ProcessBuilder</code>
instances always
* method. Two
{@code ProcessBuilder}
instances always
* contain independent process environments, so changes to the
* contain independent process environments, so changes to the
* returned map will never be reflected in any other
* returned map will never be reflected in any other
*
<code>ProcessBuilder</code>
instance or the values returned by
*
{@code ProcessBuilder}
instance or the values returned by
* {@link System#getenv System.getenv}.
* {@link System#getenv System.getenv}.
*
*
* <p>If the system does not support environment variables, an
* <p>If the system does not support environment variables, an
...
@@ -262,25 +318,24 @@ public final class ProcessBuilder
...
@@ -262,25 +318,24 @@ public final class ProcessBuilder
* <p>The returned map is typically case-sensitive on all platforms.
* <p>The returned map is typically case-sensitive on all platforms.
*
*
* <p>If a security manager exists, its
* <p>If a security manager exists, its
* {@link SecurityManager#checkPermission checkPermission}
* {@link SecurityManager#checkPermission checkPermission} method
* method is called with a
* is called with a
* <code>{@link RuntimePermission}("getenv.*")</code>
* {@link RuntimePermission}{@code ("getenv.*")} permission.
* permission. This may result in a {@link SecurityException} being
* This may result in a {@link SecurityException} being thrown.
* thrown.
*
*
* <p>When passing information to a Java subprocess,
* <p>When passing information to a Java subprocess,
* <a href=System.html#EnvironmentVSSystemProperties>system properties</a>
* <a href=System.html#EnvironmentVSSystemProperties>system properties</a>
* are generally preferred over environment variables.
</p>
* are generally preferred over environment variables.
*
*
* @return
T
his process builder's environment
* @return
t
his process builder's environment
*
*
* @throws
SecurityException
* @throws SecurityException
*
I
f a security manager exists and its
*
i
f a security manager exists and its
*
{@link SecurityManager#checkPermission checkPermission}
* {@link SecurityManager#checkPermission checkPermission}
*
method doesn't allow access to the process environment
* method doesn't allow access to the process environment
*
*
* @see
Runtime#exec(String[],String[],java.io.File)
* @see Runtime#exec(String[],String[],java.io.File)
* @see
System#getenv()
* @see System#getenv()
*/
*/
public
Map
<
String
,
String
>
environment
()
{
public
Map
<
String
,
String
>
environment
()
{
SecurityManager
security
=
System
.
getSecurityManager
();
SecurityManager
security
=
System
.
getSecurityManager
();
...
@@ -328,12 +383,12 @@ public final class ProcessBuilder
...
@@ -328,12 +383,12 @@ public final class ProcessBuilder
*
*
* Subprocesses subsequently started by this object's {@link
* Subprocesses subsequently started by this object's {@link
* #start()} method will use this as their working directory.
* #start()} method will use this as their working directory.
* The returned value may be
<code>null</code>
-- this means to use
* The returned value may be
{@code null}
-- this means to use
* the working directory of the current Java process, usually the
* the working directory of the current Java process, usually the
* directory named by the system property
<code>user.dir</code>
,
* directory named by the system property
{@code user.dir}
,
* as the working directory of the child process.
</p>
* as the working directory of the child process.
*
*
* @return
T
his process builder's working directory
* @return
t
his process builder's working directory
*/
*/
public
File
directory
()
{
public
File
directory
()
{
return
directory
;
return
directory
;
...
@@ -344,50 +399,522 @@ public final class ProcessBuilder
...
@@ -344,50 +399,522 @@ public final class ProcessBuilder
*
*
* Subprocesses subsequently started by this object's {@link
* Subprocesses subsequently started by this object's {@link
* #start()} method will use this as their working directory.
* #start()} method will use this as their working directory.
* The argument may be
<code>null</code>
-- this means to use the
* The argument may be
{@code null}
-- this means to use the
* working directory of the current Java process, usually the
* working directory of the current Java process, usually the
* directory named by the system property
<code>user.dir</code>
,
* directory named by the system property
{@code user.dir}
,
* as the working directory of the child process.
</p>
* as the working directory of the child process.
*
*
* @param
directory T
he new working directory
* @param
directory t
he new working directory
* @return
T
his process builder
* @return
t
his process builder
*/
*/
public
ProcessBuilder
directory
(
File
directory
)
{
public
ProcessBuilder
directory
(
File
directory
)
{
this
.
directory
=
directory
;
this
.
directory
=
directory
;
return
this
;
return
this
;
}
}
// ---------------- I/O Redirection ----------------
/**
* Implements a <a href="#redirect-output">null input stream</a>.
*/
static
class
NullInputStream
extends
InputStream
{
public
int
read
()
{
return
-
1
;
}
public
int
available
()
{
return
0
;
}
}
/**
* Implements a <a href="#redirect-input">null output stream</a>.
*/
static
class
NullOutputStream
extends
OutputStream
{
public
void
write
(
int
b
)
throws
IOException
{
throw
new
IOException
(
"Stream closed"
);
}
}
/**
* Represents a source of subprocess input or a destination of
* subprocess output.
*
* Each {@code Redirect} instance is one of the following:
*
* <ul>
* <li>the special value {@link #PIPE Redirect.PIPE}
* <li>the special value {@link #INHERIT Redirect.INHERIT}
* <li>a redirection to read from a file, created by an invocation of
* {@link Redirect#from Redirect.from(File)}
* <li>a redirection to write to a file, created by an invocation of
* {@link Redirect#to Redirect.to(File)}
* <li>a redirection to append to a file, created by an invocation of
* {@link Redirect#appendTo Redirect.appendTo(File)}
* </ul>
*
* <p>Each of the above categories has an associated unique
* {@link Type Type}.
*
* @since 1.7
*/
public
static
abstract
class
Redirect
{
/**
* The type of a {@link Redirect}.
*/
public
enum
Type
{
/**
* The type of {@link Redirect#PIPE Redirect.PIPE}.
*/
PIPE
,
/**
* The type of {@link Redirect#INHERIT Redirect.INHERIT}.
*/
INHERIT
,
/**
* The type of redirects returned from
* {@link Redirect#from Redirect.from(File)}.
*/
READ
,
/**
* The type of redirects returned from
* {@link Redirect#to Redirect.to(File)}.
*/
WRITE
,
/**
* The type of redirects returned from
* {@link Redirect#appendTo Redirect.appendTo(File)}.
*/
APPEND
};
/**
* Returns the type of this {@code Redirect}.
* @return the type of this {@code Redirect}
*/
public
abstract
Type
type
();
/**
* Indicates that subprocess I/O will be connected to the
* current Java process over a pipe.
*
* This is the default handling of subprocess standard I/O.
*
* <p>It will always be true that
* <pre> {@code
* Redirect.PIPE.file() == null &&
* Redirect.PIPE.type() == Redirect.Type.PIPE
* }</pre>
*/
public
static
final
Redirect
PIPE
=
new
Redirect
()
{
public
Type
type
()
{
return
Type
.
PIPE
;
}
public
String
toString
()
{
return
type
().
toString
();
}};
/**
* Indicates that subprocess I/O source or destination will be the
* same as those of the current process. This is the normal
* behavior of most operating system command interpreters (shells).
*
* <p>It will always be true that
* <pre> {@code
* Redirect.INHERIT.file() == null &&
* Redirect.INHERIT.type() == Redirect.Type.INHERIT
* }</pre>
*/
public
static
final
Redirect
INHERIT
=
new
Redirect
()
{
public
Type
type
()
{
return
Type
.
INHERIT
;
}
public
String
toString
()
{
return
type
().
toString
();
}};
/**
* Returns the {@link File} source or destination associated
* with this redirect, or {@code null} if there is no such file.
*
* @return the file associated with this redirect,
* or {@code null} if there is no such file
*/
public
File
file
()
{
return
null
;
}
FileOutputStream
toFileOutputStream
()
throws
IOException
{
throw
new
UnsupportedOperationException
();
}
/**
* Returns a redirect to read from the specified file.
*
* <p>It will always be true that
* <pre> {@code
* Redirect.from(file).file() == file &&
* Redirect.from(file).type() == Redirect.Type.READ
* }</pre>
*
* @throws NullPointerException if the specified file is null
* @return a redirect to read from the specified file
*/
public
static
Redirect
from
(
final
File
file
)
{
if
(
file
==
null
)
throw
new
NullPointerException
();
return
new
Redirect
()
{
public
Type
type
()
{
return
Type
.
READ
;
}
public
File
file
()
{
return
file
;
}
public
String
toString
()
{
return
"redirect to read from file \""
+
file
+
"\""
;
}
};
}
/**
* Returns a redirect to write to the specified file.
* If the specified file exists when the subprocess is started,
* its previous contents will be discarded.
*
* <p>It will always be true that
* <pre> {@code
* Redirect.to(file).file() == file &&
* Redirect.to(file).type() == Redirect.Type.WRITE
* }</pre>
*
* @throws NullPointerException if the specified file is null
* @return a redirect to write to the specified file
*/
public
static
Redirect
to
(
final
File
file
)
{
if
(
file
==
null
)
throw
new
NullPointerException
();
return
new
Redirect
()
{
public
Type
type
()
{
return
Type
.
WRITE
;
}
public
File
file
()
{
return
file
;
}
public
String
toString
()
{
return
"redirect to write to file \""
+
file
+
"\""
;
}
FileOutputStream
toFileOutputStream
()
throws
IOException
{
return
new
FileOutputStream
(
file
,
false
);
}
};
}
/**
* Returns a redirect to append to the specified file.
* Each write operation first advances the position to the
* end of the file and then writes the requested data.
* Whether the advancement of the position and the writing
* of the data are done in a single atomic operation is
* system-dependent and therefore unspecified.
*
* <p>It will always be true that
* <pre> {@code
* Redirect.appendTo(file).file() == file &&
* Redirect.appendTo(file).type() == Redirect.Type.APPEND
* }</pre>
*
* @throws NullPointerException if the specified file is null
* @return a redirect to append to the specified file
*/
public
static
Redirect
appendTo
(
final
File
file
)
{
if
(
file
==
null
)
throw
new
NullPointerException
();
return
new
Redirect
()
{
public
Type
type
()
{
return
Type
.
APPEND
;
}
public
File
file
()
{
return
file
;
}
public
String
toString
()
{
return
"redirect to append to file \""
+
file
+
"\""
;
}
FileOutputStream
toFileOutputStream
()
throws
IOException
{
return
new
FileOutputStream
(
file
,
true
);
}
};
}
/**
* Compares the specified object with this {@code Redirect} for
* equality. Returns {@code true} if and only if the two
* objects are identical or both objects are {@code Redirect}
* instances of the same type associated with non-null equal
* {@code File} instances.
*/
public
boolean
equals
(
Object
obj
)
{
if
(
obj
==
this
)
return
true
;
if
(!
(
obj
instanceof
Redirect
))
return
false
;
Redirect
r
=
(
Redirect
)
obj
;
if
(
r
.
type
()
!=
this
.
type
())
return
false
;
assert
this
.
file
()
!=
null
;
return
this
.
file
().
equals
(
r
.
file
());
}
/**
* Returns a hash code value for this {@code Redirect}.
* @return a hash code value for this {@code Redirect}
*/
public
int
hashCode
()
{
File
file
=
file
();
if
(
file
==
null
)
return
super
.
hashCode
();
else
return
file
.
hashCode
();
}
/**
* No public constructors. Clients must use predefined
* static {@code Redirect} instances or factory methods.
*/
private
Redirect
()
{}
}
private
Redirect
[]
redirects
()
{
if
(
redirects
==
null
)
redirects
=
new
Redirect
[]
{
Redirect
.
PIPE
,
Redirect
.
PIPE
,
Redirect
.
PIPE
};
return
redirects
;
}
/**
* Sets this process builder's standard input source.
*
* Subprocesses subsequently started by this object's {@link #start()}
* method obtain their standard input from this source.
*
* <p>If the source is {@link Redirect#PIPE Redirect.PIPE}
* (the initial value), then the standard input of a
* subprocess can be written to using the output stream
* returned by {@link Process#getOutputStream()}.
* If the source is set to any other value, then
* {@link Process#getOutputStream()} will return a
* <a href="#redirect-input">null output stream</a>.
*
* @param source the new standard input source
* @return this process builder
* @throws IllegalArgumentException
* if the redirect does not correspond to a valid source
* of data, that is, has type
* {@link Redirect.Type#WRITE WRITE} or
* {@link Redirect.Type#APPEND APPEND}
* @since 1.7
*/
public
ProcessBuilder
redirectInput
(
Redirect
source
)
{
if
(
source
.
type
()
==
Redirect
.
Type
.
WRITE
||
source
.
type
()
==
Redirect
.
Type
.
APPEND
)
throw
new
IllegalArgumentException
(
"Redirect invalid for reading: "
+
source
);
redirects
()[
0
]
=
source
;
return
this
;
}
/**
* Sets this process builder's standard output destination.
*
* Subprocesses subsequently started by this object's {@link #start()}
* method send their standard output to this destination.
*
* <p>If the destination is {@link Redirect#PIPE Redirect.PIPE}
* (the initial value), then the standard output of a subprocess
* can be read using the input stream returned by {@link
* Process#getInputStream()}.
* If the destination is set to any other value, then
* {@link Process#getInputStream()} will return a
* <a href="#redirect-output">null input stream</a>.
*
* @param destination the new standard output destination
* @return this process builder
* @throws IllegalArgumentException
* if the redirect does not correspond to a valid
* destination of data, that is, has type
* {@link Redirect.Type#READ READ}
* @since 1.7
*/
public
ProcessBuilder
redirectOutput
(
Redirect
destination
)
{
if
(
destination
.
type
()
==
Redirect
.
Type
.
READ
)
throw
new
IllegalArgumentException
(
"Redirect invalid for writing: "
+
destination
);
redirects
()[
1
]
=
destination
;
return
this
;
}
/**
* Sets this process builder's standard error destination.
*
* Subprocesses subsequently started by this object's {@link #start()}
* method send their standard error to this destination.
*
* <p>If the destination is {@link Redirect#PIPE Redirect.PIPE}
* (the initial value), then the error output of a subprocess
* can be read using the input stream returned by {@link
* Process#getErrorStream()}.
* If the destination is set to any other value, then
* {@link Process#getErrorStream()} will return a
* <a href="#redirect-output">null input stream</a>.
*
* <p>If the {@link #redirectErrorStream redirectErrorStream}
* attribute has been set {@code true}, then the redirection set
* by this method has no effect.
*
* @param destination the new standard error destination
* @return this process builder
* @throws IllegalArgumentException
* if the redirect does not correspond to a valid
* destination of data, that is, has type
* {@link Redirect.Type#READ READ}
* @since 1.7
*/
public
ProcessBuilder
redirectError
(
Redirect
destination
)
{
if
(
destination
.
type
()
==
Redirect
.
Type
.
READ
)
throw
new
IllegalArgumentException
(
"Redirect invalid for writing: "
+
destination
);
redirects
()[
2
]
=
destination
;
return
this
;
}
/**
* Sets this process builder's standard input source to a file.
*
* <p>This is a convenience method. An invocation of the form
* {@code redirectInput(file)}
* behaves in exactly the same way as the invocation
* {@link #redirectInput(Redirect) redirectInput}
* {@code (Redirect.from(file))}.
*
* @param file the new standard input source
* @return this process builder
* @since 1.7
*/
public
ProcessBuilder
redirectInput
(
File
file
)
{
return
redirectInput
(
Redirect
.
from
(
file
));
}
/**
* Sets this process builder's standard output destination to a file.
*
* <p>This is a convenience method. An invocation of the form
* {@code redirectOutput(file)}
* behaves in exactly the same way as the invocation
* {@link #redirectOutput(Redirect) redirectOutput}
* {@code (Redirect.to(file))}.
*
* @param file the new standard output destination
* @return this process builder
* @since 1.7
*/
public
ProcessBuilder
redirectOutput
(
File
file
)
{
return
redirectOutput
(
Redirect
.
to
(
file
));
}
/**
* Sets this process builder's standard error destination to a file.
*
* <p>This is a convenience method. An invocation of the form
* {@code redirectError(file)}
* behaves in exactly the same way as the invocation
* {@link #redirectError(Redirect) redirectError}
* {@code (Redirect.to(file))}.
*
* @param file the new standard error destination
* @return this process builder
* @since 1.7
*/
public
ProcessBuilder
redirectError
(
File
file
)
{
return
redirectError
(
Redirect
.
to
(
file
));
}
/**
* Returns this process builder's standard input source.
*
* Subprocesses subsequently started by this object's {@link #start()}
* method obtain their standard input from this source.
* The initial value is {@link Redirect#PIPE Redirect.PIPE}.
*
* @return this process builder's standard input source
* @since 1.7
*/
public
Redirect
redirectInput
()
{
return
(
redirects
==
null
)
?
Redirect
.
PIPE
:
redirects
[
0
];
}
/**
* Returns this process builder's standard output destination.
*
* Subprocesses subsequently started by this object's {@link #start()}
* method redirect their standard output to this destination.
* The initial value is {@link Redirect#PIPE Redirect.PIPE}.
*
* @return this process builder's standard output destination
* @since 1.7
*/
public
Redirect
redirectOutput
()
{
return
(
redirects
==
null
)
?
Redirect
.
PIPE
:
redirects
[
1
];
}
/**
* Returns this process builder's standard error destination.
*
* Subprocesses subsequently started by this object's {@link #start()}
* method redirect their standard error to this destination.
* The initial value is {@link Redirect#PIPE Redirect.PIPE}.
*
* @return this process builder's standard error destination
* @since 1.7
*/
public
Redirect
redirectError
()
{
return
(
redirects
==
null
)
?
Redirect
.
PIPE
:
redirects
[
2
];
}
/**
* Sets the source and destination for subprocess standard I/O
* to be the same as those of the current Java process.
*
* <p>This is a convenience method. An invocation of the form
* <pre> {@code
* pb.inheritIO()
* }</pre>
* behaves in exactly the same way as the invocation
* <pre> {@code
* pb.redirectInput(Redirect.INHERIT)
* .redirectOutput(Redirect.INHERIT)
* .redirectError(Redirect.INHERIT)
* }</pre>
*
* This gives behavior equivalent to most operating system
* command interpreters, or the standard C library function
* {@code system()}.
*
* @return this process builder
* @since 1.7
*/
public
ProcessBuilder
inheritIO
()
{
Arrays
.
fill
(
redirects
(),
Redirect
.
INHERIT
);
return
this
;
}
/**
/**
* Tells whether this process builder merges standard error and
* Tells whether this process builder merges standard error and
* standard output.
* standard output.
*
*
* <p>If this property is
<code>true</code>
, then any error output
* <p>If this property is
{@code true}
, then any error output
* generated by subprocesses subsequently started by this object's
* generated by subprocesses subsequently started by this object's
* {@link #start()} method will be merged with the standard
* {@link #start()} method will be merged with the standard
* output, so that both can be read using the
* output, so that both can be read using the
* {@link Process#getInputStream()} method. This makes it easier
* {@link Process#getInputStream()} method. This makes it easier
* to correlate error messages with the corresponding output.
* to correlate error messages with the corresponding output.
* The initial value is
<code>false</code>.</p>
* The initial value is
{@code false}.
*
*
* @return
This process builder's <code>redirectErrorStream</code>
property
* @return
this process builder's {@code redirectErrorStream}
property
*/
*/
public
boolean
redirectErrorStream
()
{
public
boolean
redirectErrorStream
()
{
return
redirectErrorStream
;
return
redirectErrorStream
;
}
}
/**
/**
* Sets this process builder's
<code>redirectErrorStream</code>
property.
* Sets this process builder's
{@code redirectErrorStream}
property.
*
*
* <p>If this property is
<code>true</code>
, then any error output
* <p>If this property is
{@code true}
, then any error output
* generated by subprocesses subsequently started by this object's
* generated by subprocesses subsequently started by this object's
* {@link #start()} method will be merged with the standard
* {@link #start()} method will be merged with the standard
* output, so that both can be read using the
* output, so that both can be read using the
* {@link Process#getInputStream()} method. This makes it easier
* {@link Process#getInputStream()} method. This makes it easier
* to correlate error messages with the corresponding output.
* to correlate error messages with the corresponding output.
* The initial value is
<code>false</code>.</p>
* The initial value is
{@code false}.
*
*
* @param
redirectErrorStream T
he new property value
* @param
redirectErrorStream t
he new property value
* @return
T
his process builder
* @return
t
his process builder
*/
*/
public
ProcessBuilder
redirectErrorStream
(
boolean
redirectErrorStream
)
{
public
ProcessBuilder
redirectErrorStream
(
boolean
redirectErrorStream
)
{
this
.
redirectErrorStream
=
redirectErrorStream
;
this
.
redirectErrorStream
=
redirectErrorStream
;
...
@@ -410,7 +937,7 @@ public final class ProcessBuilder
...
@@ -410,7 +937,7 @@ public final class ProcessBuilder
* <p>If there is a security manager, its
* <p>If there is a security manager, its
* {@link SecurityManager#checkExec checkExec}
* {@link SecurityManager#checkExec checkExec}
* method is called with the first component of this object's
* method is called with the first component of this object's
*
<code>command</code>
array as its argument. This may result in
*
{@code command}
array as its argument. This may result in
* a {@link SecurityException} being thrown.
* a {@link SecurityException} being thrown.
*
*
* <p>Starting an operating system process is highly system-dependent.
* <p>Starting an operating system process is highly system-dependent.
...
@@ -426,26 +953,42 @@ public final class ProcessBuilder
...
@@ -426,26 +953,42 @@ public final class ProcessBuilder
* subclass of {@link IOException}.
* subclass of {@link IOException}.
*
*
* <p>Subsequent modifications to this process builder will not
* <p>Subsequent modifications to this process builder will not
* affect the returned {@link Process}.</p>
* affect the returned {@link Process}.
*
* @return a new {@link Process} object for managing the subprocess
*
* @throws NullPointerException
* if an element of the command list is null
*
* @throws IndexOutOfBoundsException
* if the command is an empty list (has size {@code 0})
*
* @throws SecurityException
* if a security manager exists and
* <ul>
*
*
* @return A new {@link Process} object for managing the subprocess
* <li>its
* {@link SecurityManager#checkExec checkExec}
* method doesn't allow creation of the subprocess, or
*
*
* @throws NullPointerException
* <li>the standard input to the subprocess was
* If an element of the command list is null
* {@linkplain #redirectInput redirected from a file}
* and the security manager's
* {@link SecurityManager#checkRead checkRead} method
* denies read access to the file, or
*
*
* @throws IndexOutOfBoundsException
* <li>the standard output or standard error of the
* If the command is an empty list (has size <code>0</code>)
* subprocess was
* {@linkplain #redirectOutput redirected to a file}
* and the security manager's
* {@link SecurityManager#checkWrite checkWrite} method
* denies write access to the file
*
*
* @throws SecurityException
* </ul>
* If a security manager exists and its
* {@link SecurityManager#checkExec checkExec}
* method doesn't allow creation of the subprocess
*
*
* @throws IOException
* @throws IOException if an I/O error occurs
* If an I/O error occurs
*
*
* @see Runtime#exec(String[], String[], java.io.File)
* @see Runtime#exec(String[], String[], java.io.File)
* @see SecurityManager#checkExec(String)
*/
*/
public
Process
start
()
throws
IOException
{
public
Process
start
()
throws
IOException
{
// Must convert to array first -- a malicious user-supplied
// Must convert to array first -- a malicious user-supplied
...
@@ -467,6 +1010,7 @@ public final class ProcessBuilder
...
@@ -467,6 +1010,7 @@ public final class ProcessBuilder
return
ProcessImpl
.
start
(
cmdarray
,
return
ProcessImpl
.
start
(
cmdarray
,
environment
,
environment
,
dir
,
dir
,
redirects
,
redirectErrorStream
);
redirectErrorStream
);
}
catch
(
IOException
e
)
{
}
catch
(
IOException
e
)
{
// It's much easier for us to create a high-quality error
// It's much easier for us to create a high-quality error
...
...
src/share/classes/sun/misc/JavaIOFileDescriptorAccess.java
浏览文件 @
095ce48d
...
@@ -33,4 +33,8 @@ import java.io.FileDescriptor;
...
@@ -33,4 +33,8 @@ import java.io.FileDescriptor;
public
interface
JavaIOFileDescriptorAccess
{
public
interface
JavaIOFileDescriptorAccess
{
public
void
set
(
FileDescriptor
obj
,
int
fd
);
public
void
set
(
FileDescriptor
obj
,
int
fd
);
public
int
get
(
FileDescriptor
fd
);
public
int
get
(
FileDescriptor
fd
);
// Only valid on Windows
public
void
setHandle
(
FileDescriptor
obj
,
long
handle
);
public
long
getHandle
(
FileDescriptor
obj
);
}
}
src/solaris/classes/java/io/FileDescriptor.java
浏览文件 @
095ce48d
...
@@ -152,11 +152,19 @@ public final class FileDescriptor {
...
@@ -152,11 +152,19 @@ public final class FileDescriptor {
public
int
get
(
FileDescriptor
obj
)
{
public
int
get
(
FileDescriptor
obj
)
{
return
obj
.
fd
;
return
obj
.
fd
;
}
}
public
void
setHandle
(
FileDescriptor
obj
,
long
handle
)
{
throw
new
UnsupportedOperationException
();
}
public
long
getHandle
(
FileDescriptor
obj
)
{
throw
new
UnsupportedOperationException
();
}
}
}
);
);
}
}
// pac
akge private methods used by FIS,
FOS and RAF
// pac
kage private methods used by FIS,
FOS and RAF
int
incrementAndGetUseCount
()
{
int
incrementAndGetUseCount
()
{
return
useCount
.
incrementAndGet
();
return
useCount
.
incrementAndGet
();
...
...
src/solaris/classes/java/lang/ProcessImpl.java
浏览文件 @
095ce48d
...
@@ -26,7 +26,10 @@
...
@@ -26,7 +26,10 @@
package
java.lang
;
package
java.lang
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.lang.Process
;
import
java.io.FileInputStream
;
import
java.io.FileOutputStream
;
import
java.lang.ProcessBuilder.Redirect
;
import
java.lang.ProcessBuilder.Redirect
;
/**
/**
* This class is for the exclusive use of ProcessBuilder.start() to
* This class is for the exclusive use of ProcessBuilder.start() to
...
@@ -36,6 +39,9 @@ import java.lang.Process;
...
@@ -36,6 +39,9 @@ import java.lang.Process;
* @since 1.5
* @since 1.5
*/
*/
final
class
ProcessImpl
{
final
class
ProcessImpl
{
private
static
final
sun
.
misc
.
JavaIOFileDescriptorAccess
fdAccess
=
sun
.
misc
.
SharedSecrets
.
getJavaIOFileDescriptorAccess
();
private
ProcessImpl
()
{}
// Not instantiable
private
ProcessImpl
()
{}
// Not instantiable
private
static
byte
[]
toCString
(
String
s
)
{
private
static
byte
[]
toCString
(
String
s
)
{
...
@@ -54,6 +60,7 @@ final class ProcessImpl {
...
@@ -54,6 +60,7 @@ final class ProcessImpl {
static
Process
start
(
String
[]
cmdarray
,
static
Process
start
(
String
[]
cmdarray
,
java
.
util
.
Map
<
String
,
String
>
environment
,
java
.
util
.
Map
<
String
,
String
>
environment
,
String
dir
,
String
dir
,
ProcessBuilder
.
Redirect
[]
redirects
,
boolean
redirectErrorStream
)
boolean
redirectErrorStream
)
throws
IOException
throws
IOException
{
{
...
@@ -78,11 +85,61 @@ final class ProcessImpl {
...
@@ -78,11 +85,61 @@ final class ProcessImpl {
int
[]
envc
=
new
int
[
1
];
int
[]
envc
=
new
int
[
1
];
byte
[]
envBlock
=
ProcessEnvironment
.
toEnvironmentBlock
(
environment
,
envc
);
byte
[]
envBlock
=
ProcessEnvironment
.
toEnvironmentBlock
(
environment
,
envc
);
int
[]
std_fds
;
FileInputStream
f0
=
null
;
FileOutputStream
f1
=
null
;
FileOutputStream
f2
=
null
;
try
{
if
(
redirects
==
null
)
{
std_fds
=
new
int
[]
{
-
1
,
-
1
,
-
1
};
}
else
{
std_fds
=
new
int
[
3
];
if
(
redirects
[
0
]
==
Redirect
.
PIPE
)
std_fds
[
0
]
=
-
1
;
else
if
(
redirects
[
0
]
==
Redirect
.
INHERIT
)
std_fds
[
0
]
=
0
;
else
{
f0
=
new
FileInputStream
(
redirects
[
0
].
file
());
std_fds
[
0
]
=
fdAccess
.
get
(
f0
.
getFD
());
}
if
(
redirects
[
1
]
==
Redirect
.
PIPE
)
std_fds
[
1
]
=
-
1
;
else
if
(
redirects
[
1
]
==
Redirect
.
INHERIT
)
std_fds
[
1
]
=
1
;
else
{
f1
=
redirects
[
1
].
toFileOutputStream
();
std_fds
[
1
]
=
fdAccess
.
get
(
f1
.
getFD
());
}
if
(
redirects
[
2
]
==
Redirect
.
PIPE
)
std_fds
[
2
]
=
-
1
;
else
if
(
redirects
[
2
]
==
Redirect
.
INHERIT
)
std_fds
[
2
]
=
2
;
else
{
f2
=
redirects
[
2
].
toFileOutputStream
();
std_fds
[
2
]
=
fdAccess
.
get
(
f2
.
getFD
());
}
}
return
new
UNIXProcess
return
new
UNIXProcess
(
toCString
(
cmdarray
[
0
]),
(
toCString
(
cmdarray
[
0
]),
argBlock
,
args
.
length
,
argBlock
,
args
.
length
,
envBlock
,
envc
[
0
],
envBlock
,
envc
[
0
],
toCString
(
dir
),
toCString
(
dir
),
std_fds
,
redirectErrorStream
);
redirectErrorStream
);
}
finally
{
// In theory, close() can throw IOException
// (although it is rather unlikely to happen here)
try
{
if
(
f0
!=
null
)
f0
.
close
();
}
finally
{
try
{
if
(
f1
!=
null
)
f1
.
close
();
}
finally
{
if
(
f2
!=
null
)
f2
.
close
();
}
}
}
}
}
}
}
src/solaris/classes/java/lang/UNIXProcess.java.linux
浏览文件 @
095ce48d
/*
/*
*
Copyright
1995
-
200
6
Sun
Microsystems
,
Inc
.
All
Rights
Reserved
.
*
Copyright
1995
-
200
8
Sun
Microsystems
,
Inc
.
All
Rights
Reserved
.
*
DO
NOT
ALTER
OR
REMOVE
COPYRIGHT
NOTICES
OR
THIS
FILE
HEADER
.
*
DO
NOT
ALTER
OR
REMOVE
COPYRIGHT
NOTICES
OR
THIS
FILE
HEADER
.
*
*
*
This
code
is
free
software
;
you
can
redistribute
it
and
/
or
modify
it
*
This
code
is
free
software
;
you
can
redistribute
it
and
/
or
modify
it
...
@@ -34,9 +34,9 @@ import java.io.*;
...
@@ -34,9 +34,9 @@ import java.io.*;
*/
*/
final
class
UNIXProcess
extends
Process
{
final
class
UNIXProcess
extends
Process
{
private
FileDescriptor
stdin_fd
;
private
static
final
sun
.
misc
.
JavaIOFileDescriptorAccess
fdAccess
private
FileDescriptor
stdout_fd
;
=
sun
.
misc
.
SharedSecrets
.
getJavaIOFileDescriptorAccess
()
;
private
FileDescriptor
stderr_fd
;
private
int
pid
;
private
int
pid
;
private
int
exitcode
;
private
int
exitcode
;
private
boolean
hasExited
;
private
boolean
hasExited
;
...
@@ -48,15 +48,26 @@ final class UNIXProcess extends Process {
...
@@ -48,15 +48,26 @@ final class UNIXProcess extends Process {
/*
this
is
for
the
reaping
thread
*/
/*
this
is
for
the
reaping
thread
*/
private
native
int
waitForProcessExit
(
int
pid
);
private
native
int
waitForProcessExit
(
int
pid
);
/**
*
Create
a
process
using
fork
(
2
)
and
exec
(
2
).
*
*
@
param
std_fds
array
of
file
descriptors
.
Indexes
0
,
1
,
and
*
2
correspond
to
standard
input
,
standard
output
and
*
standard
error
,
respectively
.
On
input
,
a
value
of
-
1
*
means
to
create
a
pipe
to
connect
child
and
parent
*
processes
.
On
output
,
a
value
which
is
not
-
1
is
the
*
parent
pipe
fd
corresponding
to
the
pipe
which
has
*
been
created
.
An
element
of
this
array
is
-
1
on
input
*
if
and
only
if
it
is
<
em
>
not
</
em
>
-
1
on
output
.
*
@
return
the
pid
of
the
subprocess
*/
private
native
int
forkAndExec
(
byte
[]
prog
,
private
native
int
forkAndExec
(
byte
[]
prog
,
byte
[]
argBlock
,
int
argc
,
byte
[]
argBlock
,
int
argc
,
byte
[]
envBlock
,
int
envc
,
byte
[]
envBlock
,
int
envc
,
byte
[]
dir
,
byte
[]
dir
,
boolean
redirectErrorStream
,
int
[]
std_fds
,
FileDescriptor
stdin_fd
,
boolean
redirectErrorStream
)
FileDescriptor
stdout_fd
,
throws
IOException
;
FileDescriptor
stderr_fd
)
throws
IOException
;
/*
In
the
process
constructor
we
wait
on
this
gate
until
the
process
*/
/*
In
the
process
constructor
we
wait
on
this
gate
until
the
process
*/
/*
has
been
created
.
Then
we
return
from
the
constructor
.
*/
/*
has
been
created
.
Then
we
return
from
the
constructor
.
*/
...
@@ -97,67 +108,82 @@ final class UNIXProcess extends Process {
...
@@ -97,67 +108,82 @@ final class UNIXProcess extends Process {
}
}
UNIXProcess
(
final
byte
[]
prog
,
UNIXProcess
(
final
byte
[]
prog
,
final
byte
[]
argBlock
,
final
int
argc
,
final
byte
[]
argBlock
,
final
int
argc
,
final
byte
[]
envBlock
,
final
int
envc
,
final
byte
[]
envBlock
,
final
int
envc
,
final
byte
[]
dir
,
final
byte
[]
dir
,
final
boolean
redirectErrorStream
)
final
int
[]
std_fds
,
final
boolean
redirectErrorStream
)
throws
IOException
{
throws
IOException
{
stdin_fd
=
new
FileDescriptor
();
stdout_fd
=
new
FileDescriptor
();
stderr_fd
=
new
FileDescriptor
();
final
Gate
gate
=
new
Gate
();
final
Gate
gate
=
new
Gate
();
/*
/*
*
For
each
subprocess
forked
a
corresponding
reaper
thread
*
For
each
subprocess
forked
a
corresponding
reaper
thread
*
is
started
.
That
thread
is
the
only
thread
which
waits
*
is
started
.
That
thread
is
the
only
thread
which
waits
*
for
the
subprocess
to
terminate
and
it
doesn
't hold any
*
for
the
subprocess
to
terminate
and
it
doesn
't hold any
* locks while doing so. This design allows waitFor() and
* locks while doing so. This design allows waitFor() and
* exitStatus() to be safely executed in parallel (and they
* exitStatus() to be safely executed in parallel (and they
* need no native code).
* need no native code).
*/
*/
java.security.AccessController.doPrivileged(
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction
() {
new java.security.PrivilegedAction<Void>
() {
public Object
run() {
public Void
run() {
Thread t = new Thread("process reaper") {
Thread t = new Thread("process reaper") {
public void run() {
public void run() {
try {
try {
pid = forkAndExec(prog,
pid = forkAndExec(prog,
argBlock, argc,
argBlock, argc,
envBlock, envc,
envBlock, envc,
dir,
dir,
redirectErrorStream
,
std_fds
,
stdin_fd, stdout_fd, stderr_fd
);
redirectErrorStream
);
} catch (IOException e) {
} catch (IOException e) {
gate.setException(e); /*remember to rethrow later*/
gate.setException(e); /*remember to rethrow later*/
gate.exit();
gate.exit();
return;
return;
}
}
java.security.AccessController.doPrivileged(
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
new java.security.PrivilegedAction<Void>() {
public Object run() {
public Void run() {
stdin_stream = new BufferedOutputStream(new
if (std_fds[0] == -1)
FileOutputStream(stdin_fd));
stdin_stream = new ProcessBuilder.NullOutputStream();
stdout_stream = new BufferedInputStream(new
else {
FileInputStream(stdout_fd));
FileDescriptor stdin_fd = new FileDescriptor();
fdAccess.set(stdin_fd, std_fds[0]);
stdin_stream = new BufferedOutputStream(
new FileOutputStream(stdin_fd));
}
if (std_fds[1] == -1)
stdout_stream = new ProcessBuilder.NullInputStream();
else {
FileDescriptor stdout_fd = new FileDescriptor();
fdAccess.set(stdout_fd, std_fds[1]);
stdout_stream = new BufferedInputStream(
new FileInputStream(stdout_fd));
}
if (std_fds[2] == -1)
stderr_stream = new ProcessBuilder.NullInputStream();
else {
FileDescriptor stderr_fd = new FileDescriptor();
fdAccess.set(stderr_fd, std_fds[2]);
stderr_stream = new FileInputStream(stderr_fd);
stderr_stream = new FileInputStream(stderr_fd);
return null;
}
}
});
return null; }});
gate.exit(); /* exit from constructor */
gate.exit(); /* exit from constructor */
int res = waitForProcessExit(pid);
int res = waitForProcessExit(pid);
synchronized (UNIXProcess.this) {
synchronized (UNIXProcess.this) {
hasExited = true;
hasExited = true;
exitcode = res;
exitcode = res;
UNIXProcess.this.notifyAll();
UNIXProcess.this.notifyAll();
}
}
}
}
};
};
t.setDaemon(true);
t.setDaemon(true);
t.start();
t.start();
return null;
return null; }});
}
});
gate.waitForExit();
gate.waitForExit();
IOException e = gate.getException();
IOException e = gate.getException();
if (e != null)
if (e != null)
...
@@ -165,43 +191,43 @@ final class UNIXProcess extends Process {
...
@@ -165,43 +191,43 @@ final class UNIXProcess extends Process {
}
}
public OutputStream getOutputStream() {
public OutputStream getOutputStream() {
return stdin_stream;
return stdin_stream;
}
}
public InputStream getInputStream() {
public InputStream getInputStream() {
return stdout_stream;
return stdout_stream;
}
}
public InputStream getErrorStream() {
public InputStream getErrorStream() {
return stderr_stream;
return stderr_stream;
}
}
public synchronized int waitFor() throws InterruptedException {
public synchronized int waitFor() throws InterruptedException {
while (!hasExited) {
while (!hasExited) {
wait();
wait();
}
}
return exitcode;
return exitcode;
}
}
public synchronized int exitValue() {
public synchronized int exitValue() {
if (!hasExited) {
if (!hasExited) {
throw new IllegalThreadStateException("process hasn'
t
exited
");
throw new IllegalThreadStateException("process hasn'
t
exited
");
}
}
return exitcode;
return exitcode;
}
}
private static native void destroyProcess(int pid);
private static native void destroyProcess(int pid);
public void destroy() {
public void destroy() {
// There is a risk that pid will be recycled, causing us to
// There is a risk that pid will be recycled, causing us to
// kill the wrong process! So we only terminate processes
// kill the wrong process! So we only terminate processes
// that appear to still be running. Even with this check,
// that appear to still be running. Even with this check,
// there is an unavoidable race condition here, but the window
// there is an unavoidable race condition here, but the window
// is very small, and OSes try hard to not recycle pids too
// is very small, and OSes try hard to not recycle pids too
// soon, so this is quite safe.
// soon, so this is quite safe.
synchronized (this) {
synchronized (this) {
if (!hasExited)
if (!hasExited)
destroyProcess(pid);
destroyProcess(pid);
}
}
try {
try {
stdin_stream.close();
stdin_stream.close();
stdout_stream.close();
stdout_stream.close();
...
@@ -215,6 +241,6 @@ final class UNIXProcess extends Process {
...
@@ -215,6 +241,6 @@ final class UNIXProcess extends Process {
private static native void initIDs();
private static native void initIDs();
static {
static {
initIDs();
initIDs();
}
}
}
}
src/solaris/classes/java/lang/UNIXProcess.java.solaris
浏览文件 @
095ce48d
/*
/*
*
Copyright
1995
-
200
6
Sun
Microsystems
,
Inc
.
All
Rights
Reserved
.
*
Copyright
1995
-
200
8
Sun
Microsystems
,
Inc
.
All
Rights
Reserved
.
*
DO
NOT
ALTER
OR
REMOVE
COPYRIGHT
NOTICES
OR
THIS
FILE
HEADER
.
*
DO
NOT
ALTER
OR
REMOVE
COPYRIGHT
NOTICES
OR
THIS
FILE
HEADER
.
*
*
*
This
code
is
free
software
;
you
can
redistribute
it
and
/
or
modify
it
*
This
code
is
free
software
;
you
can
redistribute
it
and
/
or
modify
it
...
@@ -33,129 +33,155 @@ import java.io.*;
...
@@ -33,129 +33,155 @@ import java.io.*;
*/
*/
final
class
UNIXProcess
extends
Process
{
final
class
UNIXProcess
extends
Process
{
private
FileDescriptor
stdin_fd
;
private
static
final
sun
.
misc
.
JavaIOFileDescriptorAccess
fdAccess
private
FileDescriptor
stdout_fd
;
=
sun
.
misc
.
SharedSecrets
.
getJavaIOFileDescriptorAccess
()
;
private
FileDescriptor
stderr_fd
;
private
int
pid
;
private
final
int
pid
;
private
int
exitcode
;
private
int
exitcode
;
private
boolean
hasExited
;
private
boolean
hasExited
;
private
OutputStream
stdin_stream
;
private
OutputStream
stdin_stream
;
private
Buffered
InputStream
stdout_stream
;
private
InputStream
stdout_stream
;
private
DeferredCloseInputStream
stdout_inner_stream
;
private
DeferredCloseInputStream
stdout_inner_stream
;
private
DeferredClose
InputStream
stderr_stream
;
private
InputStream
stderr_stream
;
/*
this
is
for
the
reaping
thread
*/
/*
this
is
for
the
reaping
thread
*/
private
native
int
waitForProcessExit
(
int
pid
);
private
native
int
waitForProcessExit
(
int
pid
);
/**
*
Create
a
process
using
fork
(
2
)
and
exec
(
2
).
*
*
@
param
std_fds
array
of
file
descriptors
.
Indexes
0
,
1
,
and
*
2
correspond
to
standard
input
,
standard
output
and
*
standard
error
,
respectively
.
On
input
,
a
value
of
-
1
*
means
to
create
a
pipe
to
connect
child
and
parent
*
processes
.
On
output
,
a
value
which
is
not
-
1
is
the
*
parent
pipe
fd
corresponding
to
the
pipe
which
has
*
been
created
.
An
element
of
this
array
is
-
1
on
input
*
if
and
only
if
it
is
<
em
>
not
</
em
>
-
1
on
output
.
*
@
return
the
pid
of
the
subprocess
*/
private
native
int
forkAndExec
(
byte
[]
prog
,
private
native
int
forkAndExec
(
byte
[]
prog
,
byte
[]
argBlock
,
int
argc
,
byte
[]
argBlock
,
int
argc
,
byte
[]
envBlock
,
int
envc
,
byte
[]
envBlock
,
int
envc
,
byte
[]
dir
,
byte
[]
dir
,
boolean
redirectErrorStream
,
int
[]
std_fds
,
FileDescriptor
stdin_fd
,
boolean
redirectErrorStream
)
FileDescriptor
stdout_fd
,
throws
IOException
;
FileDescriptor
stderr_fd
)
throws
IOException
;
UNIXProcess
(
final
byte
[]
prog
,
UNIXProcess
(
final
byte
[]
prog
,
final
byte
[]
argBlock
,
int
argc
,
final
byte
[]
argBlock
,
int
argc
,
final
byte
[]
envBlock
,
int
envc
,
final
byte
[]
envBlock
,
int
envc
,
final
byte
[]
dir
,
final
byte
[]
dir
,
final
boolean
redirectErrorStream
)
final
int
[]
std_fds
,
final
boolean
redirectErrorStream
)
throws
IOException
{
throws
IOException
{
stdin_fd
=
new
FileDescriptor
();
pid
=
forkAndExec
(
prog
,
stdout_fd
=
new
FileDescriptor
();
argBlock
,
argc
,
stderr_fd
=
new
FileDescriptor
();
envBlock
,
envc
,
dir
,
pid
=
forkAndExec
(
prog
,
std_fds
,
argBlock
,
argc
,
redirectErrorStream
);
envBlock
,
envc
,
dir
,
java
.
security
.
AccessController
.
doPrivileged
(
redirectErrorStream
,
new
java
.
security
.
PrivilegedAction
<
Void
>()
{
public
Void
run
()
{
stdin_fd
,
stdout_fd
,
stderr_fd
);
if
(
std_fds
[
0
]
==
-
1
)
stdin_stream
=
new
ProcessBuilder
.
NullOutputStream
();
java
.
security
.
AccessController
.
doPrivileged
(
else
{
new
java
.
security
.
PrivilegedAction
()
{
FileDescriptor
stdin_fd
=
new
FileDescriptor
();
public
Object
run
()
{
fdAccess
.
set
(
stdin_fd
,
std_fds
[
0
]);
stdin_stream
stdin_stream
=
new
BufferedOutputStream
(
=
new
BufferedOutputStream
(
new
FileOutputStream
(
stdin_fd
));
new
FileOutputStream
(
stdin_fd
));
stdout_inner_stream
=
new
DeferredCloseInputStream
(
stdout_fd
);
}
stdout_stream
=
new
BufferedInputStream
(
stdout_inner_stream
);
stderr_stream
=
new
DeferredCloseInputStream
(
stderr_fd
);
if
(
std_fds
[
1
]
==
-
1
)
return
null
;
stdout_stream
=
new
ProcessBuilder
.
NullInputStream
();
}
else
{
});
FileDescriptor
stdout_fd
=
new
FileDescriptor
();
fdAccess
.
set
(
stdout_fd
,
std_fds
[
1
]);
/*
stdout_inner_stream
=
new
DeferredCloseInputStream
(
stdout_fd
);
*
For
each
subprocess
forked
a
corresponding
reaper
thread
stdout_stream
=
new
BufferedInputStream
(
stdout_inner_stream
);
*
is
started
.
That
thread
is
the
only
thread
which
waits
}
*
for
the
subprocess
to
terminate
and
it
doesn
't hold any
* locks while doing so. This design allows waitFor() and
if
(
std_fds
[
2
]
==
-
1
)
* exitStatus() to be safely executed in parallel (and they
stderr_stream
=
new
ProcessBuilder
.
NullInputStream
();
* need no native code).
else
{
*/
FileDescriptor
stderr_fd
=
new
FileDescriptor
();
fdAccess
.
set
(
stderr_fd
,
std_fds
[
2
]);
java.security.AccessController.doPrivileged(
stderr_stream
=
new
DeferredCloseInputStream
(
stderr_fd
);
new java.security.PrivilegedAction() {
}
public Object run() {
Thread t = new Thread("process reaper") {
return
null
;
}});
public void run() {
int res = waitForProcessExit(pid);
/*
synchronized (UNIXProcess.this) {
*
For
each
subprocess
forked
a
corresponding
reaper
thread
hasExited = true;
*
is
started
.
That
thread
is
the
only
thread
which
waits
exitcode = res;
*
for
the
subprocess
to
terminate
and
it
doesn
't hold any
UNIXProcess.this.notifyAll();
* locks while doing so. This design allows waitFor() and
}
* exitStatus() to be safely executed in parallel (and they
}
* need no native code).
};
*/
t.setDaemon(true);
t.start();
java.security.AccessController.doPrivileged(
return null;
new java.security.PrivilegedAction<Void>() { public Void run() {
}
Thread t = new Thread("process reaper") {
});
public void run() {
int res = waitForProcessExit(pid);
synchronized (UNIXProcess.this) {
hasExited = true;
exitcode = res;
UNIXProcess.this.notifyAll();
}
}
};
t.setDaemon(true);
t.start();
return null; }});
}
}
public OutputStream getOutputStream() {
public OutputStream getOutputStream() {
return stdin_stream;
return stdin_stream;
}
}
public InputStream getInputStream() {
public InputStream getInputStream() {
return stdout_stream;
return stdout_stream;
}
}
public InputStream getErrorStream() {
public InputStream getErrorStream() {
return stderr_stream;
return stderr_stream;
}
}
public synchronized int waitFor() throws InterruptedException {
public synchronized int waitFor() throws InterruptedException {
while (!hasExited) {
while (!hasExited) {
wait();
wait();
}
}
return exitcode;
return exitcode;
}
}
public synchronized int exitValue() {
public synchronized int exitValue() {
if (!hasExited) {
if (!hasExited) {
throw new IllegalThreadStateException("process hasn'
t
exited
");
throw new IllegalThreadStateException("process hasn'
t
exited
");
}
}
return exitcode;
return exitcode;
}
}
private static native void destroyProcess(int pid);
private static native void destroyProcess(int pid);
public synchronized void destroy() {
public synchronized void destroy() {
// There is a risk that pid will be recycled, causing us to
// There is a risk that pid will be recycled, causing us to
// kill the wrong process! So we only terminate processes
// kill the wrong process! So we only terminate processes
// that appear to still be running. Even with this check,
// that appear to still be running. Even with this check,
// there is an unavoidable race condition here, but the window
// there is an unavoidable race condition here, but the window
// is very small, and OSes try hard to not recycle pids too
// is very small, and OSes try hard to not recycle pids too
// soon, so this is quite safe.
// soon, so this is quite safe.
if (!hasExited)
if (!hasExited)
destroyProcess(pid);
destroyProcess(pid);
try {
try {
stdin_stream.close();
stdin_stream.close();
stdout_inner_stream.closeDeferred(stdout_stream);
if (stdout_inner_stream != null)
stderr_stream.closeDeferred(stderr_stream);
stdout_inner_stream.closeDeferred(stdout_stream);
if (stderr_stream instanceof DeferredCloseInputStream)
((DeferredCloseInputStream) stderr_stream)
.closeDeferred(stderr_stream);
} catch (IOException e) {
} catch (IOException e) {
// ignore
// ignore
}
}
...
@@ -172,99 +198,99 @@ final class UNIXProcess extends Process {
...
@@ -172,99 +198,99 @@ final class UNIXProcess extends Process {
// (EOF) as they did before.
// (EOF) as they did before.
//
//
private static class DeferredCloseInputStream
private static class DeferredCloseInputStream
extends FileInputStream
extends FileInputStream
{
{
private DeferredCloseInputStream(FileDescriptor fd) {
private DeferredCloseInputStream(FileDescriptor fd) {
super(fd);
super(fd);
}
}
private Object lock = new Object();
// For the following fields
private Object lock = new Object();
// For the following fields
private boolean closePending = false;
private boolean closePending = false;
private int useCount = 0;
private int useCount = 0;
private InputStream streamToClose;
private InputStream streamToClose;
private void raise() {
private void raise() {
synchronized (lock) {
synchronized (lock) {
useCount++;
useCount++;
}
}
}
}
private void lower() throws IOException {
private void lower() throws IOException {
synchronized (lock) {
synchronized (lock) {
useCount--;
useCount--;
if (useCount == 0 && closePending) {
if (useCount == 0 && closePending) {
streamToClose.close();
streamToClose.close();
}
}
}
}
}
}
// stc is the actual stream to be closed; it might be this object, or
// stc is the actual stream to be closed; it might be this object, or
// it might be an upstream object for which this object is downstream.
// it might be an upstream object for which this object is downstream.
//
//
private void closeDeferred(InputStream stc) throws IOException {
private void closeDeferred(InputStream stc) throws IOException {
synchronized (lock) {
synchronized (lock) {
if (useCount == 0) {
if (useCount == 0) {
stc.close();
stc.close();
} else {
} else {
closePending = true;
closePending = true;
streamToClose = stc;
streamToClose = stc;
}
}
}
}
}
}
public void close() throws IOException {
public void close() throws IOException {
synchronized (lock) {
synchronized (lock) {
useCount = 0;
useCount = 0;
closePending = false;
closePending = false;
}
}
super.close();
super.close();
}
}
public int read() throws IOException {
public int read() throws IOException {
raise();
raise();
try {
try {
return super.read();
return super.read();
} finally {
} finally {
lower();
lower();
}
}
}
}
public int read(byte[] b) throws IOException {
public int read(byte[] b) throws IOException {
raise();
raise();
try {
try {
return super.read(b);
return super.read(b);
} finally {
} finally {
lower();
lower();
}
}
}
}
public int read(byte[] b, int off, int len) throws IOException {
public int read(byte[] b, int off, int len) throws IOException {
raise();
raise();
try {
try {
return super.read(b, off, len);
return super.read(b, off, len);
} finally {
} finally {
lower();
lower();
}
}
}
}
public long skip(long n) throws IOException {
public long skip(long n) throws IOException {
raise();
raise();
try {
try {
return super.skip(n);
return super.skip(n);
} finally {
} finally {
lower();
lower();
}
}
}
}
public int available() throws IOException {
public int available() throws IOException {
raise();
raise();
try {
try {
return super.available();
return super.available();
} finally {
} finally {
lower();
lower();
}
}
}
}
}
}
...
@@ -272,6 +298,6 @@ final class UNIXProcess extends Process {
...
@@ -272,6 +298,6 @@ final class UNIXProcess extends Process {
private static native void initIDs();
private static native void initIDs();
static {
static {
initIDs();
initIDs();
}
}
}
}
src/solaris/native/java/lang/UNIXProcess_md.c
浏览文件 @
095ce48d
/*
/*
* Copyright 1995-200
6
Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1995-200
8
Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*
* This code is free software; you can redistribute it and/or modify it
* This code is free software; you can redistribute it and/or modify it
...
@@ -491,10 +491,8 @@ Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env,
...
@@ -491,10 +491,8 @@ Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env,
jbyteArray
argBlock
,
jint
argc
,
jbyteArray
argBlock
,
jint
argc
,
jbyteArray
envBlock
,
jint
envc
,
jbyteArray
envBlock
,
jint
envc
,
jbyteArray
dir
,
jbyteArray
dir
,
jboolean
redirectErrorStream
,
jintArray
std_fds
,
jobject
stdin_fd
,
jboolean
redirectErrorStream
)
jobject
stdout_fd
,
jobject
stderr_fd
)
{
{
int
errnum
;
int
errnum
;
int
resultPid
=
-
1
;
int
resultPid
=
-
1
;
...
@@ -505,6 +503,7 @@ Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env,
...
@@ -505,6 +503,7 @@ Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env,
const
char
*
pargBlock
=
getBytes
(
env
,
argBlock
);
const
char
*
pargBlock
=
getBytes
(
env
,
argBlock
);
const
char
*
penvBlock
=
getBytes
(
env
,
envBlock
);
const
char
*
penvBlock
=
getBytes
(
env
,
envBlock
);
const
char
*
pdir
=
getBytes
(
env
,
dir
);
const
char
*
pdir
=
getBytes
(
env
,
dir
);
jint
*
fds
=
NULL
;
in
[
0
]
=
in
[
1
]
=
out
[
0
]
=
out
[
1
]
=
err
[
0
]
=
err
[
1
]
=
fail
[
0
]
=
fail
[
1
]
=
-
1
;
in
[
0
]
=
in
[
1
]
=
out
[
0
]
=
out
[
1
]
=
err
[
0
]
=
err
[
1
]
=
fail
[
0
]
=
fail
[
1
]
=
-
1
;
...
@@ -527,9 +526,13 @@ Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env,
...
@@ -527,9 +526,13 @@ Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env,
initVectorFromBlock
(
envv
,
penvBlock
,
envc
);
initVectorFromBlock
(
envv
,
penvBlock
,
envc
);
}
}
if
((
pipe
(
in
)
<
0
)
||
assert
(
std_fds
!=
NULL
);
(
pipe
(
out
)
<
0
)
||
fds
=
(
*
env
)
->
GetIntArrayElements
(
env
,
std_fds
,
NULL
);
(
pipe
(
err
)
<
0
)
||
if
(
fds
==
NULL
)
goto
Catch
;
if
((
fds
[
0
]
==
-
1
&&
pipe
(
in
)
<
0
)
||
(
fds
[
1
]
==
-
1
&&
pipe
(
out
)
<
0
)
||
(
fds
[
2
]
==
-
1
&&
pipe
(
err
)
<
0
)
||
(
pipe
(
fail
)
<
0
))
{
(
pipe
(
fail
)
<
0
))
{
throwIOException
(
env
,
errno
,
"Bad file descriptor"
);
throwIOException
(
env
,
errno
,
"Bad file descriptor"
);
goto
Catch
;
goto
Catch
;
...
@@ -544,23 +547,26 @@ Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env,
...
@@ -544,23 +547,26 @@ Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env,
if
(
resultPid
==
0
)
{
if
(
resultPid
==
0
)
{
/* Child process */
/* Child process */
/* Close the parent sides of the pipe.
/* Close the parent sides of the pipes.
Give the child sides of the pipes the right fileno's.
Closing pipe fds here is redundant, since closeDescriptors()
Closing pipe fds here is redundant, since closeDescriptors()
would do it anyways, but a little paranoia is a good thing. */
would do it anyways, but a little paranoia is a good thing. */
closeSafely
(
in
[
1
]);
closeSafely
(
out
[
0
]);
closeSafely
(
err
[
0
]);
closeSafely
(
fail
[
0
]);
/* Give the child sides of the pipes the right fileno's. */
/* Note: it is possible for in[0] == 0 */
/* Note: it is possible for in[0] == 0 */
close
(
in
[
1
]);
moveDescriptor
(
in
[
0
]
!=
-
1
?
in
[
0
]
:
fds
[
0
],
STDIN_FILENO
);
moveDescriptor
(
in
[
0
],
STDIN_FILENO
);
moveDescriptor
(
out
[
1
]
!=
-
1
?
out
[
1
]
:
fds
[
1
],
STDOUT_FILENO
);
close
(
out
[
0
]);
moveDescriptor
(
out
[
1
],
STDOUT_FILENO
);
close
(
err
[
0
]);
if
(
redirectErrorStream
)
{
if
(
redirectErrorStream
)
{
close
(
err
[
1
]);
close
Safely
(
err
[
1
]);
dup2
(
STDOUT_FILENO
,
STDERR_FILENO
);
dup2
(
STDOUT_FILENO
,
STDERR_FILENO
);
}
else
{
}
else
{
moveDescriptor
(
err
[
1
],
STDERR_FILENO
);
moveDescriptor
(
err
[
1
]
!=
-
1
?
err
[
1
]
:
fds
[
2
]
,
STDERR_FILENO
);
}
}
close
(
fail
[
0
]);
moveDescriptor
(
fail
[
1
],
FAIL_FILENO
);
moveDescriptor
(
fail
[
1
],
FAIL_FILENO
);
/* close everything */
/* close everything */
...
@@ -606,9 +612,9 @@ Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env,
...
@@ -606,9 +612,9 @@ Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env,
goto
Catch
;
goto
Catch
;
}
}
(
*
env
)
->
SetIntField
(
env
,
stdin_fd
,
IO_fd_fdID
,
in
[
1
])
;
fds
[
0
]
=
(
in
[
1
]
!=
-
1
)
?
in
[
1
]
:
-
1
;
(
*
env
)
->
SetIntField
(
env
,
stdout_fd
,
IO_fd_fdID
,
out
[
0
])
;
fds
[
1
]
=
(
out
[
0
]
!=
-
1
)
?
out
[
0
]
:
-
1
;
(
*
env
)
->
SetIntField
(
env
,
stderr_fd
,
IO_fd_fdID
,
err
[
0
])
;
fds
[
2
]
=
(
err
[
0
]
!=
-
1
)
?
err
[
0
]
:
-
1
;
Finally:
Finally:
/* Always clean up the child's side of the pipes */
/* Always clean up the child's side of the pipes */
...
@@ -628,6 +634,9 @@ Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env,
...
@@ -628,6 +634,9 @@ Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env,
releaseBytes
(
env
,
envBlock
,
penvBlock
);
releaseBytes
(
env
,
envBlock
,
penvBlock
);
releaseBytes
(
env
,
dir
,
pdir
);
releaseBytes
(
env
,
dir
,
pdir
);
if
(
fds
!=
NULL
)
(
*
env
)
->
ReleaseIntArrayElements
(
env
,
std_fds
,
fds
,
0
);
return
resultPid
;
return
resultPid
;
Catch:
Catch:
...
...
src/windows/classes/java/io/FileDescriptor.java
浏览文件 @
095ce48d
...
@@ -29,17 +29,14 @@ import java.util.concurrent.atomic.AtomicInteger;
...
@@ -29,17 +29,14 @@ import java.util.concurrent.atomic.AtomicInteger;
/**
/**
* Instances of the file descriptor class serve as an opaque handle
* Instances of the file descriptor class serve as an opaque handle
* to the underlying machine-specific structure representing an open
* to the underlying machine-specific structure representing an
* file, an open socket, or another source or sink of bytes. The
* open file, an open socket, or another source or sink of bytes.
* main practical use for a file descriptor is to create a
* The main practical use for a file descriptor is to create a
* <code>FileInputStream</code> or <code>FileOutputStream</code> to
* {@link FileInputStream} or {@link FileOutputStream} to contain it.
* contain it.
*
* <p>
* <p>Applications should not create their own file descriptors.
* Applications should not create their own file descriptors.
*
*
* @author Pavani Diwanji
* @author Pavani Diwanji
* @see java.io.FileInputStream
* @see java.io.FileOutputStream
* @since JDK1.0
* @since JDK1.0
*/
*/
public
final
class
FileDescriptor
{
public
final
class
FileDescriptor
{
...
@@ -81,6 +78,14 @@ public final class FileDescriptor {
...
@@ -81,6 +78,14 @@ public final class FileDescriptor {
public
int
get
(
FileDescriptor
obj
)
{
public
int
get
(
FileDescriptor
obj
)
{
return
obj
.
fd
;
return
obj
.
fd
;
}
}
public
void
setHandle
(
FileDescriptor
obj
,
long
handle
)
{
obj
.
handle
=
handle
;
}
public
long
getHandle
(
FileDescriptor
obj
)
{
return
obj
.
handle
;
}
}
}
);
);
}
}
...
@@ -88,7 +93,7 @@ public final class FileDescriptor {
...
@@ -88,7 +93,7 @@ public final class FileDescriptor {
/**
/**
* A handle to the standard input stream. Usually, this file
* A handle to the standard input stream. Usually, this file
* descriptor is not used directly, but rather via the input stream
* descriptor is not used directly, but rather via the input stream
* known as
<code>System.in</code>
.
* known as
{@code System.in}
.
*
*
* @see java.lang.System#in
* @see java.lang.System#in
*/
*/
...
@@ -97,7 +102,7 @@ public final class FileDescriptor {
...
@@ -97,7 +102,7 @@ public final class FileDescriptor {
/**
/**
* A handle to the standard output stream. Usually, this file
* A handle to the standard output stream. Usually, this file
* descriptor is not used directly, but rather via the output stream
* descriptor is not used directly, but rather via the output stream
* known as
<code>System.out</code>
.
* known as
{@code System.out}
.
* @see java.lang.System#out
* @see java.lang.System#out
*/
*/
public
static
final
FileDescriptor
out
=
standardStream
(
1
);
public
static
final
FileDescriptor
out
=
standardStream
(
1
);
...
@@ -105,7 +110,7 @@ public final class FileDescriptor {
...
@@ -105,7 +110,7 @@ public final class FileDescriptor {
/**
/**
* A handle to the standard error stream. Usually, this file
* A handle to the standard error stream. Usually, this file
* descriptor is not used directly, but rather via the output stream
* descriptor is not used directly, but rather via the output stream
* known as
<code>System.err</code>
.
* known as
{@code System.err}
.
*
*
* @see java.lang.System#err
* @see java.lang.System#err
*/
*/
...
@@ -114,9 +119,9 @@ public final class FileDescriptor {
...
@@ -114,9 +119,9 @@ public final class FileDescriptor {
/**
/**
* Tests if this file descriptor object is valid.
* Tests if this file descriptor object is valid.
*
*
* @return
<code>true</code>
if the file descriptor object represents a
* @return
{@code true}
if the file descriptor object represents a
* valid, open file, socket, or other active I/O connection;
* valid, open file, socket, or other active I/O connection;
*
<code>false</code>
otherwise.
*
{@code false}
otherwise.
*/
*/
public
boolean
valid
()
{
public
boolean
valid
()
{
return
((
handle
!=
-
1
)
||
(
fd
!=
-
1
));
return
((
handle
!=
-
1
)
||
(
fd
!=
-
1
));
...
...
src/windows/classes/java/lang/ProcessImpl.java
浏览文件 @
095ce48d
...
@@ -25,7 +25,16 @@
...
@@ -25,7 +25,16 @@
package
java.lang
;
package
java.lang
;
import
java.io.*
;
import
java.io.IOException
;
import
java.io.File
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.io.FileInputStream
;
import
java.io.FileOutputStream
;
import
java.io.FileDescriptor
;
import
java.io.BufferedInputStream
;
import
java.io.BufferedOutputStream
;
import
java.lang.ProcessBuilder.Redirect
;
/* This class is for the exclusive use of ProcessBuilder.start() to
/* This class is for the exclusive use of ProcessBuilder.start() to
* create new processes.
* create new processes.
...
@@ -35,30 +44,82 @@ import java.io.*;
...
@@ -35,30 +44,82 @@ import java.io.*;
*/
*/
final
class
ProcessImpl
extends
Process
{
final
class
ProcessImpl
extends
Process
{
private
static
final
sun
.
misc
.
JavaIOFileDescriptorAccess
fdAccess
=
sun
.
misc
.
SharedSecrets
.
getJavaIOFileDescriptorAccess
();
// System-dependent portion of ProcessBuilder.start()
// System-dependent portion of ProcessBuilder.start()
static
Process
start
(
String
cmdarray
[],
static
Process
start
(
String
cmdarray
[],
java
.
util
.
Map
<
String
,
String
>
environment
,
java
.
util
.
Map
<
String
,
String
>
environment
,
String
dir
,
String
dir
,
ProcessBuilder
.
Redirect
[]
redirects
,
boolean
redirectErrorStream
)
boolean
redirectErrorStream
)
throws
IOException
throws
IOException
{
{
String
envblock
=
ProcessEnvironment
.
toEnvironmentBlock
(
environment
);
String
envblock
=
ProcessEnvironment
.
toEnvironmentBlock
(
environment
);
return
new
ProcessImpl
(
cmdarray
,
envblock
,
dir
,
redirectErrorStream
);
FileInputStream
f0
=
null
;
FileOutputStream
f1
=
null
;
FileOutputStream
f2
=
null
;
try
{
long
[]
stdHandles
;
if
(
redirects
==
null
)
{
stdHandles
=
new
long
[]
{
-
1L
,
-
1L
,
-
1L
};
}
else
{
stdHandles
=
new
long
[
3
];
if
(
redirects
[
0
]
==
Redirect
.
PIPE
)
stdHandles
[
0
]
=
-
1L
;
else
if
(
redirects
[
0
]
==
Redirect
.
INHERIT
)
stdHandles
[
0
]
=
fdAccess
.
getHandle
(
FileDescriptor
.
in
);
else
{
f0
=
new
FileInputStream
(
redirects
[
0
].
file
());
stdHandles
[
0
]
=
fdAccess
.
getHandle
(
f0
.
getFD
());
}
if
(
redirects
[
1
]
==
Redirect
.
PIPE
)
stdHandles
[
1
]
=
-
1L
;
else
if
(
redirects
[
1
]
==
Redirect
.
INHERIT
)
stdHandles
[
1
]
=
fdAccess
.
getHandle
(
FileDescriptor
.
out
);
else
{
f1
=
redirects
[
1
].
toFileOutputStream
();
stdHandles
[
1
]
=
fdAccess
.
getHandle
(
f1
.
getFD
());
}
if
(
redirects
[
2
]
==
Redirect
.
PIPE
)
stdHandles
[
2
]
=
-
1L
;
else
if
(
redirects
[
2
]
==
Redirect
.
INHERIT
)
stdHandles
[
2
]
=
fdAccess
.
getHandle
(
FileDescriptor
.
err
);
else
{
f2
=
redirects
[
2
].
toFileOutputStream
();
stdHandles
[
2
]
=
fdAccess
.
getHandle
(
f2
.
getFD
());
}
}
return
new
ProcessImpl
(
cmdarray
,
envblock
,
dir
,
stdHandles
,
redirectErrorStream
);
}
finally
{
// In theory, close() can throw IOException
// (although it is rather unlikely to happen here)
try
{
if
(
f0
!=
null
)
f0
.
close
();
}
finally
{
try
{
if
(
f1
!=
null
)
f1
.
close
();
}
finally
{
if
(
f2
!=
null
)
f2
.
close
();
}
}
}
}
}
private
long
handle
=
0
;
private
long
handle
=
0
;
private
FileDescriptor
stdin_fd
;
private
FileDescriptor
stdout_fd
;
private
FileDescriptor
stderr_fd
;
private
OutputStream
stdin_stream
;
private
OutputStream
stdin_stream
;
private
InputStream
stdout_stream
;
private
InputStream
stdout_stream
;
private
InputStream
stderr_stream
;
private
InputStream
stderr_stream
;
private
ProcessImpl
(
String
cmd
[],
private
ProcessImpl
(
final
String
cmd
[],
String
envblock
,
final
String
envblock
,
String
path
,
final
String
path
,
boolean
redirectErrorStream
)
final
long
[]
stdHandles
,
final
boolean
redirectErrorStream
)
throws
IOException
throws
IOException
{
{
// Win32 CreateProcess requires cmd[0] to be normalized
// Win32 CreateProcess requires cmd[0] to be normalized
...
@@ -91,25 +152,39 @@ final class ProcessImpl extends Process {
...
@@ -91,25 +152,39 @@ final class ProcessImpl extends Process {
}
}
String
cmdstr
=
cmdbuf
.
toString
();
String
cmdstr
=
cmdbuf
.
toString
();
stdin_fd
=
new
FileDescriptor
();
handle
=
create
(
cmdstr
,
envblock
,
path
,
stdout_fd
=
new
FileDescriptor
();
stdHandles
,
redirectErrorStream
);
stderr_fd
=
new
FileDescriptor
();
handle
=
create
(
cmdstr
,
envblock
,
path
,
redirectErrorStream
,
stdin_fd
,
stdout_fd
,
stderr_fd
);
java
.
security
.
AccessController
.
doPrivileged
(
java
.
security
.
AccessController
.
doPrivileged
(
new
java
.
security
.
PrivilegedAction
()
{
new
java
.
security
.
PrivilegedAction
<
Void
>
()
{
public
Object
run
()
{
public
Void
run
()
{
stdin_stream
=
if
(
stdHandles
[
0
]
==
-
1L
)
new
BufferedOutputStream
(
new
FileOutputStream
(
stdin_fd
)
);
stdin_stream
=
new
ProcessBuilder
.
NullOutputStream
(
);
stdout_stream
=
else
{
new
BufferedInputStream
(
new
FileInputStream
(
stdout_fd
)
);
FileDescriptor
stdin_fd
=
new
FileDescriptor
(
);
stderr_stream
=
fdAccess
.
setHandle
(
stdin_fd
,
stdHandles
[
0
]);
new
FileInputStream
(
stderr_fd
);
stdin_stream
=
new
BufferedOutputStream
(
return
null
;
new
FileOutputStream
(
stdin_fd
))
;
}
}
});
if
(
stdHandles
[
1
]
==
-
1L
)
stdout_stream
=
new
ProcessBuilder
.
NullInputStream
();
else
{
FileDescriptor
stdout_fd
=
new
FileDescriptor
();
fdAccess
.
setHandle
(
stdout_fd
,
stdHandles
[
1
]);
stdout_stream
=
new
BufferedInputStream
(
new
FileInputStream
(
stdout_fd
));
}
if
(
stdHandles
[
2
]
==
-
1L
)
stderr_stream
=
new
ProcessBuilder
.
NullInputStream
();
else
{
FileDescriptor
stderr_fd
=
new
FileDescriptor
();
fdAccess
.
setHandle
(
stderr_fd
,
stdHandles
[
2
]);
stderr_stream
=
new
FileInputStream
(
stderr_fd
);
}
return
null
;
}});
}
}
public
OutputStream
getOutputStream
()
{
public
OutputStream
getOutputStream
()
{
...
@@ -150,13 +225,30 @@ final class ProcessImpl extends Process {
...
@@ -150,13 +225,30 @@ final class ProcessImpl extends Process {
public
void
destroy
()
{
terminateProcess
(
handle
);
}
public
void
destroy
()
{
terminateProcess
(
handle
);
}
private
static
native
void
terminateProcess
(
long
handle
);
private
static
native
void
terminateProcess
(
long
handle
);
/**
* Create a process using the win32 function CreateProcess.
*
* @param cmdstr the Windows commandline
* @param envblock NUL-separated, double-NUL-terminated list of
* environment strings in VAR=VALUE form
* @param dir the working directory of the process, or null if
* inheriting the current directory from the parent process
* @param stdHandles array of windows HANDLEs. Indexes 0, 1, and
* 2 correspond to standard input, standard output and
* standard error, respectively. On input, a value of -1
* means to create a pipe to connect child and parent
* processes. On output, a value which is not -1 is the
* parent pipe handle corresponding to the pipe which has
* been created. An element of this array is -1 on input
* if and only if it is <em>not</em> -1 on output.
* @param redirectErrorStream redirectErrorStream attribute
* @return the native subprocess HANDLE returned by CreateProcess
*/
private
static
native
long
create
(
String
cmdstr
,
private
static
native
long
create
(
String
cmdstr
,
String
envblock
,
String
envblock
,
String
dir
,
String
dir
,
boolean
redirectErrorStream
,
long
[]
stdHandles
,
FileDescriptor
in_fd
,
boolean
redirectErrorStream
)
FileDescriptor
out_fd
,
FileDescriptor
err_fd
)
throws
IOException
;
throws
IOException
;
private
static
native
boolean
closeHandle
(
long
handle
);
private
static
native
boolean
closeHandle
(
long
handle
);
...
...
src/windows/native/java/lang/ProcessImpl_md.c
浏览文件 @
095ce48d
...
@@ -125,7 +125,7 @@ win32Error(JNIEnv *env, const char *functionName)
...
@@ -125,7 +125,7 @@ win32Error(JNIEnv *env, const char *functionName)
static
void
static
void
closeSafely
(
HANDLE
handle
)
closeSafely
(
HANDLE
handle
)
{
{
if
(
handle
)
if
(
handle
!=
INVALID_HANDLE_VALUE
)
CloseHandle
(
handle
);
CloseHandle
(
handle
);
}
}
...
@@ -134,23 +134,22 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
...
@@ -134,23 +134,22 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
jstring
cmd
,
jstring
cmd
,
jstring
envBlock
,
jstring
envBlock
,
jstring
dir
,
jstring
dir
,
jboolean
redirectErrorStream
,
jlongArray
stdHandles
,
jobject
in_fd
,
jboolean
redirectErrorStream
)
jobject
out_fd
,
jobject
err_fd
)
{
{
HANDLE
inRead
=
0
;
HANDLE
inRead
=
INVALID_HANDLE_VALUE
;
HANDLE
inWrite
=
0
;
HANDLE
inWrite
=
INVALID_HANDLE_VALUE
;
HANDLE
outRead
=
0
;
HANDLE
outRead
=
INVALID_HANDLE_VALUE
;
HANDLE
outWrite
=
0
;
HANDLE
outWrite
=
INVALID_HANDLE_VALUE
;
HANDLE
errRead
=
0
;
HANDLE
errRead
=
INVALID_HANDLE_VALUE
;
HANDLE
errWrite
=
0
;
HANDLE
errWrite
=
INVALID_HANDLE_VALUE
;
SECURITY_ATTRIBUTES
sa
;
SECURITY_ATTRIBUTES
sa
;
PROCESS_INFORMATION
pi
;
PROCESS_INFORMATION
pi
;
STARTUPINFO
si
;
STARTUPINFO
si
;
LPTSTR
pcmd
=
NULL
;
LPTSTR
pcmd
=
NULL
;
LPCTSTR
pdir
=
NULL
;
LPCTSTR
pdir
=
NULL
;
LPVOID
penvBlock
=
NULL
;
LPVOID
penvBlock
=
NULL
;
jlong
*
handles
=
NULL
;
jlong
ret
=
0
;
jlong
ret
=
0
;
OSVERSIONINFO
ver
;
OSVERSIONINFO
ver
;
jboolean
onNT
=
JNI_FALSE
;
jboolean
onNT
=
JNI_FALSE
;
...
@@ -161,17 +160,6 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
...
@@ -161,17 +160,6 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
if
(
ver
.
dwPlatformId
==
VER_PLATFORM_WIN32_NT
)
if
(
ver
.
dwPlatformId
==
VER_PLATFORM_WIN32_NT
)
onNT
=
JNI_TRUE
;
onNT
=
JNI_TRUE
;
sa
.
nLength
=
sizeof
(
sa
);
sa
.
lpSecurityDescriptor
=
0
;
sa
.
bInheritHandle
=
TRUE
;
if
(
!
(
CreatePipe
(
&
inRead
,
&
inWrite
,
&
sa
,
PIPE_SIZE
)
&&
CreatePipe
(
&
outRead
,
&
outWrite
,
&
sa
,
PIPE_SIZE
)
&&
CreatePipe
(
&
errRead
,
&
errWrite
,
&
sa
,
PIPE_SIZE
)))
{
win32Error
(
env
,
"CreatePipe"
);
goto
Catch
;
}
assert
(
cmd
!=
NULL
);
assert
(
cmd
!=
NULL
);
pcmd
=
(
LPTSTR
)
JNU_GetStringPlatformChars
(
env
,
cmd
,
NULL
);
pcmd
=
(
LPTSTR
)
JNU_GetStringPlatformChars
(
env
,
cmd
,
NULL
);
if
(
pcmd
==
NULL
)
goto
Catch
;
if
(
pcmd
==
NULL
)
goto
Catch
;
...
@@ -189,19 +177,62 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
...
@@ -189,19 +177,62 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
if
(
penvBlock
==
NULL
)
goto
Catch
;
if
(
penvBlock
==
NULL
)
goto
Catch
;
}
}
assert
(
stdHandles
!=
NULL
);
handles
=
(
*
env
)
->
GetLongArrayElements
(
env
,
stdHandles
,
NULL
);
if
(
handles
==
NULL
)
goto
Catch
;
memset
(
&
si
,
0
,
sizeof
(
si
));
memset
(
&
si
,
0
,
sizeof
(
si
));
si
.
cb
=
sizeof
(
si
);
si
.
cb
=
sizeof
(
si
);
si
.
dwFlags
=
STARTF_USESTDHANDLES
;
si
.
dwFlags
=
STARTF_USESTDHANDLES
;
si
.
hStdInput
=
inRead
;
si
.
hStdOutput
=
outWrite
;
si
.
hStdError
=
redirectErrorStream
?
outWrite
:
errWrite
;
SetHandleInformation
(
inWrite
,
HANDLE_FLAG_INHERIT
,
FALSE
);
sa
.
nLength
=
sizeof
(
sa
);
SetHandleInformation
(
outRead
,
HANDLE_FLAG_INHERIT
,
FALSE
)
;
sa
.
lpSecurityDescriptor
=
0
;
SetHandleInformation
(
errRead
,
HANDLE_FLAG_INHERIT
,
FALSE
)
;
sa
.
bInheritHandle
=
TRUE
;
if
(
redirectErrorStream
)
if
(
handles
[
0
]
!=
(
jlong
)
-
1
)
{
SetHandleInformation
(
errWrite
,
HANDLE_FLAG_INHERIT
,
FALSE
);
si
.
hStdInput
=
(
HANDLE
)
handles
[
0
];
handles
[
0
]
=
(
jlong
)
-
1
;
}
else
{
if
(
!
CreatePipe
(
&
inRead
,
&
inWrite
,
&
sa
,
PIPE_SIZE
))
{
win32Error
(
env
,
"CreatePipe"
);
goto
Catch
;
}
si
.
hStdInput
=
inRead
;
SetHandleInformation
(
inWrite
,
HANDLE_FLAG_INHERIT
,
FALSE
);
handles
[
0
]
=
(
jlong
)
inWrite
;
}
SetHandleInformation
(
si
.
hStdInput
,
HANDLE_FLAG_INHERIT
,
TRUE
);
if
(
handles
[
1
]
!=
(
jlong
)
-
1
)
{
si
.
hStdOutput
=
(
HANDLE
)
handles
[
1
];
handles
[
1
]
=
(
jlong
)
-
1
;
}
else
{
if
(
!
CreatePipe
(
&
outRead
,
&
outWrite
,
&
sa
,
PIPE_SIZE
))
{
win32Error
(
env
,
"CreatePipe"
);
goto
Catch
;
}
si
.
hStdOutput
=
outWrite
;
SetHandleInformation
(
outRead
,
HANDLE_FLAG_INHERIT
,
FALSE
);
handles
[
1
]
=
(
jlong
)
outRead
;
}
SetHandleInformation
(
si
.
hStdOutput
,
HANDLE_FLAG_INHERIT
,
TRUE
);
if
(
redirectErrorStream
)
{
si
.
hStdError
=
si
.
hStdOutput
;
handles
[
2
]
=
(
jlong
)
-
1
;
}
else
if
(
handles
[
2
]
!=
(
jlong
)
-
1
)
{
si
.
hStdError
=
(
HANDLE
)
handles
[
2
];
handles
[
2
]
=
(
jlong
)
-
1
;
}
else
{
if
(
!
CreatePipe
(
&
errRead
,
&
errWrite
,
&
sa
,
PIPE_SIZE
))
{
win32Error
(
env
,
"CreatePipe"
);
goto
Catch
;
}
si
.
hStdError
=
errWrite
;
SetHandleInformation
(
errRead
,
HANDLE_FLAG_INHERIT
,
FALSE
);
handles
[
2
]
=
(
jlong
)
errRead
;
}
SetHandleInformation
(
si
.
hStdError
,
HANDLE_FLAG_INHERIT
,
TRUE
);
if
(
onNT
)
if
(
onNT
)
processFlag
=
CREATE_NO_WINDOW
|
CREATE_UNICODE_ENVIRONMENT
;
processFlag
=
CREATE_NO_WINDOW
|
CREATE_UNICODE_ENVIRONMENT
;
...
@@ -237,9 +268,6 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
...
@@ -237,9 +268,6 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
CloseHandle
(
pi
.
hThread
);
CloseHandle
(
pi
.
hThread
);
ret
=
(
jlong
)
pi
.
hProcess
;
ret
=
(
jlong
)
pi
.
hProcess
;
(
*
env
)
->
SetLongField
(
env
,
in_fd
,
IO_handle_fdID
,
(
jlong
)
inWrite
);
(
*
env
)
->
SetLongField
(
env
,
out_fd
,
IO_handle_fdID
,
(
jlong
)
outRead
);
(
*
env
)
->
SetLongField
(
env
,
err_fd
,
IO_handle_fdID
,
(
jlong
)
errRead
);
Finally:
Finally:
/* Always clean up the child's side of the pipes */
/* Always clean up the child's side of the pipes */
...
@@ -257,6 +285,9 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
...
@@ -257,6 +285,9 @@ Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
else
else
JNU_ReleaseStringPlatformChars
(
env
,
dir
,
(
char
*
)
penvBlock
);
JNU_ReleaseStringPlatformChars
(
env
,
dir
,
(
char
*
)
penvBlock
);
}
}
if
(
handles
!=
NULL
)
(
*
env
)
->
ReleaseLongArrayElements
(
env
,
stdHandles
,
handles
,
0
);
return
ret
;
return
ret
;
Catch:
Catch:
...
...
test/java/lang/ProcessBuilder/Basic.java
浏览文件 @
095ce48d
...
@@ -25,12 +25,15 @@
...
@@ -25,12 +25,15 @@
* @test
* @test
* @bug 4199068 4738465 4937983 4930681 4926230 4931433 4932663 4986689
* @bug 4199068 4738465 4937983 4930681 4926230 4931433 4932663 4986689
* 5026830 5023243 5070673 4052517 4811767 6192449 6397034 6413313
* 5026830 5023243 5070673 4052517 4811767 6192449 6397034 6413313
* 6464154 6523983 6206031
* 6464154 6523983 6206031
4960438 6631352 6631966
* @summary Basic tests for Process and Environment Variable code
* @summary Basic tests for Process and Environment Variable code
* @run main/othervm Basic
* @run main/othervm Basic
* @author Martin Buchholz
* @author Martin Buchholz
*/
*/
import
java.lang.ProcessBuilder.Redirect
;
import
static
java
.
lang
.
ProcessBuilder
.
Redirect
.*;
import
java.io.*
;
import
java.io.*
;
import
java.util.*
;
import
java.util.*
;
import
java.security.*
;
import
java.security.*
;
...
@@ -257,7 +260,29 @@ public class Basic {
...
@@ -257,7 +260,29 @@ public class Basic {
public
static
class
JavaChild
{
public
static
class
JavaChild
{
public
static
void
main
(
String
args
[])
throws
Throwable
{
public
static
void
main
(
String
args
[])
throws
Throwable
{
String
action
=
args
[
0
];
String
action
=
args
[
0
];
if
(
action
.
equals
(
"System.getenv(String)"
))
{
if
(
action
.
equals
(
"testIO"
))
{
String
expected
=
"standard input"
;
char
[]
buf
=
new
char
[
expected
.
length
()+
1
];
int
n
=
new
InputStreamReader
(
System
.
in
).
read
(
buf
,
0
,
buf
.
length
);
if
(
n
!=
expected
.
length
())
System
.
exit
(
5
);
if
(!
new
String
(
buf
,
0
,
n
).
equals
(
expected
))
System
.
exit
(
5
);
System
.
err
.
print
(
"standard error"
);
System
.
out
.
print
(
"standard output"
);
}
else
if
(
action
.
equals
(
"testInheritIO"
))
{
List
<
String
>
childArgs
=
new
ArrayList
<
String
>(
javaChildArgs
);
childArgs
.
add
(
"testIO"
);
ProcessBuilder
pb
=
new
ProcessBuilder
(
childArgs
);
pb
.
inheritIO
();
ProcessResults
r
=
run
(
pb
);
if
(!
r
.
out
().
equals
(
""
))
System
.
exit
(
7
);
if
(!
r
.
err
().
equals
(
""
))
System
.
exit
(
8
);
if
(
r
.
exitValue
()
!=
0
)
System
.
exit
(
9
);
}
else
if
(
action
.
equals
(
"System.getenv(String)"
))
{
String
val
=
System
.
getenv
(
args
[
1
]);
String
val
=
System
.
getenv
(
args
[
1
]);
printUTF8
(
val
==
null
?
"null"
:
val
);
printUTF8
(
val
==
null
?
"null"
:
val
);
}
else
if
(
action
.
equals
(
"System.getenv(\\u1234)"
))
{
}
else
if
(
action
.
equals
(
"System.getenv(\\u1234)"
))
{
...
@@ -599,6 +624,333 @@ public class Basic {
...
@@ -599,6 +624,333 @@ public class Basic {
}
catch
(
Throwable
t
)
{
unexpected
(
t
);
}
}
catch
(
Throwable
t
)
{
unexpected
(
t
);
}
}
}
static
void
checkRedirects
(
ProcessBuilder
pb
,
Redirect
in
,
Redirect
out
,
Redirect
err
)
{
equal
(
pb
.
redirectInput
(),
in
);
equal
(
pb
.
redirectOutput
(),
out
);
equal
(
pb
.
redirectError
(),
err
);
}
static
void
redirectIO
(
ProcessBuilder
pb
,
Redirect
in
,
Redirect
out
,
Redirect
err
)
{
pb
.
redirectInput
(
in
);
pb
.
redirectOutput
(
out
);
pb
.
redirectError
(
err
);
}
static
void
setFileContents
(
File
file
,
String
contents
)
{
try
{
Writer
w
=
new
FileWriter
(
file
);
w
.
write
(
contents
);
w
.
close
();
}
catch
(
Throwable
t
)
{
unexpected
(
t
);
}
}
static
String
fileContents
(
File
file
)
{
try
{
Reader
r
=
new
FileReader
(
file
);
StringBuilder
sb
=
new
StringBuilder
();
char
[]
buffer
=
new
char
[
1024
];
int
n
;
while
((
n
=
r
.
read
(
buffer
))
!=
-
1
)
sb
.
append
(
buffer
,
0
,
n
);
r
.
close
();
return
new
String
(
sb
);
}
catch
(
Throwable
t
)
{
unexpected
(
t
);
return
""
;
}
}
static
void
testIORedirection
()
throws
Throwable
{
final
File
ifile
=
new
File
(
"ifile"
);
final
File
ofile
=
new
File
(
"ofile"
);
final
File
efile
=
new
File
(
"efile"
);
ifile
.
delete
();
ofile
.
delete
();
efile
.
delete
();
//----------------------------------------------------------------
// Check mutual inequality of different types of Redirect
//----------------------------------------------------------------
Redirect
[]
redirects
=
{
PIPE
,
INHERIT
,
Redirect
.
from
(
ifile
),
Redirect
.
to
(
ifile
),
Redirect
.
appendTo
(
ifile
),
Redirect
.
from
(
ofile
),
Redirect
.
to
(
ofile
),
Redirect
.
appendTo
(
ofile
),
};
for
(
int
i
=
0
;
i
<
redirects
.
length
;
i
++)
for
(
int
j
=
0
;
j
<
redirects
.
length
;
j
++)
equal
(
redirects
[
i
].
equals
(
redirects
[
j
]),
(
i
==
j
));
//----------------------------------------------------------------
// Check basic properties of different types of Redirect
//----------------------------------------------------------------
equal
(
PIPE
.
type
(),
Redirect
.
Type
.
PIPE
);
equal
(
PIPE
.
toString
(),
"PIPE"
);
equal
(
PIPE
.
file
(),
null
);
equal
(
INHERIT
.
type
(),
Redirect
.
Type
.
INHERIT
);
equal
(
INHERIT
.
toString
(),
"INHERIT"
);
equal
(
INHERIT
.
file
(),
null
);
equal
(
Redirect
.
from
(
ifile
).
type
(),
Redirect
.
Type
.
READ
);
equal
(
Redirect
.
from
(
ifile
).
toString
(),
"redirect to read from file \"ifile\""
);
equal
(
Redirect
.
from
(
ifile
).
file
(),
ifile
);
equal
(
Redirect
.
from
(
ifile
),
Redirect
.
from
(
ifile
));
equal
(
Redirect
.
from
(
ifile
).
hashCode
(),
Redirect
.
from
(
ifile
).
hashCode
());
equal
(
Redirect
.
to
(
ofile
).
type
(),
Redirect
.
Type
.
WRITE
);
equal
(
Redirect
.
to
(
ofile
).
toString
(),
"redirect to write to file \"ofile\""
);
equal
(
Redirect
.
to
(
ofile
).
file
(),
ofile
);
equal
(
Redirect
.
to
(
ofile
),
Redirect
.
to
(
ofile
));
equal
(
Redirect
.
to
(
ofile
).
hashCode
(),
Redirect
.
to
(
ofile
).
hashCode
());
equal
(
Redirect
.
appendTo
(
ofile
).
type
(),
Redirect
.
Type
.
APPEND
);
equal
(
Redirect
.
appendTo
(
efile
).
toString
(),
"redirect to append to file \"efile\""
);
equal
(
Redirect
.
appendTo
(
efile
).
file
(),
efile
);
equal
(
Redirect
.
appendTo
(
efile
),
Redirect
.
appendTo
(
efile
));
equal
(
Redirect
.
appendTo
(
efile
).
hashCode
(),
Redirect
.
appendTo
(
efile
).
hashCode
());
//----------------------------------------------------------------
// Check initial values of redirects
//----------------------------------------------------------------
List
<
String
>
childArgs
=
new
ArrayList
<
String
>(
javaChildArgs
);
childArgs
.
add
(
"testIO"
);
final
ProcessBuilder
pb
=
new
ProcessBuilder
(
childArgs
);
checkRedirects
(
pb
,
PIPE
,
PIPE
,
PIPE
);
//----------------------------------------------------------------
// Check inheritIO
//----------------------------------------------------------------
pb
.
inheritIO
();
checkRedirects
(
pb
,
INHERIT
,
INHERIT
,
INHERIT
);
//----------------------------------------------------------------
// Check setters and getters agree
//----------------------------------------------------------------
pb
.
redirectInput
(
ifile
);
equal
(
pb
.
redirectInput
().
file
(),
ifile
);
equal
(
pb
.
redirectInput
(),
Redirect
.
from
(
ifile
));
pb
.
redirectOutput
(
ofile
);
equal
(
pb
.
redirectOutput
().
file
(),
ofile
);
equal
(
pb
.
redirectOutput
(),
Redirect
.
to
(
ofile
));
pb
.
redirectError
(
efile
);
equal
(
pb
.
redirectError
().
file
(),
efile
);
equal
(
pb
.
redirectError
(),
Redirect
.
to
(
efile
));
THROWS
(
IllegalArgumentException
.
class
,
new
Fun
(){
void
f
()
{
pb
.
redirectInput
(
Redirect
.
to
(
ofile
));
}},
new
Fun
(){
void
f
()
{
pb
.
redirectInput
(
Redirect
.
appendTo
(
ofile
));
}},
new
Fun
(){
void
f
()
{
pb
.
redirectOutput
(
Redirect
.
from
(
ifile
));
}},
new
Fun
(){
void
f
()
{
pb
.
redirectError
(
Redirect
.
from
(
ifile
));
}});
THROWS
(
IOException
.
class
,
// Input file does not exist
new
Fun
(){
void
f
()
throws
Throwable
{
pb
.
start
();
}});
setFileContents
(
ifile
,
"standard input"
);
//----------------------------------------------------------------
// Writing to non-existent files
//----------------------------------------------------------------
{
ProcessResults
r
=
run
(
pb
);
equal
(
r
.
exitValue
(),
0
);
equal
(
fileContents
(
ofile
),
"standard output"
);
equal
(
fileContents
(
efile
),
"standard error"
);
equal
(
r
.
out
(),
""
);
equal
(
r
.
err
(),
""
);
ofile
.
delete
();
efile
.
delete
();
}
//----------------------------------------------------------------
// Both redirectErrorStream + redirectError
//----------------------------------------------------------------
{
pb
.
redirectErrorStream
(
true
);
ProcessResults
r
=
run
(
pb
);
equal
(
r
.
exitValue
(),
0
);
equal
(
fileContents
(
ofile
),
"standard error"
+
"standard output"
);
equal
(
fileContents
(
efile
),
""
);
equal
(
r
.
out
(),
""
);
equal
(
r
.
err
(),
""
);
ofile
.
delete
();
efile
.
delete
();
}
//----------------------------------------------------------------
// Appending to existing files
//----------------------------------------------------------------
{
setFileContents
(
ofile
,
"ofile-contents"
);
setFileContents
(
efile
,
"efile-contents"
);
pb
.
redirectOutput
(
Redirect
.
appendTo
(
ofile
));
pb
.
redirectError
(
Redirect
.
appendTo
(
efile
));
pb
.
redirectErrorStream
(
false
);
ProcessResults
r
=
run
(
pb
);
equal
(
r
.
exitValue
(),
0
);
equal
(
fileContents
(
ofile
),
"ofile-contents"
+
"standard output"
);
equal
(
fileContents
(
efile
),
"efile-contents"
+
"standard error"
);
equal
(
r
.
out
(),
""
);
equal
(
r
.
err
(),
""
);
ofile
.
delete
();
efile
.
delete
();
}
//----------------------------------------------------------------
// Replacing existing files
//----------------------------------------------------------------
{
setFileContents
(
ofile
,
"ofile-contents"
);
setFileContents
(
efile
,
"efile-contents"
);
pb
.
redirectOutput
(
ofile
);
pb
.
redirectError
(
Redirect
.
to
(
efile
));
ProcessResults
r
=
run
(
pb
);
equal
(
r
.
exitValue
(),
0
);
equal
(
fileContents
(
ofile
),
"standard output"
);
equal
(
fileContents
(
efile
),
"standard error"
);
equal
(
r
.
out
(),
""
);
equal
(
r
.
err
(),
""
);
ofile
.
delete
();
efile
.
delete
();
}
//----------------------------------------------------------------
// Appending twice to the same file?
//----------------------------------------------------------------
{
setFileContents
(
ofile
,
"ofile-contents"
);
setFileContents
(
efile
,
"efile-contents"
);
Redirect
appender
=
Redirect
.
appendTo
(
ofile
);
pb
.
redirectOutput
(
appender
);
pb
.
redirectError
(
appender
);
ProcessResults
r
=
run
(
pb
);
equal
(
r
.
exitValue
(),
0
);
equal
(
fileContents
(
ofile
),
"ofile-contents"
+
"standard error"
+
"standard output"
);
equal
(
fileContents
(
efile
),
"efile-contents"
);
equal
(
r
.
out
(),
""
);
equal
(
r
.
err
(),
""
);
ifile
.
delete
();
ofile
.
delete
();
efile
.
delete
();
}
//----------------------------------------------------------------
// Testing INHERIT is harder.
// Note that this requires __FOUR__ nested JVMs involved in one test,
// if you count the harness JVM.
//----------------------------------------------------------------
{
redirectIO
(
pb
,
PIPE
,
PIPE
,
PIPE
);
List
<
String
>
command
=
pb
.
command
();
command
.
set
(
command
.
size
()
-
1
,
"testInheritIO"
);
Process
p
=
pb
.
start
();
new
PrintStream
(
p
.
getOutputStream
()).
print
(
"standard input"
);
p
.
getOutputStream
().
close
();
ProcessResults
r
=
run
(
p
);
equal
(
r
.
exitValue
(),
0
);
equal
(
r
.
out
(),
"standard output"
);
equal
(
r
.
err
(),
"standard error"
);
}
//----------------------------------------------------------------
// Test security implications of I/O redirection
//----------------------------------------------------------------
// Read access to current directory is always granted;
// So create a tmpfile for input instead.
final
File
tmpFile
=
File
.
createTempFile
(
"Basic"
,
"tmp"
);
setFileContents
(
tmpFile
,
"standard input"
);
final
Policy
policy
=
new
Policy
();
Policy
.
setPolicy
(
policy
);
System
.
setSecurityManager
(
new
SecurityManager
());
try
{
final
Permission
xPermission
=
new
FilePermission
(
"<<ALL FILES>>"
,
"execute"
);
final
Permission
rxPermission
=
new
FilePermission
(
"<<ALL FILES>>"
,
"read,execute"
);
final
Permission
wxPermission
=
new
FilePermission
(
"<<ALL FILES>>"
,
"write,execute"
);
final
Permission
rwxPermission
=
new
FilePermission
(
"<<ALL FILES>>"
,
"read,write,execute"
);
THROWS
(
SecurityException
.
class
,
new
Fun
()
{
void
f
()
throws
IOException
{
policy
.
setPermissions
(
xPermission
);
redirectIO
(
pb
,
from
(
tmpFile
),
PIPE
,
PIPE
);
pb
.
start
();}},
new
Fun
()
{
void
f
()
throws
IOException
{
policy
.
setPermissions
(
rxPermission
);
redirectIO
(
pb
,
PIPE
,
to
(
ofile
),
PIPE
);
pb
.
start
();}},
new
Fun
()
{
void
f
()
throws
IOException
{
policy
.
setPermissions
(
rxPermission
);
redirectIO
(
pb
,
PIPE
,
PIPE
,
to
(
efile
));
pb
.
start
();}});
{
policy
.
setPermissions
(
rxPermission
);
redirectIO
(
pb
,
from
(
tmpFile
),
PIPE
,
PIPE
);
ProcessResults
r
=
run
(
pb
);
equal
(
r
.
out
(),
"standard output"
);
equal
(
r
.
err
(),
"standard error"
);
}
{
policy
.
setPermissions
(
wxPermission
);
redirectIO
(
pb
,
PIPE
,
to
(
ofile
),
to
(
efile
));
Process
p
=
pb
.
start
();
new
PrintStream
(
p
.
getOutputStream
()).
print
(
"standard input"
);
p
.
getOutputStream
().
close
();
ProcessResults
r
=
run
(
p
);
policy
.
setPermissions
(
rwxPermission
);
equal
(
fileContents
(
ofile
),
"standard output"
);
equal
(
fileContents
(
efile
),
"standard error"
);
}
{
policy
.
setPermissions
(
rwxPermission
);
redirectIO
(
pb
,
from
(
tmpFile
),
to
(
ofile
),
to
(
efile
));
ProcessResults
r
=
run
(
pb
);
policy
.
setPermissions
(
rwxPermission
);
equal
(
fileContents
(
ofile
),
"standard output"
);
equal
(
fileContents
(
efile
),
"standard error"
);
}
}
finally
{
policy
.
setPermissions
(
new
RuntimePermission
(
"setSecurityManager"
));
System
.
setSecurityManager
(
null
);
tmpFile
.
delete
();
ifile
.
delete
();
ofile
.
delete
();
efile
.
delete
();
}
}
private
static
void
realMain
(
String
[]
args
)
throws
Throwable
{
private
static
void
realMain
(
String
[]
args
)
throws
Throwable
{
if
(
Windows
.
is
())
if
(
Windows
.
is
())
System
.
out
.
println
(
"This appears to be a Windows system."
);
System
.
out
.
println
(
"This appears to be a Windows system."
);
...
@@ -607,6 +959,9 @@ public class Basic {
...
@@ -607,6 +959,9 @@ public class Basic {
if
(
UnicodeOS
.
is
())
if
(
UnicodeOS
.
is
())
System
.
out
.
println
(
"This appears to be a Unicode-based OS."
);
System
.
out
.
println
(
"This appears to be a Unicode-based OS."
);
try
{
testIORedirection
();
}
catch
(
Throwable
t
)
{
unexpected
(
t
);
}
//----------------------------------------------------------------
//----------------------------------------------------------------
// Basic tests for setting, replacing and deleting envvars
// Basic tests for setting, replacing and deleting envvars
//----------------------------------------------------------------
//----------------------------------------------------------------
...
@@ -1354,7 +1709,8 @@ public class Basic {
...
@@ -1354,7 +1709,8 @@ public class Basic {
execPermission
);
execPermission
);
ProcessBuilder
pb
=
new
ProcessBuilder
(
"env"
);
ProcessBuilder
pb
=
new
ProcessBuilder
(
"env"
);
pb
.
environment
().
put
(
"foo"
,
"bar"
);
pb
.
environment
().
put
(
"foo"
,
"bar"
);
pb
.
start
();
Process
p
=
pb
.
start
();
closeStreams
(
p
);
}
catch
(
IOException
e
)
{
// OK
}
catch
(
IOException
e
)
{
// OK
}
catch
(
Throwable
t
)
{
unexpected
(
t
);
}
}
catch
(
Throwable
t
)
{
unexpected
(
t
);
}
...
@@ -1378,6 +1734,14 @@ public class Basic {
...
@@ -1378,6 +1734,14 @@ public class Basic {
}
}
static
void
closeStreams
(
Process
p
)
{
try
{
p
.
getOutputStream
().
close
();
p
.
getInputStream
().
close
();
p
.
getErrorStream
().
close
();
}
catch
(
Throwable
t
)
{
unexpected
(
t
);
}
}
//----------------------------------------------------------------
//----------------------------------------------------------------
// A Policy class designed to make permissions fiddling very easy.
// A Policy class designed to make permissions fiddling very easy.
//----------------------------------------------------------------
//----------------------------------------------------------------
...
@@ -1432,10 +1796,19 @@ public class Basic {
...
@@ -1432,10 +1796,19 @@ public class Basic {
}
}
}
catch
(
Throwable
t
)
{
}
catch
(
Throwable
t
)
{
throwable
=
t
;
throwable
=
t
;
}
finally
{
try
{
is
.
close
();
}
catch
(
Throwable
t
)
{
throwable
=
t
;
}
}
}
}
}
}
}
static
ProcessResults
run
(
ProcessBuilder
pb
)
{
try
{
return
run
(
pb
.
start
());
}
catch
(
Throwable
t
)
{
unexpected
(
t
);
return
null
;
}
}
private
static
ProcessResults
run
(
Process
p
)
{
private
static
ProcessResults
run
(
Process
p
)
{
Throwable
throwable
=
null
;
Throwable
throwable
=
null
;
int
exitValue
=
-
1
;
int
exitValue
=
-
1
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录