1 /*
  2  * Copyright (c) 2013, 2022, 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.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 package jdk.test.lib;
 25 
 26 import java.io.BufferedReader;
 27 import java.io.FileNotFoundException;
 28 import java.io.IOException;
 29 import java.io.InputStreamReader;
 30 import java.nio.file.Files;
 31 import java.nio.file.Path;
 32 import java.nio.file.Paths;
 33 import java.security.AccessController;
 34 import java.security.PrivilegedAction;
 35 import java.util.concurrent.TimeUnit;
 36 import java.util.regex.Pattern;
 37 
 38 public class Platform {
 39     public  static final String vmName      = privilegedGetProperty("java.vm.name");
 40     public  static final String vmInfo      = privilegedGetProperty("java.vm.info");
 41     private static final String osVersion   = privilegedGetProperty("os.version");
 42     private static       int osVersionMajor = -1;
 43     private static       int osVersionMinor = -1;
 44     private static final String osName      = privilegedGetProperty("os.name");
 45     private static final String dataModel   = privilegedGetProperty("sun.arch.data.model");
 46     private static final String vmVersion   = privilegedGetProperty("java.vm.version");
 47     private static final String jdkDebug    = privilegedGetProperty("jdk.debug");
 48     private static final String osArch      = privilegedGetProperty("os.arch");
 49     private static final String userName    = privilegedGetProperty("user.name");
 50     private static final String compiler    = privilegedGetProperty("sun.management.compiler");
 51     private static final String testJdk     = privilegedGetProperty("test.jdk");
 52 
 53     @SuppressWarnings("removal")
 54     private static String privilegedGetProperty(String key) {
 55         return AccessController.doPrivileged((
 56                 PrivilegedAction<String>) () -> System.getProperty(key));
 57     }
 58 
 59     public static boolean isClient() {
 60         return vmName.endsWith(" Client VM");
 61     }
 62 
 63     public static boolean isServer() {
 64         return vmName.endsWith(" Server VM");
 65     }
 66 
 67     public static boolean isZero() {
 68         return vmName.endsWith(" Zero VM");
 69     }
 70 
 71     public static boolean isMinimal() {
 72         return vmName.endsWith(" Minimal VM");
 73     }
 74 
 75     public static boolean isEmbedded() {
 76         return vmName.contains("Embedded");
 77     }
 78 
 79     public static boolean isEmulatedClient() {
 80         return vmInfo.contains(" emulated-client");
 81     }
 82 
 83     public static boolean isTieredSupported() {
 84         return (compiler != null) && compiler.contains("Tiered Compilers");
 85     }
 86 
 87     public static boolean isInt() {
 88         return vmInfo.contains("interpreted");
 89     }
 90 
 91     public static boolean isMixed() {
 92         return vmInfo.contains("mixed");
 93     }
 94 
 95     public static boolean isComp() {
 96         return vmInfo.contains("compiled");
 97     }
 98 
 99     public static boolean is32bit() {
100         return dataModel.equals("32");
101     }
102 
103     public static boolean is64bit() {
104         return dataModel.equals("64");
105     }
106 
107     public static boolean isAix() {
108         return isOs("aix");
109     }
110 
111     public static boolean isLinux() {
112         return isOs("linux");
113     }
114 
115     public static boolean isBusybox(String tool) {
116         try {
117             Path toolpath = Paths.get(tool);
118             return !isWindows()
119                     && Files.isSymbolicLink(toolpath)
120                     && Paths.get("/bin/busybox")
121                         .equals(Files.readSymbolicLink(toolpath));
122         } catch (IOException ignore) {
123             return false;
124         }
125     }
126 
127     public static boolean isOSX() {
128         return isOs("mac");
129     }
130 
131     public static boolean isWindows() {
132         return isOs("win");
133     }
134 
135     private static boolean isOs(String osname) {
136         return osName.toLowerCase().startsWith(osname.toLowerCase());
137     }
138 
139     public static String getOsName() {
140         return osName;
141     }
142 
143     // Os version support.
144     private static void init_version() {
145         String[] osVersionTokens = osVersion.split("\\.");
146         try {
147             if (osVersionTokens.length > 0) {
148                 osVersionMajor = Integer.parseInt(osVersionTokens[0]);
149                 if (osVersionTokens.length > 1) {
150                     osVersionMinor = Integer.parseInt(osVersionTokens[1]);
151                 }
152             }
153         } catch (NumberFormatException e) {
154             osVersionMajor = osVersionMinor = 0;
155         }
156     }
157 
158     public static String getOsVersion() {
159         return osVersion;
160     }
161 
162     // Returns major version number from os.version system property.
163     // E.g. 3 on SLES 11.3 (for the linux kernel version).
164     public static int getOsVersionMajor() {
165         if (osVersionMajor == -1) init_version();
166         return osVersionMajor;
167     }
168 
169     // Returns minor version number from os.version system property.
170     // E.g. 0 on SLES 11.3 (for the linux kernel version).
171     public static int getOsVersionMinor() {
172         if (osVersionMinor == -1) init_version();
173         return osVersionMinor;
174     }
175 
176     public static boolean isDebugBuild() {
177         return (jdkDebug.toLowerCase().contains("debug"));
178     }
179 
180     public static boolean isSlowDebugBuild() {
181         return (jdkDebug.toLowerCase().equals("slowdebug"));
182     }
183 
184     public static boolean isFastDebugBuild() {
185         return (jdkDebug.toLowerCase().equals("fastdebug"));
186     }
187 
188     public static String getVMVersion() {
189         return vmVersion;
190     }
191 
192     public static boolean isAArch64() {
193         return isArch("aarch64");
194     }
195 
196     public static boolean isARM() {
197         return isArch("arm.*");
198     }
199 
200     public static boolean isRISCV64() {
201         return isArch("riscv64");
202     }
203 
204     public static boolean isPPC() {
205         return isArch("ppc.*");
206     }
207 
208     // Returns true for IBM z System running linux.
209     public static boolean isS390x() {
210         return isArch("s390.*") || isArch("s/390.*") || isArch("zArch_64");
211     }
212 
213     public static boolean isX64() {
214         // On OSX it's 'x86_64' and on other (Linux and Windows) platforms it's 'amd64'
215         return isArch("(amd64)|(x86_64)");
216     }
217 
218     public static boolean isX86() {
219         // On Linux it's 'i386', Windows 'x86' without '_64' suffix.
220         return isArch("(i386)|(x86(?!_64))");
221     }
222 
223     public static String getOsArch() {
224         return osArch;
225     }
226 
227     public static boolean isRoot() {
228         return userName.equals("root");
229     }
230 
231     /**
232      * Return a boolean for whether SA and jhsdb are ported/available
233      * on this platform.
234      */
235     public static boolean hasSA() {
236         if (isZero()) {
237             return false; // SA is not enabled.
238         }
239         if (isAix()) {
240             return false; // SA not implemented.
241         } else if (isLinux()) {
242             if (isS390x() || isARM()) {
243                 return false; // SA not implemented.
244             }
245         }
246         // Other platforms expected to work:
247         return true;
248     }
249 
250     /**
251      * Return true if the test JDK is hardened, otherwise false. Only valid on OSX.
252      */
253     public static boolean isHardenedOSX() throws IOException {
254         // We only care about hardened binaries for 10.14 and later (actually 10.14.5, but
255         // for simplicity we'll also include earlier 10.14 versions).
256         if (getOsVersionMajor() == 10 && getOsVersionMinor() < 14) {
257             return false; // assume not hardened
258         }
259 
260         // Find the path to the java binary.
261         String jdkPath = System.getProperty("java.home");
262         Path javaPath = Paths.get(jdkPath + "/bin/java");
263         String javaFileName = javaPath.toAbsolutePath().toString();
264         if (Files.notExists(javaPath)) {
265             throw new FileNotFoundException("Could not find file " + javaFileName);
266         }
267 
268         // Run codesign on the java binary.
269         ProcessBuilder pb = new ProcessBuilder("codesign", "--display", "--verbose", javaFileName);
270         pb.redirectErrorStream(true); // redirect stderr to stdout
271         Process codesignProcess = pb.start();
272         BufferedReader is = new BufferedReader(new InputStreamReader(codesignProcess.getInputStream()));
273         String line;
274         boolean isHardened = false;
275         boolean hardenedStatusConfirmed = false; // set true when we confirm whether or not hardened
276         while ((line = is.readLine()) != null) {
277             System.out.println("STDOUT: " + line);
278             if (line.indexOf("flags=0x10000(runtime)") != -1 ) {
279                 hardenedStatusConfirmed = true;
280                 isHardened = true;
281                 System.out.println("Target JDK is hardened. Some tests may be skipped.");
282             } else if (line.indexOf("flags=0x20002(adhoc,linker-signed)") != -1 ) {
283                 hardenedStatusConfirmed = true;
284                 isHardened = false;
285                 System.out.println("Target JDK is adhoc signed, but not hardened.");
286             } else if (line.indexOf("code object is not signed at all") != -1) {
287                 hardenedStatusConfirmed = true;
288                 isHardened = false;
289                 System.out.println("Target JDK is not signed, therefore not hardened.");
290             }
291         }
292         if (!hardenedStatusConfirmed) {
293             System.out.println("Could not confirm if TargetJDK is hardened. Assuming not hardened.");
294             isHardened = false;
295         }
296 
297         try {
298             if (codesignProcess.waitFor(10, TimeUnit.SECONDS) == false) {
299                 System.err.println("Timed out waiting for the codesign process to complete. Assuming not hardened.");
300                 codesignProcess.destroyForcibly();
301                 return false; // assume not hardened
302             }
303         } catch (InterruptedException e) {
304             throw new RuntimeException(e);
305         }
306 
307         return isHardened;
308     }
309 
310     private static boolean isArch(String archnameRE) {
311         return Pattern.compile(archnameRE, Pattern.CASE_INSENSITIVE)
312                       .matcher(osArch)
313                       .matches();
314     }
315 
316     /**
317      * Returns file extension of shared library, e.g. "so" on linux, "dll" on windows.
318      * @return file extension
319      */
320     public static String sharedLibraryExt() {
321         if (isWindows()) {
322             return "dll";
323         } else if (isOSX()) {
324             return "dylib";
325         } else {
326             return "so";
327         }
328     }
329 
330     /*
331      * Returns name of system variable containing paths to shared native libraries.
332      */
333     public static String sharedLibraryPathVariableName() {
334         if (isWindows()) {
335             return "PATH";
336         } else if (isOSX()) {
337             return "DYLD_LIBRARY_PATH";
338         } else if (isAix()) {
339             return "LIBPATH";
340         } else {
341             return "LD_LIBRARY_PATH";
342         }
343     }
344 
345     /**
346      * Returns absolute path to directory containing shared libraries in the tested JDK.
347      */
348     public static Path libDir() {
349         return libDir(Paths.get(testJdk)).toAbsolutePath();
350     }
351 
352     /**
353      * Resolves a given path, to a JDK image, to the directory containing shared libraries.
354      *
355      * @param image the path to a JDK image
356      * @return the resolved path to the directory containing shared libraries
357      */
358     public static Path libDir(Path image) {
359         if (Platform.isWindows()) {
360             return image.resolve("bin");
361         } else {
362             return image.resolve("lib");
363         }
364     }
365 
366     /**
367      * Returns absolute path to directory containing JVM shared library.
368      */
369     public static Path jvmLibDir() {
370         return libDir().resolve(variant());
371     }
372 
373     private static String variant() {
374         if (Platform.isServer()) {
375             return "server";
376         } else if (Platform.isClient()) {
377             return "client";
378         } else if (Platform.isMinimal()) {
379             return "minimal";
380         } else if (Platform.isZero()) {
381             return "zero";
382         } else {
383             throw new Error("TESTBUG: unsupported vm variant");
384         }
385     }
386 
387 
388     public static boolean isDefaultCDSArchiveSupported() {
389         return (is64bit()  &&
390                 isServer() &&
391                 (isLinux()   ||
392                  isOSX()     ||
393                  isWindows()) &&
394                 !isZero()    &&
395                 !isMinimal() &&
396                 !isARM());
397     }
398 
399     /*
400      * This should match the #if condition in ClassListParser::load_class_from_source().
401      */
402     public static boolean areCustomLoadersSupportedForCDS() {
403         return (is64bit() && (isLinux() || isOSX() || isWindows()));
404     }
405 }