mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
8187443: Forest Consolidation: Move files to unified layout
Reviewed-by: darcy, ihse
This commit is contained in:
parent
270fe13182
commit
3789983e89
56923 changed files with 3 additions and 15727 deletions
69
src/java.base/unix/native/libjava/Console_md.c
Normal file
69
src/java.base/unix/native/libjava/Console_md.c
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2006, 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 "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "java_io_Console.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_java_io_Console_istty(JNIEnv *env, jclass cls)
|
||||
{
|
||||
return isatty(fileno(stdin)) && isatty(fileno(stdout));
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_java_io_Console_encoding(JNIEnv *env, jclass cls)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_java_io_Console_echo(JNIEnv *env,
|
||||
jclass cls,
|
||||
jboolean on)
|
||||
{
|
||||
struct termios tio;
|
||||
jboolean old;
|
||||
int tty = fileno(stdin);
|
||||
if (tcgetattr(tty, &tio) == -1) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "tcgetattr failed");
|
||||
return !on;
|
||||
}
|
||||
old = (tio.c_lflag & ECHO);
|
||||
if (on) {
|
||||
tio.c_lflag |= ECHO;
|
||||
} else {
|
||||
tio.c_lflag &= ~ECHO;
|
||||
}
|
||||
if (tcsetattr(tty, TCSANOW, &tio) == -1) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "tcsetattr failed");
|
||||
}
|
||||
return old;
|
||||
}
|
72
src/java.base/unix/native/libjava/FileDescriptor_md.c
Normal file
72
src/java.base/unix/native/libjava/FileDescriptor_md.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2013, 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 <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
|
||||
#include "io_util_md.h"
|
||||
#include "java_io_FileDescriptor.h"
|
||||
|
||||
/*******************************************************************/
|
||||
/* BEGIN JNI ********* BEGIN JNI *********** BEGIN JNI ************/
|
||||
/*******************************************************************/
|
||||
|
||||
/* field id for jint 'fd' in java.io.FileDescriptor */
|
||||
jfieldID IO_fd_fdID;
|
||||
|
||||
/* field id for jboolean 'append' in java.io.FileDescriptor */
|
||||
jfieldID IO_append_fdID;
|
||||
|
||||
/**************************************************************
|
||||
* static methods to store field ID's in initializers
|
||||
*/
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_io_FileDescriptor_initIDs(JNIEnv *env, jclass fdClass) {
|
||||
CHECK_NULL(IO_fd_fdID = (*env)->GetFieldID(env, fdClass, "fd", "I"));
|
||||
CHECK_NULL(IO_append_fdID = (*env)->GetFieldID(env, fdClass, "append", "Z"));
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
* File Descriptor
|
||||
*/
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_io_FileDescriptor_sync(JNIEnv *env, jobject this) {
|
||||
FD fd = THIS_FD(this);
|
||||
if (IO_Sync(fd) == -1) {
|
||||
JNU_ThrowByName(env, "java/io/SyncFailedException", "sync failed");
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_java_io_FileDescriptor_getAppend(JNIEnv *env, jclass fdClass, jint fd) {
|
||||
int flags = fcntl(fd, F_GETFL);
|
||||
return ((flags & O_APPEND) == 0) ? JNI_FALSE : JNI_TRUE;
|
||||
}
|
48
src/java.base/unix/native/libjava/FileInputStream_md.c
Normal file
48
src/java.base/unix/native/libjava/FileInputStream_md.c
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 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 <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "io_util.h"
|
||||
#include "io_util_md.h"
|
||||
|
||||
#include "java_io_FileInputStream.h"
|
||||
|
||||
extern jfieldID fis_fd; /* id for jobject 'fd' in java.io.FileInputStream */
|
||||
|
||||
/*********************************************************************
|
||||
* Platform specific implementation of input stream native methods
|
||||
*/
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_io_FileInputStream_close0(JNIEnv *env, jobject this) {
|
||||
fileClose(env, this, fis_fd);
|
||||
}
|
76
src/java.base/unix/native/libjava/FileOutputStream_md.c
Normal file
76
src/java.base/unix/native/libjava/FileOutputStream_md.c
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2010, 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 "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
|
||||
#include "io_util.h"
|
||||
#include "io_util_md.h"
|
||||
#include "java_io_FileOutputStream.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
/*******************************************************************/
|
||||
/* BEGIN JNI ********* BEGIN JNI *********** BEGIN JNI ************/
|
||||
/*******************************************************************/
|
||||
|
||||
jfieldID fos_fd; /* id for jobject 'fd' in java.io.FileOutputStream */
|
||||
|
||||
/**************************************************************
|
||||
* static methods to store field ID's in initializers
|
||||
*/
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_io_FileOutputStream_initIDs(JNIEnv *env, jclass fdClass) {
|
||||
fos_fd = (*env)->GetFieldID(env, fdClass, "fd", "Ljava/io/FileDescriptor;");
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
* Output stream
|
||||
*/
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_io_FileOutputStream_open0(JNIEnv *env, jobject this,
|
||||
jstring path, jboolean append) {
|
||||
fileOpen(env, this, path, fos_fd,
|
||||
O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC));
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_io_FileOutputStream_write(JNIEnv *env, jobject this, jint byte, jboolean append) {
|
||||
writeSingle(env, this, byte, append, fos_fd);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_io_FileOutputStream_writeBytes(JNIEnv *env,
|
||||
jobject this, jbyteArray bytes, jint off, jint len, jboolean append) {
|
||||
writeBytes(env, this, bytes, off, len, append, fos_fd);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_io_FileOutputStream_close0(JNIEnv *env, jobject this) {
|
||||
fileClose(env, this, fos_fd);
|
||||
}
|
92
src/java.base/unix/native/libjava/ProcessEnvironment_md.c
Normal file
92
src/java.base/unix/native/libjava/ProcessEnvironment_md.c
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2013, 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <crt_externs.h>
|
||||
#define environ (*_NSGetEnviron())
|
||||
#else
|
||||
/* This is one of the rare times it's more portable to declare an
|
||||
* external symbol explicitly, rather than via a system header.
|
||||
* The declaration is standardized as part of UNIX98, but there is
|
||||
* no standard (not even de-facto) header file where the
|
||||
* declaration is to be found. See:
|
||||
* http://www.opengroup.org/onlinepubs/009695399/functions/environ.html
|
||||
* http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_02.html
|
||||
*
|
||||
* "All identifiers in this volume of IEEE Std 1003.1-2001, except
|
||||
* environ, are defined in at least one of the headers" (!)
|
||||
*/
|
||||
extern char **environ;
|
||||
#endif
|
||||
|
||||
JNIEXPORT jobjectArray JNICALL
|
||||
Java_java_lang_ProcessEnvironment_environ(JNIEnv *env, jclass ign)
|
||||
{
|
||||
jsize count = 0;
|
||||
jsize i, j;
|
||||
jobjectArray result;
|
||||
jclass byteArrCls = (*env)->FindClass(env, "[B");
|
||||
CHECK_NULL_RETURN(byteArrCls, NULL);
|
||||
|
||||
for (i = 0; environ[i]; i++) {
|
||||
/* Ignore corrupted environment variables */
|
||||
if (strchr(environ[i], '=') != NULL)
|
||||
count++;
|
||||
}
|
||||
|
||||
result = (*env)->NewObjectArray(env, 2*count, byteArrCls, 0);
|
||||
CHECK_NULL_RETURN(result, NULL);
|
||||
|
||||
for (i = 0, j = 0; environ[i]; i++) {
|
||||
const char * varEnd = strchr(environ[i], '=');
|
||||
/* Ignore corrupted environment variables */
|
||||
if (varEnd != NULL) {
|
||||
jbyteArray var, val;
|
||||
const char * valBeg = varEnd + 1;
|
||||
jsize varLength = varEnd - environ[i];
|
||||
jsize valLength = strlen(valBeg);
|
||||
var = (*env)->NewByteArray(env, varLength);
|
||||
CHECK_NULL_RETURN(var, NULL);
|
||||
val = (*env)->NewByteArray(env, valLength);
|
||||
CHECK_NULL_RETURN(val, NULL);
|
||||
(*env)->SetByteArrayRegion(env, var, 0, varLength,
|
||||
(jbyte*) environ[i]);
|
||||
(*env)->SetByteArrayRegion(env, val, 0, valLength,
|
||||
(jbyte*) valBeg);
|
||||
(*env)->SetObjectArrayElement(env, result, 2*j , var);
|
||||
(*env)->SetObjectArrayElement(env, result, 2*j+1, val);
|
||||
(*env)->DeleteLocalRef(env, var);
|
||||
(*env)->DeleteLocalRef(env, val);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
728
src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c
Normal file
728
src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c
Normal file
|
@ -0,0 +1,728 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2017, 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 "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "java_lang_ProcessHandleImpl.h"
|
||||
#include "java_lang_ProcessHandleImpl_Info.h"
|
||||
|
||||
#include "ProcessHandleImpl_unix.h"
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
/* For POSIX-compliant getpwuid_r on Solaris */
|
||||
#if defined(__solaris__)
|
||||
#define _POSIX_PTHREAD_SEMANTICS
|
||||
#endif
|
||||
#include <pwd.h>
|
||||
|
||||
#ifdef _AIX
|
||||
#include <sys/procfs.h>
|
||||
#endif
|
||||
#ifdef __solaris__
|
||||
#include <procfs.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This file contains the implementation of the native ProcessHandleImpl
|
||||
* functions which are common to all Unix variants.
|
||||
*
|
||||
* The currently supported Unix variants are Solaris, Linux, MaxOS X and AIX.
|
||||
* The various similarities and differences between these systems make it hard
|
||||
* to find a clear boundary between platform specific and shared code.
|
||||
*
|
||||
* In order to ease code sharing between the platforms while still keeping the
|
||||
* code as clean as possible (i.e. free of preprocessor macros) we use the
|
||||
* following source code layout (remember that ProcessHandleImpl_unix.c will
|
||||
* be compiled on EVERY Unix platform while ProcessHandleImpl_<os>.c will be
|
||||
* only compiled on the specific OS):
|
||||
*
|
||||
* - all the JNI wrappers for the ProcessHandleImpl functions go into this file
|
||||
* - if their implementation is common on ALL the supported Unix platforms it
|
||||
* goes right into the JNI wrappers
|
||||
* - if the whole function or substantial parts of it are platform dependent,
|
||||
* the implementation goes into os_<function_name> functions in
|
||||
* ProcessHandleImpl_<os>.c
|
||||
* - if at least two platforms implement an os_<function_name> function in the
|
||||
* same way, this implementation is factored out into unix_<function_name>,
|
||||
* placed into this file and called from the corresponding os_<function_name>
|
||||
* function.
|
||||
* - For convenience, all the os_ and unix_ functions are declared in
|
||||
* ProcessHandleImpl_unix.h which is included into every
|
||||
* ProcessHandleImpl_<os>.c file.
|
||||
*
|
||||
* Example 1:
|
||||
* ----------
|
||||
* The implementation of Java_java_lang_ProcessHandleImpl_initNative()
|
||||
* is the same on all platforms except on Linux where it initilizes one
|
||||
* additional field. So we place the implementation right into
|
||||
* Java_java_lang_ProcessHandleImpl_initNative() but add call to
|
||||
* os_init() at the end of the function which is empty on all platforms
|
||||
* except Linux where it performs the additionally initializations.
|
||||
*
|
||||
* Example 2:
|
||||
* ----------
|
||||
* The implementation of Java_java_lang_ProcessHandleImpl_00024Info_info0 is the
|
||||
* same on Solaris and AIX but different on Linux and MacOSX. We therefore simply
|
||||
* call the helpers os_getParentPidAndTimings() and os_getCmdlineAndUserInfo().
|
||||
* The Linux and MaxOS X versions of these functions (in the corresponding files
|
||||
* ProcessHandleImpl_linux.c and ProcessHandleImpl_macosx.c) directly contain
|
||||
* the platform specific implementations while the Solaris and AIX
|
||||
* implementations simply call back to unix_getParentPidAndTimings() and
|
||||
* unix_getCmdlineAndUserInfo() which are implemented right in this file.
|
||||
*
|
||||
* The term "same implementation" is still a question of interpretation. It my
|
||||
* be acceptable to have a few ifdef'ed lines if that allows the sharing of a
|
||||
* huge function. On the other hand, if the platform specific code in a shared
|
||||
* function grows over a certain limit, it may be better to refactor that
|
||||
* functionality into corresponding, platform-specific os_ functions.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef WIFEXITED
|
||||
#define WIFEXITED(status) (((status)&0xFF) == 0)
|
||||
#endif
|
||||
|
||||
#ifndef WEXITSTATUS
|
||||
#define WEXITSTATUS(status) (((status)>>8)&0xFF)
|
||||
#endif
|
||||
|
||||
#ifndef WIFSIGNALED
|
||||
#define WIFSIGNALED(status) (((status)&0xFF) > 0 && ((status)&0xFF00) == 0)
|
||||
#endif
|
||||
|
||||
#ifndef WTERMSIG
|
||||
#define WTERMSIG(status) ((status)&0x7F)
|
||||
#endif
|
||||
|
||||
#ifdef __solaris__
|
||||
/* The child exited because of a signal.
|
||||
* The best value to return is 0x80 + signal number,
|
||||
* because that is what all Unix shells do, and because
|
||||
* it allows callers to distinguish between process exit and
|
||||
* process death by signal.
|
||||
* Unfortunately, the historical behavior on Solaris is to return
|
||||
* the signal number, and we preserve this for compatibility. */
|
||||
#define WTERMSIG_RETURN(status) WTERMSIG(status)
|
||||
#else
|
||||
#define WTERMSIG_RETURN(status) (WTERMSIG(status) + 0x80)
|
||||
#endif
|
||||
|
||||
#define RESTARTABLE(_cmd, _result) do { \
|
||||
do { \
|
||||
_result = _cmd; \
|
||||
} while((_result == -1) && (errno == EINTR)); \
|
||||
} while(0)
|
||||
|
||||
#define RESTARTABLE_RETURN_PTR(_cmd, _result) do { \
|
||||
do { \
|
||||
_result = _cmd; \
|
||||
} while((_result == NULL) && (errno == EINTR)); \
|
||||
} while(0)
|
||||
|
||||
|
||||
/* Field id for jString 'command' in java.lang.ProcessHandleImpl.Info */
|
||||
jfieldID ProcessHandleImpl_Info_commandID;
|
||||
|
||||
/* Field id for jString 'commandLine' in java.lang.ProcessHandleImpl.Info */
|
||||
jfieldID ProcessHandleImpl_Info_commandLineID;
|
||||
|
||||
/* Field id for jString[] 'arguments' in java.lang.ProcessHandleImpl.Info */
|
||||
jfieldID ProcessHandleImpl_Info_argumentsID;
|
||||
|
||||
/* Field id for jlong 'totalTime' in java.lang.ProcessHandleImpl.Info */
|
||||
jfieldID ProcessHandleImpl_Info_totalTimeID;
|
||||
|
||||
/* Field id for jlong 'startTime' in java.lang.ProcessHandleImpl.Info */
|
||||
jfieldID ProcessHandleImpl_Info_startTimeID;
|
||||
|
||||
/* Field id for jString 'user' in java.lang.ProcessHandleImpl.Info */
|
||||
jfieldID ProcessHandleImpl_Info_userID;
|
||||
|
||||
/* Size of password or group entry when not available via sysconf */
|
||||
#define ENT_BUF_SIZE 1024
|
||||
/* The value for the size of the buffer used by getpwuid_r(). The result of */
|
||||
/* sysconf(_SC_GETPW_R_SIZE_MAX) if available or ENT_BUF_SIZE otherwise. */
|
||||
static long getpw_buf_size;
|
||||
|
||||
/**************************************************************
|
||||
* Static method to initialize field IDs and the ticks per second rate.
|
||||
*
|
||||
* Class: java_lang_ProcessHandleImpl_Info
|
||||
* Method: initIDs
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_lang_ProcessHandleImpl_00024Info_initIDs(JNIEnv *env, jclass clazz) {
|
||||
|
||||
CHECK_NULL(ProcessHandleImpl_Info_commandID =
|
||||
(*env)->GetFieldID(env, clazz, "command", "Ljava/lang/String;"));
|
||||
CHECK_NULL(ProcessHandleImpl_Info_commandLineID =
|
||||
(*env)->GetFieldID(env, clazz, "commandLine", "Ljava/lang/String;"));
|
||||
CHECK_NULL(ProcessHandleImpl_Info_argumentsID =
|
||||
(*env)->GetFieldID(env, clazz, "arguments", "[Ljava/lang/String;"));
|
||||
CHECK_NULL(ProcessHandleImpl_Info_totalTimeID =
|
||||
(*env)->GetFieldID(env, clazz, "totalTime", "J"));
|
||||
CHECK_NULL(ProcessHandleImpl_Info_startTimeID =
|
||||
(*env)->GetFieldID(env, clazz, "startTime", "J"));
|
||||
CHECK_NULL(ProcessHandleImpl_Info_userID =
|
||||
(*env)->GetFieldID(env, clazz, "user", "Ljava/lang/String;"));
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
* Static method to initialize platform dependent constants.
|
||||
*
|
||||
* Class: java_lang_ProcessHandleImpl
|
||||
* Method: initNative
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_lang_ProcessHandleImpl_initNative(JNIEnv *env, jclass clazz) {
|
||||
getpw_buf_size = sysconf(_SC_GETPW_R_SIZE_MAX);
|
||||
if (getpw_buf_size == -1) {
|
||||
getpw_buf_size = ENT_BUF_SIZE;
|
||||
}
|
||||
os_initNative(env, clazz);
|
||||
}
|
||||
|
||||
/* Block until a child process exits and return its exit code.
|
||||
* Note, can only be called once for any given pid if reapStatus = true.
|
||||
*
|
||||
* Class: java_lang_ProcessHandleImpl
|
||||
* Method: waitForProcessExit0
|
||||
* Signature: (JZ)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_java_lang_ProcessHandleImpl_waitForProcessExit0(JNIEnv* env,
|
||||
jclass junk,
|
||||
jlong jpid,
|
||||
jboolean reapStatus) {
|
||||
pid_t pid = (pid_t)jpid;
|
||||
errno = 0;
|
||||
|
||||
if (reapStatus != JNI_FALSE) {
|
||||
/* Wait for the child process to exit.
|
||||
* waitpid() is standard, so use it on all POSIX platforms.
|
||||
* It is known to work when blocking to wait for the pid
|
||||
* This returns immediately if the child has already exited.
|
||||
*/
|
||||
int status;
|
||||
while (waitpid(pid, &status, 0) < 0) {
|
||||
switch (errno) {
|
||||
case ECHILD:
|
||||
return java_lang_ProcessHandleImpl_NOT_A_CHILD; // No child
|
||||
case EINTR: break;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (WIFEXITED(status)) {
|
||||
return WEXITSTATUS(status);
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
return WTERMSIG_RETURN(status);
|
||||
} else {
|
||||
return status;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Wait for the child process to exit without reaping the exitValue.
|
||||
* waitid() is standard on all POSIX platforms.
|
||||
* Note: waitid on Mac OS X 10.7 seems to be broken;
|
||||
* it does not return the exit status consistently.
|
||||
*/
|
||||
siginfo_t siginfo;
|
||||
int options = WEXITED | WNOWAIT;
|
||||
memset(&siginfo, 0, sizeof siginfo);
|
||||
while (waitid(P_PID, pid, &siginfo, options) < 0) {
|
||||
switch (errno) {
|
||||
case ECHILD:
|
||||
return java_lang_ProcessHandleImpl_NOT_A_CHILD; // No child
|
||||
case EINTR: break;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (siginfo.si_code == CLD_EXITED) {
|
||||
/*
|
||||
* The child exited normally; get its exit code.
|
||||
*/
|
||||
return siginfo.si_status;
|
||||
} else if (siginfo.si_code == CLD_KILLED || siginfo.si_code == CLD_DUMPED) {
|
||||
return WTERMSIG_RETURN(siginfo.si_status);
|
||||
} else {
|
||||
/*
|
||||
* Unknown exit code; pass it through.
|
||||
*/
|
||||
return siginfo.si_status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_lang_ProcessHandleImpl
|
||||
* Method: getCurrentPid0
|
||||
* Signature: ()J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_java_lang_ProcessHandleImpl_getCurrentPid0(JNIEnv *env, jclass clazz) {
|
||||
pid_t pid = getpid();
|
||||
return (jlong) pid;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_lang_ProcessHandleImpl
|
||||
* Method: destroy0
|
||||
* Signature: (JJZ)Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_java_lang_ProcessHandleImpl_destroy0(JNIEnv *env,
|
||||
jobject obj,
|
||||
jlong jpid,
|
||||
jlong startTime,
|
||||
jboolean force) {
|
||||
pid_t pid = (pid_t) jpid;
|
||||
int sig = (force == JNI_TRUE) ? SIGKILL : SIGTERM;
|
||||
jlong start = Java_java_lang_ProcessHandleImpl_isAlive0(env, obj, jpid);
|
||||
|
||||
if (start == startTime || start == 0 || startTime == 0) {
|
||||
return (kill(pid, sig) < 0) ? JNI_FALSE : JNI_TRUE;
|
||||
} else {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the children of the requested pid and optionally each parent and
|
||||
* start time.
|
||||
* Accumulates any process who parent pid matches.
|
||||
* The resulting pids are stored into the array of longs.
|
||||
* The number of pids is returned if they all fit.
|
||||
* If the array is too short, the negative of the desired length is returned.
|
||||
* Class: java_lang_ProcessHandleImpl
|
||||
* Method: getProcessPids0
|
||||
* Signature: (J[J[J[J)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_java_lang_ProcessHandleImpl_getProcessPids0(JNIEnv *env,
|
||||
jclass clazz,
|
||||
jlong jpid,
|
||||
jlongArray jarray,
|
||||
jlongArray jparentArray,
|
||||
jlongArray jstimesArray) {
|
||||
return os_getChildren(env, jpid, jarray, jparentArray, jstimesArray);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill in the Info object from the OS information about the process.
|
||||
*
|
||||
* Class: java_lang_ProcessHandleImpl_Info
|
||||
* Method: info0
|
||||
* Signature: (Ljava/lang/ProcessHandle/Info;J)I
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_lang_ProcessHandleImpl_00024Info_info0(JNIEnv *env,
|
||||
jobject jinfo,
|
||||
jlong jpid) {
|
||||
pid_t pid = (pid_t) jpid;
|
||||
pid_t ppid;
|
||||
jlong totalTime = -1L;
|
||||
jlong startTime = -1L;
|
||||
|
||||
ppid = os_getParentPidAndTimings(env, pid, &totalTime, &startTime);
|
||||
if (ppid >= 0) {
|
||||
(*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_totalTimeID, totalTime);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
|
||||
(*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_startTimeID, startTime);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
}
|
||||
os_getCmdlineAndUserInfo(env, jinfo, pid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if a process is alive.
|
||||
* Return the start time (ms since 1970) if it is available.
|
||||
* If the start time is not available return 0.
|
||||
* If the pid is invalid, return -1.
|
||||
*
|
||||
* Class: java_lang_ProcessHandleImpl
|
||||
* Method: isAlive0
|
||||
* Signature: (J)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_java_lang_ProcessHandleImpl_isAlive0(JNIEnv *env, jobject obj, jlong jpid) {
|
||||
pid_t pid = (pid_t) jpid;
|
||||
jlong startTime = 0L;
|
||||
jlong totalTime = 0L;
|
||||
pid_t ppid = os_getParentPidAndTimings(env, pid, &totalTime, &startTime);
|
||||
return (ppid < 0) ? -1 : startTime;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the parent pid of the requested pid.
|
||||
* The start time of the process must match (or be ANY).
|
||||
*
|
||||
* Class: java_lang_ProcessHandleImpl
|
||||
* Method: parent0
|
||||
* Signature: (JJ)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_java_lang_ProcessHandleImpl_parent0(JNIEnv *env,
|
||||
jobject obj,
|
||||
jlong jpid,
|
||||
jlong startTime) {
|
||||
pid_t pid = (pid_t) jpid;
|
||||
pid_t ppid;
|
||||
|
||||
if (pid == getpid()) {
|
||||
ppid = getppid();
|
||||
} else {
|
||||
jlong start = 0L;
|
||||
jlong total = 0L; // unused
|
||||
ppid = os_getParentPidAndTimings(env, pid, &total, &start);
|
||||
if (start != startTime && start != 0 && startTime != 0) {
|
||||
ppid = -1;
|
||||
}
|
||||
}
|
||||
return (jlong) ppid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the argument array by parsing the arguments from the sequence
|
||||
* of arguments.
|
||||
*/
|
||||
void unix_fillArgArray(JNIEnv *env, jobject jinfo, int nargs, char *cp,
|
||||
char *argsEnd, jstring cmdexe, char *cmdline) {
|
||||
jobject argsArray;
|
||||
int i;
|
||||
|
||||
(*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_commandID, cmdexe);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
|
||||
if (nargs >= 1) {
|
||||
// Create a String array for nargs-1 elements
|
||||
jclass clazzString = JNU_ClassString(env);
|
||||
CHECK_NULL(clazzString);
|
||||
argsArray = (*env)->NewObjectArray(env, nargs - 1, clazzString, NULL);
|
||||
CHECK_NULL(argsArray);
|
||||
|
||||
for (i = 0; i < nargs - 1; i++) {
|
||||
jstring str = NULL;
|
||||
|
||||
cp += strlen(cp) + 1;
|
||||
if (cp > argsEnd || *cp == '\0') {
|
||||
return; // Off the end pointer or an empty argument is an error
|
||||
}
|
||||
|
||||
CHECK_NULL((str = JNU_NewStringPlatform(env, cp)));
|
||||
|
||||
(*env)->SetObjectArrayElement(env, argsArray, i, str);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
}
|
||||
(*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_argumentsID, argsArray);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
}
|
||||
if (cmdline != NULL) {
|
||||
jstring commandLine = NULL;
|
||||
CHECK_NULL((commandLine = JNU_NewStringPlatform(env, cmdline)));
|
||||
(*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_commandLineID, commandLine);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
}
|
||||
}
|
||||
|
||||
void unix_getUserInfo(JNIEnv* env, jobject jinfo, uid_t uid) {
|
||||
int result = 0;
|
||||
char* pwbuf;
|
||||
jstring name = NULL;
|
||||
|
||||
/* allocate buffer for password record */
|
||||
pwbuf = (char*)malloc(getpw_buf_size);
|
||||
if (pwbuf == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, "Unable to open getpwent");
|
||||
} else {
|
||||
struct passwd pwent;
|
||||
struct passwd* p = NULL;
|
||||
RESTARTABLE(getpwuid_r(uid, &pwent, pwbuf, (size_t)getpw_buf_size, &p), result);
|
||||
|
||||
// Create the Java String if a name was found
|
||||
if (result == 0 && p != NULL &&
|
||||
p->pw_name != NULL && *(p->pw_name) != '\0') {
|
||||
name = JNU_NewStringPlatform(env, p->pw_name);
|
||||
}
|
||||
free(pwbuf);
|
||||
}
|
||||
if (name != NULL) {
|
||||
(*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_userID, name);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The following functions are common on Solaris, Linux and AIX.
|
||||
*/
|
||||
|
||||
#if defined(__solaris__) || defined (__linux__) || defined(_AIX)
|
||||
|
||||
/*
|
||||
* Returns the children of the requested pid and optionally each parent and
|
||||
* start time.
|
||||
* Reads /proc and accumulates any process who parent pid matches.
|
||||
* The resulting pids are stored into the array of longs.
|
||||
* The number of pids is returned if they all fit.
|
||||
* If the array is too short, the negative of the desired length is returned.
|
||||
*/
|
||||
jint unix_getChildren(JNIEnv *env, jlong jpid, jlongArray jarray,
|
||||
jlongArray jparentArray, jlongArray jstimesArray) {
|
||||
DIR* dir;
|
||||
struct dirent* ptr;
|
||||
pid_t pid = (pid_t) jpid;
|
||||
jlong* pids = NULL;
|
||||
jlong* ppids = NULL;
|
||||
jlong* stimes = NULL;
|
||||
jsize parentArraySize = 0;
|
||||
jsize arraySize = 0;
|
||||
jsize stimesSize = 0;
|
||||
jsize count = 0;
|
||||
|
||||
arraySize = (*env)->GetArrayLength(env, jarray);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, -1);
|
||||
if (jparentArray != NULL) {
|
||||
parentArraySize = (*env)->GetArrayLength(env, jparentArray);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, -1);
|
||||
|
||||
if (arraySize != parentArraySize) {
|
||||
JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (jstimesArray != NULL) {
|
||||
stimesSize = (*env)->GetArrayLength(env, jstimesArray);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, -1);
|
||||
|
||||
if (arraySize != stimesSize) {
|
||||
JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* To locate the children we scan /proc looking for files that have a
|
||||
* position integer as a filename.
|
||||
*/
|
||||
if ((dir = opendir("/proc")) == NULL) {
|
||||
JNU_ThrowByNameWithLastError(env,
|
||||
"java/lang/RuntimeException", "Unable to open /proc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
do { // Block to break out of on Exception
|
||||
pids = (*env)->GetLongArrayElements(env, jarray, NULL);
|
||||
if (pids == NULL) {
|
||||
break;
|
||||
}
|
||||
if (jparentArray != NULL) {
|
||||
ppids = (*env)->GetLongArrayElements(env, jparentArray, NULL);
|
||||
if (ppids == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (jstimesArray != NULL) {
|
||||
stimes = (*env)->GetLongArrayElements(env, jstimesArray, NULL);
|
||||
if (stimes == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while ((ptr = readdir(dir)) != NULL) {
|
||||
pid_t ppid = 0;
|
||||
jlong totalTime = 0L;
|
||||
jlong startTime = 0L;
|
||||
|
||||
/* skip files that aren't numbers */
|
||||
pid_t childpid = (pid_t) atoi(ptr->d_name);
|
||||
if ((int) childpid <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the parent pid, and start time
|
||||
ppid = os_getParentPidAndTimings(env, childpid, &totalTime, &startTime);
|
||||
if (ppid >= 0 && (pid == 0 || ppid == pid)) {
|
||||
if (count < arraySize) {
|
||||
// Only store if it fits
|
||||
pids[count] = (jlong) childpid;
|
||||
|
||||
if (ppids != NULL) {
|
||||
// Store the parentPid
|
||||
ppids[count] = (jlong) ppid;
|
||||
}
|
||||
if (stimes != NULL) {
|
||||
// Store the process start time
|
||||
stimes[count] = startTime;
|
||||
}
|
||||
}
|
||||
count++; // Count to tabulate size needed
|
||||
}
|
||||
}
|
||||
} while (0);
|
||||
|
||||
if (pids != NULL) {
|
||||
(*env)->ReleaseLongArrayElements(env, jarray, pids, 0);
|
||||
}
|
||||
if (ppids != NULL) {
|
||||
(*env)->ReleaseLongArrayElements(env, jparentArray, ppids, 0);
|
||||
}
|
||||
if (stimes != NULL) {
|
||||
(*env)->ReleaseLongArrayElements(env, jstimesArray, stimes, 0);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
// If more pids than array had size for; count will be greater than array size
|
||||
return count;
|
||||
}
|
||||
|
||||
#endif // defined(__solaris__) || defined (__linux__) || defined(_AIX)
|
||||
|
||||
/*
|
||||
* The following functions are common on Solaris and AIX.
|
||||
*/
|
||||
|
||||
#if defined(__solaris__) || defined(_AIX)
|
||||
|
||||
/**
|
||||
* Helper function to get the 'psinfo_t' data from "/proc/%d/psinfo".
|
||||
* Returns 0 on success and -1 on error.
|
||||
*/
|
||||
static int getPsinfo(pid_t pid, psinfo_t *psinfo) {
|
||||
FILE* fp;
|
||||
char fn[32];
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Try to open /proc/%d/psinfo
|
||||
*/
|
||||
snprintf(fn, sizeof fn, "/proc/%d/psinfo", pid);
|
||||
fp = fopen(fn, "r");
|
||||
if (fp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = fread(psinfo, 1, sizeof(psinfo_t), fp);
|
||||
fclose(fp);
|
||||
if (ret < sizeof(psinfo_t)) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read /proc/<pid>/psinfo and return the ppid, total cputime and start time.
|
||||
* Return: -1 is fail; >= 0 is parent pid
|
||||
* 'total' will contain the running time of 'pid' in nanoseconds.
|
||||
* 'start' will contain the start time of 'pid' in milliseconds since epoch.
|
||||
*/
|
||||
pid_t unix_getParentPidAndTimings(JNIEnv *env, pid_t pid,
|
||||
jlong *totalTime, jlong* startTime) {
|
||||
psinfo_t psinfo;
|
||||
|
||||
if (getPsinfo(pid, &psinfo) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Validate the pid before returning the info in case /proc/pid is racy
|
||||
if (kill(pid, 0) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*totalTime = psinfo.pr_time.tv_sec * 1000000000L + psinfo.pr_time.tv_nsec;
|
||||
|
||||
*startTime = psinfo.pr_start.tv_sec * (jlong)1000 +
|
||||
psinfo.pr_start.tv_nsec / 1000000;
|
||||
|
||||
return (pid_t) psinfo.pr_ppid;
|
||||
}
|
||||
|
||||
void unix_getCmdlineAndUserInfo(JNIEnv *env, jobject jinfo, pid_t pid) {
|
||||
psinfo_t psinfo;
|
||||
char fn[32];
|
||||
char exePath[PATH_MAX];
|
||||
char prargs[PRARGSZ + 1];
|
||||
jstring cmdexe = NULL;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* On Solaris, the full path to the executable command is the link in
|
||||
* /proc/<pid>/paths/a.out. But it is only readable for processes we own.
|
||||
*/
|
||||
#if defined(__solaris__)
|
||||
snprintf(fn, sizeof fn, "/proc/%d/path/a.out", pid);
|
||||
if ((ret = readlink(fn, exePath, PATH_MAX - 1)) > 0) {
|
||||
// null terminate and create String to store for command
|
||||
exePath[ret] = '\0';
|
||||
CHECK_NULL(cmdexe = JNU_NewStringPlatform(env, exePath));
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Now try to open /proc/%d/psinfo
|
||||
*/
|
||||
if (getPsinfo(pid, &psinfo) < 0) {
|
||||
unix_fillArgArray(env, jinfo, 0, NULL, NULL, cmdexe, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
unix_getUserInfo(env, jinfo, psinfo.pr_uid);
|
||||
|
||||
/*
|
||||
* Now read psinfo.pr_psargs which contains the first PRARGSZ characters of the
|
||||
* argument list (i.e. arg[0] arg[1] ...). Unfortunately, PRARGSZ is usually set
|
||||
* to 80 characters only. Nevertheless it's better than nothing :)
|
||||
*/
|
||||
strncpy(prargs, psinfo.pr_psargs, PRARGSZ);
|
||||
prargs[PRARGSZ] = '\0';
|
||||
if (prargs[0] == '\0') {
|
||||
/* If psinfo.pr_psargs didn't contain any strings, use psinfo.pr_fname
|
||||
* (which only contains the last component of exec()ed pathname) as a
|
||||
* last resort. This is true for AIX kernel processes for example.
|
||||
*/
|
||||
strncpy(prargs, psinfo.pr_fname, PRARGSZ);
|
||||
prargs[PRARGSZ] = '\0';
|
||||
}
|
||||
unix_fillArgArray(env, jinfo, 0, NULL, NULL, cmdexe,
|
||||
prargs[0] == '\0' ? NULL : prargs);
|
||||
}
|
||||
|
||||
#endif // defined(__solaris__) || defined(_AIX)
|
76
src/java.base/unix/native/libjava/ProcessHandleImpl_unix.h
Normal file
76
src/java.base/unix/native/libjava/ProcessHandleImpl_unix.h
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 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 <sys/types.h>
|
||||
|
||||
/*
|
||||
* Declaration of ProcessHandleImpl functions common on all Unix platforms.
|
||||
* 'unix_' functions have a single implementation in ProcessHandleImpl_unix.c
|
||||
* 'os_' prefixed functions have different, os-specific implementations in the
|
||||
* various ProcessHandleImpl_{linux,macosx,solaris,aix}.c files.
|
||||
* See ProcessHandleImpl_unix.c for more details.
|
||||
*/
|
||||
|
||||
/* Field id for jString 'command' in java.lang.ProcessHandleImpl.Info */
|
||||
extern jfieldID ProcessHandleImpl_Info_commandID;
|
||||
|
||||
/* Field id for jString 'commandLine' in java.lang.ProcessHandleImpl.Info */
|
||||
extern jfieldID ProcessHandleImpl_Info_commandLineID;
|
||||
|
||||
/* Field id for jString[] 'arguments' in java.lang.ProcessHandleImpl.Info */
|
||||
extern jfieldID ProcessHandleImpl_Info_argumentsID;
|
||||
|
||||
/* Field id for jlong 'totalTime' in java.lang.ProcessHandleImpl.Info */
|
||||
extern jfieldID ProcessHandleImpl_Info_totalTimeID;
|
||||
|
||||
/* Field id for jlong 'startTime' in java.lang.ProcessHandleImpl.Info */
|
||||
extern jfieldID ProcessHandleImpl_Info_startTimeID;
|
||||
|
||||
/* Field id for jString 'user' in java.lang.ProcessHandleImpl.Info */
|
||||
extern jfieldID ProcessHandleImpl_Info_userID;
|
||||
|
||||
/**
|
||||
* Return: -1 is fail; >= 0 is parent pid
|
||||
* 'total' will contain the running time of 'pid' in nanoseconds.
|
||||
* 'start' will contain the start time of 'pid' in milliseconds since epoch.
|
||||
*/
|
||||
extern pid_t unix_getParentPidAndTimings(JNIEnv *env, pid_t pid,
|
||||
jlong *total, jlong *start);
|
||||
extern pid_t os_getParentPidAndTimings(JNIEnv *env, pid_t pid,
|
||||
jlong *total, jlong *start);
|
||||
|
||||
extern void unix_getCmdlineAndUserInfo(JNIEnv *env, jobject jinfo, pid_t pid);
|
||||
extern void os_getCmdlineAndUserInfo(JNIEnv *env, jobject jinfo, pid_t pid);
|
||||
|
||||
extern jint unix_getChildren(JNIEnv *env, jlong jpid, jlongArray array,
|
||||
jlongArray jparentArray, jlongArray jstimesArray);
|
||||
extern jint os_getChildren(JNIEnv *env, jlong jpid, jlongArray array,
|
||||
jlongArray jparentArray, jlongArray jstimesArray);
|
||||
|
||||
extern void unix_getUserInfo(JNIEnv* env, jobject jinfo, uid_t uid);
|
||||
extern void unix_fillArgArray(JNIEnv *env, jobject jinfo, int nargs, char *cp,
|
||||
char *argsEnd, jstring cmdexe, char *cmdline);
|
||||
|
||||
extern void os_initNative(JNIEnv *env, jclass clazz);
|
649
src/java.base/unix/native/libjava/ProcessImpl_md.c
Normal file
649
src/java.base/unix/native/libjava/ProcessImpl_md.c
Normal file
|
@ -0,0 +1,649 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2015, 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.
|
||||
*/
|
||||
|
||||
#undef _LARGEFILE64_SOURCE
|
||||
#define _LARGEFILE64_SOURCE 1
|
||||
|
||||
#include "jni.h"
|
||||
#include "jvm.h"
|
||||
#include "jvm_md.h"
|
||||
#include "jni_util.h"
|
||||
#include "io_util.h"
|
||||
|
||||
/*
|
||||
* Platform-specific support for java.lang.Process
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(__solaris__) || defined(_ALLBSD_SOURCE) || defined(_AIX)
|
||||
#include <spawn.h>
|
||||
#endif
|
||||
|
||||
#include "childproc.h"
|
||||
|
||||
/*
|
||||
* There are 4 possible strategies we might use to "fork":
|
||||
*
|
||||
* - fork(2). Very portable and reliable but subject to
|
||||
* failure due to overcommit (see the documentation on
|
||||
* /proc/sys/vm/overcommit_memory in Linux proc(5)).
|
||||
* This is the ancient problem of spurious failure whenever a large
|
||||
* process starts a small subprocess.
|
||||
*
|
||||
* - vfork(). Using this is scary because all relevant man pages
|
||||
* contain dire warnings, e.g. Linux vfork(2). But at least it's
|
||||
* documented in the glibc docs and is standardized by XPG4.
|
||||
* http://www.opengroup.org/onlinepubs/000095399/functions/vfork.html
|
||||
* On Linux, one might think that vfork() would be implemented using
|
||||
* the clone system call with flag CLONE_VFORK, but in fact vfork is
|
||||
* a separate system call (which is a good sign, suggesting that
|
||||
* vfork will continue to be supported at least on Linux).
|
||||
* Another good sign is that glibc implements posix_spawn using
|
||||
* vfork whenever possible. Note that we cannot use posix_spawn
|
||||
* ourselves because there's no reliable way to close all inherited
|
||||
* file descriptors.
|
||||
*
|
||||
* - clone() with flags CLONE_VM but not CLONE_THREAD. clone() is
|
||||
* Linux-specific, but this ought to work - at least the glibc
|
||||
* sources contain code to handle different combinations of CLONE_VM
|
||||
* and CLONE_THREAD. However, when this was implemented, it
|
||||
* appeared to fail on 32-bit i386 (but not 64-bit x86_64) Linux with
|
||||
* the simple program
|
||||
* Runtime.getRuntime().exec("/bin/true").waitFor();
|
||||
* with:
|
||||
* # Internal Error (os_linux_x86.cpp:683), pid=19940, tid=2934639536
|
||||
* # Error: pthread_getattr_np failed with errno = 3 (ESRCH)
|
||||
* We believe this is a glibc bug, reported here:
|
||||
* http://sources.redhat.com/bugzilla/show_bug.cgi?id=10311
|
||||
* but the glibc maintainers closed it as WONTFIX.
|
||||
*
|
||||
* - posix_spawn(). While posix_spawn() is a fairly elaborate and
|
||||
* complicated system call, it can't quite do everything that the old
|
||||
* fork()/exec() combination can do, so the only feasible way to do
|
||||
* this, is to use posix_spawn to launch a new helper executable
|
||||
* "jprochelper", which in turn execs the target (after cleaning
|
||||
* up file-descriptors etc.) The end result is the same as before,
|
||||
* a child process linked to the parent in the same way, but it
|
||||
* avoids the problem of duplicating the parent (VM) process
|
||||
* address space temporarily, before launching the target command.
|
||||
*
|
||||
* Based on the above analysis, we are currently using vfork() on
|
||||
* Linux and posix_spawn() on other Unix systems.
|
||||
*/
|
||||
|
||||
|
||||
static void
|
||||
setSIGCHLDHandler(JNIEnv *env)
|
||||
{
|
||||
/* There is a subtle difference between having the signal handler
|
||||
* for SIGCHLD be SIG_DFL and SIG_IGN. We cannot obtain process
|
||||
* termination information for child processes if the signal
|
||||
* handler is SIG_IGN. It must be SIG_DFL.
|
||||
*
|
||||
* We used to set the SIGCHLD handler only on Linux, but it's
|
||||
* safest to set it unconditionally.
|
||||
*
|
||||
* Consider what happens if java's parent process sets the SIGCHLD
|
||||
* handler to SIG_IGN. Normally signal handlers are inherited by
|
||||
* children, but SIGCHLD is a controversial case. Solaris appears
|
||||
* to always reset it to SIG_DFL, but this behavior may be
|
||||
* non-standard-compliant, and we shouldn't rely on it.
|
||||
*
|
||||
* References:
|
||||
* http://www.opengroup.org/onlinepubs/7908799/xsh/exec.html
|
||||
* http://www.pasc.org/interps/unofficial/db/p1003.1/pasc-1003.1-132.html
|
||||
*/
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = SIG_DFL;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
|
||||
if (sigaction(SIGCHLD, &sa, NULL) < 0)
|
||||
JNU_ThrowInternalError(env, "Can't set SIGCHLD handler");
|
||||
}
|
||||
|
||||
static void*
|
||||
xmalloc(JNIEnv *env, size_t size)
|
||||
{
|
||||
void *p = malloc(size);
|
||||
if (p == NULL)
|
||||
JNU_ThrowOutOfMemoryError(env, NULL);
|
||||
return p;
|
||||
}
|
||||
|
||||
#define NEW(type, n) ((type *) xmalloc(env, (n) * sizeof(type)))
|
||||
|
||||
/**
|
||||
* If PATH is not defined, the OS provides some default value.
|
||||
* Unfortunately, there's no portable way to get this value.
|
||||
* Fortunately, it's only needed if the child has PATH while we do not.
|
||||
*/
|
||||
static const char*
|
||||
defaultPath(void)
|
||||
{
|
||||
#ifdef __solaris__
|
||||
/* These really are the Solaris defaults! */
|
||||
return (geteuid() == 0 || getuid() == 0) ?
|
||||
"/usr/xpg4/bin:/usr/bin:/opt/SUNWspro/bin:/usr/sbin" :
|
||||
"/usr/xpg4/bin:/usr/bin:/opt/SUNWspro/bin:";
|
||||
#else
|
||||
return ":/bin:/usr/bin"; /* glibc */
|
||||
#endif
|
||||
}
|
||||
|
||||
static const char*
|
||||
effectivePath(void)
|
||||
{
|
||||
const char *s = getenv("PATH");
|
||||
return (s != NULL) ? s : defaultPath();
|
||||
}
|
||||
|
||||
static int
|
||||
countOccurrences(const char *s, char c)
|
||||
{
|
||||
int count;
|
||||
for (count = 0; *s != '\0'; s++)
|
||||
count += (*s == c);
|
||||
return count;
|
||||
}
|
||||
|
||||
static const char * const *
|
||||
effectivePathv(JNIEnv *env)
|
||||
{
|
||||
char *p;
|
||||
int i;
|
||||
const char *path = effectivePath();
|
||||
int count = countOccurrences(path, ':') + 1;
|
||||
size_t pathvsize = sizeof(const char *) * (count+1);
|
||||
size_t pathsize = strlen(path) + 1;
|
||||
const char **pathv = (const char **) xmalloc(env, pathvsize + pathsize);
|
||||
|
||||
if (pathv == NULL)
|
||||
return NULL;
|
||||
p = (char *) pathv + pathvsize;
|
||||
memcpy(p, path, pathsize);
|
||||
/* split PATH by replacing ':' with NULs; empty components => "." */
|
||||
for (i = 0; i < count; i++) {
|
||||
char *q = p + strcspn(p, ":");
|
||||
pathv[i] = (p == q) ? "." : p;
|
||||
*q = '\0';
|
||||
p = q + 1;
|
||||
}
|
||||
pathv[count] = NULL;
|
||||
return pathv;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_lang_ProcessImpl_init(JNIEnv *env, jclass clazz)
|
||||
{
|
||||
parentPathv = effectivePathv(env);
|
||||
CHECK_NULL(parentPathv);
|
||||
setSIGCHLDHandler(env);
|
||||
}
|
||||
|
||||
|
||||
#ifndef WIFEXITED
|
||||
#define WIFEXITED(status) (((status)&0xFF) == 0)
|
||||
#endif
|
||||
|
||||
#ifndef WEXITSTATUS
|
||||
#define WEXITSTATUS(status) (((status)>>8)&0xFF)
|
||||
#endif
|
||||
|
||||
#ifndef WIFSIGNALED
|
||||
#define WIFSIGNALED(status) (((status)&0xFF) > 0 && ((status)&0xFF00) == 0)
|
||||
#endif
|
||||
|
||||
#ifndef WTERMSIG
|
||||
#define WTERMSIG(status) ((status)&0x7F)
|
||||
#endif
|
||||
|
||||
static const char *
|
||||
getBytes(JNIEnv *env, jbyteArray arr)
|
||||
{
|
||||
return arr == NULL ? NULL :
|
||||
(const char*) (*env)->GetByteArrayElements(env, arr, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
releaseBytes(JNIEnv *env, jbyteArray arr, const char* parr)
|
||||
{
|
||||
if (parr != NULL)
|
||||
(*env)->ReleaseByteArrayElements(env, arr, (jbyte*) parr, JNI_ABORT);
|
||||
}
|
||||
|
||||
#define IOE_FORMAT "error=%d, %s"
|
||||
|
||||
static void
|
||||
throwIOException(JNIEnv *env, int errnum, const char *defaultDetail)
|
||||
{
|
||||
const char *detail = defaultDetail;
|
||||
char *errmsg;
|
||||
size_t fmtsize;
|
||||
char tmpbuf[1024];
|
||||
jstring s;
|
||||
|
||||
if (errnum != 0) {
|
||||
int ret = getErrorString(errnum, tmpbuf, sizeof(tmpbuf));
|
||||
if (ret != EINVAL)
|
||||
detail = tmpbuf;
|
||||
}
|
||||
/* ASCII Decimal representation uses 2.4 times as many bits as binary. */
|
||||
fmtsize = sizeof(IOE_FORMAT) + strlen(detail) + 3 * sizeof(errnum);
|
||||
errmsg = NEW(char, fmtsize);
|
||||
if (errmsg == NULL)
|
||||
return;
|
||||
|
||||
snprintf(errmsg, fmtsize, IOE_FORMAT, errnum, detail);
|
||||
s = JNU_NewStringPlatform(env, errmsg);
|
||||
if (s != NULL) {
|
||||
jobject x = JNU_NewObjectByName(env, "java/io/IOException",
|
||||
"(Ljava/lang/String;)V", s);
|
||||
if (x != NULL)
|
||||
(*env)->Throw(env, x);
|
||||
}
|
||||
free(errmsg);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_PROCESS
|
||||
/* Debugging process code is difficult; where to write debug output? */
|
||||
static void
|
||||
debugPrint(char *format, ...)
|
||||
{
|
||||
FILE *tty = fopen("/dev/tty", "w");
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vfprintf(tty, format, ap);
|
||||
va_end(ap);
|
||||
fclose(tty);
|
||||
}
|
||||
#endif /* DEBUG_PROCESS */
|
||||
|
||||
static void
|
||||
copyPipe(int from[2], int to[2])
|
||||
{
|
||||
to[0] = from[0];
|
||||
to[1] = from[1];
|
||||
}
|
||||
|
||||
/* arg is an array of pointers to 0 terminated strings. array is terminated
|
||||
* by a null element.
|
||||
*
|
||||
* *nelems and *nbytes receive the number of elements of array (incl 0)
|
||||
* and total number of bytes (incl. 0)
|
||||
* Note. An empty array will have one null element
|
||||
* But if arg is null, then *nelems set to 0, and *nbytes to 0
|
||||
*/
|
||||
static void arraysize(const char * const *arg, int *nelems, int *nbytes)
|
||||
{
|
||||
int i, bytes, count;
|
||||
const char * const *a = arg;
|
||||
char *p;
|
||||
int *q;
|
||||
if (arg == 0) {
|
||||
*nelems = 0;
|
||||
*nbytes = 0;
|
||||
return;
|
||||
}
|
||||
/* count the array elements and number of bytes */
|
||||
for (count=0, bytes=0; *a != 0; count++, a++) {
|
||||
bytes += strlen(*a)+1;
|
||||
}
|
||||
*nbytes = bytes;
|
||||
*nelems = count+1;
|
||||
}
|
||||
|
||||
/* copy the strings from arg[] into buf, starting at given offset
|
||||
* return new offset to next free byte
|
||||
*/
|
||||
static int copystrings(char *buf, int offset, const char * const *arg) {
|
||||
char *p;
|
||||
const char * const *a;
|
||||
int count=0;
|
||||
|
||||
if (arg == 0) {
|
||||
return offset;
|
||||
}
|
||||
for (p=buf+offset, a=arg; *a != 0; a++) {
|
||||
int len = strlen(*a) +1;
|
||||
memcpy(p, *a, len);
|
||||
p += len;
|
||||
count += len;
|
||||
}
|
||||
return offset+count;
|
||||
}
|
||||
|
||||
/**
|
||||
* We are unusually paranoid; use of vfork is
|
||||
* especially likely to tickle gcc/glibc bugs.
|
||||
*/
|
||||
#ifdef __attribute_noinline__ /* See: sys/cdefs.h */
|
||||
__attribute_noinline__
|
||||
#endif
|
||||
|
||||
/* vfork(2) is deprecated on Solaris */
|
||||
#ifndef __solaris__
|
||||
static pid_t
|
||||
vforkChild(ChildStuff *c) {
|
||||
volatile pid_t resultPid;
|
||||
|
||||
/*
|
||||
* We separate the call to vfork into a separate function to make
|
||||
* very sure to keep stack of child from corrupting stack of parent,
|
||||
* as suggested by the scary gcc warning:
|
||||
* warning: variable 'foo' might be clobbered by 'longjmp' or 'vfork'
|
||||
*/
|
||||
resultPid = vfork();
|
||||
|
||||
if (resultPid == 0) {
|
||||
childProcess(c);
|
||||
}
|
||||
assert(resultPid != 0); /* childProcess never returns */
|
||||
return resultPid;
|
||||
}
|
||||
#endif
|
||||
|
||||
static pid_t
|
||||
forkChild(ChildStuff *c) {
|
||||
pid_t resultPid;
|
||||
|
||||
/*
|
||||
* From Solaris fork(2): In Solaris 10, a call to fork() is
|
||||
* identical to a call to fork1(); only the calling thread is
|
||||
* replicated in the child process. This is the POSIX-specified
|
||||
* behavior for fork().
|
||||
*/
|
||||
resultPid = fork();
|
||||
|
||||
if (resultPid == 0) {
|
||||
childProcess(c);
|
||||
}
|
||||
assert(resultPid != 0); /* childProcess never returns */
|
||||
return resultPid;
|
||||
}
|
||||
|
||||
#if defined(__solaris__) || defined(_ALLBSD_SOURCE) || defined(_AIX)
|
||||
static pid_t
|
||||
spawnChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) {
|
||||
pid_t resultPid;
|
||||
jboolean isCopy;
|
||||
int i, offset, rval, bufsize, magic;
|
||||
char *buf, buf1[16];
|
||||
char *hlpargs[2];
|
||||
SpawnInfo sp;
|
||||
|
||||
/* need to tell helper which fd is for receiving the childstuff
|
||||
* and which fd to send response back on
|
||||
*/
|
||||
snprintf(buf1, sizeof(buf1), "%d:%d", c->childenv[0], c->fail[1]);
|
||||
/* put the fd string as argument to the helper cmd */
|
||||
hlpargs[0] = buf1;
|
||||
hlpargs[1] = 0;
|
||||
|
||||
/* Following items are sent down the pipe to the helper
|
||||
* after it is spawned.
|
||||
* All strings are null terminated. All arrays of strings
|
||||
* have an empty string for termination.
|
||||
* - the ChildStuff struct
|
||||
* - the SpawnInfo struct
|
||||
* - the argv strings array
|
||||
* - the envv strings array
|
||||
* - the home directory string
|
||||
* - the parentPath string
|
||||
* - the parentPathv array
|
||||
*/
|
||||
/* First calculate the sizes */
|
||||
arraysize(c->argv, &sp.nargv, &sp.argvBytes);
|
||||
bufsize = sp.argvBytes;
|
||||
arraysize(c->envv, &sp.nenvv, &sp.envvBytes);
|
||||
bufsize += sp.envvBytes;
|
||||
sp.dirlen = c->pdir == 0 ? 0 : strlen(c->pdir)+1;
|
||||
bufsize += sp.dirlen;
|
||||
arraysize(parentPathv, &sp.nparentPathv, &sp.parentPathvBytes);
|
||||
bufsize += sp.parentPathvBytes;
|
||||
/* We need to clear FD_CLOEXEC if set in the fds[].
|
||||
* Files are created FD_CLOEXEC in Java.
|
||||
* Otherwise, they will be closed when the target gets exec'd */
|
||||
for (i=0; i<3; i++) {
|
||||
if (c->fds[i] != -1) {
|
||||
int flags = fcntl(c->fds[i], F_GETFD);
|
||||
if (flags & FD_CLOEXEC) {
|
||||
fcntl(c->fds[i], F_SETFD, flags & (~1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rval = posix_spawn(&resultPid, helperpath, 0, 0, (char * const *) hlpargs, environ);
|
||||
|
||||
if (rval != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* now the lengths are known, copy the data */
|
||||
buf = NEW(char, bufsize);
|
||||
if (buf == 0) {
|
||||
return -1;
|
||||
}
|
||||
offset = copystrings(buf, 0, &c->argv[0]);
|
||||
offset = copystrings(buf, offset, &c->envv[0]);
|
||||
memcpy(buf+offset, c->pdir, sp.dirlen);
|
||||
offset += sp.dirlen;
|
||||
offset = copystrings(buf, offset, parentPathv);
|
||||
assert(offset == bufsize);
|
||||
|
||||
magic = magicNumber();
|
||||
|
||||
/* write the two structs and the data buffer */
|
||||
write(c->childenv[1], (char *)&magic, sizeof(magic)); // magic number first
|
||||
write(c->childenv[1], (char *)c, sizeof(*c));
|
||||
write(c->childenv[1], (char *)&sp, sizeof(sp));
|
||||
write(c->childenv[1], buf, bufsize);
|
||||
free(buf);
|
||||
|
||||
/* In this mode an external main() in invoked which calls back into
|
||||
* childProcess() in this file, rather than directly
|
||||
* via the statement below */
|
||||
return resultPid;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Start a child process running function childProcess.
|
||||
* This function only returns in the parent.
|
||||
*/
|
||||
static pid_t
|
||||
startChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) {
|
||||
switch (c->mode) {
|
||||
/* vfork(2) is deprecated on Solaris */
|
||||
#ifndef __solaris__
|
||||
case MODE_VFORK:
|
||||
return vforkChild(c);
|
||||
#endif
|
||||
case MODE_FORK:
|
||||
return forkChild(c);
|
||||
#if defined(__solaris__) || defined(_ALLBSD_SOURCE) || defined(_AIX)
|
||||
case MODE_POSIX_SPAWN:
|
||||
return spawnChild(env, process, c, helperpath);
|
||||
#endif
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_java_lang_ProcessImpl_forkAndExec(JNIEnv *env,
|
||||
jobject process,
|
||||
jint mode,
|
||||
jbyteArray helperpath,
|
||||
jbyteArray prog,
|
||||
jbyteArray argBlock, jint argc,
|
||||
jbyteArray envBlock, jint envc,
|
||||
jbyteArray dir,
|
||||
jintArray std_fds,
|
||||
jboolean redirectErrorStream)
|
||||
{
|
||||
int errnum;
|
||||
int resultPid = -1;
|
||||
int in[2], out[2], err[2], fail[2], childenv[2];
|
||||
jint *fds = NULL;
|
||||
const char *phelperpath = NULL;
|
||||
const char *pprog = NULL;
|
||||
const char *pargBlock = NULL;
|
||||
const char *penvBlock = NULL;
|
||||
ChildStuff *c;
|
||||
|
||||
in[0] = in[1] = out[0] = out[1] = err[0] = err[1] = fail[0] = fail[1] = -1;
|
||||
childenv[0] = childenv[1] = -1;
|
||||
|
||||
if ((c = NEW(ChildStuff, 1)) == NULL) return -1;
|
||||
c->argv = NULL;
|
||||
c->envv = NULL;
|
||||
c->pdir = NULL;
|
||||
|
||||
/* Convert prog + argBlock into a char ** argv.
|
||||
* Add one word room for expansion of argv for use by
|
||||
* execve_as_traditional_shell_script.
|
||||
* This word is also used when using posix_spawn mode
|
||||
*/
|
||||
assert(prog != NULL && argBlock != NULL);
|
||||
if ((phelperpath = getBytes(env, helperpath)) == NULL) goto Catch;
|
||||
if ((pprog = getBytes(env, prog)) == NULL) goto Catch;
|
||||
if ((pargBlock = getBytes(env, argBlock)) == NULL) goto Catch;
|
||||
if ((c->argv = NEW(const char *, argc + 3)) == NULL) goto Catch;
|
||||
c->argv[0] = pprog;
|
||||
c->argc = argc + 2;
|
||||
initVectorFromBlock(c->argv+1, pargBlock, argc);
|
||||
|
||||
if (envBlock != NULL) {
|
||||
/* Convert envBlock into a char ** envv */
|
||||
if ((penvBlock = getBytes(env, envBlock)) == NULL) goto Catch;
|
||||
if ((c->envv = NEW(const char *, envc + 1)) == NULL) goto Catch;
|
||||
initVectorFromBlock(c->envv, penvBlock, envc);
|
||||
}
|
||||
|
||||
if (dir != NULL) {
|
||||
if ((c->pdir = getBytes(env, dir)) == NULL) goto Catch;
|
||||
}
|
||||
|
||||
assert(std_fds != NULL);
|
||||
fds = (*env)->GetIntArrayElements(env, std_fds, NULL);
|
||||
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(childenv) < 0) ||
|
||||
(pipe(fail) < 0)) {
|
||||
throwIOException(env, errno, "Bad file descriptor");
|
||||
goto Catch;
|
||||
}
|
||||
c->fds[0] = fds[0];
|
||||
c->fds[1] = fds[1];
|
||||
c->fds[2] = fds[2];
|
||||
|
||||
copyPipe(in, c->in);
|
||||
copyPipe(out, c->out);
|
||||
copyPipe(err, c->err);
|
||||
copyPipe(fail, c->fail);
|
||||
copyPipe(childenv, c->childenv);
|
||||
|
||||
c->redirectErrorStream = redirectErrorStream;
|
||||
c->mode = mode;
|
||||
|
||||
resultPid = startChild(env, process, c, phelperpath);
|
||||
assert(resultPid != 0);
|
||||
|
||||
if (resultPid < 0) {
|
||||
switch (c->mode) {
|
||||
case MODE_VFORK:
|
||||
throwIOException(env, errno, "vfork failed");
|
||||
break;
|
||||
case MODE_FORK:
|
||||
throwIOException(env, errno, "fork failed");
|
||||
break;
|
||||
case MODE_POSIX_SPAWN:
|
||||
throwIOException(env, errno, "posix_spawn failed");
|
||||
break;
|
||||
}
|
||||
goto Catch;
|
||||
}
|
||||
close(fail[1]); fail[1] = -1; /* See: WhyCantJohnnyExec (childproc.c) */
|
||||
|
||||
switch (readFully(fail[0], &errnum, sizeof(errnum))) {
|
||||
case 0: break; /* Exec succeeded */
|
||||
case sizeof(errnum):
|
||||
waitpid(resultPid, NULL, 0);
|
||||
throwIOException(env, errnum, "Exec failed");
|
||||
goto Catch;
|
||||
default:
|
||||
throwIOException(env, errno, "Read failed");
|
||||
goto Catch;
|
||||
}
|
||||
|
||||
fds[0] = (in [1] != -1) ? in [1] : -1;
|
||||
fds[1] = (out[0] != -1) ? out[0] : -1;
|
||||
fds[2] = (err[0] != -1) ? err[0] : -1;
|
||||
|
||||
Finally:
|
||||
/* Always clean up the child's side of the pipes */
|
||||
closeSafely(in [0]);
|
||||
closeSafely(out[1]);
|
||||
closeSafely(err[1]);
|
||||
|
||||
/* Always clean up fail and childEnv descriptors */
|
||||
closeSafely(fail[0]);
|
||||
closeSafely(fail[1]);
|
||||
closeSafely(childenv[0]);
|
||||
closeSafely(childenv[1]);
|
||||
|
||||
releaseBytes(env, helperpath, phelperpath);
|
||||
releaseBytes(env, prog, pprog);
|
||||
releaseBytes(env, argBlock, pargBlock);
|
||||
releaseBytes(env, envBlock, penvBlock);
|
||||
releaseBytes(env, dir, c->pdir);
|
||||
|
||||
free(c->argv);
|
||||
free(c->envv);
|
||||
free(c);
|
||||
|
||||
if (fds != NULL)
|
||||
(*env)->ReleaseIntArrayElements(env, std_fds, fds, 0);
|
||||
|
||||
return resultPid;
|
||||
|
||||
Catch:
|
||||
/* Clean up the parent's side of the pipes in case of failure only */
|
||||
closeSafely(in [1]); in[1] = -1;
|
||||
closeSafely(out[0]); out[0] = -1;
|
||||
closeSafely(err[0]); err[0] = -1;
|
||||
goto Finally;
|
||||
}
|
||||
|
48
src/java.base/unix/native/libjava/RandomAccessFile_md.c
Normal file
48
src/java.base/unix/native/libjava/RandomAccessFile_md.c
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 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 <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "io_util.h"
|
||||
#include "io_util_md.h"
|
||||
|
||||
#include "java_io_RandomAccessFile.h"
|
||||
|
||||
extern jfieldID raf_fd; /* id for jobject 'fd' in java.io.RandomAccessFile */
|
||||
|
||||
/*********************************************************************
|
||||
* Platform specific implementation of input stream native methods
|
||||
*/
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_io_RandomAccessFile_close0(JNIEnv *env, jobject this) {
|
||||
fileClose(env, this, raf_fd);
|
||||
}
|
912
src/java.base/unix/native/libjava/TimeZone_md.c
Normal file
912
src/java.base/unix/native/libjava/TimeZone_md.c
Normal file
|
@ -0,0 +1,912 @@
|
|||
/*
|
||||
* Copyright (c) 1999, 2016, 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <strings.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#if defined(__solaris__)
|
||||
#include <libscf.h>
|
||||
#endif
|
||||
|
||||
#include "jvm.h"
|
||||
#include "TimeZone_md.h"
|
||||
|
||||
#define SKIP_SPACE(p) while (*p == ' ' || *p == '\t') p++;
|
||||
|
||||
#define RESTARTABLE(_cmd, _result) do { \
|
||||
do { \
|
||||
_result = _cmd; \
|
||||
} while((_result == -1) && (errno == EINTR)); \
|
||||
} while(0)
|
||||
|
||||
#if defined(_ALLBSD_SOURCE)
|
||||
#define dirent64 dirent
|
||||
#define readdir64_r readdir_r
|
||||
#endif
|
||||
|
||||
#if !defined(__solaris__) || defined(__sparcv9) || defined(amd64)
|
||||
#define fileopen fopen
|
||||
#define filegets fgets
|
||||
#define fileclose fclose
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(_ALLBSD_SOURCE)
|
||||
static const char *ETC_TIMEZONE_FILE = "/etc/timezone";
|
||||
static const char *ZONEINFO_DIR = "/usr/share/zoneinfo";
|
||||
static const char *DEFAULT_ZONEINFO_FILE = "/etc/localtime";
|
||||
#else
|
||||
static const char *SYS_INIT_FILE = "/etc/default/init";
|
||||
static const char *ZONEINFO_DIR = "/usr/share/lib/zoneinfo";
|
||||
static const char *DEFAULT_ZONEINFO_FILE = "/usr/share/lib/zoneinfo/localtime";
|
||||
#endif /* defined(__linux__) || defined(_ALLBSD_SOURCE) */
|
||||
|
||||
#if defined(_AIX)
|
||||
static const char *ETC_ENVIRONMENT_FILE = "/etc/environment";
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(MACOSX) || defined(__solaris__)
|
||||
|
||||
/*
|
||||
* Returns a pointer to the zone ID portion of the given zoneinfo file
|
||||
* name, or NULL if the given string doesn't contain "zoneinfo/".
|
||||
*/
|
||||
static char *
|
||||
getZoneName(char *str)
|
||||
{
|
||||
static const char *zidir = "zoneinfo/";
|
||||
|
||||
char *pos = strstr((const char *)str, zidir);
|
||||
if (pos == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return pos + strlen(zidir);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a path name created from the given 'dir' and 'name' under
|
||||
* UNIX. This function allocates memory for the pathname calling
|
||||
* malloc(). NULL is returned if malloc() fails.
|
||||
*/
|
||||
static char *
|
||||
getPathName(const char *dir, const char *name) {
|
||||
char *path;
|
||||
|
||||
path = (char *) malloc(strlen(dir) + strlen(name) + 2);
|
||||
if (path == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return strcat(strcat(strcpy(path, dir), "/"), name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Scans the specified directory and its subdirectories to find a
|
||||
* zoneinfo file which has the same content as /etc/localtime on Linux
|
||||
* or /usr/share/lib/zoneinfo/localtime on Solaris given in 'buf'.
|
||||
* If file is symbolic link, then the contents it points to are in buf.
|
||||
* Returns a zone ID if found, otherwise, NULL is returned.
|
||||
*/
|
||||
static char *
|
||||
findZoneinfoFile(char *buf, size_t size, const char *dir)
|
||||
{
|
||||
DIR *dirp = NULL;
|
||||
struct stat statbuf;
|
||||
struct dirent64 *dp = NULL;
|
||||
struct dirent64 *entry = NULL;
|
||||
char *pathname = NULL;
|
||||
int fd = -1;
|
||||
char *dbuf = NULL;
|
||||
char *tz = NULL;
|
||||
int res;
|
||||
long name_max = 0;
|
||||
|
||||
dirp = opendir(dir);
|
||||
if (dirp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
name_max = pathconf(dir, _PC_NAME_MAX);
|
||||
// If pathconf did not work, fall back to a mimimum buffer size.
|
||||
if (name_max < 1024) {
|
||||
name_max = 1024;
|
||||
}
|
||||
|
||||
entry = (struct dirent64 *)malloc(offsetof(struct dirent64, d_name) + name_max + 1);
|
||||
if (entry == NULL) {
|
||||
(void) closedir(dirp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (readdir64_r(dirp, entry, &dp) == 0 && dp != NULL) {
|
||||
/*
|
||||
* Skip '.' and '..' (and possibly other .* files)
|
||||
*/
|
||||
if (dp->d_name[0] == '.') {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip "ROC", "posixrules", and "localtime".
|
||||
*/
|
||||
if ((strcmp(dp->d_name, "ROC") == 0)
|
||||
|| (strcmp(dp->d_name, "posixrules") == 0)
|
||||
#if defined(__solaris__)
|
||||
/*
|
||||
* Skip the "src" and "tab" directories on Solaris.
|
||||
*/
|
||||
|| (strcmp(dp->d_name, "src") == 0)
|
||||
|| (strcmp(dp->d_name, "tab") == 0)
|
||||
#endif
|
||||
|| (strcmp(dp->d_name, "localtime") == 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pathname = getPathName(dir, dp->d_name);
|
||||
if (pathname == NULL) {
|
||||
break;
|
||||
}
|
||||
RESTARTABLE(stat(pathname, &statbuf), res);
|
||||
if (res == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (S_ISDIR(statbuf.st_mode)) {
|
||||
tz = findZoneinfoFile(buf, size, pathname);
|
||||
if (tz != NULL) {
|
||||
break;
|
||||
}
|
||||
} else if (S_ISREG(statbuf.st_mode) && (size_t)statbuf.st_size == size) {
|
||||
dbuf = (char *) malloc(size);
|
||||
if (dbuf == NULL) {
|
||||
break;
|
||||
}
|
||||
RESTARTABLE(open(pathname, O_RDONLY), fd);
|
||||
if (fd == -1) {
|
||||
break;
|
||||
}
|
||||
RESTARTABLE(read(fd, dbuf, size), res);
|
||||
if (res != (ssize_t) size) {
|
||||
break;
|
||||
}
|
||||
if (memcmp(buf, dbuf, size) == 0) {
|
||||
tz = getZoneName(pathname);
|
||||
if (tz != NULL) {
|
||||
tz = strdup(tz);
|
||||
}
|
||||
break;
|
||||
}
|
||||
free((void *) dbuf);
|
||||
dbuf = NULL;
|
||||
(void) close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
free((void *) pathname);
|
||||
pathname = NULL;
|
||||
}
|
||||
|
||||
if (entry != NULL) {
|
||||
free((void *) entry);
|
||||
}
|
||||
if (dirp != NULL) {
|
||||
(void) closedir(dirp);
|
||||
}
|
||||
if (pathname != NULL) {
|
||||
free((void *) pathname);
|
||||
}
|
||||
if (fd != -1) {
|
||||
(void) close(fd);
|
||||
}
|
||||
if (dbuf != NULL) {
|
||||
free((void *) dbuf);
|
||||
}
|
||||
return tz;
|
||||
}
|
||||
|
||||
#if defined(__linux__) || defined(MACOSX)
|
||||
|
||||
/*
|
||||
* Performs Linux specific mapping and returns a zone ID
|
||||
* if found. Otherwise, NULL is returned.
|
||||
*/
|
||||
static char *
|
||||
getPlatformTimeZoneID()
|
||||
{
|
||||
struct stat statbuf;
|
||||
char *tz = NULL;
|
||||
FILE *fp;
|
||||
int fd;
|
||||
char *buf;
|
||||
size_t size;
|
||||
int res;
|
||||
|
||||
#if defined(__linux__)
|
||||
/*
|
||||
* Try reading the /etc/timezone file for Debian distros. There's
|
||||
* no spec of the file format available. This parsing assumes that
|
||||
* there's one line of an Olson tzid followed by a '\n', no
|
||||
* leading or trailing spaces, no comments.
|
||||
*/
|
||||
if ((fp = fopen(ETC_TIMEZONE_FILE, "r")) != NULL) {
|
||||
char line[256];
|
||||
|
||||
if (fgets(line, sizeof(line), fp) != NULL) {
|
||||
char *p = strchr(line, '\n');
|
||||
if (p != NULL) {
|
||||
*p = '\0';
|
||||
}
|
||||
if (strlen(line) > 0) {
|
||||
tz = strdup(line);
|
||||
}
|
||||
}
|
||||
(void) fclose(fp);
|
||||
if (tz != NULL) {
|
||||
return tz;
|
||||
}
|
||||
}
|
||||
#endif /* defined(__linux__) */
|
||||
|
||||
/*
|
||||
* Next, try /etc/localtime to find the zone ID.
|
||||
*/
|
||||
RESTARTABLE(lstat(DEFAULT_ZONEINFO_FILE, &statbuf), res);
|
||||
if (res == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If it's a symlink, get the link name and its zone ID part. (The
|
||||
* older versions of timeconfig created a symlink as described in
|
||||
* the Red Hat man page. It was changed in 1999 to create a copy
|
||||
* of a zoneinfo file. It's no longer possible to get the zone ID
|
||||
* from /etc/localtime.)
|
||||
*/
|
||||
if (S_ISLNK(statbuf.st_mode)) {
|
||||
char linkbuf[PATH_MAX+1];
|
||||
int len;
|
||||
|
||||
if ((len = readlink(DEFAULT_ZONEINFO_FILE, linkbuf, sizeof(linkbuf)-1)) == -1) {
|
||||
jio_fprintf(stderr, (const char *) "can't get a symlink of %s\n",
|
||||
DEFAULT_ZONEINFO_FILE);
|
||||
return NULL;
|
||||
}
|
||||
linkbuf[len] = '\0';
|
||||
tz = getZoneName(linkbuf);
|
||||
if (tz != NULL) {
|
||||
tz = strdup(tz);
|
||||
return tz;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If it's a regular file, we need to find out the same zoneinfo file
|
||||
* that has been copied as /etc/localtime.
|
||||
* If initial symbolic link resolution failed, we should treat target
|
||||
* file as a regular file.
|
||||
*/
|
||||
RESTARTABLE(open(DEFAULT_ZONEINFO_FILE, O_RDONLY), fd);
|
||||
if (fd == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RESTARTABLE(fstat(fd, &statbuf), res);
|
||||
if (res == -1) {
|
||||
(void) close(fd);
|
||||
return NULL;
|
||||
}
|
||||
size = (size_t) statbuf.st_size;
|
||||
buf = (char *) malloc(size);
|
||||
if (buf == NULL) {
|
||||
(void) close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RESTARTABLE(read(fd, buf, size), res);
|
||||
if (res != (ssize_t) size) {
|
||||
(void) close(fd);
|
||||
free((void *) buf);
|
||||
return NULL;
|
||||
}
|
||||
(void) close(fd);
|
||||
|
||||
tz = findZoneinfoFile(buf, size, ZONEINFO_DIR);
|
||||
free((void *) buf);
|
||||
return tz;
|
||||
}
|
||||
|
||||
#elif defined(__solaris__)
|
||||
|
||||
#if !defined(__sparcv9) && !defined(amd64)
|
||||
|
||||
/*
|
||||
* Those file* functions mimic the UNIX stream io functions. This is
|
||||
* because of the limitation of the number of open files on Solaris
|
||||
* (32-bit mode only) due to the System V ABI.
|
||||
*/
|
||||
|
||||
#define BUFFER_SIZE 4096
|
||||
|
||||
static struct iobuffer {
|
||||
int magic; /* -1 to distinguish from the real FILE */
|
||||
int fd; /* file descriptor */
|
||||
char *buffer; /* pointer to buffer */
|
||||
char *ptr; /* current read pointer */
|
||||
char *endptr; /* end pointer */
|
||||
};
|
||||
|
||||
static int
|
||||
fileclose(FILE *stream)
|
||||
{
|
||||
struct iobuffer *iop = (struct iobuffer *) stream;
|
||||
|
||||
if (iop->magic != -1) {
|
||||
return fclose(stream);
|
||||
}
|
||||
|
||||
if (iop == NULL) {
|
||||
return 0;
|
||||
}
|
||||
close(iop->fd);
|
||||
free((void *)iop->buffer);
|
||||
free((void *)iop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static FILE *
|
||||
fileopen(const char *fname, const char *fmode)
|
||||
{
|
||||
FILE *fp;
|
||||
int fd;
|
||||
struct iobuffer *iop;
|
||||
|
||||
if ((fp = fopen(fname, fmode)) != NULL) {
|
||||
return fp;
|
||||
}
|
||||
|
||||
/*
|
||||
* It assumes read open.
|
||||
*/
|
||||
RESTARTABLE(open(fname, O_RDONLY), fd);
|
||||
if (fd == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate struct iobuffer and its buffer
|
||||
*/
|
||||
iop = malloc(sizeof(struct iobuffer));
|
||||
if (iop == NULL) {
|
||||
(void) close(fd);
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
iop->magic = -1;
|
||||
iop->fd = fd;
|
||||
iop->buffer = malloc(BUFFER_SIZE);
|
||||
if (iop->buffer == NULL) {
|
||||
(void) close(fd);
|
||||
free((void *) iop);
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
iop->ptr = iop->buffer;
|
||||
iop->endptr = iop->buffer;
|
||||
return (FILE *)iop;
|
||||
}
|
||||
|
||||
/*
|
||||
* This implementation assumes that n is large enough and the line
|
||||
* separator is '\n'.
|
||||
*/
|
||||
static char *
|
||||
filegets(char *s, int n, FILE *stream)
|
||||
{
|
||||
struct iobuffer *iop = (struct iobuffer *) stream;
|
||||
char *p;
|
||||
|
||||
if (iop->magic != -1) {
|
||||
return fgets(s, n, stream);
|
||||
}
|
||||
|
||||
p = s;
|
||||
for (;;) {
|
||||
char c;
|
||||
|
||||
if (iop->ptr == iop->endptr) {
|
||||
ssize_t len;
|
||||
|
||||
RESTARTABLE(read(iop->fd, (void *)iop->buffer, BUFFER_SIZE), len);
|
||||
if (len == -1) {
|
||||
return NULL;
|
||||
}
|
||||
if (len == 0) {
|
||||
*p = 0;
|
||||
if (s == p) {
|
||||
return NULL;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
iop->ptr = iop->buffer;
|
||||
iop->endptr = iop->buffer + len;
|
||||
}
|
||||
c = *iop->ptr++;
|
||||
*p++ = c;
|
||||
if ((p - s) == (n - 1)) {
|
||||
*p = 0;
|
||||
return s;
|
||||
}
|
||||
if (c == '\n') {
|
||||
*p = 0;
|
||||
return s;
|
||||
}
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
#endif /* !defined(__sparcv9) && !defined(amd64) */
|
||||
|
||||
/*
|
||||
* Performs Solaris dependent mapping. Returns a zone ID if
|
||||
* found. Otherwise, NULL is returned. Solaris libc looks up
|
||||
* "/etc/default/init" to get the default TZ value if TZ is not defined
|
||||
* as an environment variable.
|
||||
*/
|
||||
static char *
|
||||
getPlatformTimeZoneID()
|
||||
{
|
||||
char *tz = NULL;
|
||||
FILE *fp;
|
||||
|
||||
/*
|
||||
* Try the TZ entry in /etc/default/init.
|
||||
*/
|
||||
if ((fp = fileopen(SYS_INIT_FILE, "r")) != NULL) {
|
||||
char line[256];
|
||||
char quote = '\0';
|
||||
|
||||
while (filegets(line, sizeof(line), fp) != NULL) {
|
||||
char *p = line;
|
||||
char *s;
|
||||
char c;
|
||||
|
||||
/* quick check for comment lines */
|
||||
if (*p == '#') {
|
||||
continue;
|
||||
}
|
||||
if (strncmp(p, "TZ=", 3) == 0) {
|
||||
p += 3;
|
||||
SKIP_SPACE(p);
|
||||
c = *p;
|
||||
if (c == '"' || c == '\'') {
|
||||
quote = c;
|
||||
p++;
|
||||
}
|
||||
|
||||
/*
|
||||
* PSARC/2001/383: quoted string support
|
||||
*/
|
||||
for (s = p; (c = *s) != '\0' && c != '\n'; s++) {
|
||||
/* No '\\' is supported here. */
|
||||
if (c == quote) {
|
||||
quote = '\0';
|
||||
break;
|
||||
}
|
||||
if (c == ' ' && quote == '\0') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (quote != '\0') {
|
||||
jio_fprintf(stderr, "ZoneInfo: unterminated time zone name in /etc/TIMEZONE\n");
|
||||
}
|
||||
*s = '\0';
|
||||
tz = strdup(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
(void) fileclose(fp);
|
||||
}
|
||||
return tz;
|
||||
}
|
||||
|
||||
#define TIMEZONE_FMRI "svc:/system/timezone:default"
|
||||
#define TIMEZONE_PG "timezone"
|
||||
#define LOCALTIME_PROP "localtime"
|
||||
|
||||
static void
|
||||
cleanupScf(scf_handle_t *h,
|
||||
scf_snapshot_t *snap,
|
||||
scf_instance_t *inst,
|
||||
scf_propertygroup_t *pg,
|
||||
scf_property_t *prop,
|
||||
scf_value_t *val,
|
||||
char *buf) {
|
||||
if (buf != NULL) {
|
||||
free(buf);
|
||||
}
|
||||
if (snap != NULL) {
|
||||
scf_snapshot_destroy(snap);
|
||||
}
|
||||
if (val != NULL) {
|
||||
scf_value_destroy(val);
|
||||
}
|
||||
if (prop != NULL) {
|
||||
scf_property_destroy(prop);
|
||||
}
|
||||
if (pg != NULL) {
|
||||
scf_pg_destroy(pg);
|
||||
}
|
||||
if (inst != NULL) {
|
||||
scf_instance_destroy(inst);
|
||||
}
|
||||
if (h != NULL) {
|
||||
scf_handle_destroy(h);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a zone ID of Solaris when the TZ value is "localtime".
|
||||
* First, it tries scf. If scf fails, it looks for the same file as
|
||||
* /usr/share/lib/zoneinfo/localtime under /usr/share/lib/zoneinfo/.
|
||||
*/
|
||||
static char *
|
||||
getSolarisDefaultZoneID() {
|
||||
char *tz = NULL;
|
||||
struct stat statbuf;
|
||||
size_t size;
|
||||
char *buf;
|
||||
int fd;
|
||||
int res;
|
||||
/* scf specific variables */
|
||||
scf_handle_t *h = NULL;
|
||||
scf_snapshot_t *snap = NULL;
|
||||
scf_instance_t *inst = NULL;
|
||||
scf_propertygroup_t *pg = NULL;
|
||||
scf_property_t *prop = NULL;
|
||||
scf_value_t *val = NULL;
|
||||
|
||||
if ((h = scf_handle_create(SCF_VERSION)) != NULL
|
||||
&& scf_handle_bind(h) == 0
|
||||
&& (inst = scf_instance_create(h)) != NULL
|
||||
&& (snap = scf_snapshot_create(h)) != NULL
|
||||
&& (pg = scf_pg_create(h)) != NULL
|
||||
&& (prop = scf_property_create(h)) != NULL
|
||||
&& (val = scf_value_create(h)) != NULL
|
||||
&& scf_handle_decode_fmri(h, TIMEZONE_FMRI, NULL, NULL, inst,
|
||||
NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) == 0
|
||||
&& scf_instance_get_snapshot(inst, "running", snap) == 0
|
||||
&& scf_instance_get_pg_composed(inst, snap, TIMEZONE_PG, pg) == 0
|
||||
&& scf_pg_get_property(pg, LOCALTIME_PROP, prop) == 0
|
||||
&& scf_property_get_value(prop, val) == 0) {
|
||||
ssize_t len;
|
||||
|
||||
/* Gets the length of the zone ID string */
|
||||
len = scf_value_get_astring(val, NULL, 0);
|
||||
if (len != -1) {
|
||||
tz = malloc(++len); /* +1 for a null byte */
|
||||
if (tz != NULL && scf_value_get_astring(val, tz, len) != -1) {
|
||||
cleanupScf(h, snap, inst, pg, prop, val, NULL);
|
||||
return tz;
|
||||
}
|
||||
}
|
||||
}
|
||||
cleanupScf(h, snap, inst, pg, prop, val, tz);
|
||||
|
||||
RESTARTABLE(stat(DEFAULT_ZONEINFO_FILE, &statbuf), res);
|
||||
if (res == -1) {
|
||||
return NULL;
|
||||
}
|
||||
size = (size_t) statbuf.st_size;
|
||||
buf = malloc(size);
|
||||
if (buf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
RESTARTABLE(open(DEFAULT_ZONEINFO_FILE, O_RDONLY), fd);
|
||||
if (fd == -1) {
|
||||
free((void *) buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RESTARTABLE(read(fd, buf, size), res);
|
||||
if (res != (ssize_t) size) {
|
||||
(void) close(fd);
|
||||
free((void *) buf);
|
||||
return NULL;
|
||||
}
|
||||
(void) close(fd);
|
||||
tz = findZoneinfoFile(buf, size, ZONEINFO_DIR);
|
||||
free((void *) buf);
|
||||
return tz;
|
||||
}
|
||||
|
||||
#endif /* defined(__solaris__) */
|
||||
|
||||
#elif defined(_AIX)
|
||||
|
||||
static char *
|
||||
getPlatformTimeZoneID()
|
||||
{
|
||||
FILE *fp;
|
||||
char *tz = NULL;
|
||||
char *tz_key = "TZ=";
|
||||
char line[256];
|
||||
size_t tz_key_len = strlen(tz_key);
|
||||
|
||||
if ((fp = fopen(ETC_ENVIRONMENT_FILE, "r")) != NULL) {
|
||||
while (fgets(line, sizeof(line), fp) != NULL) {
|
||||
char *p = strchr(line, '\n');
|
||||
if (p != NULL) {
|
||||
*p = '\0';
|
||||
}
|
||||
if (0 == strncmp(line, tz_key, tz_key_len)) {
|
||||
tz = strdup(line + tz_key_len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
(void) fclose(fp);
|
||||
}
|
||||
|
||||
return tz;
|
||||
}
|
||||
|
||||
static char *
|
||||
mapPlatformToJavaTimezone(const char *java_home_dir, const char *tz) {
|
||||
FILE *tzmapf;
|
||||
char mapfilename[PATH_MAX + 1];
|
||||
char line[256];
|
||||
int linecount = 0;
|
||||
char *tz_buf = NULL;
|
||||
char *temp_tz = NULL;
|
||||
char *javatz = NULL;
|
||||
size_t tz_len = 0;
|
||||
|
||||
/* On AIX, the TZ environment variable may end with a comma
|
||||
* followed by modifier fields. These are ignored here. */
|
||||
temp_tz = strchr(tz, ',');
|
||||
tz_len = (temp_tz == NULL) ? strlen(tz) : temp_tz - tz;
|
||||
tz_buf = (char *)malloc(tz_len + 1);
|
||||
memcpy(tz_buf, tz, tz_len);
|
||||
tz_buf[tz_len] = 0;
|
||||
|
||||
/* Open tzmappings file, with buffer overrun check */
|
||||
if ((strlen(java_home_dir) + 15) > PATH_MAX) {
|
||||
jio_fprintf(stderr, "Path %s/lib/tzmappings exceeds maximum path length\n", java_home_dir);
|
||||
goto tzerr;
|
||||
}
|
||||
strcpy(mapfilename, java_home_dir);
|
||||
strcat(mapfilename, "/lib/tzmappings");
|
||||
if ((tzmapf = fopen(mapfilename, "r")) == NULL) {
|
||||
jio_fprintf(stderr, "can't open %s\n", mapfilename);
|
||||
goto tzerr;
|
||||
}
|
||||
|
||||
while (fgets(line, sizeof(line), tzmapf) != NULL) {
|
||||
char *p = line;
|
||||
char *sol = line;
|
||||
char *java;
|
||||
int result;
|
||||
|
||||
linecount++;
|
||||
/*
|
||||
* Skip comments and blank lines
|
||||
*/
|
||||
if (*p == '#' || *p == '\n') {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the first field, platform zone ID
|
||||
*/
|
||||
while (*p != '\0' && *p != '\t') {
|
||||
p++;
|
||||
}
|
||||
if (*p == '\0') {
|
||||
/* mapping table is broken! */
|
||||
jio_fprintf(stderr, "tzmappings: Illegal format at near line %d.\n", linecount);
|
||||
break;
|
||||
}
|
||||
|
||||
*p++ = '\0';
|
||||
if ((result = strncmp(tz_buf, sol, tz_len)) == 0) {
|
||||
/*
|
||||
* If this is the current platform zone ID,
|
||||
* take the Java time zone ID (2nd field).
|
||||
*/
|
||||
java = p;
|
||||
while (*p != '\0' && *p != '\n') {
|
||||
p++;
|
||||
}
|
||||
|
||||
if (*p == '\0') {
|
||||
/* mapping table is broken! */
|
||||
jio_fprintf(stderr, "tzmappings: Illegal format at line %d.\n", linecount);
|
||||
break;
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
javatz = strdup(java);
|
||||
break;
|
||||
} else if (result < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
(void) fclose(tzmapf);
|
||||
|
||||
tzerr:
|
||||
if (tz_buf != NULL ) {
|
||||
free((void *) tz_buf);
|
||||
}
|
||||
|
||||
if (javatz == NULL) {
|
||||
return getGMTOffsetID();
|
||||
}
|
||||
|
||||
return javatz;
|
||||
}
|
||||
|
||||
#endif /* defined(_AIX) */
|
||||
|
||||
/*
|
||||
* findJavaTZ_md() maps platform time zone ID to Java time zone ID
|
||||
* using <java_home>/lib/tzmappings. If the TZ value is not found, it
|
||||
* trys some libc implementation dependent mappings. If it still
|
||||
* can't map to a Java time zone ID, it falls back to the GMT+/-hh:mm
|
||||
* form.
|
||||
*/
|
||||
/*ARGSUSED1*/
|
||||
char *
|
||||
findJavaTZ_md(const char *java_home_dir)
|
||||
{
|
||||
char *tz;
|
||||
char *javatz = NULL;
|
||||
char *freetz = NULL;
|
||||
|
||||
tz = getenv("TZ");
|
||||
|
||||
if (tz == NULL || *tz == '\0') {
|
||||
tz = getPlatformTimeZoneID();
|
||||
freetz = tz;
|
||||
}
|
||||
|
||||
if (tz != NULL) {
|
||||
/* Ignore preceding ':' */
|
||||
if (*tz == ':') {
|
||||
tz++;
|
||||
}
|
||||
#if defined(__linux__)
|
||||
/* Ignore "posix/" prefix on Linux. */
|
||||
if (strncmp(tz, "posix/", 6) == 0) {
|
||||
tz += 6;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_AIX)
|
||||
/* On AIX do the platform to Java mapping. */
|
||||
javatz = mapPlatformToJavaTimezone(java_home_dir, tz);
|
||||
if (freetz != NULL) {
|
||||
free((void *) freetz);
|
||||
}
|
||||
#else
|
||||
#if defined(__solaris__)
|
||||
/* Solaris might use localtime, so handle it here. */
|
||||
if (strcmp(tz, "localtime") == 0) {
|
||||
javatz = getSolarisDefaultZoneID();
|
||||
if (freetz != NULL) {
|
||||
free((void *) freetz);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
if (freetz == NULL) {
|
||||
/* strdup if we are still working on getenv result. */
|
||||
javatz = strdup(tz);
|
||||
} else if (freetz != tz) {
|
||||
/* strdup and free the old buffer, if we moved the pointer. */
|
||||
javatz = strdup(tz);
|
||||
free((void *) freetz);
|
||||
} else {
|
||||
/* we are good if we already work on a freshly allocated buffer. */
|
||||
javatz = tz;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return javatz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a GMT-offset-based zone ID. (e.g., "GMT-08:00")
|
||||
*/
|
||||
|
||||
#if defined(MACOSX)
|
||||
|
||||
char *
|
||||
getGMTOffsetID()
|
||||
{
|
||||
time_t offset;
|
||||
char sign, buf[32];
|
||||
struct tm local_tm;
|
||||
time_t clock;
|
||||
|
||||
clock = time(NULL);
|
||||
if (localtime_r(&clock, &local_tm) == NULL) {
|
||||
return strdup("GMT");
|
||||
}
|
||||
offset = (time_t)local_tm.tm_gmtoff;
|
||||
if (offset == 0) {
|
||||
return strdup("GMT");
|
||||
}
|
||||
if (offset > 0) {
|
||||
sign = '+';
|
||||
} else {
|
||||
offset = -offset;
|
||||
sign = '-';
|
||||
}
|
||||
sprintf(buf, (const char *)"GMT%c%02d:%02d",
|
||||
sign, (int)(offset/3600), (int)((offset%3600)/60));
|
||||
return strdup(buf);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
char *
|
||||
getGMTOffsetID()
|
||||
{
|
||||
time_t offset;
|
||||
char sign, buf[32];
|
||||
#if defined(__solaris__)
|
||||
struct tm localtm;
|
||||
time_t currenttime;
|
||||
|
||||
currenttime = time(NULL);
|
||||
if (localtime_r(¤ttime, &localtm) == NULL) {
|
||||
return strdup("GMT");
|
||||
}
|
||||
|
||||
offset = localtm.tm_isdst ? altzone : timezone;
|
||||
#else
|
||||
offset = timezone;
|
||||
#endif
|
||||
|
||||
if (offset == 0) {
|
||||
return strdup("GMT");
|
||||
}
|
||||
|
||||
/* Note that the time offset direction is opposite. */
|
||||
if (offset > 0) {
|
||||
sign = '-';
|
||||
} else {
|
||||
offset = -offset;
|
||||
sign = '+';
|
||||
}
|
||||
sprintf(buf, (const char *)"GMT%c%02d:%02d",
|
||||
sign, (int)(offset/3600), (int)((offset%3600)/60));
|
||||
return strdup(buf);
|
||||
}
|
||||
#endif /* MACOSX */
|
32
src/java.base/unix/native/libjava/TimeZone_md.h
Normal file
32
src/java.base/unix/native/libjava/TimeZone_md.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 1999, 2014, 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.
|
||||
*/
|
||||
|
||||
#ifndef _TIMEZONE_MD_H
|
||||
#define _TIMEZONE_MD_H
|
||||
|
||||
char *findJavaTZ_md(const char *java_home_dir);
|
||||
char *getGMTOffsetID();
|
||||
|
||||
#endif
|
530
src/java.base/unix/native/libjava/UnixFileSystem_md.c
Normal file
530
src/java.base/unix/native/libjava/UnixFileSystem_md.c
Normal file
|
@ -0,0 +1,530 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 2017, 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 <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef MACOSX
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#else
|
||||
#include <sys/statvfs.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <dlfcn.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jlong.h"
|
||||
#include "jvm.h"
|
||||
#include "io_util.h"
|
||||
#include "io_util_md.h"
|
||||
#include "java_io_FileSystem.h"
|
||||
#include "java_io_UnixFileSystem.h"
|
||||
|
||||
#if defined(_AIX)
|
||||
#if !defined(NAME_MAX)
|
||||
#define NAME_MAX MAXNAMLEN
|
||||
#endif
|
||||
#define DIR DIR64
|
||||
#define opendir opendir64
|
||||
#define closedir closedir64
|
||||
#endif
|
||||
|
||||
#if defined(__solaris__) && !defined(NAME_MAX)
|
||||
#define NAME_MAX MAXNAMLEN
|
||||
#endif
|
||||
|
||||
#if defined(_ALLBSD_SOURCE)
|
||||
#define dirent64 dirent
|
||||
#define readdir64_r readdir_r
|
||||
#define stat64 stat
|
||||
#ifndef MACOSX
|
||||
#define statvfs64 statvfs
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* -- Field IDs -- */
|
||||
|
||||
static struct {
|
||||
jfieldID path;
|
||||
} ids;
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_java_io_UnixFileSystem_initIDs(JNIEnv *env, jclass cls)
|
||||
{
|
||||
jclass fileClass = (*env)->FindClass(env, "java/io/File");
|
||||
if (!fileClass) return;
|
||||
ids.path = (*env)->GetFieldID(env, fileClass,
|
||||
"path", "Ljava/lang/String;");
|
||||
}
|
||||
|
||||
/* -- Path operations -- */
|
||||
|
||||
extern int canonicalize(char *path, const char *out, int len);
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_java_io_UnixFileSystem_canonicalize0(JNIEnv *env, jobject this,
|
||||
jstring pathname)
|
||||
{
|
||||
jstring rv = NULL;
|
||||
|
||||
WITH_PLATFORM_STRING(env, pathname, path) {
|
||||
char canonicalPath[JVM_MAXPATHLEN];
|
||||
if (canonicalize((char *)path,
|
||||
canonicalPath, JVM_MAXPATHLEN) < 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
|
||||
} else {
|
||||
#ifdef MACOSX
|
||||
rv = newStringPlatform(env, canonicalPath);
|
||||
#else
|
||||
rv = JNU_NewStringPlatform(env, canonicalPath);
|
||||
#endif
|
||||
}
|
||||
} END_PLATFORM_STRING(env, path);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
/* -- Attribute accessors -- */
|
||||
|
||||
|
||||
static jboolean
|
||||
statMode(const char *path, int *mode)
|
||||
{
|
||||
struct stat64 sb;
|
||||
if (stat64(path, &sb) == 0) {
|
||||
*mode = sb.st_mode;
|
||||
return JNI_TRUE;
|
||||
}
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_java_io_UnixFileSystem_getBooleanAttributes0(JNIEnv *env, jobject this,
|
||||
jobject file)
|
||||
{
|
||||
jint rv = 0;
|
||||
|
||||
WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
|
||||
int mode;
|
||||
if (statMode(path, &mode)) {
|
||||
int fmt = mode & S_IFMT;
|
||||
rv = (jint) (java_io_FileSystem_BA_EXISTS
|
||||
| ((fmt == S_IFREG) ? java_io_FileSystem_BA_REGULAR : 0)
|
||||
| ((fmt == S_IFDIR) ? java_io_FileSystem_BA_DIRECTORY : 0));
|
||||
}
|
||||
} END_PLATFORM_STRING(env, path);
|
||||
return rv;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_java_io_UnixFileSystem_checkAccess(JNIEnv *env, jobject this,
|
||||
jobject file, jint a)
|
||||
{
|
||||
jboolean rv = JNI_FALSE;
|
||||
int mode = 0;
|
||||
switch (a) {
|
||||
case java_io_FileSystem_ACCESS_READ:
|
||||
mode = R_OK;
|
||||
break;
|
||||
case java_io_FileSystem_ACCESS_WRITE:
|
||||
mode = W_OK;
|
||||
break;
|
||||
case java_io_FileSystem_ACCESS_EXECUTE:
|
||||
mode = X_OK;
|
||||
break;
|
||||
default: assert(0);
|
||||
}
|
||||
WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
|
||||
if (access(path, mode) == 0) {
|
||||
rv = JNI_TRUE;
|
||||
}
|
||||
} END_PLATFORM_STRING(env, path);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_java_io_UnixFileSystem_setPermission(JNIEnv *env, jobject this,
|
||||
jobject file,
|
||||
jint access,
|
||||
jboolean enable,
|
||||
jboolean owneronly)
|
||||
{
|
||||
jboolean rv = JNI_FALSE;
|
||||
|
||||
WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
|
||||
int amode = 0;
|
||||
int mode;
|
||||
switch (access) {
|
||||
case java_io_FileSystem_ACCESS_READ:
|
||||
if (owneronly)
|
||||
amode = S_IRUSR;
|
||||
else
|
||||
amode = S_IRUSR | S_IRGRP | S_IROTH;
|
||||
break;
|
||||
case java_io_FileSystem_ACCESS_WRITE:
|
||||
if (owneronly)
|
||||
amode = S_IWUSR;
|
||||
else
|
||||
amode = S_IWUSR | S_IWGRP | S_IWOTH;
|
||||
break;
|
||||
case java_io_FileSystem_ACCESS_EXECUTE:
|
||||
if (owneronly)
|
||||
amode = S_IXUSR;
|
||||
else
|
||||
amode = S_IXUSR | S_IXGRP | S_IXOTH;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
if (statMode(path, &mode)) {
|
||||
if (enable)
|
||||
mode |= amode;
|
||||
else
|
||||
mode &= ~amode;
|
||||
if (chmod(path, mode) >= 0) {
|
||||
rv = JNI_TRUE;
|
||||
}
|
||||
}
|
||||
} END_PLATFORM_STRING(env, path);
|
||||
return rv;
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_java_io_UnixFileSystem_getLastModifiedTime(JNIEnv *env, jobject this,
|
||||
jobject file)
|
||||
{
|
||||
jlong rv = 0;
|
||||
|
||||
WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
|
||||
struct stat64 sb;
|
||||
if (stat64(path, &sb) == 0) {
|
||||
#if defined(_AIX)
|
||||
rv = (jlong)sb.st_mtime * 1000;
|
||||
rv += (jlong)sb.st_mtime_n / 1000000;
|
||||
#elif defined(MACOSX)
|
||||
rv = (jlong)sb.st_mtimespec.tv_sec * 1000;
|
||||
rv += (jlong)sb.st_mtimespec.tv_nsec / 1000000;
|
||||
#else
|
||||
rv = (jlong)sb.st_mtim.tv_sec * 1000;
|
||||
rv += (jlong)sb.st_mtim.tv_nsec / 1000000;
|
||||
#endif
|
||||
}
|
||||
} END_PLATFORM_STRING(env, path);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_java_io_UnixFileSystem_getLength(JNIEnv *env, jobject this,
|
||||
jobject file)
|
||||
{
|
||||
jlong rv = 0;
|
||||
|
||||
WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
|
||||
struct stat64 sb;
|
||||
if (stat64(path, &sb) == 0) {
|
||||
rv = sb.st_size;
|
||||
}
|
||||
} END_PLATFORM_STRING(env, path);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
/* -- File operations -- */
|
||||
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_java_io_UnixFileSystem_createFileExclusively(JNIEnv *env, jclass cls,
|
||||
jstring pathname)
|
||||
{
|
||||
jboolean rv = JNI_FALSE;
|
||||
|
||||
WITH_PLATFORM_STRING(env, pathname, path) {
|
||||
FD fd;
|
||||
/* The root directory always exists */
|
||||
if (strcmp (path, "/")) {
|
||||
fd = handleOpen(path, O_RDWR | O_CREAT | O_EXCL, 0666);
|
||||
if (fd < 0) {
|
||||
if (errno != EEXIST)
|
||||
JNU_ThrowIOExceptionWithLastError(env, path);
|
||||
} else {
|
||||
if (close(fd) == -1)
|
||||
JNU_ThrowIOExceptionWithLastError(env, path);
|
||||
rv = JNI_TRUE;
|
||||
}
|
||||
}
|
||||
} END_PLATFORM_STRING(env, path);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_java_io_UnixFileSystem_delete0(JNIEnv *env, jobject this,
|
||||
jobject file)
|
||||
{
|
||||
jboolean rv = JNI_FALSE;
|
||||
|
||||
WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
|
||||
if (remove(path) == 0) {
|
||||
rv = JNI_TRUE;
|
||||
}
|
||||
} END_PLATFORM_STRING(env, path);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jobjectArray JNICALL
|
||||
Java_java_io_UnixFileSystem_list(JNIEnv *env, jobject this,
|
||||
jobject file)
|
||||
{
|
||||
DIR *dir = NULL;
|
||||
struct dirent64 *ptr;
|
||||
struct dirent64 *result;
|
||||
int len, maxlen;
|
||||
jobjectArray rv, old;
|
||||
jclass str_class;
|
||||
|
||||
str_class = JNU_ClassString(env);
|
||||
CHECK_NULL_RETURN(str_class, NULL);
|
||||
|
||||
WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
|
||||
dir = opendir(path);
|
||||
} END_PLATFORM_STRING(env, path);
|
||||
if (dir == NULL) return NULL;
|
||||
|
||||
ptr = malloc(sizeof(struct dirent64) + (PATH_MAX + 1));
|
||||
if (ptr == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
|
||||
closedir(dir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocate an initial String array */
|
||||
len = 0;
|
||||
maxlen = 16;
|
||||
rv = (*env)->NewObjectArray(env, maxlen, str_class, NULL);
|
||||
if (rv == NULL) goto error;
|
||||
|
||||
/* Scan the directory */
|
||||
while ((readdir64_r(dir, ptr, &result) == 0) && (result != NULL)) {
|
||||
jstring name;
|
||||
if (!strcmp(ptr->d_name, ".") || !strcmp(ptr->d_name, ".."))
|
||||
continue;
|
||||
if (len == maxlen) {
|
||||
old = rv;
|
||||
rv = (*env)->NewObjectArray(env, maxlen <<= 1, str_class, NULL);
|
||||
if (rv == NULL) goto error;
|
||||
if (JNU_CopyObjectArray(env, rv, old, len) < 0) goto error;
|
||||
(*env)->DeleteLocalRef(env, old);
|
||||
}
|
||||
#ifdef MACOSX
|
||||
name = newStringPlatform(env, ptr->d_name);
|
||||
#else
|
||||
name = JNU_NewStringPlatform(env, ptr->d_name);
|
||||
#endif
|
||||
if (name == NULL) goto error;
|
||||
(*env)->SetObjectArrayElement(env, rv, len++, name);
|
||||
(*env)->DeleteLocalRef(env, name);
|
||||
}
|
||||
closedir(dir);
|
||||
free(ptr);
|
||||
|
||||
/* Copy the final results into an appropriately-sized array */
|
||||
old = rv;
|
||||
rv = (*env)->NewObjectArray(env, len, str_class, NULL);
|
||||
if (rv == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (JNU_CopyObjectArray(env, rv, old, len) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
return rv;
|
||||
|
||||
error:
|
||||
closedir(dir);
|
||||
free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_java_io_UnixFileSystem_createDirectory(JNIEnv *env, jobject this,
|
||||
jobject file)
|
||||
{
|
||||
jboolean rv = JNI_FALSE;
|
||||
|
||||
WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
|
||||
if (mkdir(path, 0777) == 0) {
|
||||
rv = JNI_TRUE;
|
||||
}
|
||||
} END_PLATFORM_STRING(env, path);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_java_io_UnixFileSystem_rename0(JNIEnv *env, jobject this,
|
||||
jobject from, jobject to)
|
||||
{
|
||||
jboolean rv = JNI_FALSE;
|
||||
|
||||
WITH_FIELD_PLATFORM_STRING(env, from, ids.path, fromPath) {
|
||||
WITH_FIELD_PLATFORM_STRING(env, to, ids.path, toPath) {
|
||||
if (rename(fromPath, toPath) == 0) {
|
||||
rv = JNI_TRUE;
|
||||
}
|
||||
} END_PLATFORM_STRING(env, toPath);
|
||||
} END_PLATFORM_STRING(env, fromPath);
|
||||
return rv;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_java_io_UnixFileSystem_setLastModifiedTime(JNIEnv *env, jobject this,
|
||||
jobject file, jlong time)
|
||||
{
|
||||
jboolean rv = JNI_FALSE;
|
||||
|
||||
WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
|
||||
struct stat64 sb;
|
||||
|
||||
if (stat64(path, &sb) == 0) {
|
||||
struct timeval tv[2];
|
||||
|
||||
/* Preserve access time */
|
||||
#if defined(_AIX)
|
||||
tv[0].tv_sec = sb.st_atime;
|
||||
tv[0].tv_usec = sb.st_atime_n / 1000;
|
||||
#elif defined(MACOSX)
|
||||
tv[0].tv_sec = sb.st_atimespec.tv_sec;
|
||||
tv[0].tv_usec = sb.st_atimespec.tv_nsec / 1000;
|
||||
#else
|
||||
tv[0].tv_sec = sb.st_atim.tv_sec;
|
||||
tv[0].tv_usec = sb.st_atim.tv_nsec / 1000;
|
||||
#endif
|
||||
/* Change last-modified time */
|
||||
tv[1].tv_sec = time / 1000;
|
||||
tv[1].tv_usec = (time % 1000) * 1000;
|
||||
|
||||
if (utimes(path, tv) == 0)
|
||||
rv = JNI_TRUE;
|
||||
}
|
||||
} END_PLATFORM_STRING(env, path);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_java_io_UnixFileSystem_setReadOnly(JNIEnv *env, jobject this,
|
||||
jobject file)
|
||||
{
|
||||
jboolean rv = JNI_FALSE;
|
||||
|
||||
WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
|
||||
int mode;
|
||||
if (statMode(path, &mode)) {
|
||||
if (chmod(path, mode & ~(S_IWUSR | S_IWGRP | S_IWOTH)) >= 0) {
|
||||
rv = JNI_TRUE;
|
||||
}
|
||||
}
|
||||
} END_PLATFORM_STRING(env, path);
|
||||
return rv;
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_java_io_UnixFileSystem_getSpace(JNIEnv *env, jobject this,
|
||||
jobject file, jint t)
|
||||
{
|
||||
jlong rv = 0L;
|
||||
|
||||
WITH_FIELD_PLATFORM_STRING(env, file, ids.path, path) {
|
||||
#ifdef MACOSX
|
||||
struct statfs fsstat;
|
||||
#else
|
||||
struct statvfs64 fsstat;
|
||||
#endif
|
||||
memset(&fsstat, 0, sizeof(fsstat));
|
||||
#ifdef MACOSX
|
||||
if (statfs(path, &fsstat) == 0) {
|
||||
switch(t) {
|
||||
case java_io_FileSystem_SPACE_TOTAL:
|
||||
rv = jlong_mul(long_to_jlong(fsstat.f_bsize),
|
||||
long_to_jlong(fsstat.f_blocks));
|
||||
break;
|
||||
case java_io_FileSystem_SPACE_FREE:
|
||||
rv = jlong_mul(long_to_jlong(fsstat.f_bsize),
|
||||
long_to_jlong(fsstat.f_bfree));
|
||||
break;
|
||||
case java_io_FileSystem_SPACE_USABLE:
|
||||
rv = jlong_mul(long_to_jlong(fsstat.f_bsize),
|
||||
long_to_jlong(fsstat.f_bavail));
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (statvfs64(path, &fsstat) == 0) {
|
||||
switch(t) {
|
||||
case java_io_FileSystem_SPACE_TOTAL:
|
||||
rv = jlong_mul(long_to_jlong(fsstat.f_frsize),
|
||||
long_to_jlong(fsstat.f_blocks));
|
||||
break;
|
||||
case java_io_FileSystem_SPACE_FREE:
|
||||
rv = jlong_mul(long_to_jlong(fsstat.f_frsize),
|
||||
long_to_jlong(fsstat.f_bfree));
|
||||
break;
|
||||
case java_io_FileSystem_SPACE_USABLE:
|
||||
rv = jlong_mul(long_to_jlong(fsstat.f_frsize),
|
||||
long_to_jlong(fsstat.f_bavail));
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} END_PLATFORM_STRING(env, path);
|
||||
return rv;
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_java_io_UnixFileSystem_getNameMax0(JNIEnv *env, jobject this,
|
||||
jstring pathname)
|
||||
{
|
||||
jlong length = -1;
|
||||
WITH_PLATFORM_STRING(env, pathname, path) {
|
||||
length = (jlong)pathconf(path, _PC_NAME_MAX);
|
||||
} END_PLATFORM_STRING(env, path);
|
||||
return length != -1 ? length : (jlong)NAME_MAX;
|
||||
}
|
52
src/java.base/unix/native/libjava/VM_md.c
Normal file
52
src/java.base/unix/native/libjava/VM_md.c
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 2004, 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 <unistd.h>
|
||||
#include "jni_util.h"
|
||||
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_jdk_internal_misc_VM_getuid(JNIEnv *env, jclass thisclass) {
|
||||
|
||||
return getuid();
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_jdk_internal_misc_VM_geteuid(JNIEnv *env, jclass thisclass) {
|
||||
|
||||
return geteuid();
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_jdk_internal_misc_VM_getgid(JNIEnv *env, jclass thisclass) {
|
||||
|
||||
return getgid();
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_jdk_internal_misc_VM_getegid(JNIEnv *env, jclass thisclass) {
|
||||
|
||||
return getegid();
|
||||
}
|
272
src/java.base/unix/native/libjava/canonicalize_md.c
Normal file
272
src/java.base/unix/native/libjava/canonicalize_md.c
Normal file
|
@ -0,0 +1,272 @@
|
|||
/*
|
||||
* Copyright (c) 1994, 2012, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Pathname canonicalization for Unix file systems
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#if !defined(_ALLBSD_SOURCE)
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* Note: The comments in this file use the terminology
|
||||
defined in the java.io.File class */
|
||||
|
||||
|
||||
/* Check the given name sequence to see if it can be further collapsed.
|
||||
Return zero if not, otherwise return the number of names in the sequence. */
|
||||
|
||||
static int
|
||||
collapsible(char *names)
|
||||
{
|
||||
char *p = names;
|
||||
int dots = 0, n = 0;
|
||||
|
||||
while (*p) {
|
||||
if ((p[0] == '.') && ((p[1] == '\0')
|
||||
|| (p[1] == '/')
|
||||
|| ((p[1] == '.') && ((p[2] == '\0')
|
||||
|| (p[2] == '/'))))) {
|
||||
dots = 1;
|
||||
}
|
||||
n++;
|
||||
while (*p) {
|
||||
if (*p == '/') {
|
||||
p++;
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
return (dots ? n : 0);
|
||||
}
|
||||
|
||||
|
||||
/* Split the names in the given name sequence,
|
||||
replacing slashes with nulls and filling in the given index array */
|
||||
|
||||
static void
|
||||
splitNames(char *names, char **ix)
|
||||
{
|
||||
char *p = names;
|
||||
int i = 0;
|
||||
|
||||
while (*p) {
|
||||
ix[i++] = p++;
|
||||
while (*p) {
|
||||
if (*p == '/') {
|
||||
*p++ = '\0';
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Join the names in the given name sequence, ignoring names whose index
|
||||
entries have been cleared and replacing nulls with slashes as needed */
|
||||
|
||||
static void
|
||||
joinNames(char *names, int nc, char **ix)
|
||||
{
|
||||
int i;
|
||||
char *p;
|
||||
|
||||
for (i = 0, p = names; i < nc; i++) {
|
||||
if (!ix[i]) continue;
|
||||
if (i > 0) {
|
||||
p[-1] = '/';
|
||||
}
|
||||
if (p == ix[i]) {
|
||||
p += strlen(p) + 1;
|
||||
} else {
|
||||
char *q = ix[i];
|
||||
while ((*p++ = *q++));
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
|
||||
/* Collapse "." and ".." names in the given path wherever possible.
|
||||
A "." name may always be eliminated; a ".." name may be eliminated if it
|
||||
follows a name that is neither "." nor "..". This is a syntactic operation
|
||||
that performs no filesystem queries, so it should only be used to cleanup
|
||||
after invoking the realpath() procedure. */
|
||||
|
||||
static void
|
||||
collapse(char *path)
|
||||
{
|
||||
char *names = (path[0] == '/') ? path + 1 : path; /* Preserve first '/' */
|
||||
int nc;
|
||||
char **ix;
|
||||
int i, j;
|
||||
char *p, *q;
|
||||
|
||||
nc = collapsible(names);
|
||||
if (nc < 2) return; /* Nothing to do */
|
||||
ix = (char **)alloca(nc * sizeof(char *));
|
||||
splitNames(names, ix);
|
||||
|
||||
for (i = 0; i < nc; i++) {
|
||||
int dots = 0;
|
||||
|
||||
/* Find next occurrence of "." or ".." */
|
||||
do {
|
||||
char *p = ix[i];
|
||||
if (p[0] == '.') {
|
||||
if (p[1] == '\0') {
|
||||
dots = 1;
|
||||
break;
|
||||
}
|
||||
if ((p[1] == '.') && (p[2] == '\0')) {
|
||||
dots = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
} while (i < nc);
|
||||
if (i >= nc) break;
|
||||
|
||||
/* At this point i is the index of either a "." or a "..", so take the
|
||||
appropriate action and then continue the outer loop */
|
||||
if (dots == 1) {
|
||||
/* Remove this instance of "." */
|
||||
ix[i] = 0;
|
||||
}
|
||||
else {
|
||||
/* If there is a preceding name, remove both that name and this
|
||||
instance of ".."; otherwise, leave the ".." as is */
|
||||
for (j = i - 1; j >= 0; j--) {
|
||||
if (ix[j]) break;
|
||||
}
|
||||
if (j < 0) continue;
|
||||
ix[j] = 0;
|
||||
ix[i] = 0;
|
||||
}
|
||||
/* i will be incremented at the top of the loop */
|
||||
}
|
||||
|
||||
joinNames(names, nc, ix);
|
||||
}
|
||||
|
||||
|
||||
/* Convert a pathname to canonical form. The input path is assumed to contain
|
||||
no duplicate slashes. On Solaris we can use realpath() to do most of the
|
||||
work, though once that's done we still must collapse any remaining "." and
|
||||
".." names by hand. */
|
||||
|
||||
int
|
||||
canonicalize(char *original, char *resolved, int len)
|
||||
{
|
||||
if (len < PATH_MAX) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strlen(original) > PATH_MAX) {
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* First try realpath() on the entire path */
|
||||
if (realpath(original, resolved)) {
|
||||
/* That worked, so return it */
|
||||
collapse(resolved);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
/* Something's bogus in the original path, so remove names from the end
|
||||
until either some subpath works or we run out of names */
|
||||
char *p, *end, *r = NULL;
|
||||
char path[PATH_MAX + 1];
|
||||
|
||||
strncpy(path, original, sizeof(path));
|
||||
if (path[PATH_MAX] != '\0') {
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
end = path + strlen(path);
|
||||
|
||||
for (p = end; p > path;) {
|
||||
|
||||
/* Skip last element */
|
||||
while ((--p > path) && (*p != '/'));
|
||||
if (p == path) break;
|
||||
|
||||
/* Try realpath() on this subpath */
|
||||
*p = '\0';
|
||||
r = realpath(path, resolved);
|
||||
*p = (p == end) ? '\0' : '/';
|
||||
|
||||
if (r != NULL) {
|
||||
/* The subpath has a canonical path */
|
||||
break;
|
||||
}
|
||||
else if (errno == ENOENT || errno == ENOTDIR || errno == EACCES) {
|
||||
/* If the lookup of a particular subpath fails because the file
|
||||
does not exist, because it is of the wrong type, or because
|
||||
access is denied, then remove its last name and try again.
|
||||
Other I/O problems cause an error return. */
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (r != NULL) {
|
||||
/* Append unresolved subpath to resolved subpath */
|
||||
int rn = strlen(r);
|
||||
if (rn + (int)strlen(p) >= len) {
|
||||
/* Buffer overflow */
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
if ((rn > 0) && (r[rn - 1] == '/') && (*p == '/')) {
|
||||
/* Avoid duplicate slashes */
|
||||
p++;
|
||||
}
|
||||
strcpy(r + rn, p);
|
||||
collapse(r);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
/* Nothing resolved, so just return the original path */
|
||||
strcpy(resolved, path);
|
||||
collapse(resolved);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
388
src/java.base/unix/native/libjava/childproc.c
Normal file
388
src/java.base/unix/native/libjava/childproc.c
Normal file
|
@ -0,0 +1,388 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 2016, 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 <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "childproc.h"
|
||||
|
||||
|
||||
ssize_t
|
||||
restartableWrite(int fd, const void *buf, size_t count)
|
||||
{
|
||||
ssize_t result;
|
||||
RESTARTABLE(write(fd, buf, count), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
restartableDup2(int fd_from, int fd_to)
|
||||
{
|
||||
int err;
|
||||
RESTARTABLE(dup2(fd_from, fd_to), err);
|
||||
return err;
|
||||
}
|
||||
|
||||
int
|
||||
closeSafely(int fd)
|
||||
{
|
||||
return (fd == -1) ? 0 : close(fd);
|
||||
}
|
||||
|
||||
int
|
||||
isAsciiDigit(char c)
|
||||
{
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
#if defined(_AIX)
|
||||
/* AIX does not understand '/proc/self' - it requires the real process ID */
|
||||
#define FD_DIR aix_fd_dir
|
||||
#define DIR DIR64
|
||||
#define opendir opendir64
|
||||
#define closedir closedir64
|
||||
#elif defined(_ALLBSD_SOURCE)
|
||||
#define FD_DIR "/dev/fd"
|
||||
#define dirent64 dirent
|
||||
#define readdir64 readdir
|
||||
#else
|
||||
#define FD_DIR "/proc/self/fd"
|
||||
#endif
|
||||
|
||||
int
|
||||
closeDescriptors(void)
|
||||
{
|
||||
DIR *dp;
|
||||
struct dirent64 *dirp;
|
||||
int from_fd = FAIL_FILENO + 1;
|
||||
|
||||
/* We're trying to close all file descriptors, but opendir() might
|
||||
* itself be implemented using a file descriptor, and we certainly
|
||||
* don't want to close that while it's in use. We assume that if
|
||||
* opendir() is implemented using a file descriptor, then it uses
|
||||
* the lowest numbered file descriptor, just like open(). So we
|
||||
* close a couple explicitly. */
|
||||
|
||||
close(from_fd); /* for possible use by opendir() */
|
||||
close(from_fd + 1); /* another one for good luck */
|
||||
|
||||
#if defined(_AIX)
|
||||
/* AIX does not understand '/proc/self' - it requires the real process ID */
|
||||
char aix_fd_dir[32]; /* the pid has at most 19 digits */
|
||||
snprintf(aix_fd_dir, 32, "/proc/%d/fd", getpid());
|
||||
#endif
|
||||
|
||||
if ((dp = opendir(FD_DIR)) == NULL)
|
||||
return 0;
|
||||
|
||||
/* We use readdir64 instead of readdir to work around Solaris bug
|
||||
* 6395699: /proc/self/fd fails to report file descriptors >= 1024 on Solaris 9
|
||||
*/
|
||||
while ((dirp = readdir64(dp)) != NULL) {
|
||||
int fd;
|
||||
if (isAsciiDigit(dirp->d_name[0]) &&
|
||||
(fd = strtol(dirp->d_name, NULL, 10)) >= from_fd + 2)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
closedir(dp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
moveDescriptor(int fd_from, int fd_to)
|
||||
{
|
||||
if (fd_from != fd_to) {
|
||||
if ((restartableDup2(fd_from, fd_to) == -1) ||
|
||||
(close(fd_from) == -1))
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
magicNumber() {
|
||||
return 43110;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads nbyte bytes from file descriptor fd into buf,
|
||||
* The read operation is retried in case of EINTR or partial reads.
|
||||
*
|
||||
* Returns number of bytes read (normally nbyte, but may be less in
|
||||
* case of EOF). In case of read errors, returns -1 and sets errno.
|
||||
*/
|
||||
ssize_t
|
||||
readFully(int fd, void *buf, size_t nbyte)
|
||||
{
|
||||
ssize_t remaining = nbyte;
|
||||
for (;;) {
|
||||
ssize_t n = read(fd, buf, remaining);
|
||||
if (n == 0) {
|
||||
return nbyte - remaining;
|
||||
} else if (n > 0) {
|
||||
remaining -= n;
|
||||
if (remaining <= 0)
|
||||
return nbyte;
|
||||
/* We were interrupted in the middle of reading the bytes.
|
||||
* Unlikely, but possible. */
|
||||
buf = (void *) (((char *)buf) + n);
|
||||
} else if (errno == EINTR) {
|
||||
/* Strange signals like SIGJVM1 are possible at any time.
|
||||
* See http://www.dreamsongs.com/WorseIsBetter.html */
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
initVectorFromBlock(const char**vector, const char* block, int count)
|
||||
{
|
||||
int i;
|
||||
const char *p;
|
||||
for (i = 0, p = block; i < count; i++) {
|
||||
/* Invariant: p always points to the start of a C string. */
|
||||
vector[i] = p;
|
||||
while (*(p++));
|
||||
}
|
||||
vector[count] = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exec FILE as a traditional Bourne shell script (i.e. one without #!).
|
||||
* If we could do it over again, we would probably not support such an ancient
|
||||
* misfeature, but compatibility wins over sanity. The original support for
|
||||
* this was imported accidentally from execvp().
|
||||
*/
|
||||
void
|
||||
execve_as_traditional_shell_script(const char *file,
|
||||
const char *argv[],
|
||||
const char *const envp[])
|
||||
{
|
||||
/* Use the extra word of space provided for us in argv by caller. */
|
||||
const char *argv0 = argv[0];
|
||||
const char *const *end = argv;
|
||||
while (*end != NULL)
|
||||
++end;
|
||||
memmove(argv+2, argv+1, (end-argv) * sizeof(*end));
|
||||
argv[0] = "/bin/sh";
|
||||
argv[1] = file;
|
||||
execve(argv[0], (char **) argv, (char **) envp);
|
||||
/* Can't even exec /bin/sh? Big trouble, but let's soldier on... */
|
||||
memmove(argv+1, argv+2, (end-argv) * sizeof(*end));
|
||||
argv[0] = argv0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like execve(2), except that in case of ENOEXEC, FILE is assumed to
|
||||
* be a shell script and the system default shell is invoked to run it.
|
||||
*/
|
||||
void
|
||||
execve_with_shell_fallback(int mode, const char *file,
|
||||
const char *argv[],
|
||||
const char *const envp[])
|
||||
{
|
||||
if (mode == MODE_CLONE || mode == MODE_VFORK) {
|
||||
/* shared address space; be very careful. */
|
||||
execve(file, (char **) argv, (char **) envp);
|
||||
if (errno == ENOEXEC)
|
||||
execve_as_traditional_shell_script(file, argv, envp);
|
||||
} else {
|
||||
/* unshared address space; we can mutate environ. */
|
||||
environ = (char **) envp;
|
||||
execvp(file, (char **) argv);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 'execvpe' should have been included in the Unix standards,
|
||||
* and is a GNU extension in glibc 2.10.
|
||||
*
|
||||
* JDK_execvpe is identical to execvp, except that the child environment is
|
||||
* specified via the 3rd argument instead of being inherited from environ.
|
||||
*/
|
||||
void
|
||||
JDK_execvpe(int mode, const char *file,
|
||||
const char *argv[],
|
||||
const char *const envp[])
|
||||
{
|
||||
if (envp == NULL || (char **) envp == environ) {
|
||||
execvp(file, (char **) argv);
|
||||
return;
|
||||
}
|
||||
|
||||
if (*file == '\0') {
|
||||
errno = ENOENT;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strchr(file, '/') != NULL) {
|
||||
execve_with_shell_fallback(mode, file, argv, envp);
|
||||
} else {
|
||||
/* We must search PATH (parent's, not child's) */
|
||||
char expanded_file[PATH_MAX];
|
||||
int filelen = strlen(file);
|
||||
int sticky_errno = 0;
|
||||
const char * const * dirs;
|
||||
for (dirs = parentPathv; *dirs; dirs++) {
|
||||
const char * dir = *dirs;
|
||||
int dirlen = strlen(dir);
|
||||
if (filelen + dirlen + 2 >= PATH_MAX) {
|
||||
errno = ENAMETOOLONG;
|
||||
continue;
|
||||
}
|
||||
memcpy(expanded_file, dir, dirlen);
|
||||
if (expanded_file[dirlen - 1] != '/')
|
||||
expanded_file[dirlen++] = '/';
|
||||
memcpy(expanded_file + dirlen, file, filelen);
|
||||
expanded_file[dirlen + filelen] = '\0';
|
||||
execve_with_shell_fallback(mode, expanded_file, argv, envp);
|
||||
/* There are 3 responses to various classes of errno:
|
||||
* return immediately, continue (especially for ENOENT),
|
||||
* or continue with "sticky" errno.
|
||||
*
|
||||
* From exec(3):
|
||||
*
|
||||
* If permission is denied for a file (the attempted
|
||||
* execve returned EACCES), these functions will continue
|
||||
* searching the rest of the search path. If no other
|
||||
* file is found, however, they will return with the
|
||||
* global variable errno set to EACCES.
|
||||
*/
|
||||
switch (errno) {
|
||||
case EACCES:
|
||||
sticky_errno = errno;
|
||||
/* FALLTHRU */
|
||||
case ENOENT:
|
||||
case ENOTDIR:
|
||||
#ifdef ELOOP
|
||||
case ELOOP:
|
||||
#endif
|
||||
#ifdef ESTALE
|
||||
case ESTALE:
|
||||
#endif
|
||||
#ifdef ENODEV
|
||||
case ENODEV:
|
||||
#endif
|
||||
#ifdef ETIMEDOUT
|
||||
case ETIMEDOUT:
|
||||
#endif
|
||||
break; /* Try other directories in PATH */
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (sticky_errno != 0)
|
||||
errno = sticky_errno;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Child process after a successful fork().
|
||||
* This function must not return, and must be prepared for either all
|
||||
* of its address space to be shared with its parent, or to be a copy.
|
||||
* It must not modify global variables such as "environ".
|
||||
*/
|
||||
int
|
||||
childProcess(void *arg)
|
||||
{
|
||||
const ChildStuff* p = (const ChildStuff*) arg;
|
||||
|
||||
/* Close the parent sides of the pipes.
|
||||
Closing pipe fds here is redundant, since closeDescriptors()
|
||||
would do it anyways, but a little paranoia is a good thing. */
|
||||
if ((closeSafely(p->in[1]) == -1) ||
|
||||
(closeSafely(p->out[0]) == -1) ||
|
||||
(closeSafely(p->err[0]) == -1) ||
|
||||
(closeSafely(p->childenv[0]) == -1) ||
|
||||
(closeSafely(p->childenv[1]) == -1) ||
|
||||
(closeSafely(p->fail[0]) == -1))
|
||||
goto WhyCantJohnnyExec;
|
||||
|
||||
/* Give the child sides of the pipes the right fileno's. */
|
||||
/* Note: it is possible for in[0] == 0 */
|
||||
if ((moveDescriptor(p->in[0] != -1 ? p->in[0] : p->fds[0],
|
||||
STDIN_FILENO) == -1) ||
|
||||
(moveDescriptor(p->out[1]!= -1 ? p->out[1] : p->fds[1],
|
||||
STDOUT_FILENO) == -1))
|
||||
goto WhyCantJohnnyExec;
|
||||
|
||||
if (p->redirectErrorStream) {
|
||||
if ((closeSafely(p->err[1]) == -1) ||
|
||||
(restartableDup2(STDOUT_FILENO, STDERR_FILENO) == -1))
|
||||
goto WhyCantJohnnyExec;
|
||||
} else {
|
||||
if (moveDescriptor(p->err[1] != -1 ? p->err[1] : p->fds[2],
|
||||
STDERR_FILENO) == -1)
|
||||
goto WhyCantJohnnyExec;
|
||||
}
|
||||
|
||||
if (moveDescriptor(p->fail[1], FAIL_FILENO) == -1)
|
||||
goto WhyCantJohnnyExec;
|
||||
|
||||
/* close everything */
|
||||
if (closeDescriptors() == 0) { /* failed, close the old way */
|
||||
int max_fd = (int)sysconf(_SC_OPEN_MAX);
|
||||
int fd;
|
||||
for (fd = FAIL_FILENO + 1; fd < max_fd; fd++)
|
||||
if (close(fd) == -1 && errno != EBADF)
|
||||
goto WhyCantJohnnyExec;
|
||||
}
|
||||
|
||||
/* change to the new working directory */
|
||||
if (p->pdir != NULL && chdir(p->pdir) < 0)
|
||||
goto WhyCantJohnnyExec;
|
||||
|
||||
if (fcntl(FAIL_FILENO, F_SETFD, FD_CLOEXEC) == -1)
|
||||
goto WhyCantJohnnyExec;
|
||||
|
||||
JDK_execvpe(p->mode, p->argv[0], p->argv, p->envv);
|
||||
|
||||
WhyCantJohnnyExec:
|
||||
/* We used to go to an awful lot of trouble to predict whether the
|
||||
* child would fail, but there is no reliable way to predict the
|
||||
* success of an operation without *trying* it, and there's no way
|
||||
* to try a chdir or exec in the parent. Instead, all we need is a
|
||||
* way to communicate any failure back to the parent. Easy; we just
|
||||
* send the errno back to the parent over a pipe in case of failure.
|
||||
* The tricky thing is, how do we communicate the *success* of exec?
|
||||
* We use FD_CLOEXEC together with the fact that a read() on a pipe
|
||||
* yields EOF when the write ends (we have two of them!) are closed.
|
||||
*/
|
||||
{
|
||||
int errnum = errno;
|
||||
restartableWrite(FAIL_FILENO, &errnum, sizeof(errnum));
|
||||
}
|
||||
close(FAIL_FILENO);
|
||||
_exit(-1);
|
||||
return 0; /* Suppress warning "no return value from function" */
|
||||
}
|
144
src/java.base/unix/native/libjava/childproc.h
Normal file
144
src/java.base/unix/native/libjava/childproc.h
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef CHILDPROC_MD_H
|
||||
#define CHILDPROC_MD_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <crt_externs.h>
|
||||
#define environ (*_NSGetEnviron())
|
||||
#else
|
||||
/* This is one of the rare times it's more portable to declare an
|
||||
* external symbol explicitly, rather than via a system header.
|
||||
* The declaration is standardized as part of UNIX98, but there is
|
||||
* no standard (not even de-facto) header file where the
|
||||
* declaration is to be found. See:
|
||||
* http://www.opengroup.org/onlinepubs/009695399/functions/environ.html
|
||||
* http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_02.html
|
||||
*
|
||||
* "All identifiers in this volume of IEEE Std 1003.1-2001, except
|
||||
* environ, are defined in at least one of the headers" (!)
|
||||
*/
|
||||
extern char **environ;
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sched.h>
|
||||
#endif
|
||||
|
||||
#ifndef STDIN_FILENO
|
||||
#define STDIN_FILENO 0
|
||||
#endif
|
||||
|
||||
#ifndef STDOUT_FILENO
|
||||
#define STDOUT_FILENO 1
|
||||
#endif
|
||||
|
||||
#ifndef STDERR_FILENO
|
||||
#define STDERR_FILENO 2
|
||||
#endif
|
||||
|
||||
#ifndef SA_NOCLDSTOP
|
||||
#define SA_NOCLDSTOP 0
|
||||
#endif
|
||||
|
||||
#ifndef SA_RESTART
|
||||
#define SA_RESTART 0
|
||||
#endif
|
||||
|
||||
#define FAIL_FILENO (STDERR_FILENO + 1)
|
||||
|
||||
/* TODO: Refactor. */
|
||||
#define RESTARTABLE(_cmd, _result) do { \
|
||||
do { \
|
||||
_result = _cmd; \
|
||||
} while((_result == -1) && (errno == EINTR)); \
|
||||
} while(0)
|
||||
|
||||
/* These numbers must be the same as the Enum in ProcessImpl.java
|
||||
* Must be a better way of doing this.
|
||||
*/
|
||||
#define MODE_FORK 1
|
||||
#define MODE_POSIX_SPAWN 2
|
||||
#define MODE_VFORK 3
|
||||
#define MODE_CLONE 4
|
||||
|
||||
typedef struct _ChildStuff
|
||||
{
|
||||
int in[2];
|
||||
int out[2];
|
||||
int err[2];
|
||||
int fail[2];
|
||||
int childenv[2];
|
||||
int fds[3];
|
||||
int mode;
|
||||
const char **argv;
|
||||
int argc;
|
||||
const char **envv;
|
||||
const char *pdir;
|
||||
int redirectErrorStream;
|
||||
} ChildStuff;
|
||||
|
||||
/* following used in addition when mode is SPAWN */
|
||||
typedef struct _SpawnInfo {
|
||||
int nargv; /* number of argv array elements */
|
||||
int argvBytes; /* total number of bytes in argv array */
|
||||
int nenvv; /* number of envv array elements */
|
||||
int envvBytes; /* total number of bytes in envv array */
|
||||
int dirlen; /* length of home directory string */
|
||||
int nparentPathv; /* number of elements in parentPathv array */
|
||||
int parentPathvBytes; /* total number of bytes in parentPathv array */
|
||||
} SpawnInfo;
|
||||
|
||||
/**
|
||||
* The cached and split version of the JDK's effective PATH.
|
||||
* (We don't support putenv("PATH=...") in native code)
|
||||
*/
|
||||
const char * const *parentPathv;
|
||||
|
||||
ssize_t restartableWrite(int fd, const void *buf, size_t count);
|
||||
int restartableDup2(int fd_from, int fd_to);
|
||||
int closeSafely(int fd);
|
||||
int isAsciiDigit(char c);
|
||||
int closeDescriptors(void);
|
||||
int moveDescriptor(int fd_from, int fd_to);
|
||||
|
||||
int magicNumber();
|
||||
ssize_t readFully(int fd, void *buf, size_t nbyte);
|
||||
void initVectorFromBlock(const char**vector, const char* block, int count);
|
||||
void execve_as_traditional_shell_script(const char *file,
|
||||
const char *argv[],
|
||||
const char *const envp[]);
|
||||
void execve_with_shell_fallback(int mode, const char *file,
|
||||
const char *argv[],
|
||||
const char *const envp[]);
|
||||
void JDK_execvpe(int mode, const char *file,
|
||||
const char *argv[],
|
||||
const char *const envp[]);
|
||||
int childProcess(void *arg);
|
||||
|
||||
#endif
|
35
src/java.base/unix/native/libjava/gdefs_md.h
Normal file
35
src/java.base/unix/native/libjava/gdefs_md.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2008, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Solaris/Linux dependent type definitions includes intptr_t, etc
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h> /* For uintptr_t */
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
250
src/java.base/unix/native/libjava/io_util_md.c
Normal file
250
src/java.base/unix/native/libjava/io_util_md.c
Normal file
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 2017, 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 "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "io_util.h"
|
||||
#include "io_util_md.h"
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __solaris__
|
||||
#include <sys/filio.h>
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(_ALLBSD_SOURCE) || defined(_AIX)
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#ifdef MACOSX
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
__private_extern__
|
||||
jstring newStringPlatform(JNIEnv *env, const char* str)
|
||||
{
|
||||
jstring rv = NULL;
|
||||
CFMutableStringRef csref = CFStringCreateMutable(NULL, 0);
|
||||
if (csref == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, "native heap");
|
||||
} else {
|
||||
CFStringAppendCString(csref, str, kCFStringEncodingUTF8);
|
||||
CFStringNormalize(csref, kCFStringNormalizationFormC);
|
||||
int clen = CFStringGetLength(csref);
|
||||
int ulen = (clen + 1) * 2; // utf16 + zero padding
|
||||
char* chars = malloc(ulen);
|
||||
if (chars == NULL) {
|
||||
CFRelease(csref);
|
||||
JNU_ThrowOutOfMemoryError(env, "native heap");
|
||||
} else {
|
||||
if (CFStringGetCString(csref, chars, ulen, kCFStringEncodingUTF16)) {
|
||||
rv = (*env)->NewString(env, (jchar*)chars, clen);
|
||||
}
|
||||
free(chars);
|
||||
CFRelease(csref);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
FD
|
||||
handleOpen(const char *path, int oflag, int mode) {
|
||||
FD fd;
|
||||
RESTARTABLE(open64(path, oflag, mode), fd);
|
||||
if (fd != -1) {
|
||||
struct stat64 buf64;
|
||||
int result;
|
||||
RESTARTABLE(fstat64(fd, &buf64), result);
|
||||
if (result != -1) {
|
||||
if (S_ISDIR(buf64.st_mode)) {
|
||||
close(fd);
|
||||
errno = EISDIR;
|
||||
fd = -1;
|
||||
}
|
||||
} else {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
void
|
||||
fileOpen(JNIEnv *env, jobject this, jstring path, jfieldID fid, int flags)
|
||||
{
|
||||
WITH_PLATFORM_STRING(env, path, ps) {
|
||||
FD fd;
|
||||
|
||||
#if defined(__linux__) || defined(_ALLBSD_SOURCE)
|
||||
/* Remove trailing slashes, since the kernel won't */
|
||||
char *p = (char *)ps + strlen(ps) - 1;
|
||||
while ((p > ps) && (*p == '/'))
|
||||
*p-- = '\0';
|
||||
#endif
|
||||
fd = handleOpen(ps, flags, 0666);
|
||||
if (fd != -1) {
|
||||
jobject fdobj;
|
||||
jboolean append;
|
||||
SET_FD(this, fd, fid);
|
||||
|
||||
fdobj = (*env)->GetObjectField(env, this, fid);
|
||||
if (fdobj != NULL) {
|
||||
append = (flags & O_APPEND) == 0 ? JNI_FALSE : JNI_TRUE;
|
||||
(*env)->SetBooleanField(env, fdobj, IO_append_fdID, append);
|
||||
}
|
||||
} else {
|
||||
throwFileNotFoundException(env, path);
|
||||
}
|
||||
} END_PLATFORM_STRING(env, ps);
|
||||
}
|
||||
|
||||
void
|
||||
fileClose(JNIEnv *env, jobject this, jfieldID fid)
|
||||
{
|
||||
FD fd = GET_FD(this, fid);
|
||||
if (fd == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set the fd to -1 before closing it so that the timing window
|
||||
* of other threads using the wrong fd (closed but recycled fd,
|
||||
* that gets re-opened with some other filename) is reduced.
|
||||
* Practically the chance of its occurance is low, however, we are
|
||||
* taking extra precaution over here.
|
||||
*/
|
||||
SET_FD(this, -1, fid);
|
||||
|
||||
/*
|
||||
* Don't close file descriptors 0, 1, or 2. If we close these stream
|
||||
* then a subsequent file open or socket will use them. Instead we
|
||||
* just redirect these file descriptors to /dev/null.
|
||||
*/
|
||||
if (fd >= STDIN_FILENO && fd <= STDERR_FILENO) {
|
||||
int devnull = open("/dev/null", O_WRONLY);
|
||||
if (devnull < 0) {
|
||||
SET_FD(this, fd, fid); // restore fd
|
||||
JNU_ThrowIOExceptionWithLastError(env, "open /dev/null failed");
|
||||
} else {
|
||||
dup2(devnull, fd);
|
||||
close(devnull);
|
||||
}
|
||||
} else if (close(fd) == -1) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "close failed");
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t
|
||||
handleRead(FD fd, void *buf, jint len)
|
||||
{
|
||||
ssize_t result;
|
||||
RESTARTABLE(read(fd, buf, len), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
handleWrite(FD fd, const void *buf, jint len)
|
||||
{
|
||||
ssize_t result;
|
||||
RESTARTABLE(write(fd, buf, len), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
jint
|
||||
handleAvailable(FD fd, jlong *pbytes)
|
||||
{
|
||||
int mode;
|
||||
struct stat64 buf64;
|
||||
jlong size = -1, current = -1;
|
||||
|
||||
int result;
|
||||
RESTARTABLE(fstat64(fd, &buf64), result);
|
||||
if (result != -1) {
|
||||
mode = buf64.st_mode;
|
||||
if (S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode)) {
|
||||
int n;
|
||||
int result;
|
||||
RESTARTABLE(ioctl(fd, FIONREAD, &n), result);
|
||||
if (result >= 0) {
|
||||
*pbytes = n;
|
||||
return 1;
|
||||
}
|
||||
} else if (S_ISREG(mode)) {
|
||||
size = buf64.st_size;
|
||||
}
|
||||
}
|
||||
|
||||
if ((current = lseek64(fd, 0, SEEK_CUR)) == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (size < current) {
|
||||
if ((size = lseek64(fd, 0, SEEK_END)) == -1)
|
||||
return 0;
|
||||
else if (lseek64(fd, current, SEEK_SET) == -1)
|
||||
return 0;
|
||||
}
|
||||
|
||||
*pbytes = size - current;
|
||||
return 1;
|
||||
}
|
||||
|
||||
jint
|
||||
handleSetLength(FD fd, jlong length)
|
||||
{
|
||||
int result;
|
||||
#if defined(__linux__)
|
||||
/*
|
||||
* On Linux, if the file size is being increased, then ftruncate64()
|
||||
* will modify the metadata value of the size without actually allocating
|
||||
* any blocks which can cause a SIGBUS error if the file is subsequently
|
||||
* memory-mapped.
|
||||
*/
|
||||
struct stat64 sb;
|
||||
|
||||
if (fstat64(fd, &sb) == 0 && length > sb.st_blocks*512) {
|
||||
RESTARTABLE(fallocate64(fd, 0, 0, length), result);
|
||||
// Return on success or if errno is neither EOPNOTSUPP nor ENOSYS
|
||||
if (result == 0) {
|
||||
return 0;
|
||||
} else if (errno != EOPNOTSUPP && errno != ENOSYS) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
RESTARTABLE(ftruncate64(fd, length), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
jlong
|
||||
handleGetLength(FD fd)
|
||||
{
|
||||
struct stat64 sb;
|
||||
if (fstat64(fd, &sb) == 0) {
|
||||
return sb.st_size;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
109
src/java.base/unix/native/libjava/io_util_md.h
Normal file
109
src/java.base/unix/native/libjava/io_util_md.h
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2015, 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 "jni_util.h"
|
||||
|
||||
/*
|
||||
* Macros to use the right data type for file descriptors
|
||||
*/
|
||||
#define FD jint
|
||||
|
||||
/*
|
||||
* Prototypes for functions in io_util_md.c called from io_util.c,
|
||||
* FileDescriptor.c, FileInputStream.c, FileOutputStream.c,
|
||||
* UnixFileSystem_md.c
|
||||
*/
|
||||
ssize_t handleWrite(FD fd, const void *buf, jint len);
|
||||
ssize_t handleRead(FD fd, void *buf, jint len);
|
||||
jint handleAvailable(FD fd, jlong *pbytes);
|
||||
jint handleSetLength(FD fd, jlong length);
|
||||
jlong handleGetLength(FD fd);
|
||||
FD handleOpen(const char *path, int oflag, int mode);
|
||||
|
||||
/*
|
||||
* Macros to set/get fd from the java.io.FileDescriptor. These
|
||||
* macros rely on having an appropriately defined 'this' object
|
||||
* within the scope in which they're used.
|
||||
* If GetObjectField returns null, SET_FD will stop and GET_FD
|
||||
* will simply return -1 to avoid crashing VM.
|
||||
*/
|
||||
|
||||
#define SET_FD(this, fd, fid) \
|
||||
if ((*env)->GetObjectField(env, (this), (fid)) != NULL) \
|
||||
(*env)->SetIntField(env, (*env)->GetObjectField(env, (this), (fid)),IO_fd_fdID, (fd))
|
||||
|
||||
#define GET_FD(this, fid) \
|
||||
(*env)->GetObjectField(env, (this), (fid)) == NULL ? \
|
||||
-1 : (*env)->GetIntField(env, (*env)->GetObjectField(env, (this), (fid)), IO_fd_fdID)
|
||||
|
||||
/*
|
||||
* Macros to set/get fd when inside java.io.FileDescriptor
|
||||
*/
|
||||
#define THIS_FD(obj) (*env)->GetIntField(env, obj, IO_fd_fdID)
|
||||
|
||||
/*
|
||||
* Route the routines
|
||||
*/
|
||||
#define IO_Sync fsync
|
||||
#define IO_Read handleRead
|
||||
#define IO_Write handleWrite
|
||||
#define IO_Append handleWrite
|
||||
#define IO_Available handleAvailable
|
||||
#define IO_SetLength handleSetLength
|
||||
#define IO_GetLength handleGetLength
|
||||
|
||||
#ifdef _ALLBSD_SOURCE
|
||||
#define open64 open
|
||||
#define fstat64 fstat
|
||||
#define stat64 stat
|
||||
#define lseek64 lseek
|
||||
#define ftruncate64 ftruncate
|
||||
#define IO_Lseek lseek
|
||||
#else
|
||||
#define IO_Lseek lseek64
|
||||
#endif
|
||||
|
||||
/*
|
||||
* On Solaris, the handle field is unused
|
||||
*/
|
||||
#define SET_HANDLE(fd) return (jlong)-1
|
||||
|
||||
/*
|
||||
* Retry the operation if it is interrupted
|
||||
*/
|
||||
#define RESTARTABLE(_cmd, _result) do { \
|
||||
do { \
|
||||
_result = _cmd; \
|
||||
} while((_result == -1) && (errno == EINTR)); \
|
||||
} while(0)
|
||||
|
||||
/*
|
||||
* IO helper function(s)
|
||||
*/
|
||||
void fileClose(JNIEnv *env, jobject this, jfieldID fid);
|
||||
|
||||
#ifdef MACOSX
|
||||
jstring newStringPlatform(JNIEnv *env, const char* str);
|
||||
#endif
|
563
src/java.base/unix/native/libjava/java_props_md.c
Normal file
563
src/java.base/unix/native/libjava/java_props_md.c
Normal file
|
@ -0,0 +1,563 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 2016, 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.
|
||||
*/
|
||||
|
||||
#if defined(__linux__) || defined(_ALLBSD_SOURCE)
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#endif
|
||||
#include <pwd.h>
|
||||
#include <locale.h>
|
||||
#ifndef ARCHPROPNAME
|
||||
#error "The macro ARCHPROPNAME has not been defined"
|
||||
#endif
|
||||
#include <sys/utsname.h> /* For os_name and os_version */
|
||||
#include <langinfo.h> /* For nl_langinfo */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef MACOSX
|
||||
#include "java_props_macosx.h"
|
||||
#endif
|
||||
|
||||
#if defined(_ALLBSD_SOURCE)
|
||||
#if !defined(P_tmpdir)
|
||||
#include <paths.h>
|
||||
#define P_tmpdir _PATH_VARTMP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "locale_str.h"
|
||||
#include "java_props.h"
|
||||
|
||||
#if !defined(_ALLBSD_SOURCE)
|
||||
#ifdef __linux__
|
||||
#ifndef CODESET
|
||||
#define CODESET _NL_CTYPE_CODESET_NAME
|
||||
#endif
|
||||
#else
|
||||
#ifdef ALT_CODESET_KEY
|
||||
#define CODESET ALT_CODESET_KEY
|
||||
#endif
|
||||
#endif
|
||||
#endif /* !_ALLBSD_SOURCE */
|
||||
|
||||
/* Take an array of string pairs (map of key->value) and a string (key).
|
||||
* Examine each pair in the map to see if the first string (key) matches the
|
||||
* string. If so, store the second string of the pair (value) in the value and
|
||||
* return 1. Otherwise do nothing and return 0. The end of the map is
|
||||
* indicated by an empty string at the start of a pair (key of "").
|
||||
*/
|
||||
static int
|
||||
mapLookup(char* map[], const char* key, char** value) {
|
||||
int i;
|
||||
for (i = 0; strcmp(map[i], ""); i += 2){
|
||||
if (!strcmp(key, map[i])){
|
||||
*value = map[i + 1];
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef P_tmpdir
|
||||
#define P_tmpdir "/var/tmp"
|
||||
#endif
|
||||
|
||||
static int ParseLocale(JNIEnv* env, int cat, char ** std_language, char ** std_script,
|
||||
char ** std_country, char ** std_variant, char ** std_encoding) {
|
||||
char *temp = NULL;
|
||||
char *language = NULL, *country = NULL, *variant = NULL,
|
||||
*encoding = NULL;
|
||||
char *p, *encoding_variant, *old_temp, *old_ev;
|
||||
char *lc;
|
||||
|
||||
/* Query the locale set for the category */
|
||||
|
||||
#ifdef MACOSX
|
||||
lc = setupMacOSXLocale(cat); // malloc'd memory, need to free
|
||||
#else
|
||||
lc = setlocale(cat, NULL);
|
||||
#endif
|
||||
|
||||
#ifndef __linux__
|
||||
if (lc == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
temp = malloc(strlen(lc) + 1);
|
||||
if (temp == NULL) {
|
||||
#ifdef MACOSX
|
||||
free(lc); // malloced memory
|
||||
#endif
|
||||
JNU_ThrowOutOfMemoryError(env, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cat == LC_CTYPE) {
|
||||
/*
|
||||
* Workaround for Solaris bug 4201684: Xlib doesn't like @euro
|
||||
* locales. Since we don't depend on the libc @euro behavior,
|
||||
* we just remove the qualifier.
|
||||
* On Linux, the bug doesn't occur; on the other hand, @euro
|
||||
* is needed there because it's a shortcut that also determines
|
||||
* the encoding - without it, we wouldn't get ISO-8859-15.
|
||||
* Therefore, this code section is Solaris-specific.
|
||||
*/
|
||||
strcpy(temp, lc);
|
||||
p = strstr(temp, "@euro");
|
||||
if (p != NULL) {
|
||||
*p = '\0';
|
||||
setlocale(LC_ALL, temp);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (lc == NULL || !strcmp(lc, "C") || !strcmp(lc, "POSIX")) {
|
||||
lc = "en_US";
|
||||
}
|
||||
|
||||
temp = malloc(strlen(lc) + 1);
|
||||
if (temp == NULL) {
|
||||
JNU_ThrowOutOfMemoryError(env, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* locale string format in Solaris is
|
||||
* <language name>_<country name>.<encoding name>@<variant name>
|
||||
* <country name>, <encoding name>, and <variant name> are optional.
|
||||
*/
|
||||
|
||||
strcpy(temp, lc);
|
||||
#ifdef MACOSX
|
||||
free(lc); // malloced memory
|
||||
#endif
|
||||
/* Parse the language, country, encoding, and variant from the
|
||||
* locale. Any of the elements may be missing, but they must occur
|
||||
* in the order language_country.encoding@variant, and must be
|
||||
* preceded by their delimiter (except for language).
|
||||
*
|
||||
* If the locale name (without .encoding@variant, if any) matches
|
||||
* any of the names in the locale_aliases list, map it to the
|
||||
* corresponding full locale name. Most of the entries in the
|
||||
* locale_aliases list are locales that include a language name but
|
||||
* no country name, and this facility is used to map each language
|
||||
* to a default country if that's possible. It's also used to map
|
||||
* the Solaris locale aliases to their proper Java locale IDs.
|
||||
*/
|
||||
|
||||
encoding_variant = malloc(strlen(temp)+1);
|
||||
if (encoding_variant == NULL) {
|
||||
free(temp);
|
||||
JNU_ThrowOutOfMemoryError(env, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((p = strchr(temp, '.')) != NULL) {
|
||||
strcpy(encoding_variant, p); /* Copy the leading '.' */
|
||||
*p = '\0';
|
||||
} else if ((p = strchr(temp, '@')) != NULL) {
|
||||
strcpy(encoding_variant, p); /* Copy the leading '@' */
|
||||
*p = '\0';
|
||||
} else {
|
||||
*encoding_variant = '\0';
|
||||
}
|
||||
|
||||
if (mapLookup(locale_aliases, temp, &p)) {
|
||||
old_temp = temp;
|
||||
temp = realloc(temp, strlen(p)+1);
|
||||
if (temp == NULL) {
|
||||
free(old_temp);
|
||||
free(encoding_variant);
|
||||
JNU_ThrowOutOfMemoryError(env, NULL);
|
||||
return 0;
|
||||
}
|
||||
strcpy(temp, p);
|
||||
old_ev = encoding_variant;
|
||||
encoding_variant = realloc(encoding_variant, strlen(temp)+1);
|
||||
if (encoding_variant == NULL) {
|
||||
free(old_ev);
|
||||
free(temp);
|
||||
JNU_ThrowOutOfMemoryError(env, NULL);
|
||||
return 0;
|
||||
}
|
||||
// check the "encoding_variant" again, if any.
|
||||
if ((p = strchr(temp, '.')) != NULL) {
|
||||
strcpy(encoding_variant, p); /* Copy the leading '.' */
|
||||
*p = '\0';
|
||||
} else if ((p = strchr(temp, '@')) != NULL) {
|
||||
strcpy(encoding_variant, p); /* Copy the leading '@' */
|
||||
*p = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
language = temp;
|
||||
if ((country = strchr(temp, '_')) != NULL) {
|
||||
*country++ = '\0';
|
||||
}
|
||||
|
||||
p = encoding_variant;
|
||||
if ((encoding = strchr(p, '.')) != NULL) {
|
||||
p[encoding++ - p] = '\0';
|
||||
p = encoding;
|
||||
}
|
||||
if ((variant = strchr(p, '@')) != NULL) {
|
||||
p[variant++ - p] = '\0';
|
||||
}
|
||||
|
||||
/* Normalize the language name */
|
||||
if (std_language != NULL) {
|
||||
*std_language = "en";
|
||||
if (language != NULL && mapLookup(language_names, language, std_language) == 0) {
|
||||
*std_language = malloc(strlen(language)+1);
|
||||
strcpy(*std_language, language);
|
||||
}
|
||||
}
|
||||
|
||||
/* Normalize the country name */
|
||||
if (std_country != NULL && country != NULL) {
|
||||
if (mapLookup(country_names, country, std_country) == 0) {
|
||||
*std_country = malloc(strlen(country)+1);
|
||||
strcpy(*std_country, country);
|
||||
}
|
||||
}
|
||||
|
||||
/* Normalize the script and variant name. Note that we only use
|
||||
* variants listed in the mapping array; others are ignored.
|
||||
*/
|
||||
if (variant != NULL) {
|
||||
if (std_script != NULL) {
|
||||
mapLookup(script_names, variant, std_script);
|
||||
}
|
||||
|
||||
if (std_variant != NULL) {
|
||||
mapLookup(variant_names, variant, std_variant);
|
||||
}
|
||||
}
|
||||
|
||||
/* Normalize the encoding name. Note that we IGNORE the string
|
||||
* 'encoding' extracted from the locale name above. Instead, we use the
|
||||
* more reliable method of calling nl_langinfo(CODESET). This function
|
||||
* returns an empty string if no encoding is set for the given locale
|
||||
* (e.g., the C or POSIX locales); we use the default ISO 8859-1
|
||||
* converter for such locales.
|
||||
*/
|
||||
if (std_encoding != NULL) {
|
||||
/* OK, not so reliable - nl_langinfo() gives wrong answers on
|
||||
* Euro locales, in particular. */
|
||||
if (strcmp(p, "ISO8859-15") == 0)
|
||||
p = "ISO8859-15";
|
||||
else
|
||||
p = nl_langinfo(CODESET);
|
||||
|
||||
/* Convert the bare "646" used on Solaris to a proper IANA name */
|
||||
if (strcmp(p, "646") == 0)
|
||||
p = "ISO646-US";
|
||||
|
||||
/* return same result nl_langinfo would return for en_UK,
|
||||
* in order to use optimizations. */
|
||||
*std_encoding = (*p != '\0') ? p : "ISO8859-1";
|
||||
|
||||
#ifdef __linux__
|
||||
/*
|
||||
* Remap the encoding string to a different value for japanese
|
||||
* locales on linux so that customized converters are used instead
|
||||
* of the default converter for "EUC-JP". The customized converters
|
||||
* omit support for the JIS0212 encoding which is not supported by
|
||||
* the variant of "EUC-JP" encoding used on linux
|
||||
*/
|
||||
if (strcmp(p, "EUC-JP") == 0) {
|
||||
*std_encoding = "EUC-JP-LINUX";
|
||||
}
|
||||
#else
|
||||
if (strcmp(p,"eucJP") == 0) {
|
||||
/* For Solaris use customized vendor defined character
|
||||
* customized EUC-JP converter
|
||||
*/
|
||||
*std_encoding = "eucJP-open";
|
||||
} else if (strcmp(p, "Big5") == 0 || strcmp(p, "BIG5") == 0) {
|
||||
/*
|
||||
* Remap the encoding string to Big5_Solaris which augments
|
||||
* the default converter for Solaris Big5 locales to include
|
||||
* seven additional ideographic characters beyond those included
|
||||
* in the Java "Big5" converter.
|
||||
*/
|
||||
*std_encoding = "Big5_Solaris";
|
||||
} else if (strcmp(p, "Big5-HKSCS") == 0) {
|
||||
/*
|
||||
* Solaris uses HKSCS2001
|
||||
*/
|
||||
*std_encoding = "Big5-HKSCS-2001";
|
||||
}
|
||||
#endif
|
||||
#ifdef MACOSX
|
||||
/*
|
||||
* For the case on MacOS X where encoding is set to US-ASCII, but we
|
||||
* don't have any encoding hints from LANG/LC_ALL/LC_CTYPE, use UTF-8
|
||||
* instead.
|
||||
*
|
||||
* The contents of ASCII files will still be read and displayed
|
||||
* correctly, but so will files containing UTF-8 characters beyond the
|
||||
* standard ASCII range.
|
||||
*
|
||||
* Specifically, this allows apps launched by double-clicking a .jar
|
||||
* file to correctly read UTF-8 files using the default encoding (see
|
||||
* 8011194).
|
||||
*/
|
||||
if (strcmp(p,"US-ASCII") == 0 && getenv("LANG") == NULL &&
|
||||
getenv("LC_ALL") == NULL && getenv("LC_CTYPE") == NULL) {
|
||||
*std_encoding = "UTF-8";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
free(temp);
|
||||
free(encoding_variant);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* This function gets called very early, before VM_CALLS are setup.
|
||||
* Do not use any of the VM_CALLS entries!!!
|
||||
*/
|
||||
java_props_t *
|
||||
GetJavaProperties(JNIEnv *env)
|
||||
{
|
||||
static java_props_t sprops;
|
||||
char *v; /* tmp var */
|
||||
|
||||
if (sprops.user_dir) {
|
||||
return &sprops;
|
||||
}
|
||||
|
||||
/* tmp dir */
|
||||
sprops.tmp_dir = P_tmpdir;
|
||||
#ifdef MACOSX
|
||||
/* darwin has a per-user temp dir */
|
||||
static char tmp_path[PATH_MAX];
|
||||
int pathSize = confstr(_CS_DARWIN_USER_TEMP_DIR, tmp_path, PATH_MAX);
|
||||
if (pathSize > 0 && pathSize <= PATH_MAX) {
|
||||
sprops.tmp_dir = tmp_path;
|
||||
}
|
||||
#endif /* MACOSX */
|
||||
|
||||
/* Printing properties */
|
||||
#ifdef MACOSX
|
||||
sprops.printerJob = "sun.lwawt.macosx.CPrinterJob";
|
||||
#else
|
||||
sprops.printerJob = "sun.print.PSPrinterJob";
|
||||
#endif
|
||||
|
||||
/* patches/service packs installed */
|
||||
sprops.patch_level = "unknown";
|
||||
|
||||
/* Java 2D/AWT properties */
|
||||
#ifdef MACOSX
|
||||
// Always the same GraphicsEnvironment and Toolkit on Mac OS X
|
||||
sprops.graphics_env = "sun.awt.CGraphicsEnvironment";
|
||||
sprops.awt_toolkit = "sun.lwawt.macosx.LWCToolkit";
|
||||
|
||||
// check if we're in a GUI login session and set java.awt.headless=true if not
|
||||
sprops.awt_headless = isInAquaSession() ? NULL : "true";
|
||||
#else
|
||||
sprops.graphics_env = "sun.awt.X11GraphicsEnvironment";
|
||||
sprops.awt_toolkit = "sun.awt.X11.XToolkit";
|
||||
#endif
|
||||
|
||||
/* This is used only for debugging of font problems. */
|
||||
v = getenv("JAVA2D_FONTPATH");
|
||||
sprops.font_dir = v ? v : NULL;
|
||||
|
||||
#ifdef SI_ISALIST
|
||||
/* supported instruction sets */
|
||||
{
|
||||
char list[258];
|
||||
sysinfo(SI_ISALIST, list, sizeof(list));
|
||||
sprops.cpu_isalist = strdup(list);
|
||||
}
|
||||
#else
|
||||
sprops.cpu_isalist = NULL;
|
||||
#endif
|
||||
|
||||
/* endianness of platform */
|
||||
{
|
||||
unsigned int endianTest = 0xff000000;
|
||||
if (((char*)(&endianTest))[0] != 0)
|
||||
sprops.cpu_endian = "big";
|
||||
else
|
||||
sprops.cpu_endian = "little";
|
||||
}
|
||||
|
||||
/* os properties */
|
||||
{
|
||||
#ifdef MACOSX
|
||||
setOSNameAndVersion(&sprops);
|
||||
#else
|
||||
struct utsname name;
|
||||
uname(&name);
|
||||
sprops.os_name = strdup(name.sysname);
|
||||
#ifdef _AIX
|
||||
{
|
||||
char *os_version = malloc(strlen(name.version) +
|
||||
strlen(name.release) + 2);
|
||||
if (os_version != NULL) {
|
||||
strcpy(os_version, name.version);
|
||||
strcat(os_version, ".");
|
||||
strcat(os_version, name.release);
|
||||
}
|
||||
sprops.os_version = os_version;
|
||||
}
|
||||
#else
|
||||
sprops.os_version = strdup(name.release);
|
||||
#endif /* _AIX */
|
||||
#endif /* MACOSX */
|
||||
|
||||
sprops.os_arch = ARCHPROPNAME;
|
||||
|
||||
if (getenv("GNOME_DESKTOP_SESSION_ID") != NULL) {
|
||||
sprops.desktop = "gnome";
|
||||
}
|
||||
else {
|
||||
sprops.desktop = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* ABI property (optional) */
|
||||
#ifdef JDK_ARCH_ABI_PROP_NAME
|
||||
sprops.sun_arch_abi = JDK_ARCH_ABI_PROP_NAME;
|
||||
#endif
|
||||
|
||||
/* Determine the language, country, variant, and encoding from the host,
|
||||
* and store these in the user.language, user.country, user.variant and
|
||||
* file.encoding system properties. */
|
||||
setlocale(LC_ALL, "");
|
||||
if (ParseLocale(env, LC_CTYPE,
|
||||
&(sprops.format_language),
|
||||
&(sprops.format_script),
|
||||
&(sprops.format_country),
|
||||
&(sprops.format_variant),
|
||||
&(sprops.encoding))) {
|
||||
ParseLocale(env, LC_MESSAGES,
|
||||
&(sprops.language),
|
||||
&(sprops.script),
|
||||
&(sprops.country),
|
||||
&(sprops.variant),
|
||||
NULL);
|
||||
} else {
|
||||
sprops.language = "en";
|
||||
sprops.encoding = "ISO8859-1";
|
||||
}
|
||||
sprops.display_language = sprops.language;
|
||||
sprops.display_script = sprops.script;
|
||||
sprops.display_country = sprops.country;
|
||||
sprops.display_variant = sprops.variant;
|
||||
|
||||
/* ParseLocale failed with OOME */
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
|
||||
|
||||
#ifdef MACOSX
|
||||
sprops.sun_jnu_encoding = "UTF-8";
|
||||
#else
|
||||
sprops.sun_jnu_encoding = sprops.encoding;
|
||||
#endif
|
||||
|
||||
#ifdef _ALLBSD_SOURCE
|
||||
#if BYTE_ORDER == _LITTLE_ENDIAN
|
||||
sprops.unicode_encoding = "UnicodeLittle";
|
||||
#else
|
||||
sprops.unicode_encoding = "UnicodeBig";
|
||||
#endif
|
||||
#else /* !_ALLBSD_SOURCE */
|
||||
#ifdef __linux__
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
sprops.unicode_encoding = "UnicodeLittle";
|
||||
#else
|
||||
sprops.unicode_encoding = "UnicodeBig";
|
||||
#endif
|
||||
#else
|
||||
sprops.unicode_encoding = "UnicodeBig";
|
||||
#endif
|
||||
#endif /* _ALLBSD_SOURCE */
|
||||
|
||||
/* user properties */
|
||||
{
|
||||
struct passwd *pwent = getpwuid(getuid());
|
||||
sprops.user_name = pwent ? strdup(pwent->pw_name) : "?";
|
||||
#ifdef MACOSX
|
||||
setUserHome(&sprops);
|
||||
#else
|
||||
sprops.user_home = pwent ? strdup(pwent->pw_dir) : NULL;
|
||||
#endif
|
||||
if (sprops.user_home == NULL) {
|
||||
sprops.user_home = "?";
|
||||
}
|
||||
}
|
||||
|
||||
/* User TIMEZONE */
|
||||
{
|
||||
/*
|
||||
* We defer setting up timezone until it's actually necessary.
|
||||
* Refer to TimeZone.getDefault(). However, the system
|
||||
* property is necessary to be able to be set by the command
|
||||
* line interface -D. Here temporarily set a null string to
|
||||
* timezone.
|
||||
*/
|
||||
tzset(); /* for compatibility */
|
||||
sprops.timezone = "";
|
||||
}
|
||||
|
||||
/* Current directory */
|
||||
{
|
||||
char buf[MAXPATHLEN];
|
||||
errno = 0;
|
||||
if (getcwd(buf, sizeof(buf)) == NULL)
|
||||
JNU_ThrowByName(env, "java/lang/Error",
|
||||
"Properties init: Could not determine current working directory.");
|
||||
else
|
||||
sprops.user_dir = strdup(buf);
|
||||
}
|
||||
|
||||
sprops.file_separator = "/";
|
||||
sprops.path_separator = ":";
|
||||
sprops.line_separator = "\n";
|
||||
|
||||
#ifdef MACOSX
|
||||
setProxyProperties(&sprops);
|
||||
#endif
|
||||
|
||||
return &sprops;
|
||||
}
|
||||
|
||||
jstring
|
||||
GetStringPlatform(JNIEnv *env, nchar* cstr)
|
||||
{
|
||||
return JNU_NewStringPlatform(env, cstr);
|
||||
}
|
36
src/java.base/unix/native/libjava/jdk_util_md.c
Normal file
36
src/java.base/unix/native/libjava/jdk_util_md.c
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2004, 2005, 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 <dlfcn.h>
|
||||
#include "jdk_util.h"
|
||||
|
||||
int JDK_InitJvmHandle() {
|
||||
/* nop */
|
||||
return 1;
|
||||
}
|
||||
|
||||
void* JDK_FindJvmEntry(const char* name) {
|
||||
return dlsym(RTLD_DEFAULT, name);
|
||||
}
|
50
src/java.base/unix/native/libjava/jdk_util_md.h
Normal file
50
src/java.base/unix/native/libjava/jdk_util_md.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 2013, 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.
|
||||
*/
|
||||
|
||||
#ifndef JDK_UTIL_MD_H
|
||||
#define JDK_UTIL_MD_H
|
||||
|
||||
// checking for nanness
|
||||
#ifdef __solaris__
|
||||
#include <ieeefp.h>
|
||||
#define ISNANF(f) isnanf(f)
|
||||
#define ISNAND(d) isnand(d)
|
||||
#elif defined(MACOSX)
|
||||
#include <math.h>
|
||||
#define ISNANF(f) isnan(f)
|
||||
#define ISNAND(d) isnan(d)
|
||||
#elif defined(__linux__) || defined(_ALLBSD_SOURCE)
|
||||
#include <math.h>
|
||||
#define ISNANF(f) isnanf(f)
|
||||
#define ISNAND(d) isnan(d)
|
||||
#elif defined(_AIX)
|
||||
#include <math.h>
|
||||
#define ISNANF(f) _isnanf(f)
|
||||
#define ISNAND(d) _isnan(d)
|
||||
#else
|
||||
#error "missing platform-specific definition here"
|
||||
#endif
|
||||
|
||||
#endif /* JDK_UTIL_MD_H */
|
100
src/java.base/unix/native/libjava/jlong_md.h
Normal file
100
src/java.base/unix/native/libjava/jlong_md.h
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2015, 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.
|
||||
*/
|
||||
|
||||
#ifndef _SOLARIS_JLONG_MD_H_
|
||||
#define _SOLARIS_JLONG_MD_H_
|
||||
|
||||
/* Make sure ptrdiff_t is defined */
|
||||
#include <stddef.h>
|
||||
#include <stdint.h> /* For uintptr_t */
|
||||
|
||||
#define jlong_high(a) ((jint)((a)>>32))
|
||||
#define jlong_low(a) ((jint)(a))
|
||||
#define jlong_add(a, b) ((a) + (b))
|
||||
#define jlong_and(a, b) ((a) & (b))
|
||||
#define jlong_div(a, b) ((a) / (b))
|
||||
#define jlong_mul(a, b) ((a) * (b))
|
||||
#define jlong_neg(a) (-(a))
|
||||
#define jlong_not(a) (~(a))
|
||||
#define jlong_or(a, b) ((a) | (b))
|
||||
#define jlong_shl(a, n) ((a) << (n))
|
||||
#define jlong_shr(a, n) ((a) >> (n))
|
||||
#define jlong_sub(a, b) ((a) - (b))
|
||||
#define jlong_xor(a, b) ((a) ^ (b))
|
||||
#define jlong_rem(a,b) ((a) % (b))
|
||||
|
||||
/* comparison operators */
|
||||
#define jlong_ltz(ll) ((ll)<0)
|
||||
#define jlong_gez(ll) ((ll)>=0)
|
||||
#define jlong_gtz(ll) ((ll)>0)
|
||||
#define jlong_eqz(a) ((a) == 0)
|
||||
#define jlong_eq(a, b) ((a) == (b))
|
||||
#define jlong_ne(a,b) ((a) != (b))
|
||||
#define jlong_ge(a,b) ((a) >= (b))
|
||||
#define jlong_le(a,b) ((a) <= (b))
|
||||
#define jlong_lt(a,b) ((a) < (b))
|
||||
#define jlong_gt(a,b) ((a) > (b))
|
||||
|
||||
#define jlong_zero ((jlong) 0)
|
||||
#define jlong_one ((jlong) 1)
|
||||
#define jlong_minus_one ((jlong) -1)
|
||||
|
||||
/* For static variables initialized to zero */
|
||||
#define jlong_zero_init ((jlong) 0L)
|
||||
|
||||
#ifdef _LP64
|
||||
#ifndef jlong_to_ptr
|
||||
#define jlong_to_ptr(a) ((void*)(a))
|
||||
#endif
|
||||
#ifndef ptr_to_jlong
|
||||
#define ptr_to_jlong(a) ((jlong)(a))
|
||||
#endif
|
||||
#else
|
||||
#ifndef jlong_to_ptr
|
||||
#define jlong_to_ptr(a) ((void*)(int)(a))
|
||||
#endif
|
||||
#ifndef ptr_to_jlong
|
||||
#define ptr_to_jlong(a) ((jlong)(int)(a))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define jint_to_jlong(a) ((jlong)(a))
|
||||
#define jlong_to_jint(a) ((jint)(a))
|
||||
|
||||
/* Useful on machines where jlong and jdouble have different endianness. */
|
||||
#define jlong_to_jdouble_bits(a)
|
||||
#define jdouble_to_jlong_bits(a)
|
||||
|
||||
#define jlong_to_int(a) ((int)(a))
|
||||
#define int_to_jlong(a) ((jlong)(a))
|
||||
#define jlong_to_uint(a) ((unsigned int)(a))
|
||||
#define uint_to_jlong(a) ((jlong)(a))
|
||||
#define jlong_to_ptrdiff(a) ((ptrdiff_t)(a))
|
||||
#define ptrdiff_to_jlong(a) ((jlong)(a))
|
||||
#define jlong_to_size(a) ((size_t)(a))
|
||||
#define size_to_jlong(a) ((jlong)(a))
|
||||
#define long_to_jlong(a) ((jlong)(a))
|
||||
|
||||
#endif /* !_SOLARIS_JLONG_MD_H_ */
|
75
src/java.base/unix/native/libjava/jni_util_md.c
Normal file
75
src/java.base/unix/native/libjava/jni_util_md.c
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2014, 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 <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "dlfcn.h"
|
||||
|
||||
#if defined(LINUX) && (defined(_GNU_SOURCE) || \
|
||||
(defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE < 200112L \
|
||||
&& defined(_XOPEN_SOURCE) && _XOPEN_SOURCE < 600))
|
||||
extern int __xpg_strerror_r(int, char *, size_t);
|
||||
#define strerror_r(a, b, c) __xpg_strerror_r((a), (b), (c))
|
||||
#endif
|
||||
|
||||
void* getProcessHandle() {
|
||||
static void *procHandle = NULL;
|
||||
if (procHandle != NULL) {
|
||||
return procHandle;
|
||||
}
|
||||
#ifdef __APPLE__
|
||||
procHandle = (void*)dlopen(NULL, RTLD_FIRST);
|
||||
#else
|
||||
procHandle = (void*)dlopen(NULL, RTLD_LAZY);
|
||||
#endif
|
||||
return procHandle;
|
||||
}
|
||||
|
||||
void buildJniFunctionName(const char *sym, const char *cname,
|
||||
char *jniEntryName) {
|
||||
strcpy(jniEntryName, sym);
|
||||
if (cname != NULL) {
|
||||
strcat(jniEntryName, "_");
|
||||
strcat(jniEntryName, cname);
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
getLastErrorString(char *buf, size_t len)
|
||||
{
|
||||
if (errno == 0 || len < 1) return 0;
|
||||
getErrorString(errno, buf, len);
|
||||
return strlen(buf);
|
||||
}
|
||||
|
||||
int
|
||||
getErrorString(int err, char *buf, size_t len)
|
||||
{
|
||||
if (err == 0 || len < 1) return 0;
|
||||
return strerror_r(err, buf, len);
|
||||
}
|
234
src/java.base/unix/native/libjava/locale_str.h
Normal file
234
src/java.base/unix/native/libjava/locale_str.h
Normal file
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2017, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Mappings from partial locale names to full locale names
|
||||
*/
|
||||
static char *locale_aliases[] = {
|
||||
"ar", "ar_EG",
|
||||
"be", "be_BY",
|
||||
"bg", "bg_BG",
|
||||
"br", "br_FR",
|
||||
"ca", "ca_ES",
|
||||
"cs", "cs_CZ",
|
||||
"cz", "cs_CZ",
|
||||
"da", "da_DK",
|
||||
"de", "de_DE",
|
||||
"el", "el_GR",
|
||||
"en", "en_US",
|
||||
"eo", "eo", /* no country for Esperanto */
|
||||
"es", "es_ES",
|
||||
"et", "et_EE",
|
||||
"eu", "eu_ES",
|
||||
"fi", "fi_FI",
|
||||
"fr", "fr_FR",
|
||||
"ga", "ga_IE",
|
||||
"gl", "gl_ES",
|
||||
"he", "iw_IL",
|
||||
"hr", "hr_HR",
|
||||
#ifdef __linux__
|
||||
"hs", "en_US", // used on Linux, not clear what it stands for
|
||||
#endif
|
||||
"hu", "hu_HU",
|
||||
"id", "in_ID",
|
||||
"in", "in_ID",
|
||||
"is", "is_IS",
|
||||
"it", "it_IT",
|
||||
"iw", "iw_IL",
|
||||
"ja", "ja_JP",
|
||||
"kl", "kl_GL",
|
||||
"ko", "ko_KR",
|
||||
"lt", "lt_LT",
|
||||
"lv", "lv_LV",
|
||||
"mk", "mk_MK",
|
||||
"nl", "nl_NL",
|
||||
"no", "no_NO",
|
||||
"pl", "pl_PL",
|
||||
"pt", "pt_PT",
|
||||
"ro", "ro_RO",
|
||||
"ru", "ru_RU",
|
||||
"se", "se_NO",
|
||||
"sk", "sk_SK",
|
||||
"sl", "sl_SI",
|
||||
"sq", "sq_AL",
|
||||
"sr", "sr_CS",
|
||||
"su", "fi_FI",
|
||||
"sv", "sv_SE",
|
||||
"th", "th_TH",
|
||||
"tr", "tr_TR",
|
||||
#ifdef __linux__
|
||||
"ua", "en_US", // used on Linux, not clear what it stands for
|
||||
#endif
|
||||
"uk", "uk_UA",
|
||||
"vi", "vi_VN",
|
||||
"wa", "wa_BE",
|
||||
"zh", "zh_CN",
|
||||
#ifdef __linux__
|
||||
"bokmal", "nb_NO",
|
||||
"bokm\xE5l", "nb_NO",
|
||||
"catalan", "ca_ES",
|
||||
"croatian", "hr_HR",
|
||||
"czech", "cs_CZ",
|
||||
"danish", "da_DK",
|
||||
"dansk", "da_DK",
|
||||
"deutsch", "de_DE",
|
||||
"dutch", "nl_NL",
|
||||
"eesti", "et_EE",
|
||||
"estonian", "et_EE",
|
||||
"finnish", "fi_FI",
|
||||
"fran\xE7\x61is", "fr_FR",
|
||||
"french", "fr_FR",
|
||||
"galego", "gl_ES",
|
||||
"galician", "gl_ES",
|
||||
"german", "de_DE",
|
||||
"greek", "el_GR",
|
||||
"hebrew", "iw_IL",
|
||||
"hrvatski", "hr_HR",
|
||||
"hungarian", "hu_HU",
|
||||
"icelandic", "is_IS",
|
||||
"italian", "it_IT",
|
||||
"japanese", "ja_JP",
|
||||
"korean", "ko_KR",
|
||||
"lithuanian", "lt_LT",
|
||||
"norwegian", "no_NO",
|
||||
"nynorsk", "nn_NO",
|
||||
"polish", "pl_PL",
|
||||
"portuguese", "pt_PT",
|
||||
"romanian", "ro_RO",
|
||||
"russian", "ru_RU",
|
||||
"slovak", "sk_SK",
|
||||
"slovene", "sl_SI",
|
||||
"slovenian", "sl_SI",
|
||||
"spanish", "es_ES",
|
||||
"swedish", "sv_SE",
|
||||
"thai", "th_TH",
|
||||
"turkish", "tr_TR",
|
||||
#else
|
||||
"big5", "zh_TW.Big5",
|
||||
"chinese", "zh_CN",
|
||||
"iso_8859_1", "en_US.ISO8859-1",
|
||||
"iso_8859_15", "en_US.ISO8859-15",
|
||||
"japanese", "ja_JP",
|
||||
"no_NY", "no_NO@nynorsk",
|
||||
"sr_SP", "sr_YU",
|
||||
"tchinese", "zh_TW",
|
||||
#endif
|
||||
"", "",
|
||||
};
|
||||
|
||||
/*
|
||||
* Linux/Solaris language string to ISO639 string mapping table.
|
||||
*/
|
||||
static char *language_names[] = {
|
||||
"C", "en",
|
||||
"POSIX", "en",
|
||||
"cz", "cs",
|
||||
"he", "iw",
|
||||
#ifdef __linux__
|
||||
"hs", "en", // used on Linux, not clear what it stands for
|
||||
#endif
|
||||
"id", "in",
|
||||
"sh", "sr", // sh is deprecated
|
||||
"su", "fi",
|
||||
#ifdef __linux__
|
||||
"ua", "en", // used on Linux, not clear what it stands for
|
||||
"catalan", "ca",
|
||||
"croatian", "hr",
|
||||
"czech", "cs",
|
||||
"danish", "da",
|
||||
"dansk", "da",
|
||||
"deutsch", "de",
|
||||
"dutch", "nl",
|
||||
"finnish", "fi",
|
||||
"fran\xE7\x61is", "fr",
|
||||
"french", "fr",
|
||||
"german", "de",
|
||||
"greek", "el",
|
||||
"hebrew", "he",
|
||||
"hrvatski", "hr",
|
||||
"hungarian", "hu",
|
||||
"icelandic", "is",
|
||||
"italian", "it",
|
||||
"japanese", "ja",
|
||||
"norwegian", "no",
|
||||
"polish", "pl",
|
||||
"portuguese", "pt",
|
||||
"romanian", "ro",
|
||||
"russian", "ru",
|
||||
"slovak", "sk",
|
||||
"slovene", "sl",
|
||||
"slovenian", "sl",
|
||||
"spanish", "es",
|
||||
"swedish", "sv",
|
||||
"turkish", "tr",
|
||||
#else
|
||||
"chinese", "zh",
|
||||
"japanese", "ja",
|
||||
"korean", "ko",
|
||||
#endif
|
||||
"", "",
|
||||
};
|
||||
|
||||
/*
|
||||
* Linux/Solaris script string to Java script name mapping table.
|
||||
*/
|
||||
static char *script_names[] = {
|
||||
#ifdef __linux__
|
||||
"cyrillic", "Cyrl",
|
||||
"devanagari", "Deva",
|
||||
"iqtelif", "Latn",
|
||||
"latin", "Latn",
|
||||
#endif
|
||||
"Arab", "Arab",
|
||||
"Cyrl", "Cyrl",
|
||||
"Deva", "Deva",
|
||||
"Ethi", "Ethi",
|
||||
"Hans", "Hans",
|
||||
"Hant", "Hant",
|
||||
"Latn", "Latn",
|
||||
"Sund", "Sund",
|
||||
"Syrc", "Syrc",
|
||||
"Tfng", "Tfng",
|
||||
"", "",
|
||||
};
|
||||
|
||||
/*
|
||||
* Linux/Solaris country string to ISO3166 string mapping table.
|
||||
*/
|
||||
static char *country_names[] = {
|
||||
#ifdef __linux__
|
||||
"RN", "US", // used on Linux, not clear what it stands for
|
||||
#endif
|
||||
"YU", "CS", // YU has been removed from ISO 3166
|
||||
"", "",
|
||||
};
|
||||
|
||||
/*
|
||||
* Linux/Solaris variant string to Java variant name mapping table.
|
||||
*/
|
||||
static char *variant_names[] = {
|
||||
"nynorsk", "NY",
|
||||
"", "",
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue