blob: ca5e69564444cbcaee9734708444c441e00d9376 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "Exec"
18
19#include "JNIHelp.h"
20#include "jni.h"
21#include "utils/Log.h"
22#include "utils/misc.h"
23#include "android_runtime/AndroidRuntime.h"
24
25#include <sys/types.h>
26#include <sys/ioctl.h>
27#include <sys/wait.h>
28#include <errno.h>
29#include <fcntl.h>
30#include <stdlib.h>
31#include <unistd.h>
32#include <termios.h>
33
34namespace android
35{
36
37static jclass class_fileDescriptor;
38static jfieldID field_fileDescriptor_descriptor;
39static jmethodID method_fileDescriptor_init;
40
41
42static int create_subprocess(const char *cmd, const char *arg0, const char *arg1,
43 int* pProcessId)
44{
45 char *devname;
46 int ptm;
47 pid_t pid;
48
49 ptm = open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
50 if(ptm < 0){
51 LOGE("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
52 return -1;
53 }
54 fcntl(ptm, F_SETFD, FD_CLOEXEC);
55
56 if(grantpt(ptm) || unlockpt(ptm) ||
57 ((devname = (char*) ptsname(ptm)) == 0)){
58 LOGE("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
59 return -1;
60 }
61
62 pid = fork();
63 if(pid < 0) {
64 LOGE("- fork failed: %s -\n", strerror(errno));
65 return -1;
66 }
67
68 if(pid == 0){
69 int pts;
70
71 setsid();
72
73 pts = open(devname, O_RDWR);
74 if(pts < 0) exit(-1);
75
76 dup2(pts, 0);
77 dup2(pts, 1);
78 dup2(pts, 2);
79
80 close(ptm);
81
82 execl(cmd, cmd, arg0, arg1, NULL);
83 exit(-1);
84 } else {
85 *pProcessId = (int) pid;
86 return ptm;
87 }
88}
89
90
91static jobject android_os_Exec_createSubProcess(JNIEnv *env, jobject clazz,
92 jstring cmd, jstring arg0, jstring arg1, jintArray processIdArray)
93{
94 const jchar* str = cmd ? env->GetStringCritical(cmd, 0) : 0;
95 String8 cmd_8;
96 if (str) {
97 cmd_8 = String8(str, env->GetStringLength(cmd));
98 env->ReleaseStringCritical(cmd, str);
99 }
100
101 str = arg0 ? env->GetStringCritical(arg0, 0) : 0;
102 const char* arg0Str = 0;
103 String8 arg0_8;
104 if (str) {
105 arg0_8 = String8(str, env->GetStringLength(arg0));
106 env->ReleaseStringCritical(arg0, str);
107 arg0Str = arg0_8.string();
108 }
109
110 str = arg1 ? env->GetStringCritical(arg1, 0) : 0;
111 const char* arg1Str = 0;
112 String8 arg1_8;
113 if (str) {
114 arg1_8 = String8(str, env->GetStringLength(arg1));
115 env->ReleaseStringCritical(arg1, str);
116 arg1Str = arg1_8.string();
117 }
118
119 int procId;
120 int ptm = create_subprocess(cmd_8.string(), arg0Str, arg1Str, &procId);
121
122 if (processIdArray) {
123 int procIdLen = env->GetArrayLength(processIdArray);
124 if (procIdLen > 0) {
125 jboolean isCopy;
126
127 int* pProcId = (int*) env->GetPrimitiveArrayCritical(processIdArray, &isCopy);
128 if (pProcId) {
129 *pProcId = procId;
130 env->ReleasePrimitiveArrayCritical(processIdArray, pProcId, 0);
131 }
132 }
133 }
134
135 jobject result = env->NewObject(class_fileDescriptor, method_fileDescriptor_init);
136
137 if (!result) {
138 LOGE("Couldn't create a FileDescriptor.");
139 }
140 else {
141 env->SetIntField(result, field_fileDescriptor_descriptor, ptm);
142 }
143
144 return result;
145}
146
147
148static void android_os_Exec_setPtyWindowSize(JNIEnv *env, jobject clazz,
149 jobject fileDescriptor, jint row, jint col, jint xpixel, jint ypixel)
150{
151 int fd;
152 struct winsize sz;
153
154 fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
155
156 if (env->ExceptionOccurred() != NULL) {
157 return;
158 }
159
160 sz.ws_row = row;
161 sz.ws_col = col;
162 sz.ws_xpixel = xpixel;
163 sz.ws_ypixel = ypixel;
164
165 ioctl(fd, TIOCSWINSZ, &sz);
166}
167
168static int android_os_Exec_waitFor(JNIEnv *env, jobject clazz,
169 jint procId) {
170 int status;
171 waitpid(procId, &status, 0);
172 int result = 0;
173 if (WIFEXITED(status)) {
174 result = WEXITSTATUS(status);
175 }
176 return result;
177}
178
179static JNINativeMethod method_table[] = {
180 { "createSubprocess", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[I)Ljava/io/FileDescriptor;",
181 (void*) android_os_Exec_createSubProcess },
182 { "setPtyWindowSize", "(Ljava/io/FileDescriptor;IIII)V",
183 (void*) android_os_Exec_setPtyWindowSize},
184 { "waitFor", "(I)I",
185 (void*) android_os_Exec_waitFor}
186};
187
188int register_android_os_Exec(JNIEnv *env)
189{
190 class_fileDescriptor = env->FindClass("java/io/FileDescriptor");
191
192 if (class_fileDescriptor == NULL) {
193 LOGE("Can't find java/io/FileDescriptor");
194 return -1;
195 }
196
197 field_fileDescriptor_descriptor = env->GetFieldID(class_fileDescriptor, "descriptor", "I");
198
199 if (field_fileDescriptor_descriptor == NULL) {
200 LOGE("Can't find FileDescriptor.descriptor");
201 return -1;
202 }
203
204 method_fileDescriptor_init = env->GetMethodID(class_fileDescriptor, "<init>", "()V");
205 if (method_fileDescriptor_init == NULL) {
206 LOGE("Can't find FileDescriptor.init");
207 return -1;
208 }
209
210 return AndroidRuntime::registerNativeMethods(
211 env, "android/os/Exec",
212 method_table, NELEM(method_table));
213}
214
215};