src/jdk.jcmd/linux/classes/sun/tools/ProcessHelper.java
changeset 54460 6733a9176cce
parent 53707 67537bbafd7f
child 55386 2f4e214781a1
equal deleted inserted replaced
54459:e5713cefcf41 54460:6733a9176cce
    29 import java.io.UncheckedIOException;
    29 import java.io.UncheckedIOException;
    30 import java.nio.file.Files;
    30 import java.nio.file.Files;
    31 import java.nio.file.Paths;
    31 import java.nio.file.Paths;
    32 import java.util.jar.Attributes;
    32 import java.util.jar.Attributes;
    33 import java.util.jar.JarFile;
    33 import java.util.jar.JarFile;
    34 import java.util.jar.Manifest;
       
    35 import java.util.stream.Stream;
    34 import java.util.stream.Stream;
    36 
    35 
    37 /**
    36 /**
    38  * A helper class that retrieves the main class name for
    37  * A helper class that retrieves the main class name for
    39  * a running Java process using the proc filesystem (procfs)
    38  * a running Java process using the proc filesystem (procfs)
    48         return INSTANCE;
    47         return INSTANCE;
    49     }
    48     }
    50 
    49 
    51     /**
    50     /**
    52      * Gets the main class name for the given Java process by parsing the
    51      * Gets the main class name for the given Java process by parsing the
    53      * process command line.
    52      * process command line. If the application was started with the <em>-jar</em>
       
    53      * option this method returns the name of the jar file. If the application
       
    54      * was started with <em>-m</em> or <em>--module</em> option, the method returns
       
    55      * the module name and the main class name.
    54      * @param pid - process ID (pid)
    56      * @param pid - process ID (pid)
    55      * @return main class name or null if the process no longer exists or
    57      * @return the main class name or null if the process no longer exists or
    56      * was started with a native launcher (e.g. jcmd etc)
    58      * was started with a native launcher (e.g. jcmd etc)
    57      */
    59      */
    58 
    60 
    59     public String getMainClass(String pid) {
    61     public String getMainClass(String pid) {
    60         String cmdLine = getCommandLine(pid);
    62         String cmdLine = getCommandLine(pid);
    79                 // Skip the process if it is not started with java launcher
    81                 // Skip the process if it is not started with java launcher
    80                 return null;
    82                 return null;
    81             }
    83             }
    82         }
    84         }
    83 
    85 
    84         // If -jar option is used then read the main class name from the manifest file.
    86         // To be consistent with the behavior on other platforms, if -jar, -m, or --module
    85         // Otherwise, the main class name is either specified in -m or --module options or it
    87         // options are used then just return the value (the path to the jar file or module
    86         // is the first part that is not a Java option (doesn't start with '-' and is not a
    88         // name with a main class). Otherwise, the main class name is the first part that
    87         // classpath or a module path).
    89         // is not a Java option (doesn't start with '-' and is not a classpath or a module
       
    90         // path).
    88 
    91 
    89         for (int i = 1; i < parts.length && mainClass == null; i++) {
    92         for (int i = 1; i < parts.length && mainClass == null; i++) {
    90             if (i < parts.length - 1) {
    93             if (i < parts.length - 1) {
    91                 // Check if the module is executed with explicitly specified main class
    94                 if (parts[i].equals("-m") || parts[i].equals("--module") || parts[i].equals("-jar")) {
    92                 if ((parts[i].equals("-m") || parts[i].equals("--module"))) {
    95                     return parts[i + 1];
    93                     return getMainClassFromModuleArg(parts[i + 1]);
       
    94                 }
       
    95                 // Check if the main class needs to be read from the manifest.mf in a JAR file
       
    96                 if (parts[i].equals("-jar")) {
       
    97                     return getMainClassFromJar(parts[i + 1], pid);
       
    98                 }
    96                 }
    99             }
    97             }
   100             // If this is a classpath or a module path option then skip the next part
    98             // If this is a classpath or a module path option then skip the next part
   101             // (the classpath or the module path itself)
    99             // (the classpath or the module path itself)
   102             if (parts[i].equals("-cp") || parts[i].equals("-classpath") ||  parts[i].equals("--class-path") ||
   100             if (parts[i].equals("-cp") || parts[i].equals("-classpath") ||  parts[i].equals("--class-path") ||
   112         }
   110         }
   113         return mainClass;
   111         return mainClass;
   114 
   112 
   115     }
   113     }
   116 
   114 
   117     private String getMainClassFromModuleArg(String moduleArg) {
       
   118         int pos = moduleArg.lastIndexOf("/");
       
   119         return (pos > 0 && pos < moduleArg.length()-1) ? moduleArg.substring(pos + 1) : null;
       
   120     }
       
   121 
       
   122     private String getMainClassFromJar(String jar, String pid) {
       
   123         if (!jar.startsWith("/")) {
       
   124             String cwd = getCurrentWorkingDir(pid);
       
   125             if (cwd != null) {
       
   126                 jar = cwd + "/" + jar;
       
   127             }
       
   128         }
       
   129         try (JarFile jarFile = new JarFile(jar)) {
       
   130             Manifest mf = jarFile.getManifest();
       
   131             if (mf != null) {
       
   132                 Attributes mainAttributes = mf.getMainAttributes();
       
   133                 return mainAttributes.getValue("Main-Class");
       
   134             }
       
   135         } catch (IOException e) {
       
   136             return null;
       
   137         }
       
   138         return null;
       
   139     }
       
   140 
       
   141     private static String getCurrentWorkingDir(String pid) {
       
   142         return ("/proc/" + pid + "/cwd");
       
   143     }
       
   144 
       
   145     private static String getCommandLine(String pid) {
   115     private static String getCommandLine(String pid) {
   146         try (Stream<String> lines =
   116         try (Stream<String> lines =
   147                      Files.lines(Paths.get("/proc/" + pid + "/cmdline"))) {
   117                      Files.lines(Paths.get("/proc/" + pid + "/cmdline"))) {
   148             return lines.map(x -> x.replaceAll("\0", " ")).findFirst().orElse(null);
   118             return lines.map(x -> x.replaceAll("\0", " ")).findFirst().orElse(null);
   149         } catch (IOException | UncheckedIOException e) {
   119         } catch (IOException | UncheckedIOException e) {