#include #include #include #include #include #define OPEN_MAX_FD 512 #include #include #include #ifndef _AIX #include #endif #include #include #include #include "native-file-utils.h" #include "native-utils.h" #include "layout!PPT6String4lang4java.h" #include "layout!PTAPT6String4lang4java.h" #include "layout!PT6String4lang4java.h" #include "layout!TAPT6String4lang4java.h" #define tossIllegalArgumentException m29throwIllegalArgumentExceptionmT11NativeUtils4lang2ti #define tossOutOfMemoryError m21throwOutOfMemoryErrormT11NativeUtils4lang2ti #if defined(USE_RUNTIME_SYS_PARAM_H_MAXPATHLEN) # define TI_MAXPATHLEN MAXPATHLEN #else # if defined(USE_RUNTIME_SYS_PARAM_H_PATHSIZE) # define TI_MAXPATHLEN PATHSIZE # endif #endif /* path in the environment */ static char **PATH = 0; /* effective uid */ static uid_t uid; /* effective group id */ static gid_t gid; static char *fullPath(char *part, char *full); static int statExecutable(char *, struct stat *); static void parsePath (); static int pforked = 0; /* * This routine is called once from the Process Reaper thread and * never returns. Its job is to catch sigchld events and pass them * on to class UNIXProcess. */ void m14waitUntilDeathmT11UNIXProcess4lang4java(PT11UNIXProcess4lang4java this) { Pjint gp_pid; int pid, status; FIELD_ADDR_GLOBAL(gp_pid, this, f3pidT11UNIXProcess4lang4java); FENCE_PRE_READ(); DEREF_GLOBAL_jint(pid, gp_pid); FENCE_POST_READ(); /* block this reaper thread until the child process exits */ while (waitpid(pid, &status, WNOHANG) == 0); m9deadChildIImT11UNIXProcess4lang4java(pid, WEXITSTATUS(status)); /* keep the reference alive */ CHECK_NULL_GLOBAL(this); } jint ml11forkAndExecPTAPT6String4lang4javaPTAPT6String4lang4javamT11UNIXProcess4lang4java( T11UNIXProcess4lang4java *me, PTAPT6String4lang4java cmdarray, PTAPT6String4lang4java envp) { /* let's do all the setup for the exec before we fork */ int fdin[2], fdout[2], fderr[2], fdsync[2]; char **envstr = NULL; char fullpath[TI_MAXPATHLEN+1]; int i; char **argv = NULL; char * savedArgv0 = NULL; int argc; int pid = -1; /* this is the error return value */ PPT6String4lang4java gp_jstr; PT6String4lang4java jstr; /* On error_cleanup, we don't want to close() some random junk. */ fdsync[0] = fdsync[1] = fdin[0] = fdin[1] = fdout[0] = fdout[1] = fderr[0] = fderr[1] = -1; JAVA_ARRAY_LENGTH_GLOBAL(argc, cmdarray); if (argc == 0) { tossIllegalArgumentException(); return -1; } #define BODYOF(h) unhand(h)->body /* calloc null terminates for us */ argv = (char**)ti_malloc((argc + 1) * sizeof(char *)); for(i = 0; i<(argc+1); i++) argv[i]=0; if (argv == 0) { tossOutOfMemoryError(); goto error_cleanup; } for (i = 0; i < argc; i++) { char *str, *newstr; JAVA_ARRAY_ADDR_GLOBAL(gp_jstr, cmdarray, i, "in UNIXProcess.forkAndExec()"); FENCE_PRE_READ(); DEREF_GLOBAL_gp(jstr, gp_jstr); FENCE_POST_READ(); str = globalJstringToCstring(jstr); newstr = ti_malloc(strlen(str) + 1); if (newstr == 0) { tossOutOfMemoryError(); goto error_cleanup; } strcpy(newstr, str); /* KEEP_POINTER_ALIVE(str); */ argv[i] = newstr; } parsePath(); savedArgv0 = argv[0]; argv[0] = fullPath(*argv, fullpath); if (argv[0] == NULL) { /* fullPath has signalled an exception so we just return */ goto error_cleanup; } if (!isNull(envp)) { int len; JAVA_ARRAY_LENGTH_GLOBAL(len, envp); if (len != 0) { int i; /* calloc null terminates for us */ envstr = (char **)ti_malloc((len + 1) * sizeof(char *)); for(i=0; i<(len+1); i++) envstr[i] = 0; if (envstr == 0) { tossOutOfMemoryError(); goto error_cleanup; } for (i=0; if8stdin_fdT11UNIXProcess4lang4java ->f2fdT14FileDescriptor2io4java = fdin[1]; me->f9stdout_fdT11UNIXProcess4lang4java->f2fdT14FileDescriptor2io4java = fdout[0]; me->f9stderr_fdT11UNIXProcess4lang4java->f2fdT14FileDescriptor2io4java = fderr[0]; me->f7sync_fdT11UNIXProcess4lang4java ->f2fdT14FileDescriptor2io4java = fdsync[1]; } normal_cleanup: if (argv) { int len; JAVA_ARRAY_LENGTH_GLOBAL(len, cmdarray); ti_free(savedArgv0); for (i = 1; i < len; i++) ti_free(argv[i]); ti_free(argv); } if (envstr) { int len; JAVA_ARRAY_LENGTH_GLOBAL(len, envp); for (i = 0; i < len; i++) ti_free(envstr[i]); ti_free(envstr); } return pid; /* pid will be -1 in the error case */ error_cleanup: close(fdin[0]); close(fdin[1]); close(fdout[0]); close(fdout[1]); close(fderr[0]); close(fderr[1]); close(fdsync[0]); close(fdsync[1]); goto normal_cleanup; } void m7destroymT11UNIXProcess4lang4java(PT11UNIXProcess4lang4java this) { jint pid; Pjint gp_pid; FIELD_ADDR_GLOBAL(gp_pid, this, f3pidT11UNIXProcess4lang4java); FENCE_PRE_READ(); DEREF_GLOBAL_jint(pid, gp_pid); FENCE_POST_READ(); kill(pid, SIGTERM); } /* Find the command like a shell would. * signal an error for things not executable || not readable || not found. */ static char *fullPath(char *part, char *full) { char **tmp; struct stat b; int ret; if (*part != '/' && PATH) { for (tmp = PATH; *tmp; tmp++) { strcpy(full, *tmp); full[strlen(*tmp)] = '\0'; strcat(full, "/"); strcat(full, part); ret = statExecutable(full, &b); if (ret == -1) { /* doesn't exist */ continue; } else if (ret == -2) { /* can't execute */ snprintf(full, TI_MAXPATHLEN, "%s: cannot execute", part); tossIOException_str(part); return 0; } else { return full; } } } else if (!(ret = statExecutable(part, &b))) { return part; } else if (ret == -2) { /* cannot execute */ snprintf(full, TI_MAXPATHLEN, "%s: cannot execute", part); tossIOException_str(full); return 0; } /* not found if we got here */ { snprintf(full, TI_MAXPATHLEN, "%s: not found", part); tossIOException_str(full); return 0; } } /* return 0 if it is executable && readable by this process * -1 if no such file, -2 if it cannot be executed, and raise exception */ static int statExecutable(char *exe, struct stat *b) { if (stat(exe, b)) { /* doesn't exist */ return -1; } if (S_ISDIR(b->st_mode)) { /* cannot execute */ return -2; } /* check for user permissions */ if (b->st_uid == uid) { return (b->st_mode & S_IXUSR) ? 0 : -2; } /* check for group permissions */ if (b->st_gid == gid) { return (b->st_mode & S_IXGRP) ? 0 : -2; } /* check for world permissions */ return b->st_mode & S_IXOTH ? 0 : -2; } static void parsePath () { char *env_path; char *path, *c, *len; int count = 0; int i; /* get uid, gid */ uid = geteuid(); gid = getegid(); if ((env_path = getenv("PATH")) == 0) { return; } path = (char *) ti_malloc(strlen(env_path) + 1); strcpy(path, env_path); len = path + strlen(path); /* count path elements */ for (c = path; c < len; c++) { if (*c == ':') count++; } PATH = (char **)ti_malloc((++count+1) * sizeof(char*)); /* fill it in */ PATH[0] = path; PATH[count] = 0; for (i = 1; i < count; i++) { c = strchr(path, ':'); if (c == 0) { /* shouldn't happen */ /* jio_fprintf(stderr, "processmd.c: wrong count parsing path: i=%d, count=%d\n", i, count); */ break; } *c++ = 0; PATH[i] = path = c; } }