#include "j9port.h"
#include "j9.h"
#include "ut_j9jcl.h"
#include "stackwalk.h"
#include "jclglob.h"
#include "jclprots.h"
extern char * getTmpDir(JNIEnv *env, char**envSpace);
static BOOLEAN
isFileOwnedByMe(JNIEnv *env, const char *pathUTF) {
PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );
struct J9FileStat fileStat;
jlong ownerUid = -1;
jlong myUid = (jlong) j9sysinfo_get_euid();
I_32 statRc;
if (0 == myUid) {
return TRUE;
}
statRc = j9file_stat(pathUTF, 0, &fileStat);
if (statRc == 0) {
ownerUid = fileStat.ownerUid;
}
return (ownerUid == myUid);
}
#define TMP_PATH_BUFFER_SIZE 128
jstring JNICALL
Java_openj9_internal_tools_attach_target_IPC_getTempDirImpl(JNIEnv *env, jclass clazz)
{
PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );
jstring result = NULL;
char *envSpace = NULL;
char *charResult = getTmpDir(env, &envSpace);
if (NULL != charResult) {
uint8_t defaultConversionBuffer[TMP_PATH_BUFFER_SIZE];
uint8_t *conversionBuffer = defaultConversionBuffer;
size_t pathLength = strlen(charResult);
int32_t conversionResult = 0;
Trc_JCL_attach_getTmpDir(env, charResult);
conversionResult = j9str_convert(J9STR_CODE_PLATFORM_OMR_INTERNAL, J9STR_CODE_MUTF8, charResult, pathLength, (char*)defaultConversionBuffer, sizeof(defaultConversionBuffer));
if (OMRPORT_ERROR_STRING_BUFFER_TOO_SMALL == conversionResult) {
int32_t requiredSize = j9str_convert(J9STR_CODE_PLATFORM_OMR_INTERNAL, J9STR_CODE_MUTF8, charResult, pathLength, NULL, 0);
if (requiredSize > 0) {
requiredSize += 1;
conversionBuffer = j9mem_allocate_memory(requiredSize, OMRMEM_CATEGORY_VM);
if (NULL != conversionBuffer) {
j9str_convert(J9STR_CODE_PLATFORM_OMR_INTERNAL, J9STR_CODE_MUTF8, charResult, pathLength, (char*)conversionBuffer, requiredSize);
}
} else {
conversionBuffer = NULL;
}
} else if (conversionResult < 0) {
Trc_JCL_stringConversionFailed(env, charResult, conversionResult);
conversionBuffer = NULL;
}
if (NULL != conversionBuffer) {
result = (*env)->NewStringUTF(env, (char*)conversionBuffer);
if (defaultConversionBuffer != conversionBuffer) {
jclmem_free_memory(env,conversionBuffer);
}
}
if (NULL != envSpace) {
jclmem_free_memory(env,envSpace);
}
}
return result;
}
jint JNICALL
Java_openj9_internal_tools_attach_target_IPC_chmod(JNIEnv *env, jclass clazz, jstring path, jint mode)
{
PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );
jint result = JNI_ERR;
const char *pathUTF;
pathUTF = (*env)->GetStringUTFChars(env, path, NULL);
if (NULL != pathUTF) {
if (isFileOwnedByMe(env, pathUTF)) {
result = j9file_chmod(pathUTF, mode);
Trc_JCL_attach_chmod(env, pathUTF, mode, result);
}
(*env)->ReleaseStringUTFChars(env, path, pathUTF);
}
return result;
}
jint JNICALL
Java_openj9_internal_tools_attach_target_IPC_chownFileToTargetUid(JNIEnv *env, jclass clazz, jstring path, jlong uid)
{
PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );
jint result = JNI_OK;
const char *pathUTF;
pathUTF = (*env)->GetStringUTFChars(env, path, NULL);
if (NULL != pathUTF) {
if (isFileOwnedByMe(env, pathUTF)) {
result = (jint)j9file_chown(pathUTF, (UDATA) uid, J9PORT_FILE_IGNORE_ID);
Trc_JCL_attach_chown(env, pathUTF, uid, result);
}
(*env)->ReleaseStringUTFChars(env, path, pathUTF);
} else {
result = JNI_ERR;
}
return result;
}
jlong JNICALL
Java_openj9_internal_tools_attach_target_CommonDirectory_getFileOwner(JNIEnv *env, jclass clazz, jstring path) {
PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );
jlong ownerUid = -1;
const char *pathUTF;
pathUTF = (*env)->GetStringUTFChars(env, path, NULL);
if (NULL != pathUTF) {
struct J9FileStat fileStat;
I_32 statRc = j9file_stat(pathUTF, 0, &fileStat);
if (statRc == 0) {
ownerUid = fileStat.ownerUid;
}
Trc_JCL_attach_getFileOwner(env, pathUTF, ownerUid);
(*env)->ReleaseStringUTFChars(env, path, pathUTF);
}
return ownerUid;
}
jboolean JNICALL
Java_openj9_internal_tools_attach_target_IPC_isUsingDefaultUid(JNIEnv *env, jclass clazz)
{
jboolean usingDuid = JNI_FALSE;
#if defined(J9ZOS390)
U_32* PSATOLD_ADDR = (U_32 *)(UDATA) 0x21c;
U_32 tcbBase;
const TCBSENV_OFFSET = 0x154;
U_32 aceeBaseAddr;
U_32 aceeBase;
U_32 aceeflg3Addr;
U_8 aceeflg3Value;
const U_32 ACEEFLG3_OFFSET = 0x28;
const U_8 ACEE_DUID = 0X02;
tcbBase = *PSATOLD_ADDR;
aceeBaseAddr = tcbBase+TCBSENV_OFFSET;
aceeBase = *((U_32 *)(UDATA) aceeBaseAddr);
if (0 == aceeBase) {
U_32* PSAAOLD_ADDR= (U_32 *) 0x224;
U_32 ascbAddr;
const U_32 ASCBASXB_OFFSET = 0x6c;
U_32 asxbBaseAddr;
U_32 asxbBase;
const U_32 ASXBSENV_OFFSET = 0xc8;
ascbAddr = *PSAAOLD_ADDR;
asxbBaseAddr = ascbAddr+ASCBASXB_OFFSET;
asxbBase = *((U_32 *)(UDATA) asxbBaseAddr);
aceeBaseAddr = asxbBase+ASXBSENV_OFFSET;
aceeBase = *((U_32 *)(UDATA) aceeBaseAddr);
}
aceeflg3Addr = aceeBase + ACEEFLG3_OFFSET;
aceeflg3Value = *((U_8 *)(UDATA) aceeflg3Addr);
Trc_JCL_com_ibm_tools_attach_javaSE_IPC_isUsingDefaultUid(env, aceeBase, aceeflg3Addr, aceeflg3Value);
if (0 != (aceeflg3Value & ACEE_DUID)) {
usingDuid = JNI_TRUE;
}
#endif
return usingDuid;
}
jint JNICALL
Java_openj9_internal_tools_attach_target_IPC_mkdirWithPermissionsImpl(JNIEnv *env, jclass clazz, jstring absolutePath, jint cdPerms)
{
PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );
jint status = JNI_OK;
const char *absolutePathUTF = (*env)->GetStringUTFChars(env, absolutePath, NULL);
if (NULL != absolutePathUTF) {
status = j9file_mkdir(absolutePathUTF);
Java_openj9_internal_tools_attach_target_IPC_chmod(env, clazz, absolutePath, cdPerms);
j9file_chown(absolutePathUTF, J9PORT_FILE_IGNORE_ID, j9sysinfo_get_egid());
Trc_JCL_attach_mkdirWithPermissions(env, absolutePathUTF, cdPerms, status);
(*env)->ReleaseStringUTFChars(env, absolutePath, absolutePathUTF);
} else {
status = JNI_ERR;
}
return status;
}
jint JNICALL
Java_openj9_internal_tools_attach_target_IPC_createFileWithPermissionsImpl(JNIEnv *env, jclass clazz, jstring path, jint mode)
{
PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );
jint status = JNI_OK;
const char *pathUTF = (*env)->GetStringUTFChars(env, path, NULL);
if (NULL != pathUTF) {
IDATA fd = j9file_open(pathUTF, EsOpenCreateNew | EsOpenWrite | EsOpenTruncate , mode);
if (-1 == fd) {
status = JNI_ERR;
} else {
j9file_close(fd);
}
Trc_JCL_attach_createFileWithPermissions(env, pathUTF, mode, status);
(*env)->ReleaseStringUTFChars(env, path, pathUTF);
} else {
status = JNI_ERR;
}
return status;
}
#define SHRDIR_NAME_LENGTH 255
static jint createSharedResourcesDir(JNIEnv *env, jstring ctrlDirName)
{
IDATA status = JNI_ERR;
const char *ctrlDirUTF = NULL;
PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );
ctrlDirUTF = (*env)->GetStringUTFChars(env, ctrlDirName, NULL);
if (NULL != ctrlDirUTF) {
I_32 statRc=0;
struct J9FileStat ctrlDirStat;
statRc = j9file_stat(ctrlDirUTF, 0, &ctrlDirStat);
if ((statRc == 0) && ctrlDirStat.isFile) {
j9file_unlink(ctrlDirUTF);
status = j9file_mkdir(ctrlDirUTF);
} else if (statRc < 0){
status = j9file_mkdir(ctrlDirUTF);
} else {
status = JNI_OK;
}
Trc_JCL_attach_createSharedResourcesDir(env, ctrlDirUTF, status);
(*env)->ReleaseStringUTFChars(env, ctrlDirName, ctrlDirUTF);
}
return (jint)status;
}
jint JNICALL
Java_openj9_internal_tools_attach_target_IPC_setupSemaphore(JNIEnv *env, jclass clazz, jstring ctrlDirName)
{
jint status;
status = createSharedResourcesDir(env, ctrlDirName);
return status;
}
static jint JNICALL
openSemaphore(JNIEnv *env, jclass clazz, jstring ctrlDirName, jstring semaName, BOOLEAN global, struct j9shsem_handle** semaphore)
{
PORT_ACCESS_FROM_VMC((J9VMThread *) env );
jint status = JNI_OK;
const char *semaNameUTF = (*env)->GetStringUTFChars(env, semaName, NULL);
const char *ctrlDirNameUTF = (*env)->GetStringUTFChars(env, ctrlDirName, NULL);
if ((NULL != semaNameUTF) && (NULL != ctrlDirNameUTF)) {
J9PortShSemParameters openParams;
j9shsem_params_init(&openParams);
openParams.semName = semaNameUTF;
openParams.setSize = 1;
openParams.permission = 0666;
openParams.controlFileDir = ctrlDirNameUTF;
openParams.proj_id = 0xa1;
openParams.deleteBasefile = 0;
if (global) {
openParams.global = 1;
}
status = (jint) j9shsem_open(semaphore, &openParams);
Trc_JCL_attach_openSemaphore(env, semaNameUTF, ctrlDirNameUTF, status);
} else {
status = JNI_ERR;
}
if (NULL != semaNameUTF) {
(*env)->ReleaseStringUTFChars(env, semaName, semaNameUTF);
}
if (NULL != ctrlDirNameUTF){
(*env)->ReleaseStringUTFChars(env, ctrlDirName, ctrlDirNameUTF);
}
return status;
}
jint JNICALL
Java_openj9_internal_tools_attach_target_IPC_openSemaphore(JNIEnv *env, jclass clazz, jstring ctrlDirName, jstring semaName)
{
jint rc = 0;
J9JavaVM* javaVM = ((J9VMThread*) env)->javaVM;
Trc_JCL_attach_openSemaphoreEntry(env);
rc = openSemaphore(env, clazz, ctrlDirName, semaName, TRUE, &(javaVM->attachContext.semaphore));
if ((J9PORT_INFO_SHSEM_OPENED == rc) || (J9PORT_INFO_SHSEM_OPENED_STALE == rc) || (J9PORT_INFO_SHSEM_CREATED == rc)) {
rc = JNI_OK;
}
Trc_JCL_attach_openSemaphoreExit(env, rc);
return rc;
}
jint JNICALL
Java_openj9_internal_tools_attach_target_IPC_notifyVm(JNIEnv *env, jclass clazz, jstring ctrlDirName, jstring semaName, jint numberOfPosts, jboolean global)
{
PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );
jint status;
struct j9shsem_handle* semaphore;
Trc_JCL_attach_notifyVmEntry(env);
status = openSemaphore(env, clazz, ctrlDirName, semaName, global, &semaphore);
if ((J9PORT_INFO_SHSEM_OPENED == status) || (J9PORT_INFO_SHSEM_OPENED_STALE == status)) {
while (numberOfPosts > 0) {
status = (jint) j9shsem_post(semaphore, 0, J9PORT_SHSEM_MODE_DEFAULT);
--numberOfPosts;
}
j9shsem_close(&semaphore);
status = JNI_OK;
} else if (J9PORT_INFO_SHSEM_CREATED == status) {
status = (jint) j9shsem_destroy(&semaphore);
}
Trc_JCL_attach_notifyVmExit(env, status);
return status;
}
jint JNICALL
Java_openj9_internal_tools_attach_target_IPC_cancelNotify(JNIEnv *env, jclass clazz, jstring ctrlDirName, jstring semaName, jint numberOfDecrements, jboolean global)
{
PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );
jint status;
struct j9shsem_handle* semaphore;
Trc_JCL_attach_cancelNotifyVmEntry(env);
status = openSemaphore(env, clazz, ctrlDirName, semaName, global, &semaphore);
if ((J9PORT_INFO_SHSEM_OPENED == status) || (J9PORT_INFO_SHSEM_OPENED_STALE == status)) {
while (numberOfDecrements > 0) {
status = (jint) j9shsem_wait(semaphore, 0, J9PORT_SHSEM_MODE_NOWAIT);
--numberOfDecrements;
}
j9shsem_close(&semaphore);
status = JNI_OK;
} else if (J9PORT_INFO_SHSEM_CREATED == status) {
status = (jint) j9shsem_destroy(&semaphore);
}
Trc_JCL_attach_cancelNotifyVmExit(env, status);
return status;
}
jint JNICALL
Java_openj9_internal_tools_attach_target_IPC_waitSemaphore(JNIEnv *env, jclass clazz)
{
J9JavaVM *javaVM = ((J9VMThread*) env)->javaVM;
jint status = 0;
PORT_ACCESS_FROM_JAVAVM(javaVM);
Trc_JCL_attach_waitSemaphoreEntry2(env, javaVM->attachContext.semaphore);
status = (jint) j9shsem_wait(javaVM->attachContext.semaphore, 0, 0);
Trc_JCL_attach_waitSemaphoreExit(env, status);
return status;
}
void JNICALL
Java_openj9_internal_tools_attach_target_IPC_closeSemaphore(JNIEnv *env, jclass clazz)
{
J9JavaVM *javaVM = ((J9VMThread*) env)->javaVM;
PORT_ACCESS_FROM_JAVAVM(javaVM);
Trc_JCL_attach_closeSemaphoreEntry(env, javaVM->attachContext.semaphore);
j9shsem_close(&javaVM->attachContext.semaphore);
Trc_JCL_attach_closeSemaphore(env);
return;
}
jint JNICALL
Java_openj9_internal_tools_attach_target_IPC_destroySemaphore(JNIEnv *env, jclass clazz)
{
jint status = 0;
struct j9shsem_handle **handle = NULL;
J9JavaVM *javaVM = ((J9VMThread*) env)->javaVM;
PORT_ACCESS_FROM_JAVAVM(javaVM);
Trc_JCL_attach_destroySemaphoreEntry(env, javaVM->attachContext.semaphore);
handle = &javaVM->attachContext.semaphore;
if (NULL != handle) {
status = (jint) j9shsem_destroy(handle);
}
Trc_JCL_attach_destroySemaphore(env, status);
return status;
}
jlong JNICALL
Java_openj9_internal_tools_attach_target_IPC_getUid(JNIEnv *env, jclass clazz)
{
PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );
jlong uid;
uid = (jlong) j9sysinfo_get_euid();
Trc_JCL_attach_getUid(env, uid);
return uid;
}
jlong JNICALL
Java_openj9_internal_tools_attach_target_IPC_getProcessId(JNIEnv *env, jclass clazz)
{
PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );
jlong pid;
pid = (jlong) j9sysinfo_get_pid();
Trc_JCL_attach_getProcessId(env, pid);
return pid;
}
jint JNICALL
Java_openj9_internal_tools_attach_target_IPC_processExistsImpl(JNIEnv *env, jclass clazz, jlong pid)
{
PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );
jint rc = (pid > 0) ? (jint) j9sysinfo_process_exists((UDATA) pid) : -1;
Trc_JCL_attach_processExists(env, pid, rc);
return rc;
}
jlong JNICALL
Java_openj9_internal_tools_attach_target_FileLock_lockFileImpl(JNIEnv *env, jclass clazz, jstring path, jint mode, jboolean blocking)
{
PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );
jlong result = JNI_OK;
const char *pathUTF;
pathUTF = (*env)->GetStringUTFChars(env, path, NULL);
if (NULL != pathUTF) {
IDATA fd = j9file_open(pathUTF, EsOpenCreate | EsOpenWrite, mode);
if (isFileOwnedByMe(env, pathUTF)) {
j9file_chmod(pathUTF, mode);
}
Trc_JCL_attach_lockFileImpl(env, pathUTF, mode, blocking, fd);
(*env)->ReleaseStringUTFChars(env, path, pathUTF);
if (0 >= fd) {
result = J9PORT_ERROR_FILE_OPFAILED;
} else {
IDATA lockStatus;
lockStatus = j9file_lock_bytes(fd, J9PORT_FILE_WRITE_LOCK | ((0 == blocking)? J9PORT_FILE_NOWAIT_FOR_LOCK: J9PORT_FILE_WAIT_FOR_LOCK), 0, 1);
if (0 != lockStatus) {
j9file_close(fd);
result = J9PORT_ERROR_FILE_LOCK_BADLOCK;
} else {
result = fd;
}
}
} else {
result = J9PORT_ERROR_FILE_OPFAILED;
}
Trc_JCL_attach_lockFileStatus(env, result);
return result;
}
#define TRACEPOINT_STATUS_NORMAL 0
#define TRACEPOINT_STATUS_LOGGING 1
#define TRACEPOINT_STATUS_ERROR -1
#define TRACEPOINT_STATUS_OOM_DURING_WAIT -2
#define TRACEPOINT_STATUS_OOM_DURING_TERMINATE -3
void JNICALL
Java_openj9_internal_tools_attach_target_IPC_tracepoint(JNIEnv *env, jclass clazz, jint statusCode, jstring message) {
const char *msgUTF = NULL;
const char *statusText = "STATUS_NORMAL";
if (NULL != message) {
msgUTF = (*env)->GetStringUTFChars(env, message, NULL);
}
switch (statusCode) {
case TRACEPOINT_STATUS_LOGGING:
statusText = "STATUS_LOGGING";
break;
case TRACEPOINT_STATUS_NORMAL:
statusText = "STATUS_NORMAL";
break;
case TRACEPOINT_STATUS_OOM_DURING_WAIT:
statusText = "STATUS_OOM_DURING_WAIT";
break;
case TRACEPOINT_STATUS_OOM_DURING_TERMINATE:
statusText = "STATUS_OOM_DURING_TERMINATE";
break;
default:
case -1:
statusText = "STATUS_ERROR";
break;
}
if (NULL != msgUTF) {
Trc_JCL_com_ibm_tools_attach_javaSE_IPC_tracepoint(env, statusCode, statusText, msgUTF);
(*env)->ReleaseStringUTFChars(env, message, msgUTF);
} else {
Trc_JCL_com_ibm_tools_attach_javaSE_IPC_tracepoint(env, statusCode, statusText, "<unavailable>");
}
}
jint JNICALL
Java_openj9_internal_tools_attach_target_FileLock_unlockFileImpl(JNIEnv *env, jclass clazz, jlong fd) {
PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );
jint result = JNI_OK;
j9file_unlock_bytes((IDATA) fd, 0, 0);
result = j9file_close((IDATA) fd);
Trc_JCL_attach_unlockFileWithStatus(env, (IDATA) fd, result);
return result;
}