1 /*
   2  * Copyright (c) 2006, 2011, 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 package sun.tools.jinfo;
  27 
  28 import java.lang.reflect.Method;
  29 import java.io.File;
  30 import java.io.IOException;
  31 import java.io.InputStream;
  32 
  33 import com.sun.tools.attach.VirtualMachine;
  34 import sun.tools.attach.HotSpotVirtualMachine;
  35 
  36 /*
  37  * This class is the main class for the JInfo utility. It parses its arguments
  38  * and decides if the command should be satisfied using the VM attach mechanism
  39  * or an SA tool. At this time the only option that uses the VM attach
  40  * mechanism is the -flag option to set or print a command line option of a
  41  * running application. All other options are mapped to SA tools.
  42  */
  43 public class JInfo {
  44 
  45     public static void main(String[] args) throws Exception {
  46         if (args.length == 0) {
  47             usage(1); // no arguments
  48         }
  49 
  50         boolean useSA = true;
  51         String arg1 = args[0];
  52         if (arg1.startsWith("-")) {
  53             if (arg1.equals("-flags") ||
  54                 arg1.equals("-sysprops")) {
  55                 // SA JInfo needs <pid> or <server> or
  56                 // (<executable> and <code file>). So, total
  57                 // argument count including option has to 2 or 3.
  58                 if (args.length != 2 && args.length != 3) {
  59                     usage(1);
  60                 }
  61             } else if (arg1.equals("-flag")) {
  62                 // do not use SA, use attach-on-demand
  63                 useSA = false;
  64             } else {
  65                 // unknown option or -h or -help, print help
  66                 int exit;
  67                 if (arg1.equals("-help") || arg1.equals("-h")) {
  68                     exit = 0;
  69                 } else {
  70                     exit = 1;
  71                 }
  72                 usage(exit);
  73             }
  74         }
  75 
  76         if (useSA) {
  77             runTool(args);
  78         } else {
  79             if (args.length == 3) {
  80                 String pid = args[2];
  81                 String option = args[1];
  82                 flag(pid, option);
  83             } else {
  84                 int exit = arg1.equals("-help") || arg1.equals("-h") ? 0 : 1;
  85                 usage(exit);
  86             }
  87         }
  88     }
  89 
  90     // Invoke SA tool  with the given arguments
  91     private static void runTool(String args[]) throws Exception {
  92         String tool = "sun.jvm.hotspot.tools.JInfo";
  93         // Tool not available on this  platform.
  94         Class<?> c = loadClass(tool);
  95         if (c == null) {
  96             usage(1);
  97         }
  98 
  99         // invoke the main method with the arguments
 100         Class[] argTypes = { String[].class } ;
 101         Method m = c.getDeclaredMethod("main", argTypes);
 102 
 103         Object[] invokeArgs = { args };
 104         m.invoke(null, invokeArgs);
 105     }
 106 
 107     // loads the given class using the system class loader
 108     private static Class<?> loadClass(String name) {
 109         //
 110         // We specify the system clas loader so as to cater for development
 111         // environments where this class is on the boot class path but sa-jdi.jar
 112         // is on the system class path. Once the JDK is deployed then both
 113         // tools.jar and sa-jdi.jar are on the system class path.
 114         //
 115         try {
 116             return Class.forName(name, true,
 117                                  ClassLoader.getSystemClassLoader());
 118         } catch (Exception x)  { }
 119         return null;
 120     }
 121 
 122     private static void flag(String pid, String option) throws IOException {
 123         VirtualMachine vm = attach(pid);
 124         String flag;
 125         InputStream in;
 126         int index = option.indexOf('=');
 127         if (index != -1) {
 128             flag = option.substring(0, index);
 129             String value = option.substring(index + 1);
 130             in = ((HotSpotVirtualMachine)vm).setFlag(flag, value);
 131         } else {
 132             char c = option.charAt(0);
 133             switch (c) {
 134                 case '+':
 135                     flag = option.substring(1);
 136                     in = ((HotSpotVirtualMachine)vm).setFlag(flag, "1");
 137                     break;
 138                 case '-':
 139                     flag = option.substring(1);
 140                     in = ((HotSpotVirtualMachine)vm).setFlag(flag, "0");
 141                     break;
 142                 default:
 143                     flag = option;
 144                     in = ((HotSpotVirtualMachine)vm).printFlag(flag);
 145                     break;
 146             }
 147         }
 148 
 149         drain(vm, in);
 150     }
 151 
 152     // Attach to <pid>, exiting if we fail to attach
 153     private static VirtualMachine attach(String pid) {
 154         try {
 155             return VirtualMachine.attach(pid);
 156         } catch (Exception x) {
 157             String msg = x.getMessage();
 158             if (msg != null) {
 159                 System.err.println(pid + ": " + msg);
 160             } else {
 161                 x.printStackTrace();
 162             }
 163             System.exit(1);
 164             return null; // keep compiler happy
 165         }
 166     }
 167 
 168     // Read the stream from the target VM until EOF, then detach
 169     private static void drain(VirtualMachine vm, InputStream in) throws IOException {
 170         // read to EOF and just print output
 171         byte b[] = new byte[256];
 172         int n;
 173         do {
 174             n = in.read(b);
 175             if (n > 0) {
 176                 String s = new String(b, 0, n, "UTF-8");
 177                 System.out.print(s);
 178             }
 179         } while (n > 0);
 180         in.close();
 181         vm.detach();
 182     }
 183 
 184 
 185     // print usage message
 186     private static void usage(int exit) {
 187 
 188         Class<?> c = loadClass("sun.jvm.hotspot.tools.JInfo");
 189         boolean usageSA = (c != null);
 190 
 191         System.err.println("Usage:");
 192         if (usageSA) {
 193             System.err.println("    jinfo [option] <pid>");
 194             System.err.println("        (to connect to running process)");
 195             System.err.println("    jinfo [option] <executable <core>");
 196             System.err.println("        (to connect to a core file)");
 197             System.err.println("    jinfo [option] [server_id@]<remote server IP or hostname>");
 198             System.err.println("        (to connect to remote debug server)");
 199             System.err.println("");
 200             System.err.println("where <option> is one of:");
 201             System.err.println("    -flag <name>         to print the value of the named VM flag");
 202             System.err.println("    -flag [+|-]<name>    to enable or disable the named VM flag");
 203             System.err.println("    -flag <name>=<value> to set the named VM flag to the given value");
 204             System.err.println("    -flags               to print VM flags");
 205             System.err.println("    -sysprops            to print Java system properties");
 206             System.err.println("    <no option>          to print both of the above");
 207             System.err.println("    -h | -help           to print this help message");
 208         } else {
 209             System.err.println("    jinfo <option> <pid>");
 210             System.err.println("       (to connect to a running process)");
 211             System.err.println("");
 212             System.err.println("where <option> is one of:");
 213             System.err.println("    -flag <name>         to print the value of the named VM flag");
 214             System.err.println("    -flag [+|-]<name>    to enable or disable the named VM flag");
 215             System.err.println("    -flag <name>=<value> to set the named VM flag to the given value");
 216             System.err.println("    -h | -help           to print this help message");
 217         }
 218 
 219         System.exit(exit);
 220     }
 221 }