summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2011-02-21 21:48:59 +0100
committerLennart Poettering <lennart@poettering.net>2011-02-21 21:48:59 +0100
commit07faed4f99d0c798f92de3032b9c20ca31388494 (patch)
tree01ce628c10a9e7c1c691f0424b633905ccfeb134
parentb284eabdc14683e4587baf43e83cedc6698a42df (diff)
virtualization: beef virtualization code
-rw-r--r--.gitignore1
-rw-r--r--Makefile.am10
-rw-r--r--src/detect-virt.c46
-rw-r--r--src/readahead-collect.c4
-rw-r--r--src/readahead-replay.c4
-rw-r--r--src/util.c127
-rw-r--r--src/util.h3
7 files changed, 165 insertions, 30 deletions
diff --git a/.gitignore b/.gitignore
index 1bb184f875..adee97f6ce 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+systemd-detect-virt
systemd-sysctl
test-strv
systemd-ac-power
diff --git a/Makefile.am b/Makefile.am
index f508163d5b..7e5d6d8764 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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
index 0000000000..7685d18cc6
--- /dev/null
+++ b/src/detect-virt.c
@@ -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;
+}
diff --git a/src/readahead-collect.c b/src/readahead-collect.c
index ea07b3ff49..330d10776f 100644
--- a/src/readahead-collect.c
+++ b/src/readahead-collect.c
@@ -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;
}
diff --git a/src/readahead-replay.c b/src/readahead-replay.c
index 9447fe0775..cd89654f98 100644
--- a/src/readahead-replay.c
+++ b/src/readahead-replay.c
@@ -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;
}
diff --git a/src/util.c b/src/util.c
index b8e73ef4bf..7e8246bb61 100644
--- a/src/util.c
+++ b/src/util.c
@@ -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[]) {
diff --git a/src/util.h b/src/util.h
index 80f1a38b57..7f2cc080a7 100644
--- a/src/util.h
+++ b/src/util.h
@@ -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[]);