1 /*
2  * Copyright (c) 2021, 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 
26 #include "kludge_c++11.h"
27 
28 #include <memory>
29 #include "JvmLauncher.h"
30 #include "AppLauncher.h"
31 #include "FileUtils.h"
32 #include "UnixSysInfo.h"
33 #include "Package.h"
34 #include "Log.h"
35 #include "app.h"
36 #include "ErrorHandling.h"
37 
38 
39 namespace {
40 
hash(const std::string & str)41 size_t hash(const std::string& str) {
42     size_t h = 0;
43     for(std::string::const_iterator it = str.begin(); it != str.end(); ++it) {
44         h = 31 * h + (*it & 0xff);
45     }
46     return h;
47 }
48 
49 Jvm* jvmLauncher;
50 
launchApp()51 void launchApp() {
52     const tstring launcherPath = SysInfo::getProcessModulePath();
53 
54     const Package ownerPackage = Package::findOwnerOfFile(launcherPath);
55 
56     AppLauncher appLauncher;
57     appLauncher.addJvmLibName(_T("lib/libjli.so"));
58     // add backup - older version such as JDK11 have it in jli sub-dir
59     appLauncher.addJvmLibName(_T("lib/jli/libjli.so"));
60 
61     if (ownerPackage.name().empty()) {
62         // Launcher should be in "bin" subdirectory of app image.
63         const tstring appImageRoot = FileUtils::dirname(
64                 FileUtils::dirname(launcherPath));
65 
66         appLauncher
67             .setImageRoot(appImageRoot)
68             .setAppDir(FileUtils::mkpath() << appImageRoot << _T("lib/app"))
69             .setLibEnvVariableName(_T("LD_LIBRARY_PATH"))
70             .setDefaultRuntimePath(FileUtils::mkpath() << appImageRoot
71                     << _T("lib/runtime"));
72     } else {
73         ownerPackage.initAppLauncher(appLauncher);
74     }
75 
76     const std::string _JPACKAGE_LAUNCHER = "_JPACKAGE_LAUNCHER";
77 
78     std::string launchInfo = SysInfo::getEnvVariable(std::nothrow,
79             _JPACKAGE_LAUNCHER, "");
80 
81     const std::string thisLdLibraryPath = SysInfo::getEnvVariable(std::nothrow,
82             "LD_LIBRARY_PATH", "");
83 
84     const size_t thisHash = hash(thisLdLibraryPath);
85 
86     if (!launchInfo.empty()) {
87         LOG_TRACE(tstrings::any() << "Found "
88                 << _JPACKAGE_LAUNCHER << "=[" << launchInfo << "]");
89 
90         tistringstream iss(launchInfo);
91         iss.exceptions(std::ios::failbit | std::ios::badbit);
92 
93         size_t hash = 0;
94         iss >> hash;
95 
96         launchInfo = "";
97 
98         if (thisHash != hash) {
99             // This launcher execution is the result of execve() call from
100             // withing JVM.
101             // This means all JVM arguments are already configured in launcher
102             // process command line.
103             // No need to construct command line for JVM.
104             LOG_TRACE("Not building JVM arguments from cfg file");
105             appLauncher.setInitJvmFromCmdlineOnly(true);
106         }
107     } else {
108         // Changed LD_LIBRARY_PATH environment variable might result in
109         // execve() call from within JVM.
110         // Set _JPACKAGE_LAUNCHER environment variable accordingly so that
111         // restarted launcher process can detect a restart.
112 
113         launchInfo = (tstrings::any() << thisHash).str();
114     }
115 
116     JP_TRY;
117     if (0 != setenv(_JPACKAGE_LAUNCHER.c_str(), launchInfo.c_str(), 1)) {
118         JP_THROW(tstrings::any() << "setenv(" << _JPACKAGE_LAUNCHER
119                 << ", " << launchInfo << ") failed. Error: " << lastCRTError());
120     } else {
121         LOG_TRACE(tstrings::any() << "Set "
122                 << _JPACKAGE_LAUNCHER << "=[" << launchInfo << "]");
123     }
124     JP_CATCH_ALL;
125 
126     jvmLauncher = appLauncher.createJvmLauncher();
127 }
128 
129 } // namespace
130 
131 
132 extern "C" {
133 
jvmLauncherCreate(int argc,char * argv[])134 JNIEXPORT JvmlLauncherHandle jvmLauncherCreate(int argc, char *argv[]) {
135     SysInfo::argc = argc;
136     SysInfo::argv = argv;
137     jvmLauncher = 0;
138     app::launch(std::nothrow, launchApp);
139 
140     JvmlLauncherHandle jlh = 0;
141     if (jvmLauncher) {
142         jlh = jvmLauncher->exportLauncher();
143         const std::unique_ptr<Jvm> deleter(jvmLauncher);
144     }
145 
146     return jlh;
147 }
148 
149 } // extern "C"
150 
151 
152 namespace {
153 
154 void dcon() __attribute__((destructor));
155 
dcon()156 void dcon() {
157    LOG_TRACE("unload");
158 }
159 
160 } // namespace
161