1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-22 17:35:35 +03:00

virtualization: beef virtualization code

This commit is contained in:
Lennart Poettering 2011-02-21 21:48:59 +01:00
parent b284eabdc1
commit 07faed4f99
7 changed files with 165 additions and 30 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
systemd-detect-virt
systemd-sysctl systemd-sysctl
test-strv test-strv
systemd-ac-power systemd-ac-power

View File

@ -129,6 +129,7 @@ rootlibexec_PROGRAMS = \
systemd-quotacheck \ systemd-quotacheck \
systemd-timestamp \ systemd-timestamp \
systemd-ac-power \ systemd-ac-power \
systemd-detect-virt \
systemd-sysctl systemd-sysctl
if HAVE_LIBCRYPTSETUP if HAVE_LIBCRYPTSETUP
@ -783,6 +784,15 @@ systemd_ac_power_LDADD = \
libsystemd-basic.la \ libsystemd-basic.la \
$(UDEV_LIBS) $(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 = \ systemd_cryptsetup_SOURCES = \
src/cryptsetup.c \ src/cryptsetup.c \
src/ask-password-api.c src/ask-password-api.c

46
src/detect-virt.c Normal file
View File

@ -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;
}

View File

@ -652,8 +652,8 @@ int main(int argc, char *argv[]) {
return 0; return 0;
} }
if (running_in_vm()) { if (detect_virtualization(NULL) > 0) {
log_info("Disabling readahead collector due to execution in virtual machine."); log_info("Disabling readahead collector due to execution in virtualized environment.");
return 0; return 0;
} }

View File

@ -346,8 +346,8 @@ int main(int argc, char*argv[]) {
return 0; return 0;
} }
if (running_in_vm()) { if (detect_virtualization(NULL) > 0) {
log_info("Disabling readahead replay due to execution in virtual machine."); log_info("Disabling readahead replay due to execution in virtualized environment.");
return 0; return 0;
} }

View File

@ -3706,7 +3706,8 @@ const char *default_term_for_tty(const char *tty) {
return term; 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__) #if defined(__i386__) || defined(__x86_64__)
@ -3718,39 +3719,62 @@ bool running_in_vm(void) {
"/sys/class/dmi/id/bios_vendor" "/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 { union {
uint32_t sig32[3]; uint32_t sig32[3];
char text[13]; char text[13];
} sig; } sig;
unsigned i; unsigned i;
const char *j, *k;
for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) { for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) {
char *s; char *s;
bool b; int r;
const char *found = NULL;
if ((r = read_one_line_file(dmi_vendors[i], &s)) < 0) {
if (r != -ENOENT)
return r;
if (read_one_line_file(dmi_vendors[i], &s) < 0)
continue; continue;
}
b = startswith(s, "QEMU") || NULSTR_FOREACH_PAIR(j, k, dmi_vendor_table)
/* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */ if (startswith(s, j))
startswith(s, "VMware") || found = k;
startswith(s, "VMW") ||
startswith(s, "Microsoft Corporation") ||
startswith(s, "innotek GmbH") ||
startswith(s, "Xen");
free(s); free(s);
if (b) if (found) {
return true; if (id)
*id = found;
return 1;
}
} }
/* http://lwn.net/Articles/301888/ */ /* http://lwn.net/Articles/301888/ */
zero(sig); zero(sig);
#if defined (__i386__) #if defined (__i386__)
#define REG_a "eax" #define REG_a "eax"
#define REG_b "ebx" #define REG_b "ebx"
@ -3759,27 +3783,80 @@ bool running_in_vm(void) {
#define REG_b "rbx" #define REG_b "rbx"
#endif #endif
/* First detect whether there is a hypervisor */
eax = 1;
__asm__ __volatile__ ( __asm__ __volatile__ (
/* ebx/rbx is being used for PIC! */ /* ebx/rbx is being used for PIC! */
" push %%"REG_b" \n\t" " push %%"REG_b" \n\t"
" cpuid \n\t" " cpuid \n\t"
" mov %%ebx, %1 \n\t"
" pop %%"REG_b" \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) : "0" (eax)
); );
if (streq(sig.text, "XenVMMXenVMM") || if (ecx & 0x80000000U) {
streq(sig.text, "KVMKVMKVM") ||
/* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */ /* There is a hypervisor, see what it is */
streq(sig.text, "VMwareVMware") || eax = 0x40000000U;
/* http://msdn.microsoft.com/en-us/library/bb969719.aspx */ __asm__ __volatile__ (
streq(sig.text, "Microsoft Hv")) /* ebx/rbx is being used for PIC! */
return true; " 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 #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[]) { void execute_directory(const char *directory, DIR *d, char *argv[]) {

View File

@ -378,7 +378,8 @@ void filter_environ(const char *prefix);
bool tty_is_vc(const char *tty); bool tty_is_vc(const char *tty);
const char *default_term_for_tty(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[]); void execute_directory(const char *directory, DIR *_d, char *argv[]);