Path: blob/master/runtime/jcl/common/attach.c
12409 views
/*******************************************************************************1* Copyright (c) 2009, 2020 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#include "j9port.h"23#include "j9.h"24#include "ut_j9jcl.h"25#include "stackwalk.h"26#include "jclglob.h"27#include "jclprots.h"2829extern char * getTmpDir(JNIEnv *env, char**envSpace);3031/**32* Test if the file is owned by this process's owner or the process is running as root.33* @param pathUTF pathname of the file. Must be a valid path34* @return TRUE if the file is owned by this process or the user is root.35*/36static BOOLEAN37isFileOwnedByMe(JNIEnv *env, const char *pathUTF) {3839PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );4041struct J9FileStat fileStat;42jlong ownerUid = -1;43jlong myUid = (jlong) j9sysinfo_get_euid();44I_32 statRc;4546if (0 == myUid) { /* I am root */47return TRUE;48}4950statRc = j9file_stat(pathUTF, 0, &fileStat);51if (statRc == 0) {52ownerUid = fileStat.ownerUid;53}54return (ownerUid == myUid);5556}5758/* all native methods defined herein are static */5960/**61* Get the system temporary directory path (/tmp on all but Windows).62* Note that this may be different from the java.io.tmpdir system property.63* @return jstring object with the path64*/6566#define TMP_PATH_BUFFER_SIZE 12867jstring JNICALL68Java_openj9_internal_tools_attach_target_IPC_getTempDirImpl(JNIEnv *env, jclass clazz)69{70PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );71jstring result = NULL;72char *envSpace = NULL;73char *charResult = getTmpDir(env, &envSpace);74if (NULL != charResult) {75uint8_t defaultConversionBuffer[TMP_PATH_BUFFER_SIZE];76uint8_t *conversionBuffer = defaultConversionBuffer;77size_t pathLength = strlen(charResult);78int32_t conversionResult = 0;79Trc_JCL_attach_getTmpDir(env, charResult);80conversionResult = j9str_convert(J9STR_CODE_PLATFORM_OMR_INTERNAL, J9STR_CODE_MUTF8, charResult, pathLength, (char*)defaultConversionBuffer, sizeof(defaultConversionBuffer));81if (OMRPORT_ERROR_STRING_BUFFER_TOO_SMALL == conversionResult) {82/* determine how much space we really need */83int32_t requiredSize = j9str_convert(J9STR_CODE_PLATFORM_OMR_INTERNAL, J9STR_CODE_MUTF8, charResult, pathLength, NULL, 0);84if (requiredSize > 0) {85requiredSize += 1; /* leave room for null */86conversionBuffer = j9mem_allocate_memory(requiredSize, OMRMEM_CATEGORY_VM);87if (NULL != conversionBuffer) {88j9str_convert(J9STR_CODE_PLATFORM_OMR_INTERNAL, J9STR_CODE_MUTF8, charResult, pathLength, (char*)conversionBuffer, requiredSize);89}90} else {91conversionBuffer = NULL; /* string is bogus */92}93} else if (conversionResult < 0) {94Trc_JCL_stringConversionFailed(env, charResult, conversionResult);95conversionBuffer = NULL; /* string conversion failed */96}97if (NULL != conversionBuffer) {98result = (*env)->NewStringUTF(env, (char*)conversionBuffer);99if (defaultConversionBuffer != conversionBuffer) {100jclmem_free_memory(env,conversionBuffer);101}102}103if (NULL != envSpace) {104jclmem_free_memory(env,envSpace);105}106}107return result;108}109110111/**112* @param path file system path113* @param mode the file's new access permissions (posix format)114* @return actual file permissions, which may be different than those requested due to OS limitations115*/116117jint JNICALL118Java_openj9_internal_tools_attach_target_IPC_chmod(JNIEnv *env, jclass clazz, jstring path, jint mode)119{120PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );121122jint result = JNI_ERR;123const char *pathUTF;124125pathUTF = (*env)->GetStringUTFChars(env, path, NULL);126if (NULL != pathUTF) {127if (isFileOwnedByMe(env, pathUTF)) {128result = j9file_chmod(pathUTF, mode);129Trc_JCL_attach_chmod(env, pathUTF, mode, result);130}131(*env)->ReleaseStringUTFChars(env, path, pathUTF);132}133return result;134}135136/**137* @param path file system path138* @param uid user identity to which to chown the file. This was upcast from UDATA.139* @return result of chown() operation140*/141jint JNICALL142Java_openj9_internal_tools_attach_target_IPC_chownFileToTargetUid(JNIEnv *env, jclass clazz, jstring path, jlong uid)143{144PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );145146jint result = JNI_OK;147const char *pathUTF;148149pathUTF = (*env)->GetStringUTFChars(env, path, NULL);150if (NULL != pathUTF) {151if (isFileOwnedByMe(env, pathUTF)) { /* j9file_chown takes a UTF8 string for the path */152/* uid value was upcast from a UDATA to jlong. */153result = (jint)j9file_chown(pathUTF, (UDATA) uid, J9PORT_FILE_IGNORE_ID);154Trc_JCL_attach_chown(env, pathUTF, uid, result);155}156(*env)->ReleaseStringUTFChars(env, path, pathUTF);157} else {158result = JNI_ERR;159}160return result;161}162163/**164* Call file stat and get the effective UID of the file owner.165* @param path file system path166* @return Returns 0 on Windows and the effective UID of owner on other operation systems. Returns -1 in the case of an error.167*/168jlong JNICALL169Java_openj9_internal_tools_attach_target_CommonDirectory_getFileOwner(JNIEnv *env, jclass clazz, jstring path) {170PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );171172jlong ownerUid = -1;173const char *pathUTF;174175pathUTF = (*env)->GetStringUTFChars(env, path, NULL);176if (NULL != pathUTF) {177struct J9FileStat fileStat;178I_32 statRc = j9file_stat(pathUTF, 0, &fileStat);179180if (statRc == 0) {181ownerUid = fileStat.ownerUid;182}183Trc_JCL_attach_getFileOwner(env, pathUTF, ownerUid);184(*env)->ReleaseStringUTFChars(env, path, pathUTF);185}186return ownerUid;187}188189/**190* This crawls the z/OS control blocks to determine if the current process is using the default UID.191* This handles both job- and task-level security.192* For information on the control blocks, see the z/OS V1R9.0 MVS Data Areas documentation.193* @return JNI_TRUE if the process is running on z/OS and is using the default UID194* @note A batch process runs as the default UID if it has no USS segment.195*/196jboolean JNICALL197Java_openj9_internal_tools_attach_target_IPC_isUsingDefaultUid(JNIEnv *env, jclass clazz)198{199200jboolean usingDuid = JNI_FALSE;201#if defined(J9ZOS390)202203/* all offsets are byte offsets */204U_32* PSATOLD_ADDR = (U_32 *)(UDATA) 0x21c; /* z/OS Pointer to current TCB or zero if in SRB mode. Field fixed by architecture. */205U_32 tcbBase; /* base of the z/OS Task Control Block */206const TCBSENV_OFFSET = 0x154; /* offset of the TCBSENV field in the TCB. This field contains a pointer to the ACEE. */207U_32 aceeBaseAddr; /* Address of a control block field which contains a pointer to the base of the RACF Accessor Environment Element (ACEE) */208U_32 aceeBase; /* absolute address of the start of the ACEE */209U_32 aceeflg3Addr; /* address of the "Miscellaneous flags" byte of the ACEE */210U_8 aceeflg3Value; /* contents of the "Miscellaneous flags" byte of the ACEE */211const U_32 ACEEFLG3_OFFSET = 0x28; /* offset of flag 3 from the base of the ACEE */212const U_8 ACEE_DUID = 0X02; /* 1 if current thread is using the defaultUID */213214tcbBase = *PSATOLD_ADDR;215aceeBaseAddr = tcbBase+TCBSENV_OFFSET;216aceeBase = *((U_32 *)(UDATA) aceeBaseAddr);217if (0 == aceeBase) { /* not using task-level ACEE */218U_32* PSAAOLD_ADDR= (U_32 *) 0x224; /* Pointer to the home (current) ASCB. */219U_32 ascbAddr; /* address of the ACSB (ADDRESS SPACE CONTROL BLOCK) */220const U_32 ASCBASXB_OFFSET = 0x6c; /* offset of the address space extension control block (ASXB) field in the ASCB */221U_32 asxbBaseAddr; /* absolute address of the ASXB field in the ASCB */222U_32 asxbBase; /* Contents of the ASXB field in the ASCB. This points the ASXB itself. */223const U_32 ASXBSENV_OFFSET = 0xc8; /* offset of the ASXBSENV field in the ASXB. This field contains a pointer to the ACEE. */224225ascbAddr = *PSAAOLD_ADDR;226227asxbBaseAddr = ascbAddr+ASCBASXB_OFFSET;228asxbBase = *((U_32 *)(UDATA) asxbBaseAddr);229230aceeBaseAddr = asxbBase+ASXBSENV_OFFSET;231aceeBase = *((U_32 *)(UDATA) aceeBaseAddr);232}233234aceeflg3Addr = aceeBase + ACEEFLG3_OFFSET;235aceeflg3Value = *((U_8 *)(UDATA) aceeflg3Addr);236Trc_JCL_com_ibm_tools_attach_javaSE_IPC_isUsingDefaultUid(env, aceeBase, aceeflg3Addr, aceeflg3Value);237238if (0 != (aceeflg3Value & ACEE_DUID)) { /* Running with default UID.*/239usingDuid = JNI_TRUE;240}241#endif242return usingDuid;243}244245246/**247* Create a directory with specified file permissions.248* These permissions are masked with the user's umask249* @param absolutePath path of the directory to create250* @param cdPerms file access permissions (posix format) for the new directory251* @return JNI_OK if success252*/253254jint JNICALL255Java_openj9_internal_tools_attach_target_IPC_mkdirWithPermissionsImpl(JNIEnv *env, jclass clazz, jstring absolutePath, jint cdPerms)256{257PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );258jint status = JNI_OK;259const char *absolutePathUTF = (*env)->GetStringUTFChars(env, absolutePath, NULL);260261if (NULL != absolutePathUTF) {262status = j9file_mkdir(absolutePathUTF); /* file perms ignored for now */263Java_openj9_internal_tools_attach_target_IPC_chmod(env, clazz, absolutePath, cdPerms);264/* ensure that the directory group is the same as this process's. Some OS's set the group to that of the parent directory */265j9file_chown(absolutePathUTF, J9PORT_FILE_IGNORE_ID, j9sysinfo_get_egid());266Trc_JCL_attach_mkdirWithPermissions(env, absolutePathUTF, cdPerms, status);267(*env)->ReleaseStringUTFChars(env, absolutePath, absolutePathUTF);268} else {269status = JNI_ERR;270}271return status;272}273274/**275* @param path file system path276* @param mode file access permissions (posix format) for the new file277* @return JNI_OK on success, JNI_ERR on failure278* Create the file, set the permissions (to override umask) and close it279*/280jint JNICALL281Java_openj9_internal_tools_attach_target_IPC_createFileWithPermissionsImpl(JNIEnv *env, jclass clazz, jstring path, jint mode)282{283PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );284285jint status = JNI_OK;286const char *pathUTF = (*env)->GetStringUTFChars(env, path, NULL);287288if (NULL != pathUTF) {289IDATA fd = j9file_open(pathUTF, EsOpenCreateNew | EsOpenWrite | EsOpenTruncate , mode);290if (-1 == fd) {291status = JNI_ERR;292} else {293j9file_close(fd);294}295Trc_JCL_attach_createFileWithPermissions(env, pathUTF, mode, status);296(*env)->ReleaseStringUTFChars(env, path, pathUTF);297} else {298status = JNI_ERR;299}300return status;301}302303/**304* @return JNI_OK if no error, JNI_ERR otherwise305*/306#define SHRDIR_NAME_LENGTH 255307308static jint createSharedResourcesDir(JNIEnv *env, jstring ctrlDirName)309{310IDATA status = JNI_ERR;311const char *ctrlDirUTF = NULL;312313PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );314315/* TODO: should use OS native encoding for the file path */316ctrlDirUTF = (*env)->GetStringUTFChars(env, ctrlDirName, NULL);317if (NULL != ctrlDirUTF) {318I_32 statRc=0;319struct J9FileStat ctrlDirStat;320statRc = j9file_stat(ctrlDirUTF, 0, &ctrlDirStat);321322if ((statRc == 0) && ctrlDirStat.isFile) {323j9file_unlink(ctrlDirUTF);324status = j9file_mkdir(ctrlDirUTF);325} else if (statRc < 0){ /* directory does not exist */326status = j9file_mkdir(ctrlDirUTF);327} else {328status = JNI_OK;329}330Trc_JCL_attach_createSharedResourcesDir(env, ctrlDirUTF, status);331(*env)->ReleaseStringUTFChars(env, ctrlDirName, ctrlDirUTF);332}333return (jint)status;334}335336/**337* prepare to use semaphores, creating resources as required338* @param ctrlDirName location of semaphore control files339* @return JNI_OK if no error, JNI_ERR otherwise340*/341342jint JNICALL343Java_openj9_internal_tools_attach_target_IPC_setupSemaphore(JNIEnv *env, jclass clazz, jstring ctrlDirName)344{345346347jint status;348349status = createSharedResourcesDir(env, ctrlDirName);350return status;351}352353/**354* open the semaphore and save into a specified struct355* @param ctrlDirName directory for the control file356* @param semaName name for the control file357* @param semaphore out parameter for the resulting handle358* @return JNI_ERR if cannot allocate string, j9shsem_open status otherwise359*/360361static jint JNICALL362openSemaphore(JNIEnv *env, jclass clazz, jstring ctrlDirName, jstring semaName, BOOLEAN global, struct j9shsem_handle** semaphore)363{364365PORT_ACCESS_FROM_VMC((J9VMThread *) env );366367jint status = JNI_OK;368const char *semaNameUTF = (*env)->GetStringUTFChars(env, semaName, NULL);369const char *ctrlDirNameUTF = (*env)->GetStringUTFChars(env, ctrlDirName, NULL);370371if ((NULL != semaNameUTF) && (NULL != ctrlDirNameUTF)) {372J9PortShSemParameters openParams;373j9shsem_params_init(&openParams);374openParams.semName = semaNameUTF;375openParams.setSize = 1;376openParams.permission = 0666;377openParams.controlFileDir = ctrlDirNameUTF;378openParams.proj_id = 0xa1;379openParams.deleteBasefile = 0;380if (global) {381openParams.global = 1;382}383384status = (jint) j9shsem_open(semaphore, &openParams);385Trc_JCL_attach_openSemaphore(env, semaNameUTF, ctrlDirNameUTF, status);386} else {387status = JNI_ERR;388}389if (NULL != semaNameUTF) {390(*env)->ReleaseStringUTFChars(env, semaName, semaNameUTF);391}392if (NULL != ctrlDirNameUTF){393(*env)->ReleaseStringUTFChars(env, ctrlDirName, ctrlDirNameUTF);394}395return status;396}397398/**399* @param ctrlDirName path to directory holding the semaphore files400* @param semaName name of the notification semaphore for this process401* @return JNI_OK on success, j9shsem_open status otherwise402* Saves the semaphore handle into the VM struct.403*/404405jint JNICALL406Java_openj9_internal_tools_attach_target_IPC_openSemaphore(JNIEnv *env, jclass clazz, jstring ctrlDirName, jstring semaName)407{408jint rc = 0;409J9JavaVM* javaVM = ((J9VMThread*) env)->javaVM;410411Trc_JCL_attach_openSemaphoreEntry(env);412rc = openSemaphore(env, clazz, ctrlDirName, semaName, TRUE, &(javaVM->attachContext.semaphore));413414if ((J9PORT_INFO_SHSEM_OPENED == rc) || (J9PORT_INFO_SHSEM_OPENED_STALE == rc) || (J9PORT_INFO_SHSEM_CREATED == rc)) {415rc = JNI_OK;416}417Trc_JCL_attach_openSemaphoreExit(env, rc);418return rc;419}420421/**422* Open a semaphore, post to it, and close it. Do not store the semaphore handle.423* @param ctrlDirName path to directory holding the semaphore files424* @param semaName name of the notification semaphore for this process425* @param numberOfPosts the number of times to increment the semaphore426* @param global use the global semaphore namespace (Windows only)427* @return JNI_OK on success, j9shsem_open or close status otherwise428*/429jint JNICALL430Java_openj9_internal_tools_attach_target_IPC_notifyVm(JNIEnv *env, jclass clazz, jstring ctrlDirName, jstring semaName, jint numberOfPosts, jboolean global)431{432433PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );434435jint status;436struct j9shsem_handle* semaphore;437438Trc_JCL_attach_notifyVmEntry(env);439status = openSemaphore(env, clazz, ctrlDirName, semaName, global, &semaphore);440if ((J9PORT_INFO_SHSEM_OPENED == status) || (J9PORT_INFO_SHSEM_OPENED_STALE == status)) {441while (numberOfPosts > 0) {442status = (jint) j9shsem_post(semaphore, 0, J9PORT_SHSEM_MODE_DEFAULT);443--numberOfPosts;444}445j9shsem_close(&semaphore);446status = JNI_OK;447} else if (J9PORT_INFO_SHSEM_CREATED == status) {448/* Jazz 27080. the semaphore should already have been created. We are probably shutting down. */449status = (jint) j9shsem_destroy(&semaphore);450}451Trc_JCL_attach_notifyVmExit(env, status);452return status;453}454455/**456* Open a semaphore, decrement it N times (non-blocking) to it, and close it. Do not store the semaphore handle.457* @param ctrlDirName path to directory holding the semaphore files458* @param semaName name of the notification semaphore for this process459* @param numberOfDecrements the number of times to decrement the semaphore460* @return JNI_OK on success, j9shsem_open or close status otherwise461*/462jint JNICALL463Java_openj9_internal_tools_attach_target_IPC_cancelNotify(JNIEnv *env, jclass clazz, jstring ctrlDirName, jstring semaName, jint numberOfDecrements, jboolean global)464{465466PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );467468jint status;469struct j9shsem_handle* semaphore;470471Trc_JCL_attach_cancelNotifyVmEntry(env);472status = openSemaphore(env, clazz, ctrlDirName, semaName, global, &semaphore);473if ((J9PORT_INFO_SHSEM_OPENED == status) || (J9PORT_INFO_SHSEM_OPENED_STALE == status)) {474while (numberOfDecrements > 0) {475status = (jint) j9shsem_wait(semaphore, 0, J9PORT_SHSEM_MODE_NOWAIT);476--numberOfDecrements;477}478j9shsem_close(&semaphore);479status = JNI_OK;480} else if (J9PORT_INFO_SHSEM_CREATED == status) {481/* Jazz 27080. this was supposed to be consuming posts on an existing semaphore, but it appears to have disappeared */482status = (jint) j9shsem_destroy(&semaphore);483}484Trc_JCL_attach_cancelNotifyVmExit(env, status);485return status;486}487488/**489* @return result of j9shsem_wait: 0 on success, -1 on failure490* Block until semaphore becomes non-zero.491*/492jint JNICALL493Java_openj9_internal_tools_attach_target_IPC_waitSemaphore(JNIEnv *env, jclass clazz)494{495J9JavaVM *javaVM = ((J9VMThread*) env)->javaVM;496jint status = 0;497498PORT_ACCESS_FROM_JAVAVM(javaVM);499Trc_JCL_attach_waitSemaphoreEntry2(env, javaVM->attachContext.semaphore);500status = (jint) j9shsem_wait(javaVM->attachContext.semaphore, 0, 0);501Trc_JCL_attach_waitSemaphoreExit(env, status);502return status;503}504505/**506* Close semaphore507*/508void JNICALL509Java_openj9_internal_tools_attach_target_IPC_closeSemaphore(JNIEnv *env, jclass clazz)510{511J9JavaVM *javaVM = ((J9VMThread*) env)->javaVM;512513PORT_ACCESS_FROM_JAVAVM(javaVM);514Trc_JCL_attach_closeSemaphoreEntry(env, javaVM->attachContext.semaphore);515j9shsem_close(&javaVM->attachContext.semaphore);516Trc_JCL_attach_closeSemaphore(env);517return;518}519520/**521* @return 0 on success, -1 on failure522*/523jint JNICALL524Java_openj9_internal_tools_attach_target_IPC_destroySemaphore(JNIEnv *env, jclass clazz)525{526jint status = 0; /* return success if the semaphore is already closed or destroyed */527struct j9shsem_handle **handle = NULL;528J9JavaVM *javaVM = ((J9VMThread*) env)->javaVM;529530PORT_ACCESS_FROM_JAVAVM(javaVM);531Trc_JCL_attach_destroySemaphoreEntry(env, javaVM->attachContext.semaphore);532handle = &javaVM->attachContext.semaphore;533if (NULL != handle) {534status = (jint) j9shsem_destroy(handle);535}536Trc_JCL_attach_destroySemaphore(env, status);537return status;538}539540/**541* @return numeric user ID of the caller. This is upcast from a UDATA.542*/543jlong JNICALL544Java_openj9_internal_tools_attach_target_IPC_getUid(JNIEnv *env, jclass clazz)545{546547PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );548549jlong uid;550551uid = (jlong) j9sysinfo_get_euid();552Trc_JCL_attach_getUid(env, uid);553return uid;554}555556/**557* @return process ID of the caller. This is upcast from UDATA.558*/559jlong JNICALL560Java_openj9_internal_tools_attach_target_IPC_getProcessId(JNIEnv *env, jclass clazz)561{562563PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );564565jlong pid;566567pid = (jlong) j9sysinfo_get_pid();568Trc_JCL_attach_getProcessId(env, pid);569return pid;570}571572/**573* Indicate if a specific process exists. Non-positive process IDs and processes owned by574* other users return an error.575* @param pid process ID576* @return positive value if the process exists, 0 if the process does not exist, otherwise negative error code577*/578jint JNICALL579Java_openj9_internal_tools_attach_target_IPC_processExistsImpl(JNIEnv *env, jclass clazz, jlong pid)580{581PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );582/* PID value was upcast from a UDATA to jlong. */583jint rc = (pid > 0) ? (jint) j9sysinfo_process_exists((UDATA) pid) : -1;584Trc_JCL_attach_processExists(env, pid, rc);585return rc;586}587588/**589* Opens and locks a file. Creates the file if it does not exist.590* @param path file path to the file591* @param mode file mode to create the file with592* @param blocking true if process is to wait for the file to be unlocked593* @return file descriptor if the file is successfully locked, otherwise negative value594* @note J9PORT_ERROR_FILE_OPFAILED (-300) indicates file cannot be opened or the path could not be converted, J9PORT_ERROR_FILE_LOCK_BADLOCK (-316) indicates that the file could not be locked.595*/596jlong JNICALL597Java_openj9_internal_tools_attach_target_FileLock_lockFileImpl(JNIEnv *env, jclass clazz, jstring path, jint mode, jboolean blocking)598{599PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );600601jlong result = JNI_OK;602const char *pathUTF;603604pathUTF = (*env)->GetStringUTFChars(env, path, NULL); /* j9file_open takes a UTF8 string for the path */605if (NULL != pathUTF) {606IDATA fd = j9file_open(pathUTF, EsOpenCreate | EsOpenWrite, mode);607if (isFileOwnedByMe(env, pathUTF)) {608j9file_chmod(pathUTF, mode); /* override UMASK */609}610Trc_JCL_attach_lockFileImpl(env, pathUTF, mode, blocking, fd);611(*env)->ReleaseStringUTFChars(env, path, pathUTF);612if (0 >= fd) {613result = J9PORT_ERROR_FILE_OPFAILED;614} else {615IDATA lockStatus;616/*617* Must be a write lock to get exclusive access.618* Must lock at least one byte on Windows, otherwise it returns a false positive.619* Both Posix and Windows allow the lock range to extend past the end of the file.620*/621lockStatus = j9file_lock_bytes(fd, J9PORT_FILE_WRITE_LOCK | ((0 == blocking)? J9PORT_FILE_NOWAIT_FOR_LOCK: J9PORT_FILE_WAIT_FOR_LOCK), 0, 1);622if (0 != lockStatus) {623j9file_close(fd);624result = J9PORT_ERROR_FILE_LOCK_BADLOCK;625} else {626result = fd;627}628}629} else {630result = J9PORT_ERROR_FILE_OPFAILED;631}632Trc_JCL_attach_lockFileStatus(env, result);633return result;634}635636/* use for debugging or to record normal events. Use message to distinguish errors */637#define TRACEPOINT_STATUS_NORMAL 0638#define TRACEPOINT_STATUS_LOGGING 1639640/* use for debugging only. Use message to distinguish errors */641#define TRACEPOINT_STATUS_ERROR -1642643#define TRACEPOINT_STATUS_OOM_DURING_WAIT -2644#define TRACEPOINT_STATUS_OOM_DURING_TERMINATE -3645/**646* generate a tracepoint with a status code and message.647*648* @param statusCode numeric status value649* @param message descriptive message. May be null.650*/651void JNICALL652Java_openj9_internal_tools_attach_target_IPC_tracepoint(JNIEnv *env, jclass clazz, jint statusCode, jstring message) {653654const char *msgUTF = NULL;655const char *statusText = "STATUS_NORMAL";656657if (NULL != message) {658msgUTF = (*env)->GetStringUTFChars(env, message, NULL);659}660661switch (statusCode) {662case TRACEPOINT_STATUS_LOGGING:663statusText = "STATUS_LOGGING";664break;665case TRACEPOINT_STATUS_NORMAL:666statusText = "STATUS_NORMAL";667break;668case TRACEPOINT_STATUS_OOM_DURING_WAIT:669statusText = "STATUS_OOM_DURING_WAIT"; /* from wait loop */670break;671case TRACEPOINT_STATUS_OOM_DURING_TERMINATE:672statusText = "STATUS_OOM_DURING_TERMINATE"; /* from terminate code */673break;674default: /* FALLTHROUGH */675case -1:676statusText = "STATUS_ERROR"; /* unspecified error */677break;678}679if (NULL != msgUTF) {680Trc_JCL_com_ibm_tools_attach_javaSE_IPC_tracepoint(env, statusCode, statusText, msgUTF);681(*env)->ReleaseStringUTFChars(env, message, msgUTF);682} else {683Trc_JCL_com_ibm_tools_attach_javaSE_IPC_tracepoint(env, statusCode, statusText, "<unavailable>");684}685}686687/**688* Unlock and close a file.689* @param file descriptor690* @return 0 if successful, -1 if failed691*/692jint JNICALL693Java_openj9_internal_tools_attach_target_FileLock_unlockFileImpl(JNIEnv *env, jclass clazz, jlong fd) {694PORT_ACCESS_FROM_VMC( ((J9VMThread *) env) );695696jint result = JNI_OK;697j9file_unlock_bytes((IDATA) fd, 0, 0);698result = j9file_close((IDATA) fd);699Trc_JCL_attach_unlockFileWithStatus(env, (IDATA) fd, result);700return result;701}702703704