1 /*
   2  * Copyright (c) 2005, 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 package sun.tools.attach;
  26 
  27 import com.sun.tools.attach.VirtualMachine;
  28 import com.sun.tools.attach.VirtualMachineDescriptor;
  29 import com.sun.tools.attach.AttachNotSupportedException;
  30 
  31 import java.util.ArrayList;
  32 import java.util.List;
  33 import java.io.IOException;
  34 import java.net.InetAddress;
  35 import java.net.UnknownHostException;
  36 
  37 public class AttachProviderImpl extends HotSpotAttachProvider {
  38 
  39     public AttachProviderImpl() {
  40         String os = System.getProperty("os.name");
  41         if (os.startsWith("Windows 9") || os.equals("Windows Me")) {
  42             throw new RuntimeException(
  43                 "This provider is not supported on this version of Windows");
  44         }
  45         String arch = System.getProperty("os.arch");
  46         if (!arch.equals("x86") && !arch.equals("amd64") && !arch.equals("aarch64")) {
  47             throw new RuntimeException(
  48                 "This provider is not supported on this processor architecture");
  49         }
  50     }
  51 
  52     public String name() {
  53         return "sun";
  54     }
  55 
  56     public String type() {
  57         return "windows";
  58     }
  59 
  60     public VirtualMachine attachVirtualMachine(String vmid)
  61         throws AttachNotSupportedException, IOException
  62     {
  63         checkAttachPermission();
  64 
  65         // AttachNotSupportedException will be thrown if the target VM can be determined
  66         // to be not attachable.
  67         testAttachable(vmid);
  68 
  69         return new VirtualMachineImpl(this, vmid);
  70     }
  71 
  72     public List<VirtualMachineDescriptor> listVirtualMachines() {
  73         // If the temporary file system is secure then we use the default
  74         // implementation, otherwise we create a list of Windows processes.
  75         if (isTempPathSecure()) {
  76             return super.listVirtualMachines();
  77         } else {
  78             return listJavaProcesses();
  79         }
  80     }
  81 
  82     /**
  83      * Returns true if the temporary file system supports security
  84      */
  85     private static boolean isTempPathSecure() {
  86         if (!wasTempPathChecked) {
  87             synchronized (AttachProviderImpl.class) {
  88                 if (!wasTempPathChecked) {
  89                     // get the value of TMP/TEMP, ignoring UNC, and paths that
  90                     // aren't absolute
  91                     String temp = tempPath();
  92                     if ((temp != null) && (temp.length() >= 3) &&
  93                         (temp.charAt(1) == ':') && (temp.charAt(2) == '\\'))
  94                     {
  95                         // check if the volume supports security
  96                         long flags = volumeFlags(temp.substring(0, 3));
  97                         isTempPathSecure = ((flags & FS_PERSISTENT_ACLS) != 0);
  98                     }
  99                     wasTempPathChecked = true;
 100                 }
 101             }
 102         }
 103 
 104         return isTempPathSecure;
 105     }
 106 
 107     // flag to indicate persistent ACLs are supported
 108     private static final long FS_PERSISTENT_ACLS = 0x8L;
 109 
 110     // indicates if we've checked the temporary file system
 111     private static volatile boolean wasTempPathChecked;
 112 
 113     // indicates if the temporary file system is secure (only valid when
 114     // wasTempPathChecked is true)
 115     private static boolean isTempPathSecure;
 116 
 117     // returns the value of TMP/TEMP
 118     private static native String tempPath();
 119 
 120     // returns the flags for the given volume
 121     private static native long volumeFlags(String volume);
 122 
 123 
 124     /**
 125      * Returns a list of virtual machine descriptors derived from an enumeration
 126      * of the process list.
 127      */
 128     private List<VirtualMachineDescriptor> listJavaProcesses() {
 129         ArrayList<VirtualMachineDescriptor> list =
 130             new ArrayList<VirtualMachineDescriptor>();
 131 
 132         // Use localhost in the display name
 133         String host = "localhost";
 134         try {
 135             host = InetAddress.getLocalHost().getHostName();
 136         } catch (UnknownHostException uhe) {
 137             // ignore
 138         }
 139 
 140         // Enumerate all processes.
 141         // For those processes that have loaded a library named "jvm.dll"
 142         // then we attempt to attach. If we succeed then we have a 6.0+ VM.
 143         int processes[] = new int[1024];
 144         int count = enumProcesses(processes, processes.length);
 145         for (int i=0; i<count; i++) {
 146             if (isLibraryLoadedByProcess("jvm.dll", processes[i])) {
 147                 String pid = Integer.toString(processes[i]);
 148                 try {
 149                     new VirtualMachineImpl(this, pid).detach();
 150 
 151                     // FIXME - for now we don't have an appropriate display
 152                     // name so we use pid@hostname
 153                     String name = pid + "@" + host;
 154 
 155                     list.add(new HotSpotVirtualMachineDescriptor(this, pid, name));
 156                 } catch (AttachNotSupportedException x) {
 157                 } catch (IOException ioe) {
 158                 }
 159             }
 160         }
 161 
 162         return list;
 163     }
 164 
 165     // enumerates processes using psapi's EnumProcesses
 166     private static native int enumProcesses(int[] processes, int max);
 167 
 168     // indicates if a library of a given name has been loaded by a process
 169     private static native boolean isLibraryLoadedByProcess(String library,
 170                                                            int processId);
 171 
 172 
 173     // native functions in this library
 174     static {
 175         System.loadLibrary("attach");
 176     }
 177 
 178 }