1 /*
   2  * Copyright (c) 2012, 2015, 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  * If app is "/foo/bin/javac", or "/foo/bin/sparcv9/javac" then put
  29  * "/foo" into buf.
  30  */
  31 jboolean
  32 GetApplicationHome(char *buf, jint bufsize)
  33 {
  34     const char *execname = GetExecName();
  35     if (execname != NULL) {
  36         JLI_Snprintf(buf, bufsize, "%s", execname);
  37         buf[bufsize-1] = '\0';
  38     } else {
  39         return JNI_FALSE;
  40     }
  41 
  42     if (JLI_StrRChr(buf, '/') == 0) {
  43         buf[0] = '\0';
  44         return JNI_FALSE;
  45     }
  46     *(JLI_StrRChr(buf, '/')) = '\0';    /* executable file      */
  47     if (JLI_StrLen(buf) < 4 || JLI_StrRChr(buf, '/') == 0) {
  48         buf[0] = '\0';
  49         return JNI_FALSE;
  50     }
  51     if (JLI_StrCmp("/bin", buf + JLI_StrLen(buf) - 4) != 0)
  52         *(JLI_StrRChr(buf, '/')) = '\0';        /* sparcv9 or amd64     */
  53     if (JLI_StrLen(buf) < 4 || JLI_StrCmp("/bin", buf + JLI_StrLen(buf) - 4) != 0) {
  54         buf[0] = '\0';
  55         return JNI_FALSE;
  56     }
  57     *(JLI_StrRChr(buf, '/')) = '\0';    /* bin                  */
  58 
  59     return JNI_TRUE;
  60 }
  61 /*
  62  * Return true if the named program exists
  63  */
  64 static int
  65 ProgramExists(char *name)
  66 {
  67     struct stat sb;
  68     if (stat(name, &sb) != 0) return 0;
  69     if (S_ISDIR(sb.st_mode)) return 0;
  70     return (sb.st_mode & S_IEXEC) != 0;
  71 }
  72 
  73 /*
  74  * Find a command in a directory, returning the path.
  75  */
  76 static char *
  77 Resolve(char *indir, char *cmd)
  78 {
  79     char name[PATH_MAX + 2], *real;
  80 
  81     if ((JLI_StrLen(indir) + JLI_StrLen(cmd) + 1)  > PATH_MAX) return 0;
  82     JLI_Snprintf(name, sizeof(name), "%s%c%s", indir, FILE_SEPARATOR, cmd);
  83     if (!ProgramExists(name)) return 0;
  84     real = JLI_MemAlloc(PATH_MAX + 2);
  85     if (!realpath(name, real))
  86         JLI_StrCpy(real, name);
  87     return real;
  88 }
  89 
  90 /*
  91  * Find a path for the executable
  92  */
  93 char *
  94 FindExecName(char *program)
  95 {
  96     char cwdbuf[PATH_MAX+2];
  97     char *path;
  98     char *tmp_path;
  99     char *f;
 100     char *result = NULL;
 101 
 102     /* absolute path? */
 103     if (*program == FILE_SEPARATOR ||
 104         (FILE_SEPARATOR=='\\' && JLI_StrRChr(program, ':')))
 105         return Resolve("", program+1);
 106 
 107     /* relative path? */
 108     if (JLI_StrRChr(program, FILE_SEPARATOR) != 0) {
 109         char buf[PATH_MAX+2];
 110         return Resolve(getcwd(cwdbuf, sizeof(cwdbuf)), program);
 111     }
 112 
 113     /* from search path? */
 114     path = getenv("PATH");
 115     if (!path || !*path) path = ".";
 116     tmp_path = JLI_MemAlloc(JLI_StrLen(path) + 2);
 117     JLI_StrCpy(tmp_path, path);
 118 
 119     for (f=tmp_path; *f && result==0; ) {
 120         char *s = f;
 121         while (*f && (*f != PATH_SEPARATOR)) ++f;
 122         if (*f) *f++ = 0;
 123         if (*s == FILE_SEPARATOR)
 124             result = Resolve(s, program);
 125         else {
 126             /* relative path element */
 127             char dir[2*PATH_MAX];
 128             JLI_Snprintf(dir, sizeof(dir), "%s%c%s", getcwd(cwdbuf, sizeof(cwdbuf)),
 129                     FILE_SEPARATOR, s);
 130             result = Resolve(dir, program);
 131         }
 132         if (result != 0) break;
 133     }
 134 
 135     JLI_MemFree(tmp_path);
 136     return result;
 137 }
 138 
 139 void JLI_ReportErrorMessage(const char* fmt, ...) {
 140     va_list vl;
 141     va_start(vl, fmt);
 142     vfprintf(stderr, fmt, vl);
 143     fprintf(stderr, "\n");
 144     va_end(vl);
 145 }
 146 
 147 void JLI_ReportErrorMessageSys(const char* fmt, ...) {
 148     va_list vl;
 149     char *emsg;
 150 
 151     /*
 152      * TODO: its safer to use strerror_r but is not available on
 153      * Solaris 8. Until then....
 154      */
 155     emsg = strerror(errno);
 156     if (emsg != NULL) {
 157         fprintf(stderr, "%s\n", emsg);
 158     }
 159 
 160     va_start(vl, fmt);
 161     vfprintf(stderr, fmt, vl);
 162     fprintf(stderr, "\n");
 163     va_end(vl);
 164 }
 165 
 166 void  JLI_ReportExceptionDescription(JNIEnv * env) {
 167   (*env)->ExceptionDescribe(env);
 168 }
 169 
 170 /*
 171  *      Since using the file system as a registry is a bit risky, perform
 172  *      additional sanity checks on the identified directory to validate
 173  *      it as a valid jre/sdk.
 174  *
 175  *      Return 0 if the tests fail; otherwise return non-zero (true).
 176  *
 177  *      Note that checking for anything more than the existence of an
 178  *      executable object at bin/java relative to the path being checked
 179  *      will break the regression tests.
 180  */
 181 static int
 182 CheckSanity(char *path, char *dir)
 183 {
 184     char    buffer[PATH_MAX];
 185 
 186     if (JLI_StrLen(path) + JLI_StrLen(dir) + 11 > PATH_MAX)
 187         return (0);     /* Silently reject "impossibly" long paths */
 188 
 189     JLI_Snprintf(buffer, sizeof(buffer), "%s/%s/bin/java", path, dir);
 190     return ((access(buffer, X_OK) == 0) ? 1 : 0);
 191 }
 192 
 193 /*
 194  * "Borrowed" from Solaris 10 where the unsetenv() function is being added
 195  * to libc thanks to SUSv3 (Standard Unix Specification, version 3). As
 196  * such, in the fullness of time this will appear in libc on all relevant
 197  * Solaris/Linux platforms and maybe even the Windows platform.  At that
 198  * time, this stub can be removed.
 199  *
 200  * This implementation removes the environment locking for multithreaded
 201  * applications.  (We don't have access to these mutexes within libc and
 202  * the launcher isn't multithreaded.)  Note that what remains is platform
 203  * independent, because it only relies on attributes that a POSIX environment
 204  * defines.
 205  *
 206  * Returns 0 on success, -1 on failure.
 207  *
 208  * Also removed was the setting of errno.  The only value of errno set
 209  * was EINVAL ("Invalid Argument").
 210  */
 211 
 212 /*
 213  * s1(environ) is name=value
 214  * s2(name) is name(not the form of name=value).
 215  * if names match, return value of 1, else return 0
 216  */
 217 static int
 218 match_noeq(const char *s1, const char *s2)
 219 {
 220         while (*s1 == *s2++) {
 221                 if (*s1++ == '=')
 222                         return (1);
 223         }
 224         if (*s1 == '=' && s2[-1] == '\0')
 225                 return (1);
 226         return (0);
 227 }
 228 
 229 /*
 230  * added for SUSv3 standard
 231  *
 232  * Delete entry from environ.
 233  * Do not free() memory!  Other threads may be using it.
 234  * Keep it around forever.
 235  */
 236 static int
 237 borrowed_unsetenv(const char *name)
 238 {
 239         long    idx;            /* index into environ */
 240 
 241         if (name == NULL || *name == '\0' ||
 242             JLI_StrChr(name, '=') != NULL) {
 243                 return (-1);
 244         }
 245 
 246         for (idx = 0; environ[idx] != NULL; idx++) {
 247                 if (match_noeq(environ[idx], name))
 248                         break;
 249         }
 250         if (environ[idx] == NULL) {
 251                 /* name not found but still a success */
 252                 return (0);
 253         }
 254         /* squeeze up one entry */
 255         do {
 256                 environ[idx] = environ[idx+1];
 257         } while (environ[++idx] != NULL);
 258 
 259         return (0);
 260 }
 261 /* --- End of "borrowed" code --- */
 262 
 263 /*
 264  * Wrapper for unsetenv() function.
 265  */
 266 int
 267 UnsetEnv(char *name)
 268 {
 269     return(borrowed_unsetenv(name));
 270 }
 271 
 272 jboolean
 273 IsJavaw()
 274 {
 275     /* noop on UNIX */
 276     return JNI_FALSE;
 277 }
 278 
 279 void
 280 InitLauncher(jboolean javaw)
 281 {
 282     JLI_SetTraceLauncher();
 283 }
 284 
 285 /*
 286  * The implementation for finding classes from the bootstrap
 287  * class loader, refer to java.h
 288  */
 289 static FindClassFromBootLoader_t *findBootClass = NULL;
 290 
 291 jclass
 292 FindBootStrapClass(JNIEnv *env, const char* classname)
 293 {
 294    if (findBootClass == NULL) {
 295        findBootClass = (FindClassFromBootLoader_t *)dlsym(RTLD_DEFAULT,
 296           "JVM_FindClassFromBootLoader");
 297        if (findBootClass == NULL) {
 298            JLI_ReportErrorMessage(DLL_ERROR4,
 299                "JVM_FindClassFromBootLoader");
 300            return NULL;
 301        }
 302    }
 303    return findBootClass(env, classname);
 304 }
 305 
 306 StdArg
 307 *JLI_GetStdArgs()
 308 {
 309     return NULL;
 310 }
 311 
 312 int
 313 JLI_GetStdArgc() {
 314     return 0;
 315 }
 316 
 317 jobjectArray
 318 CreateApplicationArgs(JNIEnv *env, char **strv, int argc)
 319 {
 320     return NewPlatformStringArray(env, strv, argc);
 321 }