Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
edc21737
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看板
提交
edc21737
编写于
7月 31, 2012
作者:
K
ksrini
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
7146424: Wildcard expansion for single entry classpath
Reviewed-by: dholmes, darcy, jjh, sherman
上级
175e85db
变更
17
显示空白变更内容
内联
并排
Showing
17 changed file
with
732 addition
and
1622 deletion
+732
-1622
make/common/Program.gmk
make/common/Program.gmk
+0
-1
make/java/jli/Makefile
make/java/jli/Makefile
+7
-2
make/java/jli/mapfile-vers
make/java/jli/mapfile-vers
+3
-1
src/share/bin/java.c
src/share/bin/java.c
+16
-18
src/share/bin/java.h
src/share/bin/java.h
+4
-0
src/share/bin/jli_util.c
src/share/bin/jli_util.c
+3
-3
src/share/bin/jli_util.h
src/share/bin/jli_util.h
+11
-1
src/share/bin/main.c
src/share/bin/main.c
+27
-8
src/share/bin/wildcard.c
src/share/bin/wildcard.c
+4
-5
src/share/classes/sun/launcher/LauncherHelper.java
src/share/classes/sun/launcher/LauncherHelper.java
+83
-3
src/share/classes/sun/launcher/resources/launcher.properties
src/share/classes/sun/launcher/resources/launcher.properties
+1
-0
src/solaris/bin/java_md.c
src/solaris/bin/java_md.c
+0
-1522
src/solaris/bin/java_md_common.c
src/solaris/bin/java_md_common.c
+16
-0
src/windows/bin/java_md.c
src/windows/bin/java_md.c
+86
-0
test/tools/launcher/Arrrghs.java
test/tools/launcher/Arrrghs.java
+411
-57
test/tools/launcher/TestHelper.java
test/tools/launcher/TestHelper.java
+59
-0
test/tools/launcher/ToolsOpts.java
test/tools/launcher/ToolsOpts.java
+1
-1
未找到文件。
make/common/Program.gmk
浏览文件 @
edc21737
...
...
@@ -153,7 +153,6 @@ ifeq ($(PLATFORM), windows)
ifndef LOCAL_RESOURCE_FILE
@$(ECHO) $(OBJDIR)/$(PROGRAM).res >> $@
endif
@$(ECHO) setargv.obj >> $@
@$(ECHO) Created $@
$(ACTUAL_PROGRAM):: $(OBJDIR)/$(PROGRAM)$(EXE_SUFFIX)
...
...
make/java/jli/Makefile
浏览文件 @
edc21737
...
...
@@ -90,7 +90,8 @@ endif # SYSTEM_ZLIB
# add platform specific files
ifeq
($(PLATFORM), windows)
FILES_c
+=
java_md.c
FILES_c
+=
java_md.c
\
cmdtoargs.c
else
# NIXES
FILES_c
+=
java_md_common.c
ifeq
($(PLATFORM), macosx)
...
...
@@ -149,7 +150,11 @@ ifeq ($(PLATFORM), windows)
-export
:JLI_ReportErrorMessage
\
-export
:JLI_ReportErrorMessageSys
\
-export
:JLI_ReportMessage
\
-export
:JLI_ReportExceptionDescription
-export
:JLI_ReportExceptionDescription
\
-export
:JLI_MemAlloc
\
-export
:JLI_CmdToArgs
\
-export
:JLI_GetStdArgc
\
-export
:JLI_GetStdArgs
endif
# PLATFORM
OTHER_INCLUDES
+=
-I
$(LAUNCHER_SHARE_SRC)
...
...
make/java/jli/mapfile-vers
浏览文件 @
edc21737
#
# Copyright (c) 2005, 20
08
, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2005, 20
12
, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
...
...
@@ -34,6 +34,8 @@ SUNWprivate_1.1 {
JLI_ReportErrorMessageSys;
JLI_ReportMessage;
JLI_ReportExceptionDescription;
JLI_GetStdArgs;
JLI_GetStdArgc;
local:
*;
};
src/share/bin/java.c
浏览文件 @
edc21737
...
...
@@ -104,7 +104,6 @@ static jboolean ParseArguments(int *pargc, char ***pargv,
static
jboolean
InitializeJVM
(
JavaVM
**
pvm
,
JNIEnv
**
penv
,
InvocationFunctions
*
ifn
);
static
jstring
NewPlatformString
(
JNIEnv
*
env
,
char
*
s
);
static
jobjectArray
NewPlatformStringArray
(
JNIEnv
*
env
,
char
**
strv
,
int
strc
);
static
jclass
LoadMainClass
(
JNIEnv
*
env
,
int
mode
,
char
*
name
);
static
void
TranslateApplicationArgs
(
int
jargc
,
const
char
**
jargv
,
int
*
pargc
,
char
***
pargv
);
...
...
@@ -202,6 +201,14 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */
InitLauncher
(
javaw
);
DumpState
();
if
(
JLI_IsTraceLauncher
())
{
int
i
;
printf
(
"Command line args:
\n
"
);
for
(
i
=
0
;
i
<
argc
;
i
++
)
{
printf
(
"argv[%d] = %s
\n
"
,
i
,
argv
[
i
]);
}
AddOption
(
"-Dsun.java.launcher.diag=true"
,
NULL
);
}
/*
* Make sure the specified version of the JRE is running.
...
...
@@ -222,15 +229,6 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */
*/
SelectVersion
(
argc
,
argv
,
&
main_class
);
if
(
JLI_IsTraceLauncher
())
{
int
i
;
printf
(
"Command line args:
\n
"
);
for
(
i
=
0
;
i
<
argc
;
i
++
)
{
printf
(
"argv[%d] = %s
\n
"
,
i
,
argv
[
i
]);
}
AddOption
(
"-Dsun.java.launcher.diag=true"
,
NULL
);
}
CreateExecutionEnvironment
(
&
argc
,
&
argv
,
jrepath
,
sizeof
(
jrepath
),
jvmpath
,
sizeof
(
jvmpath
),
...
...
@@ -435,8 +433,8 @@ JavaMain(void * _args)
"([Ljava/lang/String;)V"
);
CHECK_EXCEPTION_NULL_LEAVE
(
mainID
);
/* Build argument array */
mainArgs
=
NewPlatformStringArray
(
env
,
argv
,
argc
);
/* Build
platform specific
argument array */
mainArgs
=
CreateApplicationArgs
(
env
,
argv
,
argc
);
CHECK_EXCEPTION_NULL_LEAVE
(
mainArgs
);
/* Invoke main method. */
...
...
@@ -1120,8 +1118,9 @@ InitializeJVM(JavaVM **pvm, JNIEnv **penv, InvocationFunctions *ifn)
static
jclass
helperClass
=
NULL
;
static
jclass
GetLauncherHelperClass
(
JNIEnv
*
env
)
{
jclass
GetLauncherHelperClass
(
JNIEnv
*
env
)
{
if
(
helperClass
==
NULL
)
{
NULL_CHECK0
(
helperClass
=
FindBootStrapClass
(
env
,
"sun/launcher/LauncherHelper"
));
...
...
@@ -1165,7 +1164,7 @@ NewPlatformString(JNIEnv *env, char *s)
* Returns a new array of Java string objects for the specified
* array of platform strings.
*/
static
jobjectArray
jobjectArray
NewPlatformStringArray
(
JNIEnv
*
env
,
char
**
strv
,
int
strc
)
{
jarray
cls
;
...
...
@@ -1210,7 +1209,7 @@ LoadMainClass(JNIEnv *env, int mode, char *name)
end
=
CounterGet
();
printf
(
"%ld micro seconds to load main class
\n
"
,
(
long
)(
jint
)
Counter2Micros
(
end
-
start
));
printf
(
"----
_JAVA_LAUNCHER_DEBUG----
\n
"
);
printf
(
"----
%s----
\n
"
,
JLDEBUG_ENV_ENTRY
);
}
return
(
jclass
)
result
;
...
...
@@ -1745,7 +1744,6 @@ FreeKnownVMs()
JLI_MemFree
(
knownVMs
);
}
/*
* Displays the splash screen according to the jar file name
* and image file names stored in environment variables
...
...
src/share/bin/java.h
浏览文件 @
edc21737
...
...
@@ -219,6 +219,10 @@ typedef jclass (JNICALL FindClassFromBootLoader_t(JNIEnv *env,
const
char
*
name
));
jclass
FindBootStrapClass
(
JNIEnv
*
env
,
const
char
*
classname
);
jobjectArray
CreateApplicationArgs
(
JNIEnv
*
env
,
char
**
strv
,
int
argc
);
jobjectArray
NewPlatformStringArray
(
JNIEnv
*
env
,
char
**
strv
,
int
strc
);
jclass
GetLauncherHelperClass
(
JNIEnv
*
env
);
int
JNICALL
JavaMain
(
void
*
args
);
/* entry point */
enum
LaunchMode
{
// cf. sun.launcher.LauncherHelper
...
...
src/share/bin/jli_util.c
浏览文件 @
edc21737
/*
* Copyright (c) 2005, 201
0
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 201
2
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
@@ -102,9 +102,9 @@ JLI_TraceLauncher(const char* fmt, ...)
void
JLI_SetTraceLauncher
()
{
if
(
getenv
(
"_JAVA_LAUNCHER_DEBUG"
)
!=
0
)
{
if
(
getenv
(
JLDEBUG_ENV_ENTRY
)
!=
0
)
{
_launcher_debug
=
JNI_TRUE
;
JLI_TraceLauncher
(
"----
_JAVA_LAUNCHER_DEBUG----
\n
"
);
JLI_TraceLauncher
(
"----
%s----
\n
"
,
JLDEBUG_ENV_ENTRY
);
}
}
...
...
src/share/bin/jli_util.h
浏览文件 @
edc21737
/*
* Copyright (c) 2005, 201
1
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 201
2
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
@@ -30,6 +30,7 @@
#include <string.h>
#include <stdio.h>
#include <jni.h>
#define JLDEBUG_ENV_ENTRY "_JAVA_LAUNCHER_DEBUG"
void
*
JLI_MemAlloc
(
size_t
size
);
void
*
JLI_MemRealloc
(
void
*
ptr
,
size_t
size
);
...
...
@@ -37,6 +38,14 @@ char *JLI_StringDup(const char *s1);
void
JLI_MemFree
(
void
*
ptr
);
int
JLI_StrCCmp
(
const
char
*
s1
,
const
char
*
s2
);
typedef
struct
{
char
*
arg
;
jboolean
has_wildcard
;
}
StdArg
;
StdArg
*
JLI_GetStdArgs
();
int
JLI_GetStdArgc
();
#define JLI_StrLen(p1) strlen((p1))
#define JLI_StrChr(p1, p2) strchr((p1), (p2))
#define JLI_StrRChr(p1, p2) strrchr((p1), (p2))
...
...
@@ -58,6 +67,7 @@ int JLI_StrCCmp(const char *s1, const char* s2);
#define JLI_StrCaseCmp(p1, p2) stricmp((p1), (p2))
#define JLI_StrNCaseCmp(p1, p2, p3) strnicmp((p1), (p2), (p3))
#define JLI_Snprintf _snprintf
void
JLI_CmdToArgs
(
char
*
cmdline
);
#else
#include <unistd.h>
#include <strings.h>
...
...
src/share/bin/main.c
浏览文件 @
edc21737
/*
* Copyright (c) 1995, 201
0
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1995, 201
2
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
@@ -87,22 +87,41 @@ WinMain(HINSTANCE inst, HINSTANCE previnst, LPSTR cmdline, int cmdshow)
const
jboolean
const_javaw
=
JNI_TRUE
;
__initenv
=
_environ
;
margc
=
__argc
;
margv
=
__argv
;
#else
/* JAVAW */
int
main
(
int
argc
,
char
**
argv
)
main
(
int
argc
,
char
**
argv
)
{
int
margc
;
char
**
margv
;
const
jboolean
const_javaw
=
JNI_FALSE
;
#endif
/* JAVAW */
#ifdef _WIN32
{
int
i
=
0
;
if
(
getenv
(
JLDEBUG_ENV_ENTRY
)
!=
NULL
)
{
printf
(
"Windows original main args:
\n
"
);
for
(
i
=
0
;
i
<
__argc
;
i
++
)
{
printf
(
"wwwd_args[%d] = %s
\n
"
,
i
,
__argv
[
i
]);
}
}
}
JLI_CmdToArgs
(
GetCommandLine
());
margc
=
JLI_GetStdArgc
();
// add one more to mark the end
margv
=
(
char
**
)
JLI_MemAlloc
((
margc
+
1
)
*
(
sizeof
(
char
*
)));
{
int
i
=
0
;
StdArg
*
stdargs
=
JLI_GetStdArgs
();
for
(
i
=
0
;
i
<
margc
;
i
++
)
{
margv
[
i
]
=
stdargs
[
i
].
arg
;
}
margv
[
i
]
=
NULL
;
}
#else
/* *NIXES */
margc
=
argc
;
margv
=
argv
;
#endif
/* JAVAW */
#endif
/* WIN32 */
return
JLI_Launch
(
margc
,
margv
,
sizeof
(
const_jargs
)
/
sizeof
(
char
*
),
const_jargs
,
sizeof
(
const_appclasspath
)
/
sizeof
(
char
*
),
const_appclasspath
,
...
...
src/share/bin/wildcard.c
浏览文件 @
edc21737
/*
* Copyright (c) 2005, 201
0
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 201
2
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
@@ -129,11 +129,11 @@ struct WildcardIterator_
HANDLE
handle
;
char
*
firstFile
;
/* Stupid FindFirstFile...FindNextFile */
};
// since this is used repeatedly we keep it here.
static
WIN32_FIND_DATA
find_data
;
static
WildcardIterator
WildcardIterator_for
(
const
char
*
wildcard
)
{
WIN32_FIND_DATA
find_data
;
WildcardIterator
it
=
NEW_
(
WildcardIterator
);
HANDLE
handle
=
FindFirstFile
(
wildcard
,
&
find_data
);
if
(
handle
==
INVALID_HANDLE_VALUE
)
...
...
@@ -146,7 +146,6 @@ WildcardIterator_for(const char *wildcard)
static
char
*
WildcardIterator_next
(
WildcardIterator
it
)
{
WIN32_FIND_DATA
find_data
;
if
(
it
->
firstFile
!=
NULL
)
{
char
*
firstFile
=
it
->
firstFile
;
it
->
firstFile
=
NULL
;
...
...
@@ -412,7 +411,7 @@ JLI_WildcardExpandClasspath(const char *classpath)
FileList_expandWildcards
(
fl
);
expanded
=
FileList_join
(
fl
,
PATH_SEPARATOR
);
FileList_free
(
fl
);
if
(
getenv
(
"_JAVA_LAUNCHER_DEBUG"
)
!=
0
)
if
(
getenv
(
JLDEBUG_ENV_ENTRY
)
!=
0
)
printf
(
"Expanded wildcards:
\n
"
" before:
\"
%s
\"\n
"
" after :
\"
%s
\"\n
"
,
...
...
src/share/classes/sun/launcher/LauncherHelper.java
浏览文件 @
edc21737
...
...
@@ -48,6 +48,9 @@ import java.lang.reflect.Modifier;
import
java.math.BigDecimal
;
import
java.math.RoundingMode
;
import
java.nio.charset.Charset
;
import
java.nio.file.DirectoryStream
;
import
java.nio.file.Files
;
import
java.nio.file.Path
;
import
java.util.ResourceBundle
;
import
java.text.MessageFormat
;
import
java.util.ArrayList
;
...
...
@@ -69,8 +72,6 @@ public enum LauncherHelper {
private
static
StringBuilder
outBuf
=
new
StringBuilder
();
private
static
ResourceBundle
javarb
=
null
;
private
static
final
String
INDENT
=
" "
;
private
static
final
String
VM_SETTINGS
=
"VM settings:"
;
private
static
final
String
PROP_SETTINGS
=
"Property settings:"
;
...
...
@@ -78,6 +79,7 @@ public enum LauncherHelper {
// sync with java.c and sun.misc.VM
private
static
final
String
diagprop
=
"sun.java.launcher.diag"
;
final
static
boolean
trace
=
sun
.
misc
.
VM
.
getSavedProperty
(
diagprop
)
!=
null
;
private
static
final
String
defaultBundleName
=
"sun.launcher.resources.launcher"
;
...
...
@@ -428,7 +430,7 @@ public enum LauncherHelper {
if
(
msgKey
!=
null
)
{
ostream
.
println
(
getLocalizedMessage
(
msgKey
,
args
));
}
if
(
sun
.
misc
.
VM
.
getSavedProperty
(
diagprop
)
!=
null
)
{
if
(
trace
)
{
if
(
t
!=
null
)
{
t
.
printStackTrace
();
}
else
{
...
...
@@ -532,4 +534,82 @@ public enum LauncherHelper {
}
return
null
;
// keep the compiler happy
}
static
String
[]
expandArgs
(
String
[]
argArray
)
{
List
<
StdArg
>
aList
=
new
ArrayList
<>();
for
(
String
x
:
argArray
)
{
aList
.
add
(
new
StdArg
(
x
));
}
return
expandArgs
(
aList
);
}
static
String
[]
expandArgs
(
List
<
StdArg
>
argList
)
{
ArrayList
<
String
>
out
=
new
ArrayList
<>();
if
(
trace
)
{
System
.
err
.
println
(
"Incoming arguments:"
);
}
for
(
StdArg
a
:
argList
)
{
if
(
trace
)
{
System
.
err
.
println
(
a
);
}
if
(
a
.
needsExpansion
)
{
File
x
=
new
File
(
a
.
arg
);
File
parent
=
x
.
getParentFile
();
String
glob
=
x
.
getName
();
if
(
parent
==
null
)
{
parent
=
new
File
(
"."
);
}
try
(
DirectoryStream
<
Path
>
dstream
=
Files
.
newDirectoryStream
(
parent
.
toPath
(),
glob
))
{
int
entries
=
0
;
for
(
Path
p
:
dstream
)
{
out
.
add
(
p
.
normalize
().
toString
());
entries
++;
}
if
(
entries
==
0
)
{
out
.
add
(
a
.
arg
);
}
}
catch
(
Exception
e
)
{
out
.
add
(
a
.
arg
);
if
(
trace
)
{
System
.
err
.
println
(
"Warning: passing argument as-is "
+
a
);
System
.
err
.
print
(
e
);
}
}
}
else
{
out
.
add
(
a
.
arg
);
}
}
String
[]
oarray
=
new
String
[
out
.
size
()];
out
.
toArray
(
oarray
);
if
(
trace
)
{
System
.
err
.
println
(
"Expanded arguments:"
);
for
(
String
x
:
oarray
)
{
System
.
err
.
println
(
x
);
}
}
return
oarray
;
}
/* duplicate of the native StdArg struct */
private
static
class
StdArg
{
final
String
arg
;
final
boolean
needsExpansion
;
StdArg
(
String
arg
,
boolean
expand
)
{
this
.
arg
=
arg
;
this
.
needsExpansion
=
expand
;
}
// protocol: first char indicates whether expansion is required
// 'T' = true ; needs expansion
// 'F' = false; needs no expansion
StdArg
(
String
in
)
{
this
.
arg
=
in
.
substring
(
1
);
needsExpansion
=
in
.
charAt
(
0
)
==
'T'
;
}
public
String
toString
()
{
return
"StdArg{"
+
"arg="
+
arg
+
", needsExpansion="
+
needsExpansion
+
'}'
;
}
}
}
src/share/classes/sun/launcher/resources/launcher.properties
浏览文件 @
edc21737
...
...
@@ -136,3 +136,4 @@ java.launcher.jar.error1=\
Error: An unexpected error occurred while trying to open file {0}
java.launcher.jar.error2
=
manifest not found in {0}
java.launcher.jar.error3
=
no main manifest attribute, in {0}
java.launcher.init.error
=
initialization error
src/solaris/bin/java_md.c
已删除
100644 → 0
浏览文件 @
175e85db
/*
* Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "java.h"
#include <dirent.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include "manifest_info.h"
#include "version_comp.h"
#ifdef __solaris__
#include <thread.h>
#else
#include <pthread.h>
#endif
#define JVM_DLL "libjvm.so"
#define JAVA_DLL "libjava.so"
/* help jettison the LD_LIBRARY_PATH settings in the future */
#ifndef SETENV_REQUIRED
#define SETENV_REQUIRED
#endif
/*
* If a processor / os combination has the ability to run binaries of
* two data models and cohabitation of jre/jdk bits with both data
* models is supported, then DUAL_MODE is defined. When DUAL_MODE is
* defined, the architecture names for the narrow and wide version of
* the architecture are defined in LIBARCH64NAME and LIBARCH32NAME.
* Currently only Solaris on sparc/sparcv9 and i586/amd64 is DUAL_MODE;
* linux i586/amd64 could be defined as DUAL_MODE but that is not the
* current policy.
*/
#ifdef __solaris__
# define DUAL_MODE
# ifndef LIBARCH32NAME
# error "The macro LIBARCH32NAME was not defined on the compile line"
# endif
# ifndef LIBARCH64NAME
# error "The macro LIBARCH64NAME was not defined on the compile line"
# endif
# include <sys/systeminfo.h>
# include <sys/elf.h>
# include <stdio.h>
#endif
/* pointer to environment */
extern
char
**
environ
;
/*
* A collection of useful strings. One should think of these as #define
* entries, but actual strings can be more efficient (with many compilers).
*/
#ifdef __linux__
static
const
char
*
system_dir
=
"/usr/java"
;
static
const
char
*
user_dir
=
"/java"
;
#else
/* Solaris */
static
const
char
*
system_dir
=
"/usr/jdk"
;
static
const
char
*
user_dir
=
"/jdk"
;
#endif
/* Store the name of the executable once computed */
static
char
*
execname
=
NULL
;
/*
* Flowchart of launcher execs and options processing on unix
*
* The selection of the proper vm shared library to open depends on
* several classes of command line options, including vm "flavor"
* options (-client, -server) and the data model options, -d32 and
* -d64, as well as a version specification which may have come from
* the command line or from the manifest of an executable jar file.
* The vm selection options are not passed to the running
* virtual machine; they must be screened out by the launcher.
*
* The version specification (if any) is processed first by the
* platform independent routine SelectVersion. This may result in
* the exec of the specified launcher version.
*
* Previously the launcher modified the LD_LIBRARY_PATH appropriately for the
* desired data model path, regardless if data models matched or not. The
* launcher subsequently exec'ed the desired executable, in order to make the
* LD_LIBRARY_PATH path available, for the runtime linker.
*
* Now, in most cases,the launcher will dlopen the target libjvm.so. All
* required libraries are loaded by the runtime linker, using the
* $RPATH/$ORIGIN baked into the shared libraries at compile time. Therefore,
* in most cases, the launcher will only exec, if the data models are
* mismatched, and will not set any environment variables, regardless of the
* data models.
*
* However, if the environment contains a LD_LIBRARY_PATH, this will cause the
* launcher to inspect the LD_LIBRARY_PATH. The launcher will check
* a. if the LD_LIBRARY_PATH's first component is the the path to the desired
* libjvm.so
* b. if any other libjvm.so is found in any of the paths.
* If case b is true, then the launcher will set the LD_LIBRARY_PATH to the
* desired JRE and reexec, in order to propagate the environment.
*
* Main
* (incoming argv)
* |
* \|/
* SelectVersion
* (selects the JRE version, note: not data model)
* |
* \|/
* CreateExecutionEnvironment
* (determines desired data model)
* |
* |
* \|/
* Have Desired Model ? --> NO --> Is Dual-Mode ? --> NO --> Exit(with error)
* | |
* | |
* | \|/
* | YES
* | |
* | |
* | \|/
* | CheckJvmType
* | (removes -client, -server etc.)
* | |
* | |
* \|/ \|/
* YES Find the desired executable/library
* | |
* | |
* \|/ \|/
* CheckJvmType RequiresSetenv
* (removes -client, -server, etc.)
* |
* |
* \|/
* TranslateDashJArgs...
* (Prepare to pass args to vm)
* |
* |
* \|/
* ParseArguments
* (removes -d32 and -d64 if any,
* processes version options,
* creates argument list for vm,
* etc.)
* |
* |
* \|/
* RequiresSetenv
* Is LD_LIBRARY_PATH
* and friends set ? --> NO --> Have Desired Model ? NO --> Re-exec --> Main
* YES YES --> Continue
* |
* |
* \|/
* Path is desired JRE ? YES --> Have Desired Model ? NO --> Re-exec --> Main
* NO YES --> Continue
* |
* |
* \|/
* Paths have well known
* jvm paths ? --> NO --> Have Desired Model ? NO --> Re-exec --> Main
* YES YES --> Continue
* |
* |
* \|/
* Does libjvm.so exit
* in any of them ? --> NO --> Have Desired Model ? NO --> Re-exec --> Main
* YES YES --> Continue
* |
* |
* \|/
* Set the LD_LIBRARY_PATH
* |
* |
* \|/
* Re-exec
* |
* |
* \|/
* Main
*/
static
const
char
*
SetExecname
(
char
**
argv
);
static
jboolean
GetJVMPath
(
const
char
*
jrepath
,
const
char
*
jvmtype
,
char
*
jvmpath
,
jint
jvmpathsize
,
const
char
*
arch
);
static
jboolean
GetJREPath
(
char
*
path
,
jint
pathsize
,
const
char
*
arch
,
jboolean
speculative
);
#define GetArch() GetArchPath(CURRENT_DATA_MODEL)
const
char
*
GetArchPath
(
int
nbits
)
{
switch
(
nbits
)
{
#ifdef DUAL_MODE
case
32
:
return
LIBARCH32NAME
;
case
64
:
return
LIBARCH64NAME
;
#endif
/* DUAL_MODE */
default:
return
LIBARCHNAME
;
}
}
#ifdef SETENV_REQUIRED
static
jboolean
JvmExists
(
const
char
*
path
)
{
char
tmp
[
PATH_MAX
+
1
];
struct
stat
statbuf
;
JLI_Snprintf
(
tmp
,
PATH_MAX
,
"%s/%s"
,
path
,
JVM_DLL
);
if
(
stat
(
tmp
,
&
statbuf
)
==
0
)
{
return
JNI_TRUE
;
}
return
JNI_FALSE
;
}
/*
* contains a lib/$LIBARCH/{server,client}/libjvm.so ?
*/
static
jboolean
ContainsLibJVM
(
int
wanted
,
const
char
*
env
)
{
char
clientPattern
[
PATH_MAX
+
1
];
char
serverPattern
[
PATH_MAX
+
1
];
char
*
envpath
;
char
*
path
;
jboolean
clientPatternFound
;
jboolean
serverPatternFound
;
/* fastest path */
if
(
env
==
NULL
)
{
return
JNI_FALSE
;
}
/* the usual suspects */
JLI_Snprintf
(
clientPattern
,
PATH_MAX
,
"lib/%s/client"
,
GetArchPath
(
wanted
));
JLI_Snprintf
(
serverPattern
,
PATH_MAX
,
"lib/%s/server"
,
GetArchPath
(
wanted
));
/* to optimize for time, test if any of our usual suspects are present. */
clientPatternFound
=
JLI_StrStr
(
env
,
clientPattern
)
!=
NULL
;
serverPatternFound
=
JLI_StrStr
(
env
,
serverPattern
)
!=
NULL
;
if
(
clientPatternFound
==
JNI_FALSE
&&
serverPatternFound
==
JNI_FALSE
)
{
return
JNI_FALSE
;
}
/*
* we have a suspicious path component, check if it contains a libjvm.so
*/
envpath
=
JLI_StringDup
(
env
);
for
(
path
=
JLI_StrTok
(
envpath
,
":"
);
path
!=
NULL
;
path
=
JLI_StrTok
(
NULL
,
":"
))
{
if
(
clientPatternFound
&&
JLI_StrStr
(
path
,
clientPattern
)
!=
NULL
)
{
if
(
JvmExists
(
path
))
{
JLI_MemFree
(
envpath
);
return
JNI_TRUE
;
}
}
if
(
serverPatternFound
&&
JLI_StrStr
(
path
,
serverPattern
)
!=
NULL
)
{
if
(
JvmExists
(
path
))
{
JLI_MemFree
(
envpath
);
return
JNI_TRUE
;
}
}
}
JLI_MemFree
(
envpath
);
return
JNI_FALSE
;
}
/*
* Test whether the environment variable needs to be set, see flowchart.
*/
static
jboolean
RequiresSetenv
(
int
wanted
,
const
char
*
jvmpath
)
{
char
jpath
[
PATH_MAX
+
1
];
char
*
llp
;
char
*
dmllp
=
NULL
;
char
*
p
;
/* a utility pointer */
llp
=
getenv
(
"LD_LIBRARY_PATH"
);
#ifdef __solaris__
dmllp
=
(
CURRENT_DATA_MODEL
==
32
)
?
getenv
(
"LD_LIBRARY_PATH_32"
)
:
getenv
(
"LD_LIBRARY_PATH_64"
);
#endif
/* __solaris__ */
/* no environment variable is a good environment variable */
if
(
llp
==
NULL
&&
dmllp
==
NULL
)
{
return
JNI_FALSE
;
}
#ifdef __linux
/*
* On linux, if a binary is running as sgid or suid, glibc sets
* LD_LIBRARY_PATH to the empty string for security purposes. (In contrast,
* on Solaris the LD_LIBRARY_PATH variable for a privileged binary does not
* lose its settings; but the dynamic linker does apply more scrutiny to the
* path.) The launcher uses the value of LD_LIBRARY_PATH to prevent an exec
* loop, here and further downstream. Therefore, if we are running sgid or
* suid, this function's setting of LD_LIBRARY_PATH will be ineffective and
* we should case a return from the calling function. Getting the right
* libraries will be handled by the RPATH. In reality, this check is
* redundant, as the previous check for a non-null LD_LIBRARY_PATH will
* return back to the calling function forthwith, it is left here to safe
* guard against any changes, in the glibc's existing security policy.
*/
if
((
getgid
()
!=
getegid
())
||
(
getuid
()
!=
geteuid
()))
{
return
JNI_FALSE
;
}
#endif
/* __linux */
/*
* Prevent recursions. Since LD_LIBRARY_PATH is the one which will be set by
* previous versions of the JRE, thus it is the only path that matters here.
* So we check to see if the desired JRE is set.
*/
JLI_StrNCpy
(
jpath
,
jvmpath
,
PATH_MAX
);
p
=
JLI_StrRChr
(
jpath
,
'/'
);
*
p
=
'\0'
;
if
(
llp
!=
NULL
&&
JLI_StrNCmp
(
llp
,
jpath
,
JLI_StrLen
(
jpath
))
==
0
)
{
return
JNI_FALSE
;
}
/* scrutinize all the paths further */
if
(
llp
!=
NULL
&&
ContainsLibJVM
(
wanted
,
llp
))
{
return
JNI_TRUE
;
}
if
(
dmllp
!=
NULL
&&
ContainsLibJVM
(
wanted
,
dmllp
))
{
return
JNI_TRUE
;
}
return
JNI_FALSE
;
}
#endif
/* SETENV_REQUIRED */
void
CreateExecutionEnvironment
(
int
*
pargc
,
char
***
pargv
,
char
jrepath
[],
jint
so_jrepath
,
char
jvmpath
[],
jint
so_jvmpath
)
{
/*
* First, determine if we are running the desired data model. If we
* are running the desired data model, all the error messages
* associated with calling GetJREPath, ReadKnownVMs, etc. should be
* output. However, if we are not running the desired data model,
* some of the errors should be suppressed since it is more
* informative to issue an error message based on whether or not the
* os/processor combination has dual mode capabilities.
*/
jboolean
jvmpathExists
;
/* Compute/set the name of the executable */
SetExecname
(
*
pargv
);
/* Check data model flags, and exec process, if needed */
{
char
*
arch
=
(
char
*
)
GetArch
();
/* like sparc or sparcv9 */
char
*
jvmtype
=
NULL
;
int
argc
=
*
pargc
;
char
**
argv
=
*
pargv
;
int
running
=
CURRENT_DATA_MODEL
;
int
wanted
=
running
;
/* What data mode is being
asked for? Current model is
fine unless another model
is asked for */
#ifdef SETENV_REQUIRED
jboolean
mustsetenv
=
JNI_FALSE
;
char
*
runpath
=
NULL
;
/* existing effective LD_LIBRARY_PATH setting */
char
*
new_runpath
=
NULL
;
/* desired new LD_LIBRARY_PATH string */
char
*
newpath
=
NULL
;
/* path on new LD_LIBRARY_PATH */
char
*
lastslash
=
NULL
;
char
**
newenvp
=
NULL
;
/* current environment */
#ifdef __solaris__
char
*
dmpath
=
NULL
;
/* data model specific LD_LIBRARY_PATH,
Solaris only */
#endif
/* __solaris__ */
#endif
/* SETENV_REQUIRED */
char
**
newargv
=
NULL
;
int
newargc
=
0
;
/*
* Starting in 1.5, all unix platforms accept the -d32 and -d64
* options. On platforms where only one data-model is supported
* (e.g. ia-64 Linux), using the flag for the other data model is
* an error and will terminate the program.
*/
{
/* open new scope to declare local variables */
int
i
;
newargv
=
(
char
**
)
JLI_MemAlloc
((
argc
+
1
)
*
sizeof
(
char
*
));
newargv
[
newargc
++
]
=
argv
[
0
];
/* scan for data model arguments and remove from argument list;
last occurrence determines desired data model */
for
(
i
=
1
;
i
<
argc
;
i
++
)
{
if
(
JLI_StrCmp
(
argv
[
i
],
"-J-d64"
)
==
0
||
JLI_StrCmp
(
argv
[
i
],
"-d64"
)
==
0
)
{
wanted
=
64
;
continue
;
}
if
(
JLI_StrCmp
(
argv
[
i
],
"-J-d32"
)
==
0
||
JLI_StrCmp
(
argv
[
i
],
"-d32"
)
==
0
)
{
wanted
=
32
;
continue
;
}
newargv
[
newargc
++
]
=
argv
[
i
];
if
(
IsJavaArgs
())
{
if
(
argv
[
i
][
0
]
!=
'-'
)
continue
;
}
else
{
if
(
JLI_StrCmp
(
argv
[
i
],
"-classpath"
)
==
0
||
JLI_StrCmp
(
argv
[
i
],
"-cp"
)
==
0
)
{
i
++
;
if
(
i
>=
argc
)
break
;
newargv
[
newargc
++
]
=
argv
[
i
];
continue
;
}
if
(
argv
[
i
][
0
]
!=
'-'
)
{
i
++
;
break
;
}
}
}
/* copy rest of args [i .. argc) */
while
(
i
<
argc
)
{
newargv
[
newargc
++
]
=
argv
[
i
++
];
}
newargv
[
newargc
]
=
NULL
;
/*
* newargv has all proper arguments here
*/
argc
=
newargc
;
argv
=
newargv
;
}
/* If the data model is not changing, it is an error if the
jvmpath does not exist */
if
(
wanted
==
running
)
{
/* Find out where the JRE is that we will be using. */
if
(
!
GetJREPath
(
jrepath
,
so_jrepath
,
arch
,
JNI_FALSE
)
)
{
JLI_ReportErrorMessage
(
JRE_ERROR1
);
exit
(
2
);
}
/* Find the specified JVM type */
if
(
ReadKnownVMs
(
jrepath
,
arch
,
JNI_FALSE
)
<
1
)
{
JLI_ReportErrorMessage
(
CFG_ERROR7
);
exit
(
1
);
}
jvmpath
[
0
]
=
'\0'
;
jvmtype
=
CheckJvmType
(
pargc
,
pargv
,
JNI_FALSE
);
if
(
JLI_StrCmp
(
jvmtype
,
"ERROR"
)
==
0
)
{
JLI_ReportErrorMessage
(
CFG_ERROR9
);
exit
(
4
);
}
if
(
!
GetJVMPath
(
jrepath
,
jvmtype
,
jvmpath
,
so_jvmpath
,
arch
))
{
JLI_ReportErrorMessage
(
CFG_ERROR8
,
jvmtype
,
jvmpath
);
exit
(
4
);
}
/*
* we seem to have everything we need, so without further ado
* we return back, otherwise proceed to set the environment.
*/
#ifdef SETENV_REQUIRED
mustsetenv
=
RequiresSetenv
(
wanted
,
jvmpath
);
JLI_TraceLauncher
(
"mustsetenv: %s
\n
"
,
mustsetenv
?
"TRUE"
:
"FALSE"
);
if
(
mustsetenv
==
JNI_FALSE
)
{
return
;
}
#else
return
;
#endif
/* SETENV_REQUIRED */
}
else
{
/* do the same speculatively or exit */
#ifdef DUAL_MODE
if
(
running
!=
wanted
)
{
/* Find out where the JRE is that we will be using. */
if
(
!
GetJREPath
(
jrepath
,
so_jrepath
,
GetArchPath
(
wanted
),
JNI_TRUE
))
{
/* give up and let other code report error message */
JLI_ReportErrorMessage
(
JRE_ERROR2
,
wanted
);
exit
(
1
);
}
/*
* Read in jvm.cfg for target data model and process vm
* selection options.
*/
if
(
ReadKnownVMs
(
jrepath
,
GetArchPath
(
wanted
),
JNI_TRUE
)
<
1
)
{
/* give up and let other code report error message */
JLI_ReportErrorMessage
(
JRE_ERROR2
,
wanted
);
exit
(
1
);
}
jvmpath
[
0
]
=
'\0'
;
jvmtype
=
CheckJvmType
(
pargc
,
pargv
,
JNI_TRUE
);
if
(
JLI_StrCmp
(
jvmtype
,
"ERROR"
)
==
0
)
{
JLI_ReportErrorMessage
(
CFG_ERROR9
);
exit
(
4
);
}
/* exec child can do error checking on the existence of the path */
jvmpathExists
=
GetJVMPath
(
jrepath
,
jvmtype
,
jvmpath
,
so_jvmpath
,
GetArchPath
(
wanted
));
#ifdef SETENV_REQUIRED
mustsetenv
=
RequiresSetenv
(
wanted
,
jvmpath
);
#endif
/* SETENV_REQUIRED */
}
#else
JLI_ReportErrorMessage
(
JRE_ERROR2
,
wanted
);
exit
(
1
);
#endif
}
#ifdef SETENV_REQUIRED
if
(
mustsetenv
)
{
/*
* We will set the LD_LIBRARY_PATH as follows:
*
* o $JVMPATH (directory portion only)
* o $JRE/lib/$LIBARCHNAME
* o $JRE/../lib/$LIBARCHNAME
*
* followed by the user's previous effective LD_LIBRARY_PATH, if
* any.
*/
#ifdef __solaris__
/*
* Starting in Solaris 7, ld.so.1 supports three LD_LIBRARY_PATH
* variables:
*
* 1. LD_LIBRARY_PATH -- used for 32 and 64 bit searches if
* data-model specific variables are not set.
*
* 2. LD_LIBRARY_PATH_64 -- overrides and replaces LD_LIBRARY_PATH
* for 64-bit binaries.
*
* 3. LD_LIBRARY_PATH_32 -- overrides and replaces LD_LIBRARY_PATH
* for 32-bit binaries.
*
* The vm uses LD_LIBRARY_PATH to set the java.library.path system
* property. To shield the vm from the complication of multiple
* LD_LIBRARY_PATH variables, if the appropriate data model
* specific variable is set, we will act as if LD_LIBRARY_PATH had
* the value of the data model specific variant and the data model
* specific variant will be unset. Note that the variable for the
* *wanted* data model must be used (if it is set), not simply the
* current running data model.
*/
switch
(
wanted
)
{
case
0
:
if
(
running
==
32
)
{
dmpath
=
getenv
(
"LD_LIBRARY_PATH_32"
);
wanted
=
32
;
}
else
{
dmpath
=
getenv
(
"LD_LIBRARY_PATH_64"
);
wanted
=
64
;
}
break
;
case
32
:
dmpath
=
getenv
(
"LD_LIBRARY_PATH_32"
);
break
;
case
64
:
dmpath
=
getenv
(
"LD_LIBRARY_PATH_64"
);
break
;
default:
JLI_ReportErrorMessage
(
JRE_ERROR3
,
__LINE__
);
exit
(
1
);
/* unknown value in wanted */
break
;
}
/*
* If dmpath is NULL, the relevant data model specific variable is
* not set and normal LD_LIBRARY_PATH should be used.
*/
if
(
dmpath
==
NULL
)
{
runpath
=
getenv
(
"LD_LIBRARY_PATH"
);
}
else
{
runpath
=
dmpath
;
}
#else
/*
* If not on Solaris, assume only a single LD_LIBRARY_PATH
* variable.
*/
runpath
=
getenv
(
"LD_LIBRARY_PATH"
);
#endif
/* __solaris__ */
/* runpath contains current effective LD_LIBRARY_PATH setting */
jvmpath
=
JLI_StringDup
(
jvmpath
);
new_runpath
=
JLI_MemAlloc
(((
runpath
!=
NULL
)
?
JLI_StrLen
(
runpath
)
:
0
)
+
2
*
JLI_StrLen
(
jrepath
)
+
2
*
JLI_StrLen
(
arch
)
+
JLI_StrLen
(
jvmpath
)
+
52
);
newpath
=
new_runpath
+
JLI_StrLen
(
"LD_LIBRARY_PATH="
);
/*
* Create desired LD_LIBRARY_PATH value for target data model.
*/
{
/* remove the name of the .so from the JVM path */
lastslash
=
JLI_StrRChr
(
jvmpath
,
'/'
);
if
(
lastslash
)
*
lastslash
=
'\0'
;
sprintf
(
new_runpath
,
"LD_LIBRARY_PATH="
"%s:"
"%s/lib/%s:"
"%s/../lib/%s"
,
jvmpath
,
#ifdef DUAL_MODE
jrepath
,
GetArchPath
(
wanted
),
jrepath
,
GetArchPath
(
wanted
)
#else
jrepath
,
arch
,
jrepath
,
arch
#endif
);
/*
* Check to make sure that the prefix of the current path is the
* desired environment variable setting, though the RequiresSetenv
* checks if the desired runpath exists, this logic does a more
* comprehensive check.
*/
if
(
runpath
!=
NULL
&&
JLI_StrNCmp
(
newpath
,
runpath
,
JLI_StrLen
(
newpath
))
==
0
&&
(
runpath
[
JLI_StrLen
(
newpath
)]
==
0
||
runpath
[
JLI_StrLen
(
newpath
)]
==
':'
)
&&
(
running
==
wanted
)
/* data model does not have to be changed */
#ifdef __solaris__
&&
(
dmpath
==
NULL
)
/* data model specific variables not set */
#endif
)
{
return
;
}
}
/*
* Place the desired environment setting onto the prefix of
* LD_LIBRARY_PATH. Note that this prevents any possible infinite
* loop of execv() because we test for the prefix, above.
*/
if
(
runpath
!=
0
)
{
JLI_StrCat
(
new_runpath
,
":"
);
JLI_StrCat
(
new_runpath
,
runpath
);
}
if
(
putenv
(
new_runpath
)
!=
0
)
{
exit
(
1
);
/* problem allocating memory; LD_LIBRARY_PATH not set
properly */
}
/*
* Unix systems document that they look at LD_LIBRARY_PATH only
* once at startup, so we have to re-exec the current executable
* to get the changed environment variable to have an effect.
*/
#ifdef __solaris__
/*
* If dmpath is not NULL, remove the data model specific string
* in the environment for the exec'ed child.
*/
if
(
dmpath
!=
NULL
)
(
void
)
UnsetEnv
((
wanted
==
32
)
?
"LD_LIBRARY_PATH_32"
:
"LD_LIBRARY_PATH_64"
);
#endif
newenvp
=
environ
;
}
#endif
/* SETENV_REQUIRED */
{
char
*
newexec
=
execname
;
#ifdef DUAL_MODE
/*
* If the data model is being changed, the path to the
* executable must be updated accordingly; the executable name
* and directory the executable resides in are separate. In the
* case of 32 => 64, the new bits are assumed to reside in, e.g.
* "olddir/LIBARCH64NAME/execname"; in the case of 64 => 32,
* the bits are assumed to be in "olddir/../execname". For example,
*
* olddir/sparcv9/execname
* olddir/amd64/execname
*
* for Solaris SPARC and Linux amd64, respectively.
*/
if
(
running
!=
wanted
)
{
char
*
oldexec
=
JLI_StrCpy
(
JLI_MemAlloc
(
JLI_StrLen
(
execname
)
+
1
),
execname
);
char
*
olddir
=
oldexec
;
char
*
oldbase
=
JLI_StrRChr
(
oldexec
,
'/'
);
newexec
=
JLI_MemAlloc
(
JLI_StrLen
(
execname
)
+
20
);
*
oldbase
++
=
0
;
sprintf
(
newexec
,
"%s/%s/%s"
,
olddir
,
((
wanted
==
64
)
?
LIBARCH64NAME
:
".."
),
oldbase
);
argv
[
0
]
=
newexec
;
}
#endif
/* DUAL_MODE */
JLI_TraceLauncher
(
"TRACER_MARKER:About to EXEC
\n
"
);
(
void
)
fflush
(
stdout
);
(
void
)
fflush
(
stderr
);
#ifdef SETENV_REQUIRED
if
(
mustsetenv
)
{
execve
(
newexec
,
argv
,
newenvp
);
}
else
{
execv
(
newexec
,
argv
);
}
#else
execv
(
newexec
,
argv
);
#endif
/* SETENV_REQUIRED */
JLI_ReportErrorMessageSys
(
JRE_ERROR4
,
newexec
);
#ifdef DUAL_MODE
if
(
running
!=
wanted
)
{
JLI_ReportErrorMessage
(
JRE_ERROR5
,
wanted
,
running
);
#ifdef __solaris__
#ifdef __sparc
JLI_ReportErrorMessage
(
JRE_ERROR6
);
#else
JLI_ReportErrorMessage
(
JRE_ERROR7
);
#endif
/* __sparc */
}
#endif
/* __solaris__ */
#endif
/* DUAL_MODE */
}
exit
(
1
);
}
}
/*
* On Solaris VM choosing is done by the launcher (java.c).
*/
static
jboolean
GetJVMPath
(
const
char
*
jrepath
,
const
char
*
jvmtype
,
char
*
jvmpath
,
jint
jvmpathsize
,
const
char
*
arch
)
{
struct
stat
s
;
if
(
JLI_StrChr
(
jvmtype
,
'/'
))
{
JLI_Snprintf
(
jvmpath
,
jvmpathsize
,
"%s/"
JVM_DLL
,
jvmtype
);
}
else
{
JLI_Snprintf
(
jvmpath
,
jvmpathsize
,
"%s/lib/%s/%s/"
JVM_DLL
,
jrepath
,
arch
,
jvmtype
);
}
JLI_TraceLauncher
(
"Does `%s' exist ... "
,
jvmpath
);
if
(
stat
(
jvmpath
,
&
s
)
==
0
)
{
JLI_TraceLauncher
(
"yes.
\n
"
);
return
JNI_TRUE
;
}
else
{
JLI_TraceLauncher
(
"no.
\n
"
);
return
JNI_FALSE
;
}
}
/*
* Find path to JRE based on .exe's location or registry settings.
*/
static
jboolean
GetJREPath
(
char
*
path
,
jint
pathsize
,
const
char
*
arch
,
jboolean
speculative
)
{
char
libjava
[
MAXPATHLEN
];
if
(
GetApplicationHome
(
path
,
pathsize
))
{
/* Is JRE co-located with the application? */
JLI_Snprintf
(
libjava
,
sizeof
(
libjava
),
"%s/lib/%s/"
JAVA_DLL
,
path
,
arch
);
if
(
access
(
libjava
,
F_OK
)
==
0
)
{
JLI_TraceLauncher
(
"JRE path is %s
\n
"
,
path
);
return
JNI_TRUE
;
}
/* Does the app ship a private JRE in <apphome>/jre directory? */
JLI_Snprintf
(
libjava
,
sizeof
(
libjava
),
"%s/jre/lib/%s/"
JAVA_DLL
,
path
,
arch
);
if
(
access
(
libjava
,
F_OK
)
==
0
)
{
JLI_StrCat
(
path
,
"/jre"
);
JLI_TraceLauncher
(
"JRE path is %s
\n
"
,
path
);
return
JNI_TRUE
;
}
}
if
(
!
speculative
)
JLI_ReportErrorMessage
(
JRE_ERROR8
JAVA_DLL
);
return
JNI_FALSE
;
}
jboolean
LoadJavaVM
(
const
char
*
jvmpath
,
InvocationFunctions
*
ifn
)
{
void
*
libjvm
;
JLI_TraceLauncher
(
"JVM path is %s
\n
"
,
jvmpath
);
libjvm
=
dlopen
(
jvmpath
,
RTLD_NOW
+
RTLD_GLOBAL
);
if
(
libjvm
==
NULL
)
{
#if defined(__solaris__) && defined(__sparc) && !defined(_LP64)
/* i.e. 32-bit sparc */
FILE
*
fp
;
Elf32_Ehdr
elf_head
;
int
count
;
int
location
;
fp
=
fopen
(
jvmpath
,
"r"
);
if
(
fp
==
NULL
)
{
JLI_ReportErrorMessage
(
DLL_ERROR2
,
jvmpath
,
dlerror
());
return
JNI_FALSE
;
}
/* read in elf header */
count
=
fread
((
void
*
)(
&
elf_head
),
sizeof
(
Elf32_Ehdr
),
1
,
fp
);
fclose
(
fp
);
if
(
count
<
1
)
{
JLI_ReportErrorMessage
(
DLL_ERROR2
,
jvmpath
,
dlerror
());
return
JNI_FALSE
;
}
/*
* Check for running a server vm (compiled with -xarch=v8plus)
* on a stock v8 processor. In this case, the machine type in
* the elf header would not be included the architecture list
* provided by the isalist command, which is turn is gotten from
* sysinfo. This case cannot occur on 64-bit hardware and thus
* does not have to be checked for in binaries with an LP64 data
* model.
*/
if
(
elf_head
.
e_machine
==
EM_SPARC32PLUS
)
{
char
buf
[
257
];
/* recommended buffer size from sysinfo man
page */
long
length
;
char
*
location
;
length
=
sysinfo
(
SI_ISALIST
,
buf
,
257
);
if
(
length
>
0
)
{
location
=
JLI_StrStr
(
buf
,
"sparcv8plus "
);
if
(
location
==
NULL
)
{
JLI_ReportErrorMessage
(
JVM_ERROR3
);
return
JNI_FALSE
;
}
}
}
#endif
JLI_ReportErrorMessage
(
DLL_ERROR1
,
__LINE__
);
JLI_ReportErrorMessage
(
DLL_ERROR2
,
jvmpath
,
dlerror
());
return
JNI_FALSE
;
}
ifn
->
CreateJavaVM
=
(
CreateJavaVM_t
)
dlsym
(
libjvm
,
"JNI_CreateJavaVM"
);
if
(
ifn
->
CreateJavaVM
==
NULL
)
{
JLI_ReportErrorMessage
(
DLL_ERROR2
,
jvmpath
,
dlerror
());
return
JNI_FALSE
;
}
ifn
->
GetDefaultJavaVMInitArgs
=
(
GetDefaultJavaVMInitArgs_t
)
dlsym
(
libjvm
,
"JNI_GetDefaultJavaVMInitArgs"
);
if
(
ifn
->
GetDefaultJavaVMInitArgs
==
NULL
)
{
JLI_ReportErrorMessage
(
DLL_ERROR2
,
jvmpath
,
dlerror
());
return
JNI_FALSE
;
}
return
JNI_TRUE
;
}
/*
* If app is "/foo/bin/javac", or "/foo/bin/sparcv9/javac" then put
* "/foo" into buf.
*/
jboolean
GetApplicationHome
(
char
*
buf
,
jint
bufsize
)
{
if
(
execname
!=
NULL
)
{
JLI_Snprintf
(
buf
,
bufsize
,
"%s"
,
execname
);
buf
[
bufsize
-
1
]
=
'\0'
;
}
else
{
return
JNI_FALSE
;
}
if
(
JLI_StrRChr
(
buf
,
'/'
)
==
0
)
{
buf
[
0
]
=
'\0'
;
return
JNI_FALSE
;
}
*
(
JLI_StrRChr
(
buf
,
'/'
))
=
'\0'
;
/* executable file */
if
(
JLI_StrLen
(
buf
)
<
4
||
JLI_StrRChr
(
buf
,
'/'
)
==
0
)
{
buf
[
0
]
=
'\0'
;
return
JNI_FALSE
;
}
if
(
JLI_StrCmp
(
"/bin"
,
buf
+
JLI_StrLen
(
buf
)
-
4
)
!=
0
)
*
(
JLI_StrRChr
(
buf
,
'/'
))
=
'\0'
;
/* sparcv9 or amd64 */
if
(
JLI_StrLen
(
buf
)
<
4
||
JLI_StrCmp
(
"/bin"
,
buf
+
JLI_StrLen
(
buf
)
-
4
)
!=
0
)
{
buf
[
0
]
=
'\0'
;
return
JNI_FALSE
;
}
*
(
JLI_StrRChr
(
buf
,
'/'
))
=
'\0'
;
/* bin */
return
JNI_TRUE
;
}
/*
* Return true if the named program exists
*/
static
int
ProgramExists
(
char
*
name
)
{
struct
stat
sb
;
if
(
stat
(
name
,
&
sb
)
!=
0
)
return
0
;
if
(
S_ISDIR
(
sb
.
st_mode
))
return
0
;
return
(
sb
.
st_mode
&
S_IEXEC
)
!=
0
;
}
/*
* Find a command in a directory, returning the path.
*/
static
char
*
Resolve
(
char
*
indir
,
char
*
cmd
)
{
char
name
[
PATH_MAX
+
2
],
*
real
;
if
((
JLI_StrLen
(
indir
)
+
JLI_StrLen
(
cmd
)
+
1
)
>
PATH_MAX
)
return
0
;
JLI_Snprintf
(
name
,
sizeof
(
name
),
"%s%c%s"
,
indir
,
FILE_SEPARATOR
,
cmd
);
if
(
!
ProgramExists
(
name
))
return
0
;
real
=
JLI_MemAlloc
(
PATH_MAX
+
2
);
if
(
!
realpath
(
name
,
real
))
JLI_StrCpy
(
real
,
name
);
return
real
;
}
/*
* Find a path for the executable
*/
static
char
*
FindExecName
(
char
*
program
)
{
char
cwdbuf
[
PATH_MAX
+
2
];
char
*
path
;
char
*
tmp_path
;
char
*
f
;
char
*
result
=
NULL
;
/* absolute path? */
if
(
*
program
==
FILE_SEPARATOR
||
(
FILE_SEPARATOR
==
'\\'
&&
JLI_StrRChr
(
program
,
':'
)))
return
Resolve
(
""
,
program
+
1
);
/* relative path? */
if
(
JLI_StrRChr
(
program
,
FILE_SEPARATOR
)
!=
0
)
{
char
buf
[
PATH_MAX
+
2
];
return
Resolve
(
getcwd
(
cwdbuf
,
sizeof
(
cwdbuf
)),
program
);
}
/* from search path? */
path
=
getenv
(
"PATH"
);
if
(
!
path
||
!*
path
)
path
=
"."
;
tmp_path
=
JLI_MemAlloc
(
JLI_StrLen
(
path
)
+
2
);
JLI_StrCpy
(
tmp_path
,
path
);
for
(
f
=
tmp_path
;
*
f
&&
result
==
0
;
)
{
char
*
s
=
f
;
while
(
*
f
&&
(
*
f
!=
PATH_SEPARATOR
))
++
f
;
if
(
*
f
)
*
f
++
=
0
;
if
(
*
s
==
FILE_SEPARATOR
)
result
=
Resolve
(
s
,
program
);
else
{
/* relative path element */
char
dir
[
2
*
PATH_MAX
];
JLI_Snprintf
(
dir
,
sizeof
(
dir
),
"%s%c%s"
,
getcwd
(
cwdbuf
,
sizeof
(
cwdbuf
)),
FILE_SEPARATOR
,
s
);
result
=
Resolve
(
dir
,
program
);
}
if
(
result
!=
0
)
break
;
}
JLI_MemFree
(
tmp_path
);
return
result
;
}
/*
* Compute the name of the executable
*
* In order to re-exec securely we need the absolute path of the
* executable. On Solaris getexecname(3c) may not return an absolute
* path so we use dladdr to get the filename of the executable and
* then use realpath to derive an absolute path. From Solaris 9
* onwards the filename returned in DL_info structure from dladdr is
* an absolute pathname so technically realpath isn't required.
* On Linux we read the executable name from /proc/self/exe.
* As a fallback, and for platforms other than Solaris and Linux,
* we use FindExecName to compute the executable name.
*/
static
const
char
*
SetExecname
(
char
**
argv
)
{
char
*
exec_path
=
NULL
;
#if defined(__solaris__)
{
Dl_info
dlinfo
;
int
(
*
fptr
)();
fptr
=
(
int
(
*
)())
dlsym
(
RTLD_DEFAULT
,
"main"
);
if
(
fptr
==
NULL
)
{
JLI_ReportErrorMessage
(
DLL_ERROR3
,
dlerror
());
return
JNI_FALSE
;
}
if
(
dladdr
((
void
*
)
fptr
,
&
dlinfo
))
{
char
*
resolved
=
(
char
*
)
JLI_MemAlloc
(
PATH_MAX
+
1
);
if
(
resolved
!=
NULL
)
{
exec_path
=
realpath
(
dlinfo
.
dli_fname
,
resolved
);
if
(
exec_path
==
NULL
)
{
JLI_MemFree
(
resolved
);
}
}
}
}
#elif defined(__linux__)
{
const
char
*
self
=
"/proc/self/exe"
;
char
buf
[
PATH_MAX
+
1
];
int
len
=
readlink
(
self
,
buf
,
PATH_MAX
);
if
(
len
>=
0
)
{
buf
[
len
]
=
'\0'
;
/* readlink doesn't nul terminate */
exec_path
=
JLI_StringDup
(
buf
);
}
}
#else
/* !__solaris__ && !__linux */
{
/* Not implemented */
}
#endif
if
(
exec_path
==
NULL
)
{
exec_path
=
FindExecName
(
argv
[
0
]);
}
execname
=
exec_path
;
return
exec_path
;
}
void
JLI_ReportErrorMessage
(
const
char
*
fmt
,
...)
{
va_list
vl
;
va_start
(
vl
,
fmt
);
vfprintf
(
stderr
,
fmt
,
vl
);
fprintf
(
stderr
,
"
\n
"
);
va_end
(
vl
);
}
void
JLI_ReportErrorMessageSys
(
const
char
*
fmt
,
...)
{
va_list
vl
;
char
*
emsg
;
/*
* TODO: its safer to use strerror_r but is not available on
* Solaris 8. Until then....
*/
emsg
=
strerror
(
errno
);
if
(
emsg
!=
NULL
)
{
fprintf
(
stderr
,
"%s
\n
"
,
emsg
);
}
va_start
(
vl
,
fmt
);
vfprintf
(
stderr
,
fmt
,
vl
);
fprintf
(
stderr
,
"
\n
"
);
va_end
(
vl
);
}
void
JLI_ReportExceptionDescription
(
JNIEnv
*
env
)
{
(
*
env
)
->
ExceptionDescribe
(
env
);
}
/*
* Since using the file system as a registry is a bit risky, perform
* additional sanity checks on the identified directory to validate
* it as a valid jre/sdk.
*
* Return 0 if the tests fail; otherwise return non-zero (true).
*
* Note that checking for anything more than the existence of an
* executable object at bin/java relative to the path being checked
* will break the regression tests.
*/
static
int
CheckSanity
(
char
*
path
,
char
*
dir
)
{
char
buffer
[
PATH_MAX
];
if
(
JLI_StrLen
(
path
)
+
JLI_StrLen
(
dir
)
+
11
>
PATH_MAX
)
return
(
0
);
/* Silently reject "impossibly" long paths */
JLI_Snprintf
(
buffer
,
sizeof
(
buffer
),
"%s/%s/bin/java"
,
path
,
dir
);
return
((
access
(
buffer
,
X_OK
)
==
0
)
?
1
:
0
);
}
/*
* Determine if there is an acceptable JRE in the directory dirname.
* Upon locating the "best" one, return a fully qualified path to
* it. "Best" is defined as the most advanced JRE meeting the
* constraints contained in the manifest_info. If no JRE in this
* directory meets the constraints, return NULL.
*
* Note that we don't check for errors in reading the directory
* (which would be done by checking errno). This is because it
* doesn't matter if we get an error reading the directory, or
* we just don't find anything interesting in the directory. We
* just return NULL in either case.
*
* The historical names of j2sdk and j2re were changed to jdk and
* jre respecively as part of the 1.5 rebranding effort. Since the
* former names are legacy on Linux, they must be recognized for
* all time. Fortunately, this is a minor cost.
*/
static
char
*
ProcessDir
(
manifest_info
*
info
,
char
*
dirname
)
{
DIR
*
dirp
;
struct
dirent
*
dp
;
char
*
best
=
NULL
;
int
offset
;
int
best_offset
=
0
;
char
*
ret_str
=
NULL
;
char
buffer
[
PATH_MAX
];
if
((
dirp
=
opendir
(
dirname
))
==
NULL
)
return
(
NULL
);
do
{
if
((
dp
=
readdir
(
dirp
))
!=
NULL
)
{
offset
=
0
;
if
((
JLI_StrNCmp
(
dp
->
d_name
,
"jre"
,
3
)
==
0
)
||
(
JLI_StrNCmp
(
dp
->
d_name
,
"jdk"
,
3
)
==
0
))
offset
=
3
;
else
if
(
JLI_StrNCmp
(
dp
->
d_name
,
"j2re"
,
4
)
==
0
)
offset
=
4
;
else
if
(
JLI_StrNCmp
(
dp
->
d_name
,
"j2sdk"
,
5
)
==
0
)
offset
=
5
;
if
(
offset
>
0
)
{
if
((
JLI_AcceptableRelease
(
dp
->
d_name
+
offset
,
info
->
jre_version
))
&&
CheckSanity
(
dirname
,
dp
->
d_name
))
if
((
best
==
NULL
)
||
(
JLI_ExactVersionId
(
dp
->
d_name
+
offset
,
best
+
best_offset
)
>
0
))
{
if
(
best
!=
NULL
)
JLI_MemFree
(
best
);
best
=
JLI_StringDup
(
dp
->
d_name
);
best_offset
=
offset
;
}
}
}
}
while
(
dp
!=
NULL
);
(
void
)
closedir
(
dirp
);
if
(
best
==
NULL
)
return
(
NULL
);
else
{
ret_str
=
JLI_MemAlloc
(
JLI_StrLen
(
dirname
)
+
JLI_StrLen
(
best
)
+
2
);
sprintf
(
ret_str
,
"%s/%s"
,
dirname
,
best
);
JLI_MemFree
(
best
);
return
(
ret_str
);
}
}
/*
* This is the global entry point. It examines the host for the optimal
* JRE to be used by scanning a set of directories. The set of directories
* is platform dependent and can be overridden by the environment
* variable JAVA_VERSION_PATH.
*
* This routine itself simply determines the set of appropriate
* directories before passing control onto ProcessDir().
*/
char
*
LocateJRE
(
manifest_info
*
info
)
{
char
*
path
;
char
*
home
;
char
*
target
=
NULL
;
char
*
dp
;
char
*
cp
;
/*
* Start by getting JAVA_VERSION_PATH
*/
if
(
info
->
jre_restrict_search
)
{
path
=
JLI_StringDup
(
system_dir
);
}
else
if
((
path
=
getenv
(
"JAVA_VERSION_PATH"
))
!=
NULL
)
{
path
=
JLI_StringDup
(
path
);
}
else
{
if
((
home
=
getenv
(
"HOME"
))
!=
NULL
)
{
path
=
(
char
*
)
JLI_MemAlloc
(
JLI_StrLen
(
home
)
+
\
JLI_StrLen
(
system_dir
)
+
JLI_StrLen
(
user_dir
)
+
2
);
sprintf
(
path
,
"%s%s:%s"
,
home
,
user_dir
,
system_dir
);
}
else
{
path
=
JLI_StringDup
(
system_dir
);
}
}
/*
* Step through each directory on the path. Terminate the scan with
* the first directory with an acceptable JRE.
*/
cp
=
dp
=
path
;
while
(
dp
!=
NULL
)
{
cp
=
JLI_StrChr
(
dp
,
(
int
)
':'
);
if
(
cp
!=
NULL
)
*
cp
=
'\0'
;
if
((
target
=
ProcessDir
(
info
,
dp
))
!=
NULL
)
break
;
dp
=
cp
;
if
(
dp
!=
NULL
)
dp
++
;
}
JLI_MemFree
(
path
);
return
(
target
);
}
/*
* Given a path to a jre to execute, this routine checks if this process
* is indeed that jre. If not, it exec's that jre.
*
* We want to actually check the paths rather than just the version string
* built into the executable, so that given version specification (and
* JAVA_VERSION_PATH) will yield the exact same Java environment, regardless
* of the version of the arbitrary launcher we start with.
*/
void
ExecJRE
(
char
*
jre
,
char
**
argv
)
{
char
wanted
[
PATH_MAX
];
const
char
*
progname
=
GetProgramName
();
/*
* Resolve the real path to the directory containing the selected JRE.
*/
if
(
realpath
(
jre
,
wanted
)
==
NULL
)
{
JLI_ReportErrorMessage
(
JRE_ERROR9
,
jre
);
exit
(
1
);
}
/*
* Resolve the real path to the currently running launcher.
*/
SetExecname
(
argv
);
if
(
execname
==
NULL
)
{
JLI_ReportErrorMessage
(
JRE_ERROR10
);
exit
(
1
);
}
/*
* If the path to the selected JRE directory is a match to the initial
* portion of the path to the currently executing JRE, we have a winner!
* If so, just return.
*/
if
(
JLI_StrNCmp
(
wanted
,
execname
,
JLI_StrLen
(
wanted
))
==
0
)
return
;
/* I am the droid you were looking for */
/*
* This should never happen (because of the selection code in SelectJRE),
* but check for "impossibly" long path names just because buffer overruns
* can be so deadly.
*/
if
(
JLI_StrLen
(
wanted
)
+
JLI_StrLen
(
progname
)
+
6
>
PATH_MAX
)
{
JLI_ReportErrorMessage
(
JRE_ERROR11
);
exit
(
1
);
}
/*
* Construct the path and exec it.
*/
(
void
)
JLI_StrCat
(
JLI_StrCat
(
wanted
,
"/bin/"
),
progname
);
argv
[
0
]
=
JLI_StringDup
(
progname
);
if
(
JLI_IsTraceLauncher
())
{
int
i
;
printf
(
"ReExec Command: %s (%s)
\n
"
,
wanted
,
argv
[
0
]);
printf
(
"ReExec Args:"
);
for
(
i
=
1
;
argv
[
i
]
!=
NULL
;
i
++
)
printf
(
" %s"
,
argv
[
i
]);
printf
(
"
\n
"
);
}
JLI_TraceLauncher
(
"TRACER_MARKER:About to EXEC
\n
"
);
(
void
)
fflush
(
stdout
);
(
void
)
fflush
(
stderr
);
execv
(
wanted
,
argv
);
JLI_ReportErrorMessageSys
(
JRE_ERROR12
,
wanted
);
exit
(
1
);
}
/*
* "Borrowed" from Solaris 10 where the unsetenv() function is being added
* to libc thanks to SUSv3 (Standard Unix Specification, version 3). As
* such, in the fullness of time this will appear in libc on all relevant
* Solaris/Linux platforms and maybe even the Windows platform. At that
* time, this stub can be removed.
*
* This implementation removes the environment locking for multithreaded
* applications. (We don't have access to these mutexes within libc and
* the launcher isn't multithreaded.) Note that what remains is platform
* independent, because it only relies on attributes that a POSIX environment
* defines.
*
* Returns 0 on success, -1 on failure.
*
* Also removed was the setting of errno. The only value of errno set
* was EINVAL ("Invalid Argument").
*/
/*
* s1(environ) is name=value
* s2(name) is name(not the form of name=value).
* if names match, return value of 1, else return 0
*/
static
int
match_noeq
(
const
char
*
s1
,
const
char
*
s2
)
{
while
(
*
s1
==
*
s2
++
)
{
if
(
*
s1
++
==
'='
)
return
(
1
);
}
if
(
*
s1
==
'='
&&
s2
[
-
1
]
==
'\0'
)
return
(
1
);
return
(
0
);
}
/*
* added for SUSv3 standard
*
* Delete entry from environ.
* Do not free() memory! Other threads may be using it.
* Keep it around forever.
*/
static
int
borrowed_unsetenv
(
const
char
*
name
)
{
long
idx
;
/* index into environ */
if
(
name
==
NULL
||
*
name
==
'\0'
||
JLI_StrChr
(
name
,
'='
)
!=
NULL
)
{
return
(
-
1
);
}
for
(
idx
=
0
;
environ
[
idx
]
!=
NULL
;
idx
++
)
{
if
(
match_noeq
(
environ
[
idx
],
name
))
break
;
}
if
(
environ
[
idx
]
==
NULL
)
{
/* name not found but still a success */
return
(
0
);
}
/* squeeze up one entry */
do
{
environ
[
idx
]
=
environ
[
idx
+
1
];
}
while
(
environ
[
++
idx
]
!=
NULL
);
return
(
0
);
}
/* --- End of "borrowed" code --- */
/*
* Wrapper for unsetenv() function.
*/
int
UnsetEnv
(
char
*
name
)
{
return
(
borrowed_unsetenv
(
name
));
}
/* --- Splash Screen shared library support --- */
static
const
char
*
SPLASHSCREEN_SO
=
"libsplashscreen.so"
;
static
void
*
hSplashLib
=
NULL
;
void
*
SplashProcAddress
(
const
char
*
name
)
{
if
(
!
hSplashLib
)
{
hSplashLib
=
dlopen
(
SPLASHSCREEN_SO
,
RTLD_LAZY
|
RTLD_GLOBAL
);
}
if
(
hSplashLib
)
{
void
*
sym
=
dlsym
(
hSplashLib
,
name
);
return
sym
;
}
else
{
return
NULL
;
}
}
void
SplashFreeLibrary
()
{
if
(
hSplashLib
)
{
dlclose
(
hSplashLib
);
hSplashLib
=
NULL
;
}
}
const
char
*
jlong_format_specifier
()
{
return
"%lld"
;
}
/*
* Block current thread and continue execution in a new thread
*/
int
ContinueInNewThread0
(
int
(
JNICALL
*
continuation
)(
void
*
),
jlong
stack_size
,
void
*
args
)
{
int
rslt
;
#ifdef __solaris__
thread_t
tid
;
long
flags
=
0
;
if
(
thr_create
(
NULL
,
stack_size
,
(
void
*
(
*
)(
void
*
))
continuation
,
args
,
flags
,
&
tid
)
==
0
)
{
void
*
tmp
;
thr_join
(
tid
,
NULL
,
&
tmp
);
rslt
=
(
int
)
tmp
;
}
else
{
/* See below. Continue in current thread if thr_create() failed */
rslt
=
continuation
(
args
);
}
#else
pthread_t
tid
;
pthread_attr_t
attr
;
pthread_attr_init
(
&
attr
);
pthread_attr_setdetachstate
(
&
attr
,
PTHREAD_CREATE_JOINABLE
);
if
(
stack_size
>
0
)
{
pthread_attr_setstacksize
(
&
attr
,
stack_size
);
}
if
(
pthread_create
(
&
tid
,
&
attr
,
(
void
*
(
*
)(
void
*
))
continuation
,
(
void
*
)
args
)
==
0
)
{
void
*
tmp
;
pthread_join
(
tid
,
&
tmp
);
rslt
=
(
int
)
tmp
;
}
else
{
/*
* Continue execution in current thread if for some reason (e.g. out of
* memory/LWP) a new thread can't be created. This will likely fail
* later in continuation as JNI_CreateJavaVM needs to create quite a
* few new threads, anyway, just give it a try..
*/
rslt
=
continuation
(
args
);
}
pthread_attr_destroy
(
&
attr
);
#endif
return
rslt
;
}
/* Coarse estimation of number of digits assuming the worst case is a 64-bit pid. */
#define MAX_PID_STR_SZ 20
void
SetJavaLauncherPlatformProps
()
{
/* Linux only */
#ifdef __linux__
const
char
*
substr
=
"-Dsun.java.launcher.pid="
;
char
*
pid_prop_str
=
(
char
*
)
JLI_MemAlloc
(
JLI_StrLen
(
substr
)
+
MAX_PID_STR_SZ
+
1
);
sprintf
(
pid_prop_str
,
"%s%d"
,
substr
,
getpid
());
AddOption
(
pid_prop_str
,
NULL
);
#endif
}
jboolean
IsJavaw
()
{
/* noop on UNIX */
return
JNI_FALSE
;
}
void
InitLauncher
(
jboolean
javaw
)
{
JLI_SetTraceLauncher
();
}
/*
* The implementation for finding classes from the bootstrap
* class loader, refer to java.h
*/
static
FindClassFromBootLoader_t
*
findBootClass
=
NULL
;
jclass
FindBootStrapClass
(
JNIEnv
*
env
,
const
char
*
classname
)
{
if
(
findBootClass
==
NULL
)
{
findBootClass
=
(
FindClassFromBootLoader_t
*
)
dlsym
(
RTLD_DEFAULT
,
"JVM_FindClassFromBootLoader"
);
if
(
findBootClass
==
NULL
)
{
JLI_ReportErrorMessage
(
DLL_ERROR4
,
"JVM_FindClassFromBootLoader"
);
return
NULL
;
}
}
return
findBootClass
(
env
,
classname
);
}
src/solaris/bin/java_md_common.c
浏览文件 @
edc21737
...
...
@@ -502,3 +502,19 @@ FindBootStrapClass(JNIEnv *env, const char* classname)
return
findBootClass
(
env
,
classname
);
}
StdArg
*
JLI_GetStdArgs
()
{
return
NULL
;
}
int
JLI_GetStdArgc
()
{
return
0
;
}
jobjectArray
CreateApplicationArgs
(
JNIEnv
*
env
,
char
**
strv
,
int
argc
)
{
return
NewPlatformStringArray
(
env
,
strv
,
argc
);
}
src/windows/bin/java_md.c
浏览文件 @
edc21737
...
...
@@ -1357,3 +1357,89 @@ ProcessPlatformOption(const char *arg)
{
return
JNI_FALSE
;
}
/*
* At this point we have the arguments to the application, and we need to
* check with original stdargs in order to compare which of these truly
* needs expansion. cmdtoargs will specify this if it finds a bare
* (unquoted) argument containing a glob character(s) ie. * or ?
*/
jobjectArray
CreateApplicationArgs
(
JNIEnv
*
env
,
char
**
strv
,
int
argc
)
{
int
i
,
j
,
idx
,
tlen
;
jobjectArray
outArray
,
inArray
;
char
*
ostart
,
*
astart
,
**
nargv
;
jboolean
needs_expansion
=
JNI_FALSE
;
jmethodID
mid
;
int
stdargc
;
StdArg
*
stdargs
;
jclass
cls
=
GetLauncherHelperClass
(
env
);
NULL_CHECK0
(
cls
);
if
(
argc
==
0
)
{
return
NewPlatformStringArray
(
env
,
strv
,
argc
);
}
// the holy grail we need to compare with.
stdargs
=
JLI_GetStdArgs
();
stdargc
=
JLI_GetStdArgc
();
// sanity check, this should never happen
if
(
argc
>
stdargc
)
{
JLI_TraceLauncher
(
"Warning: app args is larger than the original, %d %d
\n
"
,
argc
,
stdargc
);
JLI_TraceLauncher
(
"passing arguments as-is.
\n
"
);
return
NewPlatformStringArray
(
env
,
strv
,
argc
);
}
// sanity check, match the args we have, to the holy grail
idx
=
stdargc
-
argc
;
ostart
=
stdargs
[
idx
].
arg
;
astart
=
strv
[
0
];
// sanity check, ensure that the first argument of the arrays are the same
if
(
JLI_StrCmp
(
ostart
,
astart
)
!=
0
)
{
// some thing is amiss the args don't match
JLI_TraceLauncher
(
"Warning: app args parsing error
\n
"
);
JLI_TraceLauncher
(
"passing arguments as-is
\n
"
);
return
NewPlatformStringArray
(
env
,
strv
,
argc
);
}
// make a copy of the args which will be expanded in java if required.
nargv
=
(
char
**
)
JLI_MemAlloc
(
argc
*
sizeof
(
char
*
));
for
(
i
=
0
,
j
=
idx
;
i
<
argc
;
i
++
,
j
++
)
{
jboolean
arg_expand
=
(
JLI_StrCmp
(
stdargs
[
j
].
arg
,
strv
[
i
])
==
0
)
?
stdargs
[
j
].
has_wildcard
:
JNI_FALSE
;
if
(
needs_expansion
==
JNI_FALSE
)
needs_expansion
=
arg_expand
;
// indicator char + String + NULL terminator, the java method will strip
// out the first character, the indicator character, so no matter what
// we add the indicator
tlen
=
1
+
JLI_StrLen
(
strv
[
i
])
+
1
;
nargv
[
i
]
=
(
char
*
)
JLI_MemAlloc
(
tlen
);
JLI_Snprintf
(
nargv
[
i
],
tlen
,
"%c%s"
,
arg_expand
?
'T'
:
'F'
,
strv
[
i
]);
JLI_TraceLauncher
(
"%s
\n
"
,
nargv
[
i
]);
}
if
(
!
needs_expansion
)
{
// clean up any allocated memory and return back the old arguments
for
(
i
=
0
;
i
<
argc
;
i
++
)
{
JLI_MemFree
(
nargv
[
i
]);
}
JLI_MemFree
(
nargv
);
return
NewPlatformStringArray
(
env
,
strv
,
argc
);
}
NULL_CHECK0
(
mid
=
(
*
env
)
->
GetStaticMethodID
(
env
,
cls
,
"expandArgs"
,
"([Ljava/lang/String;)[Ljava/lang/String;"
));
// expand the arguments that require expansion, the java method will strip
// out the indicator character.
inArray
=
NewPlatformStringArray
(
env
,
nargv
,
argc
);
outArray
=
(
*
env
)
->
CallStaticObjectMethod
(
env
,
cls
,
mid
,
inArray
);
for
(
i
=
0
;
i
<
argc
;
i
++
)
{
JLI_MemFree
(
nargv
[
i
]);
}
JLI_MemFree
(
nargv
);
return
outArray
;
}
test/tools/launcher/Arrrghs.java
浏览文件 @
edc21737
...
...
@@ -36,7 +36,13 @@ import java.io.FileNotFoundException;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InputStreamReader
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
public
class
Arrrghs
extends
TestHelper
{
private
Arrrghs
(){}
...
...
@@ -75,7 +81,7 @@ public class Arrrghs extends TestHelper {
/*
* This method detects the cookie in the output stream of the process.
*/
private
static
boolean
detectCookie
(
InputStream
istream
,
private
boolean
detectCookie
(
InputStream
istream
,
String
expectedArguments
)
throws
IOException
{
BufferedReader
rd
=
new
BufferedReader
(
new
InputStreamReader
(
istream
));
boolean
retval
=
false
;
...
...
@@ -105,7 +111,7 @@ public class Arrrghs extends TestHelper {
return
retval
;
}
private
static
boolean
do
Test0
(
ProcessBuilder
pb
,
String
expectedArguments
)
{
private
boolean
doReExec
Test0
(
ProcessBuilder
pb
,
String
expectedArguments
)
{
boolean
retval
=
false
;
try
{
pb
.
redirectErrorStream
(
true
);
...
...
@@ -121,26 +127,27 @@ public class Arrrghs extends TestHelper {
}
/**
* This method return true if the expected and detected arguments are the same.
* This method return
s
true if the expected and detected arguments are the same.
* Quoting could cause dissimilar testArguments and expected arguments.
*/
static
int
do
Test
(
String
testArguments
,
String
expectedPattern
)
{
int
doReExec
Test
(
String
testArguments
,
String
expectedPattern
)
{
ProcessBuilder
pb
=
new
ProcessBuilder
(
javaCmd
,
VersionStr
,
testArguments
);
Map
<
String
,
String
>
env
=
pb
.
environment
();
env
.
put
(
"_JAVA_LAUNCHER_DEBUG"
,
"true"
);
return
doTest0
(
pb
,
testArguments
)
?
0
:
1
;
env
.
put
(
JLDEBUG_KEY
,
"true"
);
return
do
ReExec
Test0
(
pb
,
testArguments
)
?
0
:
1
;
}
/**
* A convenience method for identical test pattern and expected arguments
*/
static
int
do
Test
(
String
testPattern
)
{
return
doTest
(
testPattern
,
testPattern
);
int
doReExec
Test
(
String
testPattern
)
{
return
do
ReExec
Test
(
testPattern
,
testPattern
);
}
static
void
quoteParsingTests
()
{
@Test
void
testQuoteParsingThroughReExec
()
{
/*
* Tests for 6214916
* These tests require that a JVM (any JVM) be installed in the system registry.
...
...
@@ -154,74 +161,400 @@ public class Arrrghs extends TestHelper {
}
// Basic test
testExitValue
+=
doTest
(
"-a -b -c -d"
);
testExitValue
+=
do
ReExec
Test
(
"-a -b -c -d"
);
// Basic test with many spaces
testExitValue
+=
doTest
(
"-a -b -c -d"
);
testExitValue
+=
do
ReExec
Test
(
"-a -b -c -d"
);
// Quoted whitespace does matter ?
testExitValue
+=
doTest
(
"-a \"\"-b -c\"\" -d"
);
testExitValue
+=
do
ReExec
Test
(
"-a \"\"-b -c\"\" -d"
);
// Escaped quotes outside of quotes as literals
testExitValue
+=
doTest
(
"-a \\\"-b -c\\\" -d"
);
testExitValue
+=
do
ReExec
Test
(
"-a \\\"-b -c\\\" -d"
);
// Check for escaped quotes inside of quotes as literal
testExitValue
+=
doTest
(
"-a \"-b \\\"stuff\\\"\" -c -d"
);
testExitValue
+=
do
ReExec
Test
(
"-a \"-b \\\"stuff\\\"\" -c -d"
);
// A quote preceeded by an odd number of slashes is a literal quote
testExitValue
+=
doTest
(
"-a -b\\\\\\\" -c -d"
);
testExitValue
+=
do
ReExec
Test
(
"-a -b\\\\\\\" -c -d"
);
// A quote preceeded by an even number of slashes is a literal quote
// see 6214916.
testExitValue
+=
doTest
(
"-a -b\\\\\\\\\" -c -d"
);
testExitValue
+=
do
ReExec
Test
(
"-a -b\\\\\\\\\" -c -d"
);
// Make sure that whitespace doesn't interfere with the removal of the
// appropriate tokens. (space-tab-space preceeds -jre-restict-search).
testExitValue
+=
do
Test
(
"-a -b \t -jre-restrict-search -c -d"
,
"-a -b -c -d"
);
testExitValue
+=
do
ReExecTest
(
"-a -b \t -jre-restrict-search -c -d"
,
"-a -b -c -d"
);
// Make sure that the mJRE tokens being stripped, aren't stripped if
// they happen to appear as arguments to the main class.
testExitValue
+=
doTest
(
"foo -version:1.1+"
);
testExitValue
+=
do
ReExec
Test
(
"foo -version:1.1+"
);
System
.
out
.
println
(
"Completed arguments quoting tests with "
+
testExitValue
+
" errors"
);
System
.
out
.
println
(
"Completed arguments quoting tests with "
+
testExitValue
+
" errors"
);
}
// the pattern we hope to see in the output
static
final
Pattern
ArgPattern
=
Pattern
.
compile
(
"\\s*argv\\[[0-9]*\\].*=.*"
);
void
checkArgumentParsing
(
String
inArgs
,
String
...
expArgs
)
throws
IOException
{
List
<
String
>
scratchpad
=
new
ArrayList
<>();
scratchpad
.
add
(
"set "
+
JLDEBUG_KEY
+
"=true"
);
// GAK, -version needs to be added so that windows can flush its stderr
// exiting the process prematurely can terminate the stderr.
scratchpad
.
add
(
javaCmd
+
" -version "
+
inArgs
);
File
batFile
=
new
File
(
"atest.bat"
);
java
.
nio
.
file
.
Files
.
deleteIfExists
(
batFile
.
toPath
());
createFile
(
batFile
,
scratchpad
);
TestResult
tr
=
doExec
(
batFile
.
getName
());
ArrayList
<
String
>
expList
=
new
ArrayList
<>();
expList
.
add
(
javaCmd
);
expList
.
add
(
"-version"
);
expList
.
addAll
(
Arrays
.
asList
(
expArgs
));
List
<
String
>
gotList
=
new
ArrayList
<>();
for
(
String
x
:
tr
.
testOutput
)
{
Matcher
m
=
ArgPattern
.
matcher
(
x
);
if
(
m
.
matches
())
{
String
a
[]
=
x
.
split
(
"="
);
gotList
.
add
(
a
[
a
.
length
-
1
].
trim
());
}
}
if
(!
gotList
.
equals
(
expList
))
{
System
.
out
.
println
(
tr
);
System
.
out
.
println
(
"Expected args:"
);
System
.
out
.
println
(
expList
);
System
.
out
.
println
(
"Obtained args:"
);
System
.
out
.
println
(
gotList
);
throw
new
RuntimeException
(
"Error: args do not match"
);
}
System
.
out
.
println
(
"\'"
+
inArgs
+
"\'"
+
" - Test passed"
);
}
/*
* This tests general quoting and are specific to Windows, *nixes
* need not worry about this, these have been tested with Windows
* implementation and those that are known to work are used against
* the java implementation. Note that the ProcessBuilder gets in the
* way when testing some of these arguments, therefore we need to
* create and execute a .bat file containing the arguments.
*/
@Test
void
testArgumentParsing
()
throws
IOException
{
if
(!
isWindows
)
return
;
// no quotes
checkArgumentParsing
(
"a b c d"
,
"a"
,
"b"
,
"c"
,
"d"
);
// single quotes
checkArgumentParsing
(
"\"a b c d\""
,
"a b c d"
);
//double quotes
checkArgumentParsing
(
"\"\"a b c d\"\""
,
"a"
,
"b"
,
"c"
,
"d"
);
// triple quotes
checkArgumentParsing
(
"\"\"\"a b c d\"\"\""
,
"\"a b c d\""
);
// a literal within single quotes
checkArgumentParsing
(
"\"a\"b c d\"e\""
,
"ab"
,
"c"
,
"de"
);
// a literal within double quotes
checkArgumentParsing
(
"\"\"a\"b c d\"e\"\""
,
"ab c de"
);
// a literal quote
checkArgumentParsing
(
"a\\\"b"
,
"a\"b"
);
// double back-slash
checkArgumentParsing
(
"\"a b c d\\\\\""
,
"a b c d\\"
);
// triple back-slash
checkArgumentParsing
(
"a\\\\\\\"b"
,
"a\\\"b"
);
// dangling quote
checkArgumentParsing
(
"\"a b c\"\""
,
"a b c\""
);
// expansions of white space separators
checkArgumentParsing
(
"a b"
,
"a"
,
"b"
);
checkArgumentParsing
(
"a\tb"
,
"a"
,
"b"
);
checkArgumentParsing
(
"a \t b"
,
"a"
,
"b"
);
checkArgumentParsing
(
"\"C:\\TEST A\\\\\""
,
"C:\\TEST A\\"
);
checkArgumentParsing
(
"\"\"C:\\TEST A\\\\\"\""
,
"C:\\TEST"
,
"A\\"
);
// MS Windows tests
// triple back-slash
checkArgumentParsing
(
"a\\\\\\d"
,
"a\\\\\\d"
);
// triple back-slash in quotes
checkArgumentParsing
(
"\"a\\\\\\d\""
,
"a\\\\\\d"
);
// slashes separating characters
checkArgumentParsing
(
"X\\Y\\Z"
,
"X\\Y\\Z"
);
checkArgumentParsing
(
"\\X\\Y\\Z"
,
"\\X\\Y\\Z"
);
// literals within dangling quotes, etc.
checkArgumentParsing
(
"\"a b c\" d e"
,
"a b c"
,
"d"
,
"e"
);
checkArgumentParsing
(
"\"ab\\\"c\" \"\\\\\" d"
,
"ab\"c"
,
"\\"
,
"d"
);
checkArgumentParsing
(
"a\\\\\\c d\"e f\"g h"
,
"a\\\\\\c"
,
"de fg"
,
"h"
);
checkArgumentParsing
(
"a\\\\\\\"b c d"
,
"a\\\"b"
,
"c"
,
"d"
);
checkArgumentParsing
(
"a\\\\\\\\\"g c\" d e"
,
"a\\\\g c"
,
"d"
,
"e"
);
// treatment of back-slashes
checkArgumentParsing
(
"*\\"
,
"*\\"
);
checkArgumentParsing
(
"*/"
,
"*/"
);
checkArgumentParsing
(
".\\*"
,
".\\*"
);
checkArgumentParsing
(
"./*"
,
"./*"
);
checkArgumentParsing
(
"..\\..\\*"
,
"..\\..\\*"
);
checkArgumentParsing
(
"../../*"
,
"../../*"
);
checkArgumentParsing
(
"..\\..\\"
,
"..\\..\\"
);
checkArgumentParsing
(
"../../"
,
"../../"
);
}
private
void
initEmptyDir
(
File
emptyDir
)
throws
IOException
{
if
(
emptyDir
.
exists
())
{
recursiveDelete
(
emptyDir
);
}
emptyDir
.
mkdir
();
}
private
void
initDirWithJavaFiles
(
File
libDir
)
throws
IOException
{
if
(
libDir
.
exists
())
{
recursiveDelete
(
libDir
);
}
libDir
.
mkdirs
();
ArrayList
<
String
>
scratchpad
=
new
ArrayList
<>();
scratchpad
.
add
(
"package lib;"
);
scratchpad
.
add
(
"public class Fbo {"
);
scratchpad
.
add
(
"public static void main(String... args){Foo.f();}"
);
scratchpad
.
add
(
"public static void f(){}"
);
scratchpad
.
add
(
"}"
);
createFile
(
new
File
(
libDir
,
"Fbo.java"
),
scratchpad
);
scratchpad
.
clear
();
scratchpad
.
add
(
"package lib;"
);
scratchpad
.
add
(
"public class Foo {"
);
scratchpad
.
add
(
"public static void main(String... args){"
);
scratchpad
.
add
(
"for (String x : args) {"
);
scratchpad
.
add
(
"System.out.println(x);"
);
scratchpad
.
add
(
"}"
);
scratchpad
.
add
(
"Fbo.f();"
);
scratchpad
.
add
(
"}"
);
scratchpad
.
add
(
"public static void f(){}"
);
scratchpad
.
add
(
"}"
);
createFile
(
new
File
(
libDir
,
"Foo.java"
),
scratchpad
);
}
void
checkArgumentWildcard
(
String
inArgs
,
String
...
expArgs
)
throws
IOException
{
String
[]
in
=
{
inArgs
};
checkArgumentWildcard
(
in
,
expArgs
);
// now add arbitrary arguments before and after
String
[]
outInArgs
=
{
"-Q"
,
inArgs
,
"-R"
};
String
[]
outExpArgs
=
new
String
[
expArgs
.
length
+
2
];
outExpArgs
[
0
]
=
"-Q"
;
System
.
arraycopy
(
expArgs
,
0
,
outExpArgs
,
1
,
expArgs
.
length
);
outExpArgs
[
expArgs
.
length
+
1
]
=
"-R"
;
checkArgumentWildcard
(
outInArgs
,
outExpArgs
);
}
void
checkArgumentWildcard
(
String
[]
inArgs
,
String
[]
expArgs
)
throws
IOException
{
ArrayList
<
String
>
argList
=
new
ArrayList
<>();
argList
.
add
(
javaCmd
);
argList
.
add
(
"-cp"
);
argList
.
add
(
"lib"
+
File
.
separator
+
"*"
);
argList
.
add
(
"lib.Foo"
);
argList
.
addAll
(
Arrays
.
asList
(
inArgs
));
String
[]
cmds
=
new
String
[
argList
.
size
()];
argList
.
toArray
(
cmds
);
TestResult
tr
=
doExec
(
cmds
);
if
(!
tr
.
isOK
())
{
System
.
out
.
println
(
tr
);
throw
new
RuntimeException
(
"Error: classpath single entry wildcard entry"
);
}
ArrayList
<
String
>
expList
=
new
ArrayList
<>();
expList
.
addAll
(
Arrays
.
asList
(
expArgs
));
List
<
String
>
gotList
=
new
ArrayList
<>();
for
(
String
x
:
tr
.
testOutput
)
{
gotList
.
add
(
x
.
trim
());
}
if
(!
gotList
.
equals
(
expList
))
{
System
.
out
.
println
(
tr
);
System
.
out
.
println
(
"Expected args:"
);
System
.
out
.
println
(
expList
);
System
.
out
.
println
(
"Obtained args:"
);
System
.
out
.
println
(
gotList
);
throw
new
RuntimeException
(
"Error: args do not match"
);
}
System
.
out
.
print
(
"\'"
);
for
(
String
x
:
inArgs
)
{
System
.
out
.
print
(
x
+
" "
);
}
System
.
out
.
println
(
"\'"
+
" - Test passed"
);
}
/*
* These tests are not expected to work on *nixes, and are ignored.
*/
@Test
void
testWildCardArgumentProcessing
()
throws
IOException
{
if
(!
isWindows
)
return
;
File
cwd
=
new
File
(
"."
);
File
libDir
=
new
File
(
cwd
,
"lib"
);
initDirWithJavaFiles
(
libDir
);
initEmptyDir
(
new
File
(
cwd
,
"empty"
));
// test if javac (the command) can compile *.java
TestResult
tr
=
doExec
(
javacCmd
,
libDir
.
getName
()
+
File
.
separator
+
"*.java"
);
if
(!
tr
.
isOK
())
{
System
.
out
.
println
(
tr
);
throw
new
RuntimeException
(
"Error: compiling java wildcards"
);
}
// use the jar cmd to create jars using the ? wildcard
File
jarFoo
=
new
File
(
libDir
,
"Foo.jar"
);
tr
=
doExec
(
jarCmd
,
"cvf"
,
jarFoo
.
getAbsolutePath
(),
"lib"
+
File
.
separator
+
"F?o.class"
);
if
(!
tr
.
isOK
())
{
System
.
out
.
println
(
tr
);
throw
new
RuntimeException
(
"Error: creating jar with wildcards"
);
}
// now the litmus test!, this should work
checkArgumentWildcard
(
"a"
,
"a"
);
// test for basic expansion
checkArgumentWildcard
(
"lib\\F*java"
,
"lib\\Fbo.java"
,
"lib\\Foo.java"
);
// basic expansion in quotes
checkArgumentWildcard
(
"\"lib\\F*java\""
,
"lib\\F*java"
);
checkArgumentWildcard
(
"lib\\**"
,
"lib\\Fbo.class"
,
"lib\\Fbo.java"
,
"lib\\Foo.class"
,
"lib\\Foo.jar"
,
"lib\\Foo.java"
);
checkArgumentWildcard
(
"lib\\*?"
,
"lib\\Fbo.class"
,
"lib\\Fbo.java"
,
"lib\\Foo.class"
,
"lib\\Foo.jar"
,
"lib\\Foo.java"
);
checkArgumentWildcard
(
"lib\\?*"
,
"lib\\Fbo.class"
,
"lib\\Fbo.java"
,
"lib\\Foo.class"
,
"lib\\Foo.jar"
,
"lib\\Foo.java"
);
checkArgumentWildcard
(
"lib\\?"
,
"lib\\?"
);
// test for basic expansion
checkArgumentWildcard
(
"lib\\*java"
,
"lib\\Fbo.java"
,
"lib\\Foo.java"
);
// basic expansion in quotes
checkArgumentWildcard
(
"\"lib\\*.java\""
,
"lib\\*.java"
);
// suffix expansion
checkArgumentWildcard
(
"lib\\*.class"
,
"lib\\Fbo.class"
,
"lib\\Foo.class"
);
// suffix expansion in quotes
checkArgumentWildcard
(
"\"lib\\*.class\""
,
"lib\\*.class"
);
// check for ? expansion now
checkArgumentWildcard
(
"lib\\F?o.java"
,
"lib\\Fbo.java"
,
"lib\\Foo.java"
);
// check ? in quotes
checkArgumentWildcard
(
"\"lib\\F?o.java\""
,
"lib\\F?o.java"
);
// check ? as suffixes
checkArgumentWildcard
(
"lib\\F?o.????"
,
"lib\\Fbo.java"
,
"lib\\Foo.java"
);
// check ? in a leading role
checkArgumentWildcard
(
"lib\\???.java"
,
"lib\\Fbo.java"
,
"lib\\Foo.java"
);
checkArgumentWildcard
(
"\"lib\\???.java\""
,
"lib\\???.java"
);
// check ? prefixed with -
checkArgumentWildcard
(
"-?"
,
"-?"
);
// check * prefixed with -
checkArgumentWildcard
(
"-*"
,
"-*"
);
// check on empty directory
checkArgumentWildcard
(
"empty\\*"
,
"empty\\*"
);
checkArgumentWildcard
(
"empty\\**"
,
"empty\\**"
);
checkArgumentWildcard
(
"empty\\?"
,
"empty\\?"
);
checkArgumentWildcard
(
"empty\\??"
,
"empty\\??"
);
checkArgumentWildcard
(
"empty\\*?"
,
"empty\\*?"
);
checkArgumentWildcard
(
"empty\\?*"
,
"empty\\?*"
);
}
void
doArgumentCheck
(
String
inArgs
,
String
...
expArgs
)
{
Map
<
String
,
String
>
env
=
new
HashMap
<>();
env
.
put
(
JLDEBUG_KEY
,
"true"
);
TestResult
tr
=
doExec
(
env
,
javaCmd
,
inArgs
);
System
.
out
.
println
(
tr
);
int
sindex
=
tr
.
testOutput
.
indexOf
(
"Command line args:"
);
if
(
sindex
<
0
)
{
System
.
out
.
println
(
tr
);
throw
new
RuntimeException
(
"Error: no output"
);
}
sindex
++;
// skip over the tag
List
<
String
>
gotList
=
new
ArrayList
<>();
for
(
String
x
:
tr
.
testOutput
.
subList
(
sindex
,
sindex
+
expArgs
.
length
))
{
String
a
[]
=
x
.
split
(
"="
);
gotList
.
add
(
a
[
a
.
length
-
1
].
trim
());
}
List
<
String
>
expList
=
Arrays
.
asList
(
expArgs
);
if
(!
gotList
.
equals
(
expList
))
{
System
.
out
.
println
(
tr
);
System
.
out
.
println
(
"Expected args:"
);
System
.
out
.
println
(
expList
);
System
.
out
.
println
(
"Obtained args:"
);
System
.
out
.
println
(
gotList
);
throw
new
RuntimeException
(
"Error: args do not match"
);
}
}
/*
* These tests are usually run on non-existent targets to check error results
*/
static
void
runBasicErrorMessageTests
()
{
@Test
void
testBasicErrorMessages
()
{
// Tests for 5030233
TestResult
tr
=
doExec
(
javaCmd
,
"-cp"
);
tr
.
checkNegative
();
tr
.
isNotZeroOutput
();
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
tr
=
doExec
(
javaCmd
,
"-classpath"
);
tr
.
checkNegative
();
tr
.
isNotZeroOutput
();
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
tr
=
doExec
(
javaCmd
,
"-jar"
);
tr
.
checkNegative
();
tr
.
isNotZeroOutput
();
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
tr
=
doExec
(
javacCmd
,
"-cp"
);
tr
.
checkNegative
();
tr
.
isNotZeroOutput
();
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
// Test for 6356475 "REGRESSION:"java -X" from cmdline fails"
tr
=
doExec
(
javaCmd
,
"-X"
);
tr
.
checkPositive
();
tr
.
isNotZeroOutput
();
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
tr
=
doExec
(
javaCmd
,
"-help"
);
tr
.
checkPositive
();
tr
.
isNotZeroOutput
();
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
// 6753938, test for non-negative exit value for an incorrectly formed
...
...
@@ -229,6 +562,7 @@ public class Arrrghs extends TestHelper {
tr
=
doExec
(
javaCmd
);
tr
.
checkNegative
();
tr
.
isNotZeroOutput
();
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
// 6753938, test for non-negative exit value for an incorrectly formed
...
...
@@ -236,6 +570,7 @@ public class Arrrghs extends TestHelper {
tr
=
doExec
(
javaCmd
,
"-Xcomp"
);
tr
.
checkNegative
();
tr
.
isNotZeroOutput
();
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
// 7151434, test for non-negative exit value for an incorrectly formed
...
...
@@ -243,6 +578,7 @@ public class Arrrghs extends TestHelper {
tr
=
doExec
(
javaCmd
,
"-jar"
,
"-W"
);
tr
.
checkNegative
();
tr
.
contains
(
"Unrecognized option: -W"
);
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
}
...
...
@@ -250,7 +586,8 @@ public class Arrrghs extends TestHelper {
* Tests various dispositions of the main method, these tests are limited
* to English locales as they check for error messages that are localized.
*/
static
void
runMainMethodTests
()
throws
FileNotFoundException
{
@Test
void
testMainMethod
()
throws
FileNotFoundException
{
if
(!
isEnglishLocale
())
{
return
;
}
...
...
@@ -262,10 +599,12 @@ public class Arrrghs extends TestHelper {
(
String
[])
null
);
tr
=
doExec
(
javaCmd
,
"-jar"
,
"some.jar"
);
tr
.
contains
(
"Error: Could not find or load main class MIA"
);
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
// use classpath to check
tr
=
doExec
(
javaCmd
,
"-cp"
,
"some.jar"
,
"MIA"
);
tr
.
contains
(
"Error: Could not find or load main class MIA"
);
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
// incorrect method access
...
...
@@ -273,10 +612,12 @@ public class Arrrghs extends TestHelper {
"private static void main(String[] args){}"
);
tr
=
doExec
(
javaCmd
,
"-jar"
,
"some.jar"
);
tr
.
contains
(
"Error: Main method not found in class Foo"
);
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
// use classpath to check
tr
=
doExec
(
javaCmd
,
"-cp"
,
"some.jar"
,
"Foo"
);
tr
.
contains
(
"Error: Main method not found in class Foo"
);
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
// incorrect return type
...
...
@@ -284,10 +625,12 @@ public class Arrrghs extends TestHelper {
"public static int main(String[] args){return 1;}"
);
tr
=
doExec
(
javaCmd
,
"-jar"
,
"some.jar"
);
tr
.
contains
(
"Error: Main method must return a value of type void in class Foo"
);
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
// use classpath to check
tr
=
doExec
(
javaCmd
,
"-cp"
,
"some.jar"
,
"Foo"
);
tr
.
contains
(
"Error: Main method must return a value of type void in class Foo"
);
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
// incorrect parameter type
...
...
@@ -295,10 +638,12 @@ public class Arrrghs extends TestHelper {
"public static void main(Object[] args){}"
);
tr
=
doExec
(
javaCmd
,
"-jar"
,
"some.jar"
);
tr
.
contains
(
"Error: Main method not found in class Foo"
);
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
// use classpath to check
tr
=
doExec
(
javaCmd
,
"-cp"
,
"some.jar"
,
"Foo"
);
tr
.
contains
(
"Error: Main method not found in class Foo"
);
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
// incorrect method type - non-static
...
...
@@ -306,10 +651,12 @@ public class Arrrghs extends TestHelper {
"public void main(String[] args){}"
);
tr
=
doExec
(
javaCmd
,
"-jar"
,
"some.jar"
);
tr
.
contains
(
"Error: Main method is not static in class Foo"
);
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
// use classpath to check
tr
=
doExec
(
javaCmd
,
"-cp"
,
"some.jar"
,
"Foo"
);
tr
.
contains
(
"Error: Main method is not static in class Foo"
);
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
// amongst a potpourri of kindred main methods, is the right one chosen ?
...
...
@@ -322,10 +669,12 @@ public class Arrrghs extends TestHelper {
"public static void main(String[] args) {System.out.println(\"THE_CHOSEN_ONE\");}"
);
tr
=
doExec
(
javaCmd
,
"-jar"
,
"some.jar"
);
tr
.
contains
(
"THE_CHOSEN_ONE"
);
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
// use classpath to check
tr
=
doExec
(
javaCmd
,
"-cp"
,
"some.jar"
,
"Foo"
);
tr
.
contains
(
"THE_CHOSEN_ONE"
);
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
// test for extraneous whitespace in the Main-Class attribute
...
...
@@ -333,6 +682,7 @@ public class Arrrghs extends TestHelper {
"public static void main(String... args){}"
);
tr
=
doExec
(
javaCmd
,
"-jar"
,
"some.jar"
);
tr
.
checkPositive
();
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
}
/*
...
...
@@ -340,7 +690,8 @@ public class Arrrghs extends TestHelper {
* the suppressed stack traces are exposed, ignore these tests for localized
* locales, limiting to English only.
*/
static
void
runDiagOptionTests
()
throws
FileNotFoundException
{
@Test
void
testDiagOptions
()
throws
FileNotFoundException
{
if
(!
isEnglishLocale
())
{
// only english version
return
;
}
...
...
@@ -351,32 +702,38 @@ public class Arrrghs extends TestHelper {
tr
=
doExec
(
javaCmd
,
"-Xdiag"
,
"-jar"
,
"some.jar"
);
tr
.
contains
(
"Error: Could not find or load main class MIA"
);
tr
.
contains
(
"java.lang.ClassNotFoundException: MIA"
);
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
// use classpath to check
tr
=
doExec
(
javaCmd
,
"-Xdiag"
,
"-cp"
,
"some.jar"
,
"MIA"
);
tr
.
contains
(
"Error: Could not find or load main class MIA"
);
tr
.
contains
(
"java.lang.ClassNotFoundException: MIA"
);
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
// a missing class on the classpath
tr
=
doExec
(
javaCmd
,
"-Xdiag"
,
"NonExistentClass"
);
tr
.
contains
(
"Error: Could not find or load main class NonExistentClass"
);
tr
.
contains
(
"java.lang.ClassNotFoundException: NonExistentClass"
);
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
}
static
void
test6894719
()
{
@Test
static
void
testJreRestrictSearchFlag
()
{
// test both arguments to ensure they exist
TestResult
tr
=
null
;
tr
=
doExec
(
javaCmd
,
"-no-jre-restrict-search"
,
"-version"
);
tr
.
checkPositive
();
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
tr
=
doExec
(
javaCmd
,
"-jre-restrict-search"
,
"-version"
);
tr
.
checkPositive
();
if
(!
tr
.
testStatus
)
System
.
out
.
println
(
tr
);
}
...
...
@@ -384,15 +741,12 @@ public class Arrrghs extends TestHelper {
* @param args the command line arguments
* @throws java.io.FileNotFoundException
*/
public
static
void
main
(
String
[]
args
)
throws
FileNotFound
Exception
{
public
static
void
main
(
String
[]
args
)
throws
Exception
{
if
(
debug
)
{
System
.
out
.
println
(
"Starting Arrrghs tests"
);
}
quoteParsingTests
();
runBasicErrorMessageTests
();
runMainMethodTests
();
test6894719
();
runDiagOptionTests
();
Arrrghs
a
=
new
Arrrghs
();
a
.
run
(
args
);
if
(
testExitValue
>
0
)
{
System
.
out
.
println
(
"Total of "
+
testExitValue
+
" failed"
);
System
.
exit
(
1
);
...
...
test/tools/launcher/TestHelper.java
浏览文件 @
edc21737
...
...
@@ -21,6 +21,12 @@
* questions.
*/
import
java.lang.annotation.ElementType
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
import
java.lang.reflect.Method
;
import
java.util.regex.Pattern
;
import
java.io.StringWriter
;
import
java.io.PrintWriter
;
import
java.util.Set
;
...
...
@@ -63,6 +69,8 @@ public class TestHelper {
static
final
String
javawCmd
;
static
final
String
java64Cmd
;
static
final
String
javacCmd
;
static
final
String
jarCmd
;
static
final
JavaCompiler
compiler
;
static
final
boolean
debug
=
Boolean
.
getBoolean
(
"TestHelper.Debug"
);
...
...
@@ -131,6 +139,15 @@ public class TestHelper {
:
new
File
(
binDir
,
"javac"
);
javacCmd
=
javacCmdFile
.
getAbsolutePath
();
File
jarCmdFile
=
(
isWindows
)
?
new
File
(
binDir
,
"jar.exe"
)
:
new
File
(
binDir
,
"jar"
);
jarCmd
=
jarCmdFile
.
getAbsolutePath
();
if
(!
jarCmdFile
.
canExecute
())
{
throw
new
RuntimeException
(
"java <"
+
TestHelper
.
jarCmd
+
"> must exist and should be executable"
);
}
if
(
isWindows
)
{
File
javawCmdFile
=
new
File
(
binDir
,
"javaw.exe"
);
javawCmd
=
javawCmdFile
.
getAbsolutePath
();
...
...
@@ -158,6 +175,35 @@ public class TestHelper {
java64Cmd
=
null
;
}
}
void
run
(
String
[]
args
)
throws
Exception
{
int
passed
=
0
,
failed
=
0
;
final
Pattern
p
=
(
args
!=
null
&&
args
.
length
>
0
)
?
Pattern
.
compile
(
args
[
0
])
:
null
;
for
(
Method
m
:
this
.
getClass
().
getDeclaredMethods
())
{
boolean
selected
=
(
p
==
null
)
?
m
.
isAnnotationPresent
(
Test
.
class
)
:
p
.
matcher
(
m
.
getName
()).
matches
();
if
(
selected
)
{
try
{
m
.
invoke
(
this
,
(
Object
[])
null
);
System
.
out
.
println
(
m
.
getName
()
+
": OK"
);
passed
++;
}
catch
(
Throwable
ex
)
{
System
.
out
.
printf
(
"Test %s failed: %s %n"
,
m
,
ex
.
getCause
());
failed
++;
}
}
}
System
.
out
.
printf
(
"Passed: %d, Failed %d%n"
,
passed
,
failed
);
if
(
failed
>
0
)
{
throw
new
RuntimeException
(
"Tests failed: "
+
failed
);
}
if
(
passed
==
0
&&
failed
==
0
)
{
throw
new
AssertionError
(
"No test(s) selected: passed = "
+
passed
+
", failed = "
+
failed
+
" ??????????"
);
}
}
/*
* is a dual mode available in the test jdk
...
...
@@ -395,6 +441,7 @@ public class TestHelper {
List
<
String
>
testOutput
;
Map
<
String
,
String
>
env
;
Throwable
t
;
boolean
testStatus
;
public
TestResult
(
String
str
,
int
rv
,
List
<
String
>
oList
,
Map
<
String
,
String
>
env
,
Throwable
t
)
{
...
...
@@ -405,6 +452,7 @@ public class TestHelper {
testOutput
=
oList
;
this
.
env
=
env
;
this
.
t
=
t
;
testStatus
=
true
;
}
void
appendError
(
String
x
)
{
...
...
@@ -418,12 +466,14 @@ public class TestHelper {
void
checkNegative
()
{
if
(
exitValue
==
0
)
{
appendError
(
"test must not return 0 exit value"
);
testStatus
=
false
;
testExitValue
++;
}
}
void
checkPositive
()
{
if
(
exitValue
!=
0
)
{
testStatus
=
false
;
appendError
(
"test did not return 0 exit value"
);
testExitValue
++;
}
...
...
@@ -435,6 +485,7 @@ public class TestHelper {
boolean
isZeroOutput
()
{
if
(!
testOutput
.
isEmpty
())
{
testStatus
=
false
;
appendError
(
"No message from cmd please"
);
testExitValue
++;
return
false
;
...
...
@@ -444,6 +495,7 @@ public class TestHelper {
boolean
isNotZeroOutput
()
{
if
(
testOutput
.
isEmpty
())
{
testStatus
=
false
;
appendError
(
"Missing message"
);
testExitValue
++;
return
false
;
...
...
@@ -454,6 +506,7 @@ public class TestHelper {
@Override
public
String
toString
()
{
status
.
println
(
"++++Begin Test Info++++"
);
status
.
println
(
"Test Status: "
+
(
testStatus
?
"PASS"
:
"FAIL"
));
status
.
println
(
"++++Test Environment++++"
);
for
(
String
x
:
env
.
keySet
())
{
indentStatus
(
x
+
"="
+
env
.
get
(
x
));
...
...
@@ -496,4 +549,10 @@ public class TestHelper {
return
false
;
}
}
/**
* Indicates that the annotated method is a test method.
*/
@Retention
(
RetentionPolicy
.
RUNTIME
)
@Target
(
ElementType
.
METHOD
)
public
@interface
Test
{}
}
test/tools/launcher/ToolsOpts.java
浏览文件 @
edc21737
...
...
@@ -160,7 +160,7 @@ public class ToolsOpts extends TestHelper {
for
(
String
arg
[]
:
optionPatterns
)
{
jpos
=
indexOfJoption
(
arg
);
//Build a cmd string for output in results reporting.
String
cmdString
=
javacCmd
+
JBCP_PREPEND
+
sTestJar
;
String
cmdString
=
javacCmd
+
" "
+
JBCP_PREPEND
+
sTestJar
;
for
(
String
opt
:
arg
)
{
cmdString
=
cmdString
.
concat
(
" "
+
opt
);
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录