]> git.ipfire.org Git - oddments/fireinfo.git/commitdiff
Rewrite hypervisor detection.
authorMichael Tremer <michael.tremer@ipfire.org>
Sun, 1 Sep 2013 12:54:32 +0000 (14:54 +0200)
committerMichael Tremer <michael.tremer@ipfire.org>
Sun, 1 Sep 2013 12:54:32 +0000 (14:54 +0200)
Reduce the size of code and drop checks for para-virtualization.
All this should decrease false positives.

fireinfo/bios.py [new file with mode: 0644]
fireinfo/hypervisor.py
fireinfo/system.py
src/fireinfo.c

diff --git a/fireinfo/bios.py b/fireinfo/bios.py
new file mode 100644 (file)
index 0000000..56e3af0
--- /dev/null
@@ -0,0 +1,50 @@
+#!/usr/bin/python
+###############################################################################
+#                                                                             #
+# Fireinfo                                                                    #
+# Copyright (C) 2013 IPFire Team (www.ipfire.org)                             #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+import os.path
+
+DMI_VENDORS = [
+       "/sys/class/dmi/id/sys_vendor",
+       "/sys/class/dmi/id/board_vendor",
+       "/sys/class/dmi/id/bios_vendor",
+]
+
+class BIOS(object):
+       def __init__(self, system):
+               self.system = system
+
+       def check_vendor(self, vendor, startswith=True):
+               for file in DMI_VENDORS:
+                       if not os.path.exists(file):
+                               continue
+
+                       with open(file, "r") as f:
+                               v = f.read()
+
+                       # Strip the vendor string.
+                       v = v.strip()
+
+                       if startswith and v.startswith(vendor):
+                               return True
+                       elif v == vendor:
+                               return True
+
+               return False
index 9a3fb094788ef51f4fddaae166d028d21abcd53d..0c07cfad71a1d8aa7996547c598126c2733a469f 100644 (file)
@@ -24,7 +24,7 @@ import system
 
 class Hypervisor(object):
        def __init__(self):
-               self.__info = _fireinfo.get_hypervisor()
+               self.__hypervisor = _fireinfo.detect_hypervisor()
 
        @property
        def system(self):
@@ -41,109 +41,79 @@ class Hypervisor(object):
                """
                        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
index 7cca92e0c47540b3cfbc61d30661ae12c5c6289b..0a60bcc37b185539656699ba14eaa8332080ae04 100644 (file)
@@ -26,6 +26,7 @@ import string
 
 import _fireinfo
 
+import bios
 import cpu
 import device
 import hypervisor
@@ -78,6 +79,8 @@ class System(object):
        __metaclass__ = Singleton
 
        def __init__(self):
+               self.bios = bios.BIOS(self)
+
                # find all devices
                self.devices = []
                self.scan()
@@ -149,7 +152,6 @@ class System(object):
                # Only append hypervisor information if we are virtualized.
                if self.virtual:
                        p["hypervisor"] = {
-                               "type"   : self.hypervisor.type,
                                "vendor" : self.hypervisor.vendor,
                        }
 
index 25b5333651bbd49375d9f0285abd318d531a3560..77616a13c6c80b921d402dc67b7d85fef1934f1f 100644 (file)
 
 #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.
@@ -161,222 +98,96 @@ found:
  */
 #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 *
@@ -384,39 +195,30 @@ do_get_harddisk_serial(PyObject *o, PyObject *args) {
        /*
                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 }
 };
 
@@ -424,4 +226,6 @@ void init_fireinfo(void) {
        PyObject *m;
 
        m = Py_InitModule("_fireinfo", fireinfoModuleMethods);
+       if (m == NULL)
+               return;
 }