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