1 /* 2 * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 #include "java.h" 26 27 /* 28 * Find the last occurrence of a string 29 */ 30 char* findLastPathComponent(char *buffer, const char *comp) { 31 char* t = buffer; 32 char* p = NULL; 33 size_t l = JLI_StrLen(comp); 34 t = JLI_StrStr(t, comp); 35 36 while (t != NULL) { 37 p = t; 38 t += l; 39 t = JLI_StrStr(t, comp); 40 } 41 return p; 42 } 43 44 /* 45 * Removes the trailing file name and any intermediate platform 46 * directories, if any, and its enclosing directory. 47 * Ex: if a buffer contains "/foo/bin/javac" or "/foo/bin/x64/javac", the 48 * truncated resulting buffer will contain "/foo". 49 */ 50 jboolean 51 TruncatePath(char *buf) 52 { 53 // try bin directory, maybe an executable 54 char *p = findLastPathComponent(buf, "/bin/"); 55 if (p != NULL) { 56 *p = '\0'; 57 return JNI_TRUE; 58 } 59 // try lib directory, maybe a library 60 p = findLastPathComponent(buf, "/lib/"); 61 if (p != NULL) { 62 *p = '\0'; 63 return JNI_TRUE; 64 } 65 return JNI_FALSE; 66 } 67 68 /* 69 * Retrieves the path to the JRE home by locating the executable file 70 * of the current process and then truncating the path to the executable 71 */ 72 jboolean 73 GetApplicationHome(char *buf, jint bufsize) 74 { 75 const char *execname = GetExecName(); 76 if (execname != NULL) { 77 JLI_Snprintf(buf, bufsize, "%s", execname); 78 buf[bufsize-1] = '\0'; 79 } else { 80 return JNI_FALSE; 81 } 82 return TruncatePath(buf); 83 } 84 85 /* 86 * Retrieves the path to the JRE home by locating the 87 * shared library and then truncating the path to it. 88 */ 89 jboolean 90 GetApplicationHomeFromDll(char *buf, jint bufsize) 91 { 92 /* try to find ourselves instead */ 93 Dl_info info; 94 if (dladdr((void*)&GetApplicationHomeFromDll, &info) != 0) { 95 char *path = realpath(info.dli_fname, buf); 96 if (path == buf) { 97 return TruncatePath(buf); 98 } 99 } 100 return JNI_FALSE; 101 } 102 103 /* 104 * Return true if the named program exists 105 */ 106 static int 107 ProgramExists(char *name) 108 { 109 struct stat sb; 110 if (stat(name, &sb) != 0) return 0; 111 if (S_ISDIR(sb.st_mode)) return 0; 112 return (sb.st_mode & S_IEXEC) != 0; 113 } 114 115 /* 116 * Find a command in a directory, returning the path. 117 */ 118 static char * 119 Resolve(char *indir, char *cmd) 120 { 121 char name[PATH_MAX + 2], *real; 122 123 if ((JLI_StrLen(indir) + JLI_StrLen(cmd) + 1) > PATH_MAX) return 0; 124 JLI_Snprintf(name, sizeof(name), "%s%c%s", indir, FILE_SEPARATOR, cmd); 125 if (!ProgramExists(name)) return 0; 126 real = JLI_MemAlloc(PATH_MAX + 2); 127 if (!realpath(name, real)) 128 JLI_StrCpy(real, name); 129 return real; 130 } 131 132 /* 133 * Find a path for the executable 134 */ 135 char * 136 FindExecName(char *program) 137 { 138 char cwdbuf[PATH_MAX+2]; 139 char *path; 140 char *tmp_path; 141 char *f; 142 char *result = NULL; 143 144 /* absolute path? */ 145 if (*program == FILE_SEPARATOR || 146 (FILE_SEPARATOR=='\\' && JLI_StrRChr(program, ':'))) 147 return Resolve("", program+1); 148 149 /* relative path? */ 150 if (JLI_StrRChr(program, FILE_SEPARATOR) != 0) { 151 char buf[PATH_MAX+2]; 152 return Resolve(getcwd(cwdbuf, sizeof(cwdbuf)), program); 153 } 154 155 /* from search path? */ 156 path = getenv("PATH"); 157 if (!path || !*path) path = "."; 158 tmp_path = JLI_MemAlloc(JLI_StrLen(path) + 2); 159 JLI_StrCpy(tmp_path, path); 160 161 for (f=tmp_path; *f && result==0; ) { 162 char *s = f; 163 while (*f && (*f != PATH_SEPARATOR)) ++f; 164 if (*f) *f++ = 0; 165 if (*s == FILE_SEPARATOR) 166 result = Resolve(s, program); 167 else { 168 /* relative path element */ 169 char dir[2*PATH_MAX]; 170 JLI_Snprintf(dir, sizeof(dir), "%s%c%s", getcwd(cwdbuf, sizeof(cwdbuf)), 171 FILE_SEPARATOR, s); 172 result = Resolve(dir, program); 173 } 174 if (result != 0) break; 175 } 176 177 JLI_MemFree(tmp_path); 178 return result; 179 } 180 181 void JLI_ReportErrorMessage(const char* fmt, ...) { 182 va_list vl; 183 va_start(vl, fmt); 184 vfprintf(stderr, fmt, vl); 185 fprintf(stderr, "\n"); 186 va_end(vl); 187 } 188 189 void JLI_ReportErrorMessageSys(const char* fmt, ...) { 190 va_list vl; 191 char *emsg; 192 193 /* 194 * TODO: its safer to use strerror_r but is not available on 195 * Solaris 8. Until then.... 196 */ 197 emsg = strerror(errno); 198 if (emsg != NULL) { 199 fprintf(stderr, "%s\n", emsg); 200 } 201 202 va_start(vl, fmt); 203 vfprintf(stderr, fmt, vl); 204 fprintf(stderr, "\n"); 205 va_end(vl); 206 } 207 208 void JLI_ReportExceptionDescription(JNIEnv * env) { 209 (*env)->ExceptionDescribe(env); 210 } 211 212 /* 213 * Since using the file system as a registry is a bit risky, perform 214 * additional sanity checks on the identified directory to validate 215 * it as a valid jre/sdk. 216 * 217 * Return 0 if the tests fail; otherwise return non-zero (true). 218 * 219 * Note that checking for anything more than the existence of an 220 * executable object at bin/java relative to the path being checked 221 * will break the regression tests. 222 */ 223 static int 224 CheckSanity(char *path, char *dir) 225 { 226 char buffer[PATH_MAX]; 227 228 if (JLI_StrLen(path) + JLI_StrLen(dir) + 11 > PATH_MAX) 229 return (0); /* Silently reject "impossibly" long paths */ 230 231 JLI_Snprintf(buffer, sizeof(buffer), "%s/%s/bin/java", path, dir); 232 return ((access(buffer, X_OK) == 0) ? 1 : 0); 233 } 234 235 /* 236 * "Borrowed" from Solaris 10 where the unsetenv() function is being added 237 * to libc thanks to SUSv3 (Standard Unix Specification, version 3). As 238 * such, in the fullness of time this will appear in libc on all relevant 239 * Solaris/Linux platforms and maybe even the Windows platform. At that 240 * time, this stub can be removed. 241 * 242 * This implementation removes the environment locking for multithreaded 243 * applications. (We don't have access to these mutexes within libc and 244 * the launcher isn't multithreaded.) Note that what remains is platform 245 * independent, because it only relies on attributes that a POSIX environment 246 * defines. 247 * 248 * Returns 0 on success, -1 on failure. 249 * 250 * Also removed was the setting of errno. The only value of errno set 251 * was EINVAL ("Invalid Argument"). 252 */ 253 254 /* 255 * s1(environ) is name=value 256 * s2(name) is name(not the form of name=value). 257 * if names match, return value of 1, else return 0 258 */ 259 static int 260 match_noeq(const char *s1, const char *s2) 261 { 262 while (*s1 == *s2++) { 263 if (*s1++ == '=') 264 return (1); 265 } 266 if (*s1 == '=' && s2[-1] == '\0') 267 return (1); 268 return (0); 269 } 270 271 /* 272 * added for SUSv3 standard 273 * 274 * Delete entry from environ. 275 * Do not free() memory! Other threads may be using it. 276 * Keep it around forever. 277 */ 278 static int 279 borrowed_unsetenv(const char *name) 280 { 281 long idx; /* index into environ */ 282 283 if (name == NULL || *name == '\0' || 284 JLI_StrChr(name, '=') != NULL) { 285 return (-1); 286 } 287 288 for (idx = 0; environ[idx] != NULL; idx++) { 289 if (match_noeq(environ[idx], name)) 290 break; 291 } 292 if (environ[idx] == NULL) { 293 /* name not found but still a success */ 294 return (0); 295 } 296 /* squeeze up one entry */ 297 do { 298 environ[idx] = environ[idx+1]; 299 } while (environ[++idx] != NULL); 300 301 return (0); 302 } 303 /* --- End of "borrowed" code --- */ 304 305 /* 306 * Wrapper for unsetenv() function. 307 */ 308 int 309 UnsetEnv(char *name) 310 { 311 return(borrowed_unsetenv(name)); 312 } 313 314 jboolean 315 IsJavaw() 316 { 317 /* noop on UNIX */ 318 return JNI_FALSE; 319 } 320 321 void 322 InitLauncher(jboolean javaw) 323 { 324 JLI_SetTraceLauncher(); 325 } 326 327 /* 328 * The implementation for finding classes from the bootstrap 329 * class loader, refer to java.h 330 */ 331 static FindClassFromBootLoader_t *findBootClass = NULL; 332 333 jclass 334 FindBootStrapClass(JNIEnv *env, const char* classname) 335 { 336 if (findBootClass == NULL) { 337 findBootClass = (FindClassFromBootLoader_t *)dlsym(RTLD_DEFAULT, 338 "JVM_FindClassFromBootLoader"); 339 if (findBootClass == NULL) { 340 JLI_ReportErrorMessage(DLL_ERROR4, 341 "JVM_FindClassFromBootLoader"); 342 return NULL; 343 } 344 } 345 return findBootClass(env, classname); 346 } 347 348 StdArg 349 *JLI_GetStdArgs() 350 { 351 return NULL; 352 } 353 354 int 355 JLI_GetStdArgc() { 356 return 0; 357 } 358 359 jobjectArray 360 CreateApplicationArgs(JNIEnv *env, char **strv, int argc) 361 { 362 return NewPlatformStringArray(env, strv, argc); 363 }