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(); // 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();
  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                 usage();
  67             }
  68         }
  69 
  70         if (useSA) {
  71             runTool(args);
  72         } else {
  73             if (args.length == 3) {
  74                 String pid = args[2];
  75                 String option = args[1];
  76                 flag(pid, option);
  77             } else {
  78                 usage();
  79             }
  80         }
  81     }
  82 
  83     // Invoke SA tool  with the given arguments
  84     private static void runTool(String args[]) throws Exception {
  85         String tool = "sun.jvm.hotspot.tools.JInfo";
  86         // Tool not available on this  platform.
  87         Class<?> c = loadClass(tool);
  88         if (c == null) {
  89             usage();
  90         }
  91 
  92         // invoke the main method with the arguments
  93         Class[] argTypes = { String[].class } ;
  94         Method m = c.getDeclaredMethod("main", argTypes);
  95 
  96         Object[] invokeArgs = { args };
  97         m.invoke(null, invokeArgs);
  98     }
  99 
 100     // loads the given class using the system class loader
 101     private static Class<?> loadClass(String name) {
 102         //
 103         // We specify the system clas loader so as to cater for development
 104         // environments where this class is on the boot class path but sa-jdi.jar
 105         // is on the system class path. Once the JDK is deployed then both
 106         // tools.jar and sa-jdi.jar are on the system class path.
 107         //
 108         try {
 109             return Class.forName(name, true,
 110                                  ClassLoader.getSystemClassLoader());
 111         } catch (Exception x)  { }
 112         return null;
 113     }
 114 
 115     private static void flag(String pid, String option) throws IOException {
 116         VirtualMachine vm = attach(pid);
 117         String flag;
 118         InputStream in;
 119         int index = option.indexOf('=');
 120         if (index != -1) {
 121             flag = option.substring(0, index);
 122             String value = option.substring(index + 1);
 123             in = ((HotSpotVirtualMachine)vm).setFlag(flag, value);
 124         } else {
 125             char c = option.charAt(0);
 126             switch (c) {
 127                 case '+':
 128                     flag = option.substring(1);
 129                     in = ((HotSpotVirtualMachine)vm).setFlag(flag, "1");
 130                     break;
 131                 case '-':
 132                     flag = option.substring(1);
 133                     in = ((HotSpotVirtualMachine)vm).setFlag(flag, "0");
 134                     break;
 135                 default:
 136                     flag = option;
 137                     in = ((HotSpotVirtualMachine)vm).printFlag(flag);
 138                     break;
 139             }
 140         }
 141 
 142         drain(vm, in);
 143     }
 144 
 145     // Attach to <pid>, exiting if we fail to attach
 146     private static VirtualMachine attach(String pid) {
 147         try {
 148             return VirtualMachine.attach(pid);
 149         } catch (Exception x) {
 150             String msg = x.getMessage();
 151             if (msg != null) {
 152                 System.err.println(pid + ": " + msg);
 153             } else {
 154                 x.printStackTrace();
 155             }
 156             System.exit(1);
 157             return null; // keep compiler happy
 158         }
 159     }
 160 
 161     // Read the stream from the target VM until EOF, then detach
 162     private static void drain(VirtualMachine vm, InputStream in) throws IOException {
 163         // read to EOF and just print output
 164         byte b[] = new byte[256];
 165         int n;
 166         do {
 167             n = in.read(b);
 168             if (n > 0) {
 169                 String s = new String(b, 0, n, "UTF-8");
 170                 System.out.print(s);
 171             }
 172         } while (n > 0);
 173         in.close();
 174         vm.detach();
 175     }
 176 
 177 
 178     // print usage message
 179     private static void usage() {
 180 
 181         Class<?> c = loadClass("sun.jvm.hotspot.tools.JInfo");
 182         boolean usageSA = (c != null);
 183 
 184         System.out.println("Usage:");
 185         if (usageSA) {
 186             System.out.println("    jinfo [option] <pid>");
 187             System.out.println("        (to connect to running process)");
 188             System.out.println("    jinfo [option] <executable <core>");
 189             System.out.println("        (to connect to a core file)");
 190             System.out.println("    jinfo [option] [server_id@]<remote server IP or hostname>");
 191             System.out.println("        (to connect to remote debug server)");
 192             System.out.println("");
 193             System.out.println("where <option> is one of:");
 194             System.out.println("    -flag <name>         to print the value of the named VM flag");
 195             System.out.println("    -flag [+|-]<name>    to enable or disable the named VM flag");
 196             System.out.println("    -flag <name>=<value> to set the named VM flag to the given value");
 197             System.out.println("    -flags               to print VM flags");
 198             System.out.println("    -sysprops            to print Java system properties");
 199             System.out.println("    <no option>          to print both of the above");
 200             System.out.println("    -h | -help           to print this help message");
 201         } else {
 202             System.out.println("    jinfo <option> <pid>");
 203             System.out.println("       (to connect to a running process)");
 204             System.out.println("");
 205             System.out.println("where <option> is one of:");
 206             System.out.println("    -flag <name>         to print the value of the named VM flag");
 207             System.out.println("    -flag [+|-]<name>    to enable or disable the named VM flag");
 208             System.out.println("    -flag <name>=<value> to set the named VM flag to the given value");
 209             System.out.println("    -h | -help           to print this help message");
 210         }
 211 
 212         System.exit(1);
 213     }
 214 }