blob: b37359dad51d5fc86baccd2de585db8f4648165d [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
#include <jni.h>
#include "org_apache_hadoop.h"
#include "windows_secure_container_executor.h"
#include "winutils.h"
#include "file_descriptor.h"
// class of org.apache.hadoop.yarn.server.nodemanager.WindowsSecureContainerExecutor.Native.WinutilsProcessStub
static jclass wps_class = NULL;
/*
* private static native void initWsceNative();
*
* We rely on this function rather than lazy initialization because
* the lazy approach may have a race if multiple callers try to
* init at the same time.
*/
JNIEXPORT void JNICALL
Java_org_apache_hadoop_yarn_server_nodemanager_WindowsSecureContainerExecutor_00024Native_initWsceNative(
JNIEnv *env, jclass clazz) {
#ifdef WINDOWS
winutils_process_stub_init(env);
PASS_EXCEPTIONS_GOTO(env, error);
#endif
return;
error:
// these are all idempodent and safe to call even if the
// class wasn't initted yet
#ifdef WINDOWS
winutils_process_stub_deinit(env);
#endif
}
static jmethodID wps_constructor = NULL;
static jfieldID wps_hProcess = NULL;
static jfieldID wps_hThread = NULL;
static jfieldID wps_disposed = NULL;
extern void throw_ioe(JNIEnv* env, int errnum);
void winutils_process_stub_init(JNIEnv *env) {
if (wps_class != NULL) return; // already initted
wps_class = (*env)->FindClass(env, WINUTILS_PROCESS_STUB_CLASS);
PASS_EXCEPTIONS(env);
wps_class = (*env)->NewGlobalRef(env, wps_class);
PASS_EXCEPTIONS(env);
wps_hProcess = (*env)->GetFieldID(env, wps_class, "hProcess", "J");
PASS_EXCEPTIONS(env);
wps_hThread = (*env)->GetFieldID(env, wps_class, "hThread", "J");
PASS_EXCEPTIONS(env);
wps_disposed = (*env)->GetFieldID(env, wps_class, "disposed", "Z");
PASS_EXCEPTIONS(env);
wps_constructor = (*env)->GetMethodID(env, wps_class, "<init>", "(JJJJJ)V");
PASS_EXCEPTIONS(env);
LogDebugMessage(L"winutils_process_stub_init\n");
}
void winutils_process_stub_deinit(JNIEnv *env) {
if (wps_class != NULL) {
(*env)->DeleteGlobalRef(env, wps_class);
wps_class = NULL;
}
wps_hProcess = NULL;
wps_hThread = NULL;
wps_disposed = NULL;
wps_constructor = NULL;
LogDebugMessage(L"winutils_process_stub_deinit\n");
}
jobject winutils_process_stub_create(JNIEnv *env,
jlong hProcess, jlong hThread, jlong hStdIn, jlong hStdOut, jlong hStdErr) {
jobject obj = (*env)->NewObject(env, wps_class, wps_constructor,
hProcess, hThread, hStdIn, hStdOut, hStdErr);
PASS_EXCEPTIONS_RET(env, NULL);
LogDebugMessage(L"winutils_process_stub_create: %p\n", obj);
return obj;
}
/*
* Class: org.apache.hadoop.yarn.server.nodemanager.WindowsSecureContainerExecutor$Native
* Method: createTaskAsUser
* Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String)Lorg/apache/hadoop/io/nativeio/NativeIO$WinutilsProcessStub
*/
JNIEXPORT jobject JNICALL
Java_org_apache_hadoop_yarn_server_nodemanager_WindowsSecureContainerExecutor_00024Native_createTaskAsUser0(JNIEnv* env,
jclass clazz, jstring jcwd, jstring jjobName, jstring juser, jstring jpidFile, jstring jcmdLine) {
#ifdef UNIX
THROW(env, "java/io/IOException",
"The function createTaskAsUser is not supported on Unix");
return NULL;
#endif
#ifdef WINDOWS
LPCWSTR cwd = NULL, jobName = NULL,
user = NULL, pidFile = NULL, cmdLine = NULL;
DWORD dwError = ERROR_SUCCESS;
HANDLE hProcess = INVALID_HANDLE_VALUE,
hThread = INVALID_HANDLE_VALUE,
hStdIn = INVALID_HANDLE_VALUE,
hStdOut = INVALID_HANDLE_VALUE,
hStdErr = INVALID_HANDLE_VALUE;
jobject ret = NULL;
cwd = (LPCWSTR) (*env)->GetStringChars(env, jcwd, NULL);
if (!cwd) goto done; // exception was thrown
jobName = (LPCWSTR) (*env)->GetStringChars(env, jjobName, NULL);
if (!jobName) goto done; // exception was thrown
user = (LPCWSTR) (*env)->GetStringChars(env, juser, NULL);
if (!user) goto done; // exception was thrown
pidFile = (LPCWSTR) (*env)->GetStringChars(env, jpidFile, NULL);
if (!pidFile) goto done; // exception was thrown
cmdLine = (LPCWSTR) (*env)->GetStringChars(env, jcmdLine, NULL);
if (!cmdLine) goto done; // exception was thrown
LogDebugMessage(L"createTaskAsUser: jcwd:%s job:%s juser:%s pid:%s cmd:%s\n",
cwd, jobName, user, pidFile, cmdLine);
dwError = RpcCall_TaskCreateAsUser(cwd, jobName, user, pidFile, cmdLine,
&hProcess, &hThread, &hStdIn, &hStdOut, &hStdErr);
if (ERROR_SUCCESS == dwError) {
ret = winutils_process_stub_create(env, (jlong) hProcess, (jlong) hThread,
(jlong) hStdIn, (jlong) hStdOut, (jlong) hStdErr);
if (NULL == ret) {
TerminateProcess(hProcess, EXIT_FAILURE);
CloseHandle(hThread);
CloseHandle(hProcess);
CloseHandle(hStdIn);
CloseHandle(hStdOut);
CloseHandle(hStdErr);
}
}
if (dwError != ERROR_SUCCESS) {
throw_ioe (env, dwError);
}
done:
if (cwd) (*env)->ReleaseStringChars(env, jcwd, cwd);
if (jobName) (*env)->ReleaseStringChars(env, jjobName, jobName);
if (user) (*env)->ReleaseStringChars(env, juser, user);
if (pidFile) (*env)->ReleaseStringChars(env, jpidFile, pidFile);
if (cmdLine) (*env)->ReleaseStringChars(env, jcmdLine, cmdLine);
return ret;
#endif
}
/*
* Class: org.apache.hadoop.yarn.server.nodemanager.WindowsSecureContainerExecutor$Native$Elevated
* Method: elevatedKillTaskImpl
* Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL
Java_org_apache_hadoop_yarn_server_nodemanager_WindowsSecureContainerExecutor_00024Native_00024Elevated_elevatedKillTaskImpl(JNIEnv* env,
jclass clazz, jstring jtask_name) {
#ifdef UNIX
THROW(env, "java/io/IOException",
"The function elevatedSetOwner0 is not supported on Unix");
return;
#endif
#ifdef WINDOWS
LPCWSTR task_name = NULL;
DWORD dwError;
task_name = (LPCWSTR) (*env)->GetStringChars(env, jtask_name, NULL);
if (!task_name) goto done; // exception was thrown
dwError = RpcCall_WinutilsKillTask(task_name);
if (dwError != ERROR_SUCCESS) {
throw_ioe (env, dwError);
}
done:
if (task_name) (*env)->ReleaseStringChars(env, jtask_name, task_name);
#endif
}
/*
* Class: org.apache.hadoop.yarn.server.nodemanager.WindowsSecureContainerExecutor$Native$Elevated
* Method: elevatedChownImpl
* Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL
Java_org_apache_hadoop_yarn_server_nodemanager_WindowsSecureContainerExecutor_00024Native_00024Elevated_elevatedChownImpl(JNIEnv* env,
jclass clazz, jstring jpath, jstring juser, jstring jgroup) {
#ifdef UNIX
THROW(env, "java/io/IOException",
"The function elevatedSetOwner0 is not supported on Unix");
return;
#endif
#ifdef WINDOWS
LPCWSTR path = NULL, user = NULL, group = NULL;
DWORD dwError;
path = (LPCWSTR) (*env)->GetStringChars(env, jpath, NULL);
if (!path) goto done; // exception was thrown
if (juser) {
user = (LPCWSTR) (*env)->GetStringChars(env, juser, NULL);
if (!user) goto done; // exception was thrown
}
if (jgroup) {
group = (LPCWSTR) (*env)->GetStringChars(env, jgroup, NULL);
if (!group) goto done; // exception was thrown
}
dwError = RpcCall_WinutilsChown(path, user, group);
if (dwError != ERROR_SUCCESS) {
throw_ioe (env, dwError);
}
done:
if (path) (*env)->ReleaseStringChars(env, jpath, path);
if (user) (*env)->ReleaseStringChars(env, juser, user);
if (group) (*env)->ReleaseStringChars(env, jgroup, group);
#endif
}
/*
* Class: org.apache.hadoop.yarn.server.nodemanager.WindowsSecureContainerExecutor$Native$Elevated
* Method: elevatedMkDirImpl
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL
Java_org_apache_hadoop_yarn_server_nodemanager_WindowsSecureContainerExecutor_00024Native_00024Elevated_elevatedMkDirImpl(JNIEnv* env,
jclass clazz, jstring jpath) {
#ifdef UNIX
THROW(env, "java/io/IOException",
"The function elevatedMkDirImpl is not supported on Unix");
return;
#endif
#ifdef WINDOWS
LPCWSTR path = NULL, user = NULL, group = NULL;
DWORD dwError;
path = (LPCWSTR) (*env)->GetStringChars(env, jpath, NULL);
if (!path) goto done; // exception was thrown
dwError = RpcCall_WinutilsMkDir(path);
if (dwError != ERROR_SUCCESS) {
throw_ioe (env, dwError);
}
done:
if (path) (*env)->ReleaseStringChars(env, jpath, path);
#endif
}
/*
* Class: org.apache.hadoop.yarn.server.nodemanager.WindowsSecureContainerExecutor$Native$Elevated
* Method: elevatedChmodImpl
* Signature: (Ljava/lang/String;I)V
*/
JNIEXPORT void JNICALL
Java_org_apache_hadoop_yarn_server_nodemanager_WindowsSecureContainerExecutor_00024Native_00024Elevated_elevatedChmodImpl(JNIEnv* env,
jclass clazz, jstring jpath, jint jmode) {
#ifdef UNIX
THROW(env, "java/io/IOException",
"The function elevatedChmodImpl is not supported on Unix");
return;
#endif
#ifdef WINDOWS
LPCWSTR path = NULL;
DWORD dwError;
path = (LPCWSTR) (*env)->GetStringChars(env, jpath, NULL);
if (!path) goto done; // exception was thrown
dwError = RpcCall_WinutilsChmod(path, (int) jmode);
if (dwError != ERROR_SUCCESS) {
throw_ioe (env, dwError);
}
done:
if (path) (*env)->ReleaseStringChars(env, jpath, path);
#endif
}
/*
* Class: org.apache.hadoop.yarn.server.nodemanager.WindowsSecureContainerExecutor$Native$Elevated
* Method: elevatedCopyImpl
* Signature: (I;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)V
*/
JNIEXPORT void JNICALL
Java_org_apache_hadoop_yarn_server_nodemanager_WindowsSecureContainerExecutor_00024Native_00024Elevated_elevatedCopyImpl(JNIEnv* env,
jclass clazz, jint joperation, jstring jsourcePath, jstring jdestinationPath, jboolean replaceExisting) {
#ifdef UNIX
THROW(env, "java/io/IOException",
"The function elevatedCopyImpl is not supported on Unix");
return;
#endif
#ifdef WINDOWS
LPCWSTR sourcePath = NULL, destinationPath = NULL;
DWORD dwError;
sourcePath = (LPCWSTR) (*env)->GetStringChars(env, jsourcePath, NULL);
if (!sourcePath) goto done; // exception was thrown
destinationPath = (LPCWSTR) (*env)->GetStringChars(env, jdestinationPath, NULL);
if (!destinationPath) goto done; // exception was thrown
dwError = RpcCall_WinutilsMoveFile((INT) joperation, sourcePath, destinationPath, (BOOL) replaceExisting);
if (dwError != ERROR_SUCCESS) {
throw_ioe (env, dwError);
}
done:
if (sourcePath) (*env)->ReleaseStringChars(env, jsourcePath, sourcePath);
if (destinationPath) (*env)->ReleaseStringChars(env, jdestinationPath, destinationPath);
#endif
}
/*
* Class: org.apache.hadoop.yarn.server.nodemanager.WindowsSecureContainerExecutor$Native$Elevated
* Method: elevatedCreateImpl
* Signature: (Ljava/lang/String;J;J;J;J)J
*/
JNIEXPORT jlong JNICALL
Java_org_apache_hadoop_yarn_server_nodemanager_WindowsSecureContainerExecutor_00024Native_00024Elevated_elevatedCreateImpl(JNIEnv* env,
jclass clazz, jstring jpath, jlong jdesired_access, jlong jshare_mode, jlong jcreation_disposition, jlong jflags) {
#ifdef UNIX
THROW(env, "java/io/IOException",
"The function elevatedCreateImpl is not supported on Unix");
return 0;
#endif
#ifdef WINDOWS
LPCWSTR path = NULL;
DWORD dwError;
HANDLE hFile = INVALID_HANDLE_VALUE;
path = (LPCWSTR) (*env)->GetStringChars(env, jpath, NULL);
if (!path) goto done; // exception was thrown
dwError = RpcCall_WinutilsCreateFile(path,
(DWORD) jdesired_access, (DWORD) jshare_mode, (DWORD) jcreation_disposition, (DWORD) jflags,
&hFile);
if (dwError != ERROR_SUCCESS) {
throw_ioe (env, dwError);
}
done:
if (path) (*env)->ReleaseStringChars(env, jpath, path);
return (jlong) hFile;
#endif
}
/*
* Class: org.apache.hadoop.yarn.server.nodemanager.WindowsSecureContainerExecutor$Native$Elevated
* Method: elevatedDeletePathImpl
* Signature: (Ljava/lang/String;Z)Z
*/
JNIEXPORT jboolean JNICALL
Java_org_apache_hadoop_yarn_server_nodemanager_WindowsSecureContainerExecutor_00024Native_00024Elevated_elevatedDeletePathImpl(JNIEnv* env,
jclass clazz, jstring jpath, jboolean jIsDir) {
#ifdef UNIX
THROW(env, "java/io/IOException",
"The function elevatedDeleteFileImpl is not supported on Unix");
return JNI_FALSE;
#endif
#ifdef WINDOWS
LPCWSTR path = NULL;
DWORD dwError;
BOOL deleted = FALSE;
path = (LPCWSTR) (*env)->GetStringChars(env, jpath, NULL);
if (!path) goto done; // exception was thrown
dwError = RpcCall_WinutilsDeletePath(path, (BOOL) jIsDir, &deleted);
if (dwError != ERROR_SUCCESS) {
throw_ioe (env, dwError);
}
done:
if (path) (*env)->ReleaseStringChars(env, jpath, path);
return (jboolean) deleted;
#endif
}
/*
* native void destroy();
*
* The "00024" in the function name is an artifact of how JNI encodes
* special characters. U+0024 is '$'.
*/
JNIEXPORT void JNICALL
Java_org_apache_hadoop_yarn_server_nodemanager_WindowsSecureContainerExecutor_00024Native_00024WinutilsProcessStub_destroy(
JNIEnv *env, jobject objSelf) {
HANDLE hProcess = (HANDLE)(*env)->GetLongField(env, objSelf, wps_hProcess);
LogDebugMessage(L"TerminateProcess: %x\n", hProcess);
TerminateProcess(hProcess, EXIT_FAILURE);
}
/*
* native void waitFor();
*
* The "00024" in the function name is an artifact of how JNI encodes
* special characters. U+0024 is '$'.
*/
JNIEXPORT void JNICALL
Java_org_apache_hadoop_yarn_server_nodemanager_WindowsSecureContainerExecutor_00024Native_00024WinutilsProcessStub_waitFor(
JNIEnv *env, jobject objSelf) {
HANDLE hProcess = (HANDLE)(*env)->GetLongField(env, objSelf, wps_hProcess);
LogDebugMessage(L"WaitForSingleObject: %x\n", hProcess);
WaitForSingleObject(hProcess, INFINITE);
}
/*
* native void resume();
*
* The "00024" in the function name is an artifact of how JNI encodes
* special characters. U+0024 is '$'.
*/
JNIEXPORT void JNICALL
Java_org_apache_hadoop_yarn_server_nodemanager_WindowsSecureContainerExecutor_00024Native_00024WinutilsProcessStub_resume(
JNIEnv *env, jobject objSelf) {
DWORD dwError;
HANDLE hThread = (HANDLE)(*env)->GetLongField(env, objSelf, wps_hThread);
if (-1 == ResumeThread(hThread)) {
dwError = GetLastError();
LogDebugMessage(L"ResumeThread: %x error:%d\n", hThread, dwError);
throw_ioe(env, dwError);
}
}
/*
* native int exitValue();
*
* The "00024" in the function name is an artifact of how JNI encodes
* special characters. U+0024 is '$'.
*/
JNIEXPORT jint JNICALL
Java_org_apache_hadoop_yarn_server_nodemanager_WindowsSecureContainerExecutor_00024Native_00024WinutilsProcessStub_exitValue(
JNIEnv *env, jobject objSelf) {
DWORD exitCode;
DWORD dwError;
HANDLE hProcess = (HANDLE)(*env)->GetLongField(env, objSelf, wps_hProcess);
if (!GetExitCodeProcess(hProcess, &exitCode)) {
dwError = GetLastError();
throw_ioe(env, dwError);
return dwError; // exception was thrown, return value doesn't really matter
}
LogDebugMessage(L"GetExitCodeProcess: %x :%d\n", hProcess, exitCode);
return exitCode;
}
/*
* native void dispose();
*
* The "00024" in the function name is an artifact of how JNI encodes
* special characters. U+0024 is '$'.
*/
JNIEXPORT void JNICALL
Java_org_apache_hadoop_yarn_server_nodemanager_WindowsSecureContainerExecutor_00024Native_00024WinutilsProcessStub_dispose(
JNIEnv *env, jobject objSelf) {
HANDLE hProcess = INVALID_HANDLE_VALUE,
hThread = INVALID_HANDLE_VALUE;
jboolean disposed = (*env)->GetBooleanField(env, objSelf, wps_disposed);
if (JNI_TRUE != disposed) {
hProcess = (HANDLE)(*env)->GetLongField(env, objSelf, wps_hProcess);
hThread = (HANDLE)(*env)->GetLongField(env, objSelf, wps_hThread);
CloseHandle(hProcess);
CloseHandle(hThread);
(*env)->SetBooleanField(env, objSelf, wps_disposed, JNI_TRUE);
LogDebugMessage(L"disposed: %p\n", objSelf);
}
}
/*
* native static FileDescriptor getFileDescriptorFromHandle(long handle);
*
* The "00024" in the function name is an artifact of how JNI encodes
* special characters. U+0024 is '$'.
*/
JNIEXPORT jobject JNICALL
Java_org_apache_hadoop_yarn_server_nodemanager_WindowsSecureContainerExecutor_00024Native_00024WinutilsProcessStub_getFileDescriptorFromHandle(
JNIEnv *env, jclass klass, jlong handle) {
LogDebugMessage(L"getFileDescriptorFromHandle: %x\n", handle);
return fd_create(env, (long) handle);
}