class Hypervisor(object):
def __init__(self):
- self.__info = _fireinfo.get_hypervisor()
+ self.__hypervisor = _fireinfo.detect_hypervisor()
@property
def system(self):
"""
Returns the name of the hypervisor vendor.
"""
- if not self.virtual:
- return None
+ # Citrix Xen says it is Microsoft Hv.
+ if self.__hypervisor == "Microsoft" and self.system.bios_vendor == "Xen":
+ return "Xen"
# Some of the hypervisors can be detected in a right way.
# We can return them at this place.
- if self.__info["hypervisor"] in ("Xen", "VMWare", "KVM"):
- return self.__info["hypervisor"]
-
- # Citrix Xen says it is Microsoft Hv.
- if self.__info["hypervisor"] == "Microsoft" and \
- self.system.bios_vendor == "Xen":
+ if self.__hypervisor:
+ return self.__hypervisor
+
+ # Check DMI and BIOS information...
+ if self.__bios_is_bochs():
+ return "Bochs"
+ elif self.__bios_is_microsoft():
+ return "Microsoft"
+ elif self.__bios_is_qemu():
+ return "Qemu"
+ elif self.__bios_is_virtualbox():
+ return "VirtualBox"
+ elif self.__bios_is_vmware():
+ return "VMWare"
+ elif self.__bios_is_xen():
return "Xen"
- if not self.__info["hypervisor"]:
- # On VMWare systems, the bios vendor string contains "VMWare".
- if self.__is_hypervisor_vmware():
- return "VMWare"
-
- # VirtualBox got "innotek GmbH" as bios vendor.
- elif self.__is_hypervisor_virtualbox():
- return "VirtualBox"
-
- # Check for qemu.
- elif self.__is_hypervisor_qemu():
- return "Qemu"
-
- # Check for Microsoft.
- elif self.__is_hypervisor_microsoft():
- return "Microsoft"
-
- return "unknown"
-
- @property
- def type(self):
- """
- Returns if the host is running in full virt mode or
- if it is running in a paravirtualized environment.
- """
- if not self.virtual:
- return None
-
- if self.__info["virtype"]:
- return self.__info["virtype"]
-
- if self.vendor in ("Qemu", "KVM", "VirtualBox", "VMWare"):
- return "full"
-
- return "unknown"
-
@property
def virtual(self):
"""
Returns true if the host is running in a virtual environment.
Otherwise: false.
"""
- return _fireinfo.is_virtualized() or \
- "hypervisor" in self.system.cpu.flags or \
- self.__is_hypervisor_virtualbox() or \
- self.__is_hypervisor_vmware() or \
- self.__is_hypervisor_qemu() or \
- self.__is_hypervisor_microsoft()
-
- def __is_hypervisor_virtualbox(self):
+ if self.vendor:
+ return True
+
+ return False
+
+ def __bios_is_bochs(self):
"""
- Check for virtualbox hypervisor by comparing the bios vendor string
- to "innotek GmbH".
+ Check for Bochs emulator.
"""
- return self.system.bios_vendor == "innotek GmbH"
+ return self.system.bios.check_vendor("Bochs")
- def __is_hypervisor_vmware(self):
+ def __bios_is_microsoft(self):
"""
- Check for the VMWare hypervisor by the VMWare Hypervisor port check.
-
- http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458
+ Check for Microsoft hypervisor.
"""
- if self.system.vendor:
- return self.system.vendor.startswith("VMware")
-
- # XXX We should use _fireinfo.vmware_hypervisor_port_check() here, too.
- # This currently segfaults (and I have no clue why) on VMware player.
+ return self.system.bios.check_vendor("Microsoft Corporation")
- def __is_hypervisor_qemu(self):
+ def __bios_is_qemu(self):
"""
- Check for old qemu emulator.
+ Check for qemu emulator.
"""
- if self.system.bios_vendor:
- return self.system.bios_vendor == "Bochs"
+ return self.system.bios.check_vendor("QEMU")
- return False
-
- def __is_hypervisor_microsoft(self):
+ def __bios_is_virtualbox(self):
"""
- Check for Microsoft hypervisor.
+ Check for virtualbox hypervisor by comparing the bios vendor string
+ to "innotek GmbH".
"""
- if self.system.vendor:
- return "Microsoft" in self.system.vendor
+ return self.system.bios.check_vendor("innotek GmbH")
+
+ def __bios_is_vmware(self):
+ if self.system.bios.check_vendor("VMware-"):
+ return True
+ elif self.system.bios.check_vendor("VMW"):
+ return True
return False
+ def __bios_is_xen(self):
+ return self.system.bios.check_vendor("Xen")
+
if __name__ == "__main__":
h = Hypervisor()
print "Vendor:", h.vendor
- print "Type:", h.type
print "Virtual:", h.virtual
#include <Python.h>
+#include <errno.h>
#include <fcntl.h>
#include <linux/hdreg.h>
#include <stdbool.h>
+#include <string.h>
#include <sys/ioctl.h>
-/*
- Big parts of this were taken from
- http://git.kernel.org/?p=utils/util-linux-ng/util-linux-ng.git;a=blob;f=sys-utils/lscpu.c
-*/
-
-/* /sys paths */
-#define _PATH_PROC_XEN "/proc/xen"
-#define _PATH_PROC_XENCAP _PATH_PROC_XEN "/capabilities"
-#define _PATH_PROC_PCIDEVS "/proc/bus/pci/devices"
-
-/* Used for the vmware hypervisor port detection */
-#define VMWARE_HYPERVISOR_MAGIC 0x564D5868
-#define VMWARE_HYPERVISOR_PORT 0x5658
-
-#define VMWARE_PORT_CMD_GETVERSION 10
-
-/* virtualization types */
-enum {
- VIRT_NONE = 0,
- VIRT_PARA,
- VIRT_FULL
-};
-const char *virt_types[] = {
- [VIRT_NONE] = "none",
- [VIRT_PARA] = "para",
- [VIRT_FULL] = "full"
-};
-
/* hypervisor vendors */
-enum {
- HYPER_NONE = 0,
+enum hypervisors {
+ HYPER_NONE = 0,
HYPER_XEN,
HYPER_KVM,
HYPER_MSHV,
- HYPER_VMWARE
-};
-const char *hv_vendors[] = {
- [HYPER_NONE] = NULL,
- [HYPER_XEN] = "Xen",
- [HYPER_KVM] = "KVM",
- [HYPER_MSHV] = "Microsoft",
- [HYPER_VMWARE] = "VMWare"
+ HYPER_VMWARE,
+ HYPER_OTHER,
+ HYPER_LAST /* for loop - must be last*/
};
-struct hypervisor_desc {
- int hyper; /* hypervisor vendor ID */
- int virtype; /* VIRT_PARA|FULL|NONE ? */
+const char *hypervisor_ids[] = {
+ [HYPER_NONE] = NULL,
+ [HYPER_XEN] = "XenVMMXenVMM",
+ [HYPER_KVM] = "KVMKVMKVM",
+ /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */
+ [HYPER_MSHV] = "Microsoft Hv",
+ /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
+ [HYPER_VMWARE] = "VMwareVMware",
+ [HYPER_OTHER] = NULL
};
-static size_t sysrootlen;
-static char pathbuf[PATH_MAX];
-
-static FILE *path_fopen(const char *mode, const char *path, ...)
- __attribute__ ((__format__ (__printf__, 2, 3)));
-static int path_exist(const char *path, ...)
- __attribute__ ((__format__ (__printf__, 1, 2)));
-
-static const char *
-path_vcreate(const char *path, va_list ap)
-{
- if (sysrootlen)
- vsnprintf(pathbuf + sysrootlen,
- sizeof(pathbuf) - sysrootlen, path, ap);
- else
- vsnprintf(pathbuf, sizeof(pathbuf), path, ap);
- return pathbuf;
-}
-
-static FILE *
-path_vfopen(const char *mode, const char *path, va_list ap)
-{
- const char *p = path_vcreate(path, ap);
-
- return fopen(p, mode);
-}
-
-static FILE *
-path_fopen(const char *mode, const char *path, ...)
-{
- FILE *fd;
- va_list ap;
-
- va_start(ap, path);
- fd = path_vfopen(mode, path, ap);
- va_end(ap);
-
- return fd;
-}
+const char *hypervisor_vendors[] = {
+ [HYPER_NONE] = NULL,
+ [HYPER_XEN] = "Xen",
+ [HYPER_KVM] = "KVM",
+ [HYPER_MSHV] = "Microsoft",
+ [HYPER_VMWARE] = "VMWare",
+ [HYPER_OTHER] = "other"
+};
-static int
-path_exist(const char *path, ...)
-{
- va_list ap;
- const char *p;
+#define NEWLINE "\n\r"
- va_start(ap, path);
- p = path_vcreate(path, ap);
- va_end(ap);
+char *truncate_nl(char *s) {
+ assert(s);
- return access(p, F_OK) == 0;
+ s[strcspn(s, NEWLINE)] = 0;
+ return s;
}
-static int
-has_pci_device(int vendor, int device)
-{
- FILE *f;
- int num, fn, ven, dev;
- int res = 1;
+int read_one_line_file(const char *filename, char **line) {
+ assert(filename);
+ assert(line);
- f = path_fopen("r", _PATH_PROC_PCIDEVS);
+ FILE *f = NULL;
+ f = fopen(filename, "re");
if (!f)
- return 0;
+ return -errno;
- /* for more details about bus/pci/devices format see
- * drivers/pci/proc.c in linux kernel
- */
- while(fscanf(f, "%02x%02x\t%04x%04x\t%*[^\n]",
- &num, &fn, &ven, &dev) == 4) {
+ char t[2048];
+ if (!fgets(t, sizeof(t), f)) {
+ if (ferror(f))
+ return errno ? -errno : -EIO;
- if (ven == vendor && dev == device)
- goto found;
+ t[0] = 0;
}
- res = 0;
-found:
- fclose(f);
- return res;
-}
+ char *c = strdup(t);
+ if (!c)
+ return -ENOMEM;
+ truncate_nl(c);
-#if defined(__x86_64__) || defined(__i386__)
+ *line = c;
+ return 0;
+}
/*
* This CPUID leaf returns the information about the hypervisor.
*/
#define HYPERVISOR_INFO_LEAF 0x40000000
-static inline void
-cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx,
- unsigned int *ecx, unsigned int *edx)
-{
- __asm__(
-#if defined(__PIC__) && defined(__i386__)
- /* x86 PIC cannot clobber ebx -- gcc bitches */
- "pushl %%ebx;"
- "cpuid;"
- "movl %%ebx, %%esi;"
- "popl %%ebx;"
- : "=S" (*ebx),
-#else
- "cpuid;"
- : "=b" (*ebx),
-#endif
- "=a" (*eax),
- "=c" (*ecx),
- "=d" (*edx)
- : "1" (op), "c"(0));
-}
-
-static void
-read_hypervisor_cpuid(struct hypervisor_desc *desc)
-{
- unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0;
- char hyper_vendor_id[13];
-
- memset(hyper_vendor_id, 0, sizeof(hyper_vendor_id));
-
- cpuid(HYPERVISOR_INFO_LEAF, &eax, &ebx, &ecx, &edx);
- memcpy(hyper_vendor_id + 0, &ebx, 4);
- memcpy(hyper_vendor_id + 4, &ecx, 4);
- memcpy(hyper_vendor_id + 8, &edx, 4);
- hyper_vendor_id[12] = '\0';
-
- if (!hyper_vendor_id[0])
- return;
+int detect_hypervisor(int *hypervisor) {
+#if defined(__x86_64__) || defined(__i386__)
+ /* Try high-level hypervisor sysfs file first: */
+ char *hvtype = NULL;
+ int r = read_one_line_file("/sys/hypervisor/type", &hvtype);
+ if (r >= 0) {
+ if (strcmp(hvtype, "xen") == 0) {
+ *hypervisor = HYPER_XEN;
+ return 1;
+ }
+ } else if (r != -ENOENT)
+ return r;
- if (!strncmp("XenVMMXenVMM", hyper_vendor_id, 12))
- desc->hyper = HYPER_XEN;
- else if (!strncmp("KVMKVMKVM", hyper_vendor_id, 9))
- desc->hyper = HYPER_KVM;
- else if (!strncmp("Microsoft Hv", hyper_vendor_id, 12))
- desc->hyper = HYPER_MSHV;
- else if (!strncmp("VMwareVMware", hyper_vendor_id, 12))
- desc->hyper = HYPER_VMWARE;
-}
+ /* http://lwn.net/Articles/301888/ */
-#else /* ! __x86_64__ */
-static void
-read_hypervisor_cpuid(struct hypervisor_desc *desc)
-{
-}
+#if defined(__amd64__)
+#define REG_a "rax"
+#define REG_b "rbx"
+#elif defined(__i386__)
+#define REG_a "eax"
+#define REG_b "ebx"
#endif
-static void
-read_hypervisor(struct hypervisor_desc *desc)
-{
- read_hypervisor_cpuid(desc);
-
- if (desc->hyper)
- /* hvm */
- desc->virtype = VIRT_FULL;
-
- else if (path_exist(_PATH_PROC_XEN)) {
- /* Xen para-virt or dom0 */
- FILE *fd = path_fopen("r", _PATH_PROC_XENCAP);
- int dom0 = 0;
-
- if (fd) {
- char buf[256];
+ uint32_t eax = 1;
+ uint32_t ecx;
+ union {
+ uint32_t sig32[3];
+ char text[13];
+ } sig = {};
+
+ __asm__ __volatile__ (
+ /* ebx/rbx is being used for PIC! */
+ " push %%"REG_b" \n\t"
+ " cpuid \n\t"
+ " pop %%"REG_b" \n\t"
+
+ : "=a" (eax), "=c" (ecx)
+ : "0" (eax)
+ );
- if (fscanf(fd, "%s", buf) == 1 &&
- !strcmp(buf, "control_d"))
- dom0 = 1;
- fclose(fd);
+ bool has_hypervisor = !!(ecx & 0x80000000U);
+
+ if (has_hypervisor) {
+ /* There is a hypervisor, see what it is... */
+ eax = 0x40000000U;
+ __asm__ __volatile__ (
+ " push %%"REG_b" \n\t"
+ " cpuid \n\t"
+ " mov %%ebx, %1 \n\t"
+ " pop %%"REG_b" \n\t"
+
+ : "=a" (eax), "=r" (sig.sig32[0]), "=c" (sig.sig32[1]), "=d" (sig.sig32[2])
+ : "0" (eax)
+ );
+ sig.text[12] = '\0';
+
+ *hypervisor = HYPER_OTHER;
+
+ int id;
+ for (id = HYPER_NONE + 1; id < HYPER_LAST; id++) {
+ if (strcmp(hypervisor_vendors[id], sig.text) == 0) {
+ *hypervisor = id;
+ break;
+ }
}
- desc->virtype = dom0 ? VIRT_NONE : VIRT_PARA;
- desc->hyper = HYPER_XEN;
- } else if (has_pci_device(0x5853, 0x0001)) {
- /* Xen full-virt on non-x86_64 */
- desc->hyper = HYPER_XEN;
- desc->virtype = VIRT_FULL;
+ return 1;
}
-}
-
-static void
-read_harddisk_serial(char *device, char *serial) {
- static struct hd_driveid hd;
- int fd;
-
- if ((fd = open(device, O_RDONLY | O_NONBLOCK)) < 0) {
- return;
- }
-
- if (!ioctl(fd, HDIO_GET_IDENTITY, &hd)) {
- strncpy(serial, (const char *)hd.serial_no, 20);
- }
-}
-
-#if defined(__x86_64__) || defined(__i386__)
-static bool
-is_virtualized() {
- unsigned int eax, ebx, ecx, edx;
-
- cpuid(0x1, &eax, &ebx, &ecx, &edx);
-
- /*
- Bitwise detection of the 31st bit.
- This indicates if a host runs in a virtual environment.
- */
- if (ecx & (1<<31))
- return true;
-
- return false;
-}
-
-void
-hypervisor_port(unsigned int cmd, unsigned int *eax, unsigned int *ebx,
- unsigned int *ecx, unsigned int *edx)
-{
- __asm__(
-#if defined(__PIC__) && defined(__i386__)
- /* x86 PIC really cannot clobber ebx */
- "pushl %%ebx;"
- "inl (%%dx);"
- "movl %%ebx, %%esi;"
- "popl %%ebx;"
- : "=S" (*ebx),
-#else
- "inl (%%dx);"
- : "=b" (*ebx),
#endif
- "=a" (*eax),
- "=c" (*ecx),
- "=d" (*edx)
- : "0" (VMWARE_HYPERVISOR_MAGIC),
- "1" (cmd),
- "2" (VMWARE_HYPERVISOR_PORT),
- "3" (UINT_MAX)
- : "memory"
- );
-}
-#else
-static bool
-is_virtualized() {
- /*
- Always return false, because other architectures
- do not support the virtualization bit.
- */
- return false;
-}
-
-void
-hypervisor_port(unsigned int cmd, unsigned int *eax, unsigned int *ebx,
- unsigned int *ecx, unsigned int *edx)
-{
+ return 0;
}
-#endif
-
-int
-hypervisor_port_check(void) {
- uint32_t eax, ebx, ecx, edx;
- hypervisor_port(VMWARE_PORT_CMD_GETVERSION, &eax, &ebx, &ecx, &edx);
-
- if (ebx == VMWARE_HYPERVISOR_MAGIC)
- return 1; // Success - running under VMware
- else
- return 0;
-}
static PyObject *
-do_get_hypervisor() {
+do_detect_hypervisor() {
/*
Get hypervisor from the cpuid command.
*/
- struct hypervisor_desc _desc, *desc = &_desc;
- memset(desc, 0, sizeof(*desc));
-
- read_hypervisor(desc);
+ int hypervisor = HYPER_NONE;
- PyObject *d = PyDict_New();
- PyObject *o;
+ int r = detect_hypervisor(&hypervisor);
+ if (r >= 1) {
+ const char* hypervisor_vendor = hypervisor_vendors[hypervisor];
+ if (!hypervisor_vendor)
+ Py_RETURN_NONE;
- /* Hypervisor */
- if (desc->hyper == HYPER_NONE) {
- o = Py_None;
- } else {
- o = PyString_FromString((const char *)hv_vendors[desc->hyper]);
+ return PyString_FromString(hypervisor_vendor);
}
- PyDict_SetItemString(d, "hypervisor", o);
- /* Virtualization type */
- if (desc->virtype == VIRT_NONE) {
- o = Py_None;
- } else {
- o = PyString_FromString((const char *)virt_types[desc->virtype]);
- }
- PyDict_SetItemString(d, "virtype", o);
-
- return d;
-}
-
-static PyObject *
-do_is_virtualized() {
- /*
- Python wrapper around is_virtualized().
- */
-
- if (is_virtualized())
- return Py_True;
-
- return Py_False;
+ Py_RETURN_NONE;
}
static PyObject *
/*
Python wrapper around read_harddisk_serial.
*/
-
- char serial[21];
- memset(serial, 0, sizeof(serial));
-
+ static struct hd_driveid hd;
+ int fd;
char *device;
+
if (!PyArg_ParseTuple(args, "s", &device))
return NULL;
- read_harddisk_serial(device, serial);
-
- if (serial[0])
- return PyString_FromString(serial);
-
- return Py_None;
-}
+ if ((fd = open(device, O_RDONLY | O_NONBLOCK)) < 0)
+ return NULL;
-static PyObject *
-do_hypervisor_port_check() {
- /*
- Python wrapper around hypervisor_port_check().
- */
+ if (!ioctl(fd, HDIO_GET_IDENTITY, &hd)) {
+ char serial[21];
+ strncpy(serial, (const char *)hd.serial_no, sizeof(serial));
- if (hypervisor_port_check())
- return Py_True;
+ if (serial[0])
+ return PyString_FromString(serial);
+ }
- return Py_False;
+ Py_RETURN_NONE;
}
static PyMethodDef fireinfoModuleMethods[] = {
- { "get_hypervisor", (PyCFunction) do_get_hypervisor, METH_NOARGS, NULL },
- { "is_virtualized", (PyCFunction) do_is_virtualized, METH_NOARGS, NULL },
+ { "detect_hypervisor", (PyCFunction) do_detect_hypervisor, METH_NOARGS, NULL },
{ "get_harddisk_serial", (PyCFunction) do_get_harddisk_serial, METH_VARARGS, NULL },
- { "vmware_hypervisor_port_check", (PyCFunction) do_hypervisor_port_check, METH_NOARGS, NULL },
{ NULL, NULL, 0, NULL }
};
PyObject *m;
m = Py_InitModule("_fireinfo", fireinfoModuleMethods);
+ if (m == NULL)
+ return;
}