X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fshared%2Fvirt.c;h=b4368952ffac3d8f3dde431caff786e39f11a5b8;hp=537ccda654fb5d4f8ba2d0c93134fdd6a105a875;hb=f41925b4e442a34c93ad120ef1426c974a047ed1;hpb=0fb533a53359cb8d034ec926638896b93f4fa839 diff --git a/src/shared/virt.c b/src/shared/virt.c index 537ccda65..b4368952f 100644 --- a/src/shared/virt.c +++ b/src/shared/virt.c @@ -27,30 +27,10 @@ #include "virt.h" #include "fileio.h" -/* Returns a short identifier for the various VM implementations */ -int detect_vm(const char **id) { - _cleanup_free_ char *cpuinfo_contents = NULL; - int r; - -#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" @@ -60,40 +40,13 @@ int detect_vm(const char **id) { /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */ "Microsoft Hv\0" "microsoft\0"; - static __thread int cached_found = -1; - static __thread const char *cached_id = NULL; - uint32_t eax, ecx; union { uint32_t sig32[3]; char text[13]; } sig = {}; - unsigned i; const char *j, *k; bool hypervisor; - _cleanup_free_ char *hvtype = NULL; - const char *_id = NULL; - - if (_likely_(cached_found >= 0)) { - - if (id) - *id = cached_id; - - return cached_found; - } - - /* 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; /* http://lwn.net/Articles/301888/ */ @@ -136,14 +89,43 @@ int detect_vm(const char **id) { NULSTR_FOREACH_PAIR(j, k, cpuid_vendor_table) if (streq(sig.text, j)) { - _id = k; - r = 1; - goto finish; + *_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" + "innotek GmbH\0" "oracle\0" + "Xen\0" "xen\0" + "Bochs\0" "bochs\0"; + unsigned i; for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) { _cleanup_free_ char *s = NULL; + const char *j, *k; + int r; r = read_one_line_file(dmi_vendors[i], &s); if (r < 0) { @@ -155,20 +137,79 @@ int detect_vm(const char **id) { NULSTR_FOREACH_PAIR(j, k, dmi_vendor_table) if (startswith(s, j)) { - _id = k; + *_id = k; + return 1; + } + } +#endif + + return 0; +} + +/* Returns a short identifier for the various VM implementations */ +int detect_vm(const char **id) { + _cleanup_free_ char *domcap = 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; + + if (_likely_(cached_found >= 0)) { + + if (id) + *id = cached_id; + + return cached_found; + } + + /* Try xen capabilities file first, if not found try high-level hypervisor sysfs file: + * + * https://bugs.freedesktop.org/show_bug.cgi?id=77271 */ + r = read_one_line_file("/proc/xen/capabilities", &domcap); + if (r >= 0) { + char *cap, *i = domcap; + + while ((cap = strsep(&i, ","))) + if (streq(cap, "control_d")) + break; + + if (!cap) { + _id = "xen"; + r = 1; + } + + goto finish; + + } else if (r == -ENOENT) { + _cleanup_free_ char *hvtype = NULL; + + 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; + } else + return r; - if (hypervisor || hvtype) { - _id = "other"; + /* this will set _id to "other" and return 0 for unknown hypervisors */ + r = detect_vm_cpuid(&_id); + if (r != 0) + goto finish; + + r = detect_vm_dmi(&_id); + if (r != 0) + goto finish; + + if (_id) { + /* "other" */ r = 1; goto finish; } -#endif - /* Detect User-Mode Linux by reading /proc/cpuinfo */ r = read_full_file("/proc/cpuinfo", &cpuinfo_contents, NULL); if (r < 0) @@ -179,6 +220,23 @@ int detect_vm(const char **id) { goto finish; } +#if defined(__s390__) + { + _cleanup_free_ char *t = NULL; + + r = get_status_field("/proc/sysinfo", "VM00 Control Program:", &t); + if (r >= 0) { + if (streq(t, "z/VM")) + _id = "zvm"; + else + _id = "kvm"; + r = 1; + + goto finish; + } + } +#endif + r = 0; finish: @@ -193,11 +251,11 @@ finish: int detect_container(const char **id) { - static __thread int cached_found = -1; - static __thread const char *cached_id = NULL; + static thread_local int cached_found = -1; + static thread_local const char *cached_id = NULL; - _cleanup_free_ char *e = NULL; - const char *_id = NULL; + _cleanup_free_ char *m = NULL; + const char *_id = NULL, *e = NULL; int r; if (_likely_(cached_found >= 0)) { @@ -208,17 +266,6 @@ int detect_container(const char **id) { return cached_found; } - /* 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; - } - /* /proc/vz exists in container and outside of the container, * /proc/bc only outside of the container. */ if (access("/proc/vz", F_OK) >= 0 && @@ -228,11 +275,32 @@ int detect_container(const char **id) { goto finish; } - r = getenv_for_pid(1, "container", &e); - if (r < 0) - return r; - if (r == 0) - goto finish; + if (getpid() == 1) { + /* If we are PID 1 we can just check our own + * environment variable */ + + e = getenv("container"); + if (isempty(e)) { + r = 0; + goto finish; + } + } else { + + /* Otherwise, PID 1 dropped this information into a + * file in /run. This is better than accessing + * /proc/1/environ, since we don't need CAP_SYS_PTRACE + * for that. */ + + r = read_one_line_file("/run/systemd/container", &m); + if (r == -ENOENT) { + r = 0; + goto finish; + } + if (r < 0) + return r; + + e = m; + } /* We only recognize a selected few here, since we want to * enforce a redacted namespace */ @@ -245,6 +313,8 @@ int detect_container(const char **id) { else _id = "other"; + r = 1; + finish: cached_found = r; @@ -256,7 +326,7 @@ finish: } /* Returns a short identifier for the various VM/container implementations */ -Virtualization detect_virtualization(const char **id) { +int detect_virtualization(const char **id) { int r; r = detect_container(id);