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 isPPC() {
201         return isArch("ppc.*");
202     }
203 
204     // Returns true for IBM z System running linux.
205     public static boolean isS390x() {
206         return isArch("s390.*") || isArch("s/390.*") || isArch("zArch_64");
207     }
208 
209     public static boolean isX64() {
210         // On OSX it's 'x86_64' and on other (Linux and Windows) platforms it's 'amd64'
211         return isArch("(amd64)|(x86_64)");
212     }
213 
214     public static boolean isX86() {
215         // On Linux it's 'i386', Windows 'x86' without '_64' suffix.
216         return isArch("(i386)|(x86(?!_64))");
217     }
218 
219     public static String getOsArch() {
220         return osArch;
221     }
222 
223     public static boolean isRoot() {
224         return userName.equals("root");
225     }
226 
227     /**
228      * Return a boolean for whether SA and jhsdb are ported/available
229      * on this platform.
230      */
231     public static boolean hasSA() {
232         if (isZero()) {
233             return false; // SA is not enabled.
234         }
235         if (isAix()) {
236             return false; // SA not implemented.
237         } else if (isLinux()) {
238             if (isS390x() || isARM()) {
239                 return false; // SA not implemented.
240             }
241         }
242         // Other platforms expected to work:
243         return true;
244     }
245 
246     /**
247      * Return true if the test JDK is hardened, otherwise false. Only valid on OSX.
248      */
249     public static boolean isHardenedOSX() throws IOException {
250         // We only care about hardened binaries for 10.14 and later (actually 10.14.5, but
251         // for simplicity we'll also include earlier 10.14 versions).
252         if (getOsVersionMajor() == 10 && getOsVersionMinor() < 14) {
253             return false; // assume not hardened
254         }
255 
256         // Find the path to the java binary.
257         String jdkPath = System.getProperty("java.home");
258         Path javaPath = Paths.get(jdkPath + "/bin/java");
259         String javaFileName = javaPath.toAbsolutePath().toString();
260         if (Files.notExists(javaPath)) {
261             throw new FileNotFoundException("Could not find file " + javaFileName);
262         }
263 
264         // Run codesign on the java binary.
265         ProcessBuilder pb = new ProcessBuilder("codesign", "--display", "--verbose", javaFileName);
266         pb.redirectErrorStream(true); // redirect stderr to stdout
267         Process codesignProcess = pb.start();
268         BufferedReader is = new BufferedReader(new InputStreamReader(codesignProcess.getInputStream()));
269         String line;
270         boolean isHardened = false;
271         boolean hardenedStatusConfirmed = false; // set true when we confirm whether or not hardened
272         while ((line = is.readLine()) != null) {
273             System.out.println("STDOUT: " + line);
274             if (line.indexOf("flags=0x10000(runtime)") != -1 ) {
275                 hardenedStatusConfirmed = true;
276                 isHardened = true;
277                 System.out.println("Target JDK is hardened. Some tests may be skipped.");
278             } else if (line.indexOf("flags=0x20002(adhoc,linker-signed)") != -1 ) {
279                 hardenedStatusConfirmed = true;
280                 isHardened = false;
281                 System.out.println("Target JDK is adhoc signed, but not hardened.");
282             } else if (line.indexOf("code object is not signed at all") != -1) {
283                 hardenedStatusConfirmed = true;
284                 isHardened = false;
285                 System.out.println("Target JDK is not signed, therefore not hardened.");
286             }
287         }
288         if (!hardenedStatusConfirmed) {
289             System.out.println("Could not confirm if TargetJDK is hardened. Assuming not hardened.");
290             isHardened = false;
291         }
292 
293         try {
294             if (codesignProcess.waitFor(10, TimeUnit.SECONDS) == false) {
295                 System.err.println("Timed out waiting for the codesign process to complete. Assuming not hardened.");
296                 codesignProcess.destroyForcibly();
297                 return false; // assume not hardened
298             }
299         } catch (InterruptedException e) {
300             throw new RuntimeException(e);
301         }
302 
303         return isHardened;
304     }
305 
306     private static boolean isArch(String archnameRE) {
307         return Pattern.compile(archnameRE, Pattern.CASE_INSENSITIVE)
308                       .matcher(osArch)
309                       .matches();
310     }
311 
312     /**
313      * Returns file extension of shared library, e.g. "so" on linux, "dll" on windows.
314      * @return file extension
315      */
316     public static String sharedLibraryExt() {
317         if (isWindows()) {
318             return "dll";
319         } else if (isOSX()) {
320             return "dylib";
321         } else {
322             return "so";
323         }
324     }
325 
326     /*
327      * Returns name of system variable containing paths to shared native libraries.
328      */
329     public static String sharedLibraryPathVariableName() {
330         if (isWindows()) {
331             return "PATH";
332         } else if (isOSX()) {
333             return "DYLD_LIBRARY_PATH";
334         } else if (isAix()) {
335             return "LIBPATH";
336         } else {
337             return "LD_LIBRARY_PATH";
338         }
339     }
340 
341     /**
342      * Returns absolute path to directory containing shared libraries in the tested JDK.
343      */
344     public static Path libDir() {
345         return libDir(Paths.get(testJdk)).toAbsolutePath();
346     }
347 
348     /**
349      * Resolves a given path, to a JDK image, to the directory containing shared libraries.
350      *
351      * @param image the path to a JDK image
352      * @return the resolved path to the directory containing shared libraries
353      */
354     public static Path libDir(Path image) {
355         if (Platform.isWindows()) {
356             return image.resolve("bin");
357         } else {
358             return image.resolve("lib");
359         }
360     }
361 
362     /**
363      * Returns absolute path to directory containing JVM shared library.
364      */
365     public static Path jvmLibDir() {
366         return libDir().resolve(variant());
367     }
368 
369     private static String variant() {
370         if (Platform.isServer()) {
371             return "server";
372         } else if (Platform.isClient()) {
373             return "client";
374         } else if (Platform.isMinimal()) {
375             return "minimal";
376         } else if (Platform.isZero()) {
377             return "zero";
378         } else {
379             throw new Error("TESTBUG: unsupported vm variant");
380         }
381     }
382 
383 
384     public static boolean isDefaultCDSArchiveSupported() {
385         return (is64bit()  &&
386                 isServer() &&
387                 (isLinux()   ||
388                  isOSX()     ||
389                  isWindows()) &&
390                 !isZero()    &&
391                 !isMinimal() &&
392                 !isARM());
393     }
394 
395     /*
396      * This should match the #if condition in ClassListParser::load_class_from_source().
397      */
398     public static boolean areCustomLoadersSupportedForCDS() {
399         return (is64bit() && (isLinux() || isOSX() || isWindows()));
400     }
401 }