]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/basic/virt.c
shared/virt: update link to vmware article
[thirdparty/systemd.git] / src / basic / virt.c
index 9da5feca6cca015687ff2bfc47b2b0fae7b3be4d..3be3852e35c0e0829e45284a06bce54f7b610423 100644 (file)
@@ -1,9 +1,4 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
-/***
-  This file is part of systemd.
-
-  Copyright 2011 Lennart Poettering
-***/
 
 #if defined(__i386__) || defined(__x86_64__)
 #include <cpuid.h>
@@ -45,6 +40,8 @@ static int detect_vm_cpuid(void) {
                 /* https://wiki.freebsd.org/bhyve */
                 { "bhyve bhyve ", VIRTUALIZATION_BHYVE     },
                 { "QNXQVMBSQG",   VIRTUALIZATION_QNX       },
+                /* https://projectacrn.org */
+                { "ACRNACRNACRN", VIRTUALIZATION_ACRN      },
         };
 
         uint32_t eax, ebx, ecx, edx;
@@ -56,7 +53,7 @@ static int detect_vm_cpuid(void) {
         if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) == 0)
                 return VIRTUALIZATION_NONE;
 
-        hypervisor = !!(ecx & 0x80000000U);
+        hypervisor = ecx & 0x80000000U;
 
         if (hypervisor) {
                 union {
@@ -143,17 +140,17 @@ static int detect_vm_dmi(void) {
                 const char *vendor;
                 int id;
         } dmi_vendor_table[] = {
-                { "KVM",           VIRTUALIZATION_KVM       },
-                { "QEMU",          VIRTUALIZATION_QEMU      },
-                /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
-                { "VMware",        VIRTUALIZATION_VMWARE    },
-                { "VMW",           VIRTUALIZATION_VMWARE    },
-                { "innotek GmbH",  VIRTUALIZATION_ORACLE    },
-                { "Xen",           VIRTUALIZATION_XEN       },
-                { "Bochs",         VIRTUALIZATION_BOCHS     },
-                { "Parallels",     VIRTUALIZATION_PARALLELS },
+                { "KVM",                 VIRTUALIZATION_KVM       },
+                { "QEMU",                VIRTUALIZATION_QEMU      },                
+                { "VMware",              VIRTUALIZATION_VMWARE    }, /* https://kb.vmware.com/s/article/1009458 */
+                { "VMW",                 VIRTUALIZATION_VMWARE    },
+                { "innotek GmbH",        VIRTUALIZATION_ORACLE    },
+                { "Oracle Corporation",  VIRTUALIZATION_ORACLE    },
+                { "Xen",                 VIRTUALIZATION_XEN       },
+                { "Bochs",               VIRTUALIZATION_BOCHS     },
+                { "Parallels",           VIRTUALIZATION_PARALLELS },
                 /* https://wiki.freebsd.org/bhyve */
-                { "BHYVE",         VIRTUALIZATION_BHYVE     },
+                { "BHYVE",               VIRTUALIZATION_BHYVE     },
         };
         unsigned i;
         int r;
@@ -201,13 +198,12 @@ static int detect_vm_xen(void) {
 /* Returns -errno, or 0 for domU, or 1 for dom0 */
 static int detect_vm_xen_dom0(void) {
         _cleanup_free_ char *domcap = NULL;
-        char *cap, *i;
         int r;
 
         r = read_one_line_file(PATH_FEATURES, &domcap);
         if (r < 0 && r != -ENOENT)
                 return r;
-        if (r == 0) {
+        if (r >= 0) {
                 unsigned long features;
 
                 /* Here, we need to use sscanf() instead of safe_atoul()
@@ -232,17 +228,22 @@ static int detect_vm_xen_dom0(void) {
         if (r < 0)
                 return r;
 
-        i = domcap;
-        while ((cap = strsep(&i, ",")))
-                if (streq(cap, "control_d"))
-                        break;
-        if (!cap) {
-                log_debug("Virtualization XEN DomU found (/proc/xen/capabilites)");
-                return 0;
-        }
+        for (const char *i = domcap;;) {
+                _cleanup_free_ char *cap = NULL;
+
+                r = extract_first_word(&i, &cap, ",", 0);
+                if (r < 0)
+                        return r;
+                if (r == 0) {
+                        log_debug("Virtualization XEN DomU found (/proc/xen/capabilities)");
+                        return 0;
+                }
 
-        log_debug("Virtualization XEN Dom0 ignored (/proc/xen/capabilities)");
-        return 1;
+                if (streq(cap, "control_d")) {
+                        log_debug("Virtualization XEN Dom0 ignored (/proc/xen/capabilities)");
+                        return 1;
+                }
+        }
 }
 
 static int detect_vm_hypervisor(void) {
@@ -264,21 +265,38 @@ static int detect_vm_hypervisor(void) {
 }
 
 static int detect_vm_uml(void) {
-        _cleanup_free_ char *cpuinfo_contents = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
         int r;
 
         /* Detect User-Mode Linux by reading /proc/cpuinfo */
-        r = read_full_file("/proc/cpuinfo", &cpuinfo_contents, NULL);
-        if (r == -ENOENT) {
-                log_debug("/proc/cpuinfo not found, assuming no UML virtualization.");
-                return VIRTUALIZATION_NONE;
+        f = fopen("/proc/cpuinfo", "re");
+        if (!f) {
+                if (errno == ENOENT) {
+                        log_debug("/proc/cpuinfo not found, assuming no UML virtualization.");
+                        return VIRTUALIZATION_NONE;
+                }
+                return -errno;
         }
-        if (r < 0)
-                return r;
 
-        if (strstr(cpuinfo_contents, "\nvendor_id\t: User Mode Linux\n")) {
-                log_debug("UML virtualization found in /proc/cpuinfo");
-                return VIRTUALIZATION_UML;
+        for (;;) {
+                _cleanup_free_ char *line = NULL;
+                const char *t;
+
+                r = read_line(f, LONG_LINE_MAX, &line);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
+
+                t = startswith(line, "vendor_id\t: ");
+                if (t) {
+                        if (startswith(t, "User Mode Linux")) {
+                                log_debug("UML virtualization found in /proc/cpuinfo");
+                                return VIRTUALIZATION_UML;
+                        }
+
+                        break;
+                }
         }
 
         log_debug("UML virtualization not found in /proc/cpuinfo.");
@@ -414,7 +432,6 @@ finish:
 }
 
 int detect_container(void) {
-
         static const struct {
                 const char *value;
                 int id;
@@ -423,11 +440,14 @@ int detect_container(void) {
                 { "lxc-libvirt",    VIRTUALIZATION_LXC_LIBVIRT    },
                 { "systemd-nspawn", VIRTUALIZATION_SYSTEMD_NSPAWN },
                 { "docker",         VIRTUALIZATION_DOCKER         },
+                { "podman",         VIRTUALIZATION_PODMAN         },
                 { "rkt",            VIRTUALIZATION_RKT            },
+                { "wsl",            VIRTUALIZATION_WSL            },
         };
 
         static thread_local int cached_found = _VIRTUALIZATION_INVALID;
         _cleanup_free_ char *m = NULL;
+        _cleanup_free_ char *o = NULL;
         const char *e = NULL;
         unsigned j;
         int r;
@@ -442,10 +462,25 @@ int detect_container(void) {
                 goto finish;
         }
 
-        if (getpid_cached() == 1) {
-                /* If we are PID 1 we can just check our own environment variable, and that's authoritative. */
+        /* "Official" way of detecting WSL https://github.com/Microsoft/WSL/issues/423#issuecomment-221627364 */
+        r = read_one_line_file("/proc/sys/kernel/osrelease", &o);
+        if (r >= 0) {
+                if (strstr(o, "Microsoft") || strstr(o, "WSL")) {
+                        r = VIRTUALIZATION_WSL;
+                        goto finish;
+                }
+        }
 
+        if (getpid_cached() == 1) {
+                /* If we are PID 1 we can just check our own environment variable, and that's authoritative.
+                 * We distinguish three cases:
+                 * - the variable is not defined → we jump to other checks
+                 * - the variable is defined to an empty value → we are not in a container
+                 * - anything else → some container, either one of the known ones or "container-other"
+                 */
                 e = getenv("container");
+                if (!e)
+                        goto check_sched;
                 if (isempty(e)) {
                         r = VIRTUALIZATION_NONE;
                         goto finish;
@@ -457,11 +492,11 @@ int detect_container(void) {
         /* Otherwise, PID 1 might have 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 >= 0) {
+        if (r > 0) {
                 e = m;
                 goto translate_name;
         }
-        if (r != -ENOENT)
+        if (!IN_SET(r, -ENOENT, 0))
                 return log_debug_errno(r, "Failed to read /run/systemd/container: %m");
 
         /* Fallback for cases where PID 1 was not systemd (for example, cases where init=/bin/sh is used. */
@@ -473,8 +508,9 @@ int detect_container(void) {
         if (r < 0) /* This only works if we have CAP_SYS_PTRACE, hence let's better ignore failures here */
                 log_debug_errno(r, "Failed to read $container of PID 1, ignoring: %m");
 
-        /* Interestingly /proc/1/sched actually shows the host's PID for what we see as PID 1. Hence, if the PID shown
-         * there is not 1, we know we are in a PID namespace. and hence a container. */
+        /* Interestingly /proc/1/sched actually shows the host's PID for what we see as PID 1. If the PID
+         * shown there is not 1, we know we are in a PID namespace and hence a container. */
+ check_sched:
         r = read_one_line_file("/proc/1/sched", &m);
         if (r >= 0) {
                 const char *t;
@@ -616,6 +652,7 @@ static const char *const virtualization_table[_VIRTUALIZATION_MAX] = {
         [VIRTUALIZATION_PARALLELS] = "parallels",
         [VIRTUALIZATION_BHYVE] = "bhyve",
         [VIRTUALIZATION_QNX] = "qnx",
+        [VIRTUALIZATION_ACRN] = "acrn",
         [VIRTUALIZATION_VM_OTHER] = "vm-other",
 
         [VIRTUALIZATION_SYSTEMD_NSPAWN] = "systemd-nspawn",
@@ -623,7 +660,9 @@ static const char *const virtualization_table[_VIRTUALIZATION_MAX] = {
         [VIRTUALIZATION_LXC] = "lxc",
         [VIRTUALIZATION_OPENVZ] = "openvz",
         [VIRTUALIZATION_DOCKER] = "docker",
+        [VIRTUALIZATION_PODMAN] = "podman",
         [VIRTUALIZATION_RKT] = "rkt",
+        [VIRTUALIZATION_WSL] = "wsl",
         [VIRTUALIZATION_CONTAINER_OTHER] = "container-other",
 };