chiark / gitweb /
virtualization: beef virtualization code
authorLennart Poettering <lennart@poettering.net>
Mon, 21 Feb 2011 20:48:59 +0000 (21:48 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 21 Feb 2011 20:48:59 +0000 (21:48 +0100)
.gitignore
Makefile.am
src/detect-virt.c [new file with mode: 0644]
src/readahead-collect.c
src/readahead-replay.c
src/util.c
src/util.h

index 1bb184f..adee97f 100644 (file)
@@ -1,3 +1,4 @@
+systemd-detect-virt
 systemd-sysctl
 test-strv
 systemd-ac-power
index f508163..7e5d6d8 100644 (file)
@@ -129,6 +129,7 @@ rootlibexec_PROGRAMS = \
        systemd-quotacheck \
        systemd-timestamp \
        systemd-ac-power \
+       systemd-detect-virt \
        systemd-sysctl
 
 if HAVE_LIBCRYPTSETUP
@@ -783,6 +784,15 @@ systemd_ac_power_LDADD = \
        libsystemd-basic.la \
        $(UDEV_LIBS)
 
+systemd_detect_virt_SOURCES = \
+       src/detect-virt.c
+
+systemd_detect_virt_CFLAGS = \
+       $(AM_CFLAGS)
+
+systemd_detect_virt_LDADD = \
+       libsystemd-basic.la
+
 systemd_cryptsetup_SOURCES = \
        src/cryptsetup.c \
        src/ask-password-api.c
diff --git a/src/detect-virt.c b/src/detect-virt.c
new file mode 100644 (file)
index 0000000..7685d18
--- /dev/null
@@ -0,0 +1,46 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd 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 2 of the License, or
+  (at your option) any later version.
+
+  systemd 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 systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+
+#include "util.h"
+
+int main(int argc, char *argv[]) {
+        int r;
+        const char *id;
+
+        /* This is mostly intended to be used for scripts which want
+         * to detect whether we are being run in a virtualized
+         * environment or not */
+
+        if ((r = detect_virtualization(&id)) < 0) {
+                log_error("Failed to check for virtualization: %s", strerror(-r));
+                return EXIT_FAILURE;
+        }
+
+        if (r > 0)
+                printf("%s\n", id);
+
+        return r == 0;
+}
index ea07b3f..330d107 100644 (file)
@@ -652,8 +652,8 @@ int main(int argc, char *argv[]) {
                 return 0;
         }
 
-        if (running_in_vm()) {
-                log_info("Disabling readahead collector due to execution in virtual machine.");
+        if (detect_virtualization(NULL) > 0) {
+                log_info("Disabling readahead collector due to execution in virtualized environment.");
                 return 0;
         }
 
index 9447fe0..cd89654 100644 (file)
@@ -346,8 +346,8 @@ int main(int argc, char*argv[]) {
                 return 0;
         }
 
-        if (running_in_vm()) {
-                log_info("Disabling readahead replay due to execution in virtual machine.");
+        if (detect_virtualization(NULL) > 0) {
+                log_info("Disabling readahead replay due to execution in virtualized environment.");
                 return 0;
         }
 
index b8e73ef..7e8246b 100644 (file)
@@ -3706,7 +3706,8 @@ const char *default_term_for_tty(const char *tty) {
         return term;
 }
 
-bool running_in_vm(void) {
+/* Returns a short identifier for the various VM implementations */
+int detect_vm(const char **id) {
 
 #if defined(__i386__) || defined(__x86_64__)
 
@@ -3718,39 +3719,62 @@ bool running_in_vm(void) {
                 "/sys/class/dmi/id/bios_vendor"
         };
 
-        uint32_t eax = 0x40000000;
+        const char dmi_vendor_table[] =
+                "QEMU\0"                  "qemu\0"
+                /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
+                "VMware\0"                "vmware\0"
+                "VMW\0"                   "vmware\0"
+                "Microsoft Corporation\0" "microsoft\0"
+                "innotek GmbH\0"          "oracle\0"
+                "Xen\0"                   "xen\0"
+                "\0";
+
+        const char cpuid_vendor_table[] =
+                "XenVMMXenVMM\0"          "xen\0"
+                "KVMKVMKVM\0"             "kvm\0"
+                /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
+                "VMwareVMware\0"          "vmware\0"
+                /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */
+                "Microsoft Hv\0"          "microsoft\0"
+                "\0";
+
+        uint32_t eax, ecx;
         union {
                 uint32_t sig32[3];
                 char text[13];
         } sig;
 
         unsigned i;
+        const char *j, *k;
 
         for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) {
                 char *s;
-                bool b;
+                int r;
+                const char *found = NULL;
 
-                if (read_one_line_file(dmi_vendors[i], &s) < 0)
-                        continue;
+                if ((r = read_one_line_file(dmi_vendors[i], &s)) < 0) {
+                        if (r != -ENOENT)
+                                return r;
 
-                b = startswith(s, "QEMU") ||
-                        /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
-                        startswith(s, "VMware") ||
-                        startswith(s, "VMW") ||
-                        startswith(s, "Microsoft Corporation") ||
-                        startswith(s, "innotek GmbH") ||
-                        startswith(s, "Xen");
+                        continue;
+                }
 
+                NULSTR_FOREACH_PAIR(j, k, dmi_vendor_table)
+                        if (startswith(s, j))
+                                found = k;
                 free(s);
 
-                if (b)
-                        return true;
+                if (found) {
+                        if (id)
+                                *id = found;
+
+                        return 1;
+                }
         }
 
         /* http://lwn.net/Articles/301888/ */
         zero(sig);
 
-
 #if defined (__i386__)
 #define REG_a "eax"
 #define REG_b "ebx"
@@ -3759,27 +3783,80 @@ bool running_in_vm(void) {
 #define REG_b "rbx"
 #endif
 
+        /* First detect whether there is a hypervisor */
+        eax = 1;
         __asm__ __volatile__ (
                 /* ebx/rbx is being used for PIC! */
                 "  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])
+                : "=a" (eax), "=c" (ecx)
                 : "0" (eax)
         );
 
-        if (streq(sig.text, "XenVMMXenVMM") ||
-            streq(sig.text, "KVMKVMKVM") ||
-            /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
-            streq(sig.text, "VMwareVMware") ||
-            /* http://msdn.microsoft.com/en-us/library/bb969719.aspx */
-            streq(sig.text, "Microsoft Hv"))
-                return true;
+        if (ecx & 0x80000000U) {
+
+                /* There is a hypervisor, see what it is */
+                eax = 0x40000000U;
+                __asm__ __volatile__ (
+                        /* ebx/rbx is being used for PIC! */
+                        "  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)
+                );
+
+                NULSTR_FOREACH_PAIR(j, k, cpuid_vendor_table)
+                        if (streq(sig.text, j)) {
+
+                                if (id)
+                                        *id = k;
+
+                                return 1;
+                        }
+
+                if (id)
+                        *id = "other";
+
+                return 1;
+        }
 #endif
 
-        return false;
+        return 0;
+}
+
+/* Returns a short identifier for the various VM/container implementations */
+int detect_virtualization(const char **id) {
+        int r;
+
+        /* Unfortunately most of these operations require root access
+         * in one way or another */
+        if (geteuid() != 0)
+                return -EPERM;
+
+        if ((r = running_in_chroot()) > 0) {
+                if (id)
+                        *id = "chroot";
+
+                return r;
+        }
+
+        /* /proc/vz exists in container and outside of the container,
+         * /proc/bc only outside of the container. */
+        if (access("/proc/vz", F_OK) >= 0 &&
+            access("/proc/bc", F_OK) < 0) {
+
+                if (id)
+                        *id = "openvz";
+
+                return 1;
+        }
+
+        return detect_vm(id);
 }
 
 void execute_directory(const char *directory, DIR *d, char *argv[]) {
index 80f1a38..7f2cc08 100644 (file)
@@ -378,7 +378,8 @@ void filter_environ(const char *prefix);
 bool tty_is_vc(const char *tty);
 const char *default_term_for_tty(const char *tty);
 
-bool running_in_vm(void);
+int detect_vm(const char **id);
+int detect_virtualization(const char **id);
 
 void execute_directory(const char *directory, DIR *_d, char *argv[]);