virt.c revision d84248ebec77d7d22c2035c786437d0c58641a6b
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering This file is part of systemd.
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering Copyright 2011 Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering systemd is free software; you can redistribute it and/or modify it
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering under the terms of the GNU Lesser General Public License as published by
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering (at your option) any later version.
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering systemd is distributed in the hope that it will be useful, but
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering Lesser General Public License for more details.
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering You should have received a copy of the GNU Lesser General Public License
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* Both CPUID and DMI are x86 specific interfaces... */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#if defined(__i386__) || defined(__x86_64__)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering static const char cpuid_vendor_table[] =
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "XenVMMXenVMM\0" "xen\0"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "KVMKVMKVM\0" "kvm\0"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "VMwareVMware\0" "vmware\0"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "Microsoft Hv\0" "microsoft\0";
9eb977db5b89b44f254ab40c1876a76b7d7ea2d0Kay Sievers const char *j, *k;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* First detect whether there is a hypervisor */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* ebx/rbx is being used for PIC! */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* There is a hypervisor, see what it is */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* ebx/rbx is being used for PIC! */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering " mov %%ebx, %1 \n\t"
d2e54fae5ca7a0f71b5ac8b356a589ff0a09ea0aKay Sievers : "=a" (eax), "=r" (sig.sig32[0]), "=c" (sig.sig32[1]), "=d" (sig.sig32[2])
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering NULSTR_FOREACH_PAIR(j, k, cpuid_vendor_table)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringstatic int detect_vm_devicetree(const char **_id) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#if defined(__arm__) || defined(__aarch64__) || defined(__powerpc__) || defined(__powerpc64__)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = read_one_line_file("/proc/device-tree/hypervisor/compatible", &hvtype);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering } else if (r == -ENOENT) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering FOREACH_DIRENT(dent, dir, return -errno) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringstatic int detect_vm_dmi(const char **_id) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* Both CPUID and DMI are x86 specific interfaces... */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#if defined(__i386__) || defined(__x86_64__)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering static const char *const dmi_vendors[] = {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering static const char dmi_vendor_table[] =
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "QEMU\0" "qemu\0"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering "VMware\0" "vmware\0"
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering "VMW\0" "vmware\0"
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering "innotek GmbH\0" "oracle\0"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "Xen\0" "xen\0"
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering "Bochs\0" "bochs\0"
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering "Parallels\0" "parallels\0";
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering const char *j, *k;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = read_one_line_file(dmi_vendors[i], &s);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering NULSTR_FOREACH_PAIR(j, k, dmi_vendor_table)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering/* Returns a short identifier for the various VM implementations */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering _cleanup_free_ char *domcap = NULL, *cpuinfo_contents = NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering static thread_local int cached_found = -1;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering static thread_local const char *cached_id = NULL;
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering const char *_id = NULL, *_id_cpuid = NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* Try xen capabilities file first, if not found try high-level hypervisor sysfs file:
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering * https://bugs.freedesktop.org/show_bug.cgi?id=77271 */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = read_one_line_file("/proc/xen/capabilities", &domcap);
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering } else if (r == -ENOENT) {
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering r = read_one_line_file("/sys/hypervisor/type", &hvtype);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering } else if (r != -ENOENT)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* this will set _id to "other" and return 0 for unknown hypervisors */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* finish when found a known hypervisor other than kvm */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (r < 0 || (r > 0 && !streq(_id, "kvm")))
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* kvm with and without Virtualbox */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* Parallels exports KVMKVMKVM leaf */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (r > 0 && (streq(_id, "oracle") || streq(_id, "parallels")))
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* information from dmi */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* Detect User-Mode Linux by reading /proc/cpuinfo */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = read_full_file("/proc/cpuinfo", &cpuinfo_contents, NULL);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (strstr(cpuinfo_contents, "\nvendor_id\t: User Mode Linux\n")) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = get_status_field("/proc/sysinfo", "VM00 Control Program:", &t);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering static thread_local int cached_found = -1;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering static thread_local const char *cached_id = NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* /proc/vz exists in container and outside of the container,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering * /proc/bc only outside of the container. */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* If we are PID 1 we can just check our own
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering * environment variable */
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering /* Otherwise, PID 1 dropped this information into a
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering * file in /run. This is better than accessing
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering * /proc/1/environ, since we don't need CAP_SYS_PTRACE
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering * for that. */
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering r = read_one_line_file("/run/systemd/container", &m);
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering /* Fallback for cases where PID 1 was not
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering * systemd (for example, cases where
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering * init=/bin/sh is used. */
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering /* If that didn't work, give up,
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering * assume no container manager.
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering * Note: This means we still cannot
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering * detect containers if init=/bin/sh
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering * is passed but privileges dropped,
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering * as /proc/1/environ is only readable
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering * with privileges. */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* We only recognize a selected few here, since we want to
4943c1c94ba751c98763f4232b4350481b22c90aLennart Poettering * enforce a redacted namespace */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering/* Returns a short identifier for the various VM/container implementations */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringint detect_virtualization(const char **id) {
return VIRTUALIZATION_VM;
return VIRTUALIZATION_NONE;