X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fshared%2Fvirt.c;h=ec2ddcfe6722fac6f6335bccfc8bf478a8bb3968;hp=4c526ff45471620616237ac3176ca594e7921bc5;hb=b5d742138f71e87312541a89aac5657015f50f48;hpb=d7832d2c6e0ef5f2839a2296c1cc2fc85c7d9632 diff --git a/src/shared/virt.c b/src/shared/virt.c index 4c526ff45..ec2ddcfe6 100644 --- a/src/shared/virt.c +++ b/src/shared/virt.c @@ -6,16 +6,16 @@ Copyright 2011 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 + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ @@ -25,29 +25,12 @@ #include "util.h" #include "virt.h" +#include "fileio.h" -/* Returns a short identifier for the various VM implementations */ -int detect_vm(const char **id) { - -#if defined(__i386__) || defined(__x86_64__) +static int detect_vm_cpuid(const char **_id) { /* Both CPUID and DMI are x86 specific interfaces... */ - - static const char *const dmi_vendors[] = { - "/sys/class/dmi/id/sys_vendor", - "/sys/class/dmi/id/board_vendor", - "/sys/class/dmi/id/bios_vendor" - }; - - static 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" - "Bochs\0" "bochs\0"; +#if defined(__i386__) || defined(__x86_64__) static const char cpuid_vendor_table[] = "XenVMMXenVMM\0" "xen\0" @@ -61,13 +44,11 @@ int detect_vm(const char **id) { union { uint32_t sig32[3]; char text[13]; - } sig; - unsigned i; + } sig = {}; const char *j, *k; bool hypervisor; /* http://lwn.net/Articles/301888/ */ - zero(sig); #if defined (__i386__) #define REG_a "eax" @@ -108,20 +89,47 @@ int detect_vm(const char **id) { NULSTR_FOREACH_PAIR(j, k, cpuid_vendor_table) if (streq(sig.text, j)) { - - if (id) - *id = k; - + *_id = k; return 1; } + + *_id = "other"; + return 0; } +#endif + + return 0; +} + +static int detect_vm_dmi(const char **_id) { + + /* Both CPUID and DMI are x86 specific interfaces... */ +#if defined(__i386__) || defined(__x86_64__) + + static const char *const dmi_vendors[] = { + "/sys/class/dmi/id/sys_vendor", + "/sys/class/dmi/id/board_vendor", + "/sys/class/dmi/id/bios_vendor" + }; + + static 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" + "Bochs\0" "bochs\0"; + unsigned i; for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) { - char *s; + _cleanup_free_ char *s = NULL; + const char *j, *k; int r; - const char *found = NULL; - if ((r = read_one_line_file(dmi_vendors[i], &s)) < 0) { + r = read_one_line_file(dmi_vendors[i], &s); + if (r < 0) { if (r != -ENOENT) return r; @@ -129,164 +137,161 @@ int detect_vm(const char **id) { } NULSTR_FOREACH_PAIR(j, k, dmi_vendor_table) - if (startswith(s, j)) - found = k; - free(s); - - if (found) { - if (id) - *id = found; - - return 1; - } - } - - if (hypervisor) { - if (id) - *id = "other"; - - return 1; + if (startswith(s, j)) { + *_id = k; + return 1; + } } - #endif + return 0; } -int detect_container(const char **id) { - FILE *f; - - /* Unfortunately many of these operations require root access - * in one way or another */ - - if (geteuid() != 0) - return -EPERM; - - if (running_in_chroot() > 0) { - - if (id) - *id = "chroot"; - - return 1; - } +/* Returns a short identifier for the various VM implementations */ +int detect_vm(const char **id) { + _cleanup_free_ char *hvtype = NULL, *cpuinfo_contents = NULL; + static thread_local int cached_found = -1; + static thread_local const char *cached_id = NULL; + const char *_id = NULL; + int 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 (_likely_(cached_found >= 0)) { if (id) - *id = "openvz"; + *id = cached_id; - return 1; + return cached_found; } - f = fopen("/proc/1/environ", "re"); - if (f) { - bool done = false; - - do { - char line[LINE_MAX]; - unsigned i; - - for (i = 0; i < sizeof(line)-1; i++) { - int c; - - c = getc(f); - if (_unlikely_(c == EOF)) { - done = true; - break; - } else if (c == 0) - break; - - line[i] = c; - } - line[i] = 0; - - if (streq(line, "container=lxc")) { - fclose(f); - - if (id) - *id = "lxc"; - return 1; - - } else if (streq(line, "container=lxc-libvirt")) { - fclose(f); + /* Try high-level hypervisor sysfs file first: + * + * https://bugs.freedesktop.org/show_bug.cgi?id=61491 */ + r = read_one_line_file("/sys/hypervisor/type", &hvtype); + if (r >= 0) { + if (streq(hvtype, "xen")) { + _id = "xen"; + r = 1; + goto finish; + } + } else if (r != -ENOENT) + return r; - if (id) - *id = "lxc-libvirt"; - return 1; + /* this will set _id to "other" and return 0 for unknown hypervisors */ + r = detect_vm_cpuid(&_id); + if (r != 0) + goto finish; - } else if (streq(line, "container=systemd-nspawn")) { - fclose(f); + r = detect_vm_dmi(&_id); + if (r != 0) + goto finish; - if (id) - *id = "systemd-nspawn"; - return 1; + if (_id) { + /* "other" */ + r = 1; + goto finish; + } - } else if (startswith(line, "container=")) { - fclose(f); + /* Detect User-Mode Linux by reading /proc/cpuinfo */ + r = read_full_file("/proc/cpuinfo", &cpuinfo_contents, NULL); + if (r < 0) + return r; + if (strstr(cpuinfo_contents, "\nvendor_id\t: User Mode Linux\n")) { + _id = "uml"; + r = 1; + goto finish; + } - if (id) - *id = "other"; - return 1; - } + r = 0; - } while (!done); +finish: + cached_found = r; - fclose(f); - } + cached_id = _id; + if (id) + *id = _id; - return 0; + return r; } -/* Returns a short identifier for the various VM/container implementations */ -Virtualization detect_virtualization(const char **id) { +int detect_container(const char **id) { - static __thread Virtualization cached_virt = _VIRTUALIZATION_INVALID; - static __thread const char *cached_id = NULL; + static thread_local int cached_found = -1; + static thread_local const char *cached_id = NULL; - const char *_id; + _cleanup_free_ char *e = NULL; + const char *_id = NULL; int r; - Virtualization v; - if (_likely_(cached_virt >= 0)) { + if (_likely_(cached_found >= 0)) { - if (id && cached_virt > 0) + if (id) *id = cached_id; - return cached_virt; + return cached_found; } - r = detect_container(&_id); - if (r < 0) { - v = r; - goto finish; - } else if (r > 0) { - v = VIRTUALIZATION_CONTAINER; + /* Unfortunately many of these operations require root access + * in one way or another */ + + r = running_in_chroot(); + if (r < 0) + return r; + if (r > 0) { + _id = "chroot"; goto finish; } - r = detect_vm(&_id); - if (r < 0) { - v = r; - goto finish; - } else if (r > 0) { - v = VIRTUALIZATION_VM; + /* /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) { + _id = "openvz"; + r = 1; goto finish; } - v = VIRTUALIZATION_NONE; + r = getenv_for_pid(1, "container", &e); + if (r < 0) + return r; + if (r == 0) + goto finish; + + /* We only recognize a selected few here, since we want to + * enforce a redacted namespace */ + if (streq(e, "lxc")) + _id ="lxc"; + else if (streq(e, "lxc-libvirt")) + _id = "lxc-libvirt"; + else if (streq(e, "systemd-nspawn")) + _id = "systemd-nspawn"; + else + _id = "other"; finish: - if (v > 0) { - cached_id = _id; + cached_found = r; - if (id) - *id = _id; - } + cached_id = _id; + if (id) + *id = _id; + + return r; +} + +/* Returns a short identifier for the various VM/container implementations */ +int detect_virtualization(const char **id) { + int r; + + r = detect_container(id); + if (r < 0) + return r; + if (r > 0) + return VIRTUALIZATION_CONTAINER; - if (v >= 0) - cached_virt = v; + r = detect_vm(id); + if (r < 0) + return r; + if (r > 0) + return VIRTUALIZATION_VM; - return v; + return VIRTUALIZATION_NONE; }