< prev index next >

src/jdk.jcmd/linux/classes/sun/tools/ProcessHelper.java

Print this page

        

@@ -29,10 +29,11 @@
 import java.io.UncheckedIOException;
 import java.nio.file.Files;
 import java.nio.file.Paths;
 import java.util.jar.Attributes;
 import java.util.jar.JarFile;
+import java.util.jar.Manifest;
 import java.util.stream.Stream;
 
 /**
  * A helper class that retrieves the main class name for
  * a running Java process using the proc filesystem (procfs)

@@ -47,16 +48,13 @@
         return INSTANCE;
     }
 
     /**
      * Gets the main class name for the given Java process by parsing the
-     * process command line. If the application was started with the <em>-jar</em>
-     * option this method returns the name of the jar file. If the application
-     * was started with <em>-m</em> or <em>--module</em> option, the method returns
-     * the module name and the main class name.
+     * process command line.
      * @param pid - process ID (pid)
-     * @return the main class name or null if the process no longer exists or
+     * @return main class name or null if the process no longer exists or
      * was started with a native launcher (e.g. jcmd etc)
      */
 
     public String getMainClass(String pid) {
         String cmdLine = getCommandLine(pid);

@@ -81,20 +79,24 @@
                 // Skip the process if it is not started with java launcher
                 return null;
             }
         }
 
-        // To be consistent with the behavior on other platforms, if -jar, -m, or --module
-        // options are used then just return the value (the path to the jar file or module
-        // name with a main class). Otherwise, the main class name is the first part that
-        // is not a Java option (doesn't start with '-' and is not a classpath or a module
-        // path).
+        // If -jar option is used then read the main class name from the manifest file.
+        // Otherwise, the main class name is either specified in -m or --module options or it
+        // is the first part that is not a Java option (doesn't start with '-' and is not a
+        // classpath or a module path).
 
         for (int i = 1; i < parts.length && mainClass == null; i++) {
             if (i < parts.length - 1) {
-                if (parts[i].equals("-m") || parts[i].equals("--module") || parts[i].equals("-jar")) {
-                    return parts[i + 1];
+                // Check if the module is executed with explicitly specified main class
+                if ((parts[i].equals("-m") || parts[i].equals("--module"))) {
+                    return getMainClassFromModuleArg(parts[i + 1]);
+                }
+                // Check if the main class needs to be read from the manifest.mf in a JAR file
+                if (parts[i].equals("-jar")) {
+                    return getMainClassFromJar(parts[i + 1], pid);
                 }
             }
             // If this is a classpath or a module path option then skip the next part
             // (the classpath or the module path itself)
             if (parts[i].equals("-cp") || parts[i].equals("-classpath") ||  parts[i].equals("--class-path") ||

@@ -110,10 +112,38 @@
         }
         return mainClass;
 
     }
 
+    private String getMainClassFromModuleArg(String moduleArg) {
+        int pos = moduleArg.lastIndexOf("/");
+        return (pos > 0 && pos < moduleArg.length()-1) ? moduleArg.substring(pos + 1) : null;
+    }
+
+    private String getMainClassFromJar(String jar, String pid) {
+        if (!jar.startsWith("/")) {
+            String cwd = getCurrentWorkingDir(pid);
+            if (cwd != null) {
+                jar = cwd + "/" + jar;
+            }
+        }
+        try (JarFile jarFile = new JarFile(jar)) {
+            Manifest mf = jarFile.getManifest();
+            if (mf != null) {
+                Attributes mainAttributes = mf.getMainAttributes();
+                return mainAttributes.getValue("Main-Class");
+            }
+        } catch (IOException e) {
+            return null;
+        }
+        return null;
+    }
+
+    private static String getCurrentWorkingDir(String pid) {
+        return ("/proc/" + pid + "/cwd");
+    }
+
     private static String getCommandLine(String pid) {
         try (Stream<String> lines =
                      Files.lines(Paths.get("/proc/" + pid + "/cmdline"))) {
             return lines.map(x -> x.replaceAll("\0", " ")).findFirst().orElse(null);
         } catch (IOException | UncheckedIOException e) {
< prev index next >