2011-09-23 17:00:33 +02:00
|
|
|
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
|
|
|
|
|
|
|
/***
|
|
|
|
This file is part of systemd.
|
|
|
|
|
|
|
|
Copyright 2011 Lennart Poettering
|
|
|
|
|
|
|
|
systemd is free software; you can redistribute it and/or modify it
|
2012-04-12 00:20:58 +02:00
|
|
|
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
|
2011-09-23 17:00:33 +02:00
|
|
|
(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
|
2012-04-12 00:20:58 +02:00
|
|
|
Lesser General Public License for more details.
|
2011-09-23 17:00:33 +02:00
|
|
|
|
2012-04-12 00:20:58 +02:00
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
2011-09-23 17:00:33 +02:00
|
|
|
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
***/
|
|
|
|
|
|
|
|
#include <errno.h>
|
2015-11-30 21:43:37 +01:00
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdlib.h>
|
2015-10-24 22:58:24 +02:00
|
|
|
#include <string.h>
|
2011-09-23 17:00:33 +02:00
|
|
|
#include <unistd.h>
|
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "fileio.h"
|
2015-11-30 21:43:37 +01:00
|
|
|
#include "macro.h"
|
2015-12-01 23:22:03 +01:00
|
|
|
#include "process-util.h"
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "stat-util.h"
|
2015-10-26 22:31:05 +01:00
|
|
|
#include "string-table.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "string-util.h"
|
2011-09-23 17:00:33 +02:00
|
|
|
#include "virt.h"
|
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
static int detect_vm_cpuid(void) {
|
2011-09-23 17:00:33 +02:00
|
|
|
|
2015-11-03 19:10:13 +01:00
|
|
|
/* CPUID is an x86 specific interface. */
|
2013-11-28 19:34:08 +01:00
|
|
|
#if defined(__i386__) || defined(__x86_64__)
|
2011-09-23 17:00:33 +02:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
static const struct {
|
|
|
|
const char *cpuid;
|
|
|
|
int id;
|
|
|
|
} cpuid_vendor_table[] = {
|
|
|
|
{ "XenVMMXenVMM", VIRTUALIZATION_XEN },
|
|
|
|
{ "KVMKVMKVM", VIRTUALIZATION_KVM },
|
2011-09-23 17:00:33 +02:00
|
|
|
/* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
|
2015-09-07 13:42:47 +02:00
|
|
|
{ "VMwareVMware", VIRTUALIZATION_VMWARE },
|
2011-09-23 17:00:33 +02:00
|
|
|
/* http://msdn.microsoft.com/en-us/library/ff542428.aspx */
|
2015-09-07 13:42:47 +02:00
|
|
|
{ "Microsoft Hv", VIRTUALIZATION_MICROSOFT },
|
|
|
|
};
|
2011-09-23 17:00:33 +02:00
|
|
|
|
|
|
|
uint32_t eax, ecx;
|
|
|
|
bool hypervisor;
|
|
|
|
|
|
|
|
/* http://lwn.net/Articles/301888/ */
|
|
|
|
|
|
|
|
#if defined (__i386__)
|
|
|
|
#define REG_a "eax"
|
|
|
|
#define REG_b "ebx"
|
|
|
|
#elif defined (__amd64__)
|
|
|
|
#define REG_a "rax"
|
|
|
|
#define REG_b "rbx"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* First detect whether there is a hypervisor */
|
|
|
|
eax = 1;
|
|
|
|
__asm__ __volatile__ (
|
|
|
|
/* ebx/rbx is being used for PIC! */
|
|
|
|
" push %%"REG_b" \n\t"
|
|
|
|
" cpuid \n\t"
|
|
|
|
" pop %%"REG_b" \n\t"
|
|
|
|
|
|
|
|
: "=a" (eax), "=c" (ecx)
|
|
|
|
: "0" (eax)
|
|
|
|
);
|
|
|
|
|
|
|
|
hypervisor = !!(ecx & 0x80000000U);
|
|
|
|
|
|
|
|
if (hypervisor) {
|
2015-09-07 13:42:47 +02:00
|
|
|
union {
|
|
|
|
uint32_t sig32[3];
|
|
|
|
char text[13];
|
|
|
|
} sig = {};
|
|
|
|
unsigned j;
|
2011-09-23 17:00:33 +02:00
|
|
|
|
|
|
|
/* There is a hypervisor, see what it is */
|
|
|
|
eax = 0x40000000U;
|
|
|
|
__asm__ __volatile__ (
|
|
|
|
/* ebx/rbx is being used for PIC! */
|
|
|
|
" 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)
|
|
|
|
);
|
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
for (j = 0; j < ELEMENTSOF(cpuid_vendor_table); j ++)
|
|
|
|
if (streq(sig.text, cpuid_vendor_table[j].cpuid))
|
|
|
|
return cpuid_vendor_table[j].id;
|
2013-11-28 19:34:08 +01:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
return VIRTUALIZATION_VM_OTHER;
|
2011-09-23 17:00:33 +02:00
|
|
|
}
|
2013-11-28 19:34:08 +01:00
|
|
|
#endif
|
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
return VIRTUALIZATION_NONE;
|
2013-11-28 19:34:08 +01:00
|
|
|
}
|
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
static int detect_vm_device_tree(void) {
|
2015-03-31 11:08:12 +02:00
|
|
|
#if defined(__arm__) || defined(__aarch64__) || defined(__powerpc__) || defined(__powerpc64__)
|
2015-02-04 00:56:06 +01:00
|
|
|
_cleanup_free_ char *hvtype = NULL;
|
|
|
|
int r;
|
|
|
|
|
2015-03-31 11:08:11 +02:00
|
|
|
r = read_one_line_file("/proc/device-tree/hypervisor/compatible", &hvtype);
|
2015-09-07 13:42:47 +02:00
|
|
|
if (r == -ENOENT) {
|
ARM: detect-virt: detect QEMU/KVM
QEMU/KVM guests do not have hypervisor nodes, but they do have
fw-cfg nodes (since qemu v2.3.0-rc0). fw-cfg nodes are documented,
see kernel doc Documentation/devicetree/bindings/arm/fw-cfg.txt,
and therefore we should be able to rely on it in this detection.
Unfortunately, we currently don't have enough information in the
DT, or elsewhere, to determine if we're using KVM acceleration
with QEMU or not, so we can only report 'qemu' at this time, even
if KVM is in use. This shouldn't really matter in practice though,
because if detect-virt is used interactively it will be clear to
the user whether or not KVM acceleration is present by the overall
speed of the guest. If used by a script, then the script's behavior
should not change whether it's 'qemu' or 'kvm'. QEMU emulated
guests and QEMU/KVM guests of the same type should behave
identically, only the speed at which they run should differ.
2015-03-31 11:08:13 +02:00
|
|
|
_cleanup_closedir_ DIR *dir = NULL;
|
|
|
|
struct dirent *dent;
|
|
|
|
|
|
|
|
dir = opendir("/proc/device-tree");
|
|
|
|
if (!dir) {
|
|
|
|
if (errno == ENOENT)
|
2015-09-07 13:42:47 +02:00
|
|
|
return VIRTUALIZATION_NONE;
|
ARM: detect-virt: detect QEMU/KVM
QEMU/KVM guests do not have hypervisor nodes, but they do have
fw-cfg nodes (since qemu v2.3.0-rc0). fw-cfg nodes are documented,
see kernel doc Documentation/devicetree/bindings/arm/fw-cfg.txt,
and therefore we should be able to rely on it in this detection.
Unfortunately, we currently don't have enough information in the
DT, or elsewhere, to determine if we're using KVM acceleration
with QEMU or not, so we can only report 'qemu' at this time, even
if KVM is in use. This shouldn't really matter in practice though,
because if detect-virt is used interactively it will be clear to
the user whether or not KVM acceleration is present by the overall
speed of the guest. If used by a script, then the script's behavior
should not change whether it's 'qemu' or 'kvm'. QEMU emulated
guests and QEMU/KVM guests of the same type should behave
identically, only the speed at which they run should differ.
2015-03-31 11:08:13 +02:00
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
FOREACH_DIRENT(dent, dir, return -errno)
|
|
|
|
if (strstr(dent->d_name, "fw-cfg"))
|
|
|
|
return VIRTUALIZATION_QEMU;
|
|
|
|
|
|
|
|
return VIRTUALIZATION_NONE;
|
|
|
|
} else if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (streq(hvtype, "linux,kvm"))
|
|
|
|
return VIRTUALIZATION_KVM;
|
|
|
|
else if (strstr(hvtype, "xen"))
|
|
|
|
return VIRTUALIZATION_XEN;
|
|
|
|
else
|
|
|
|
return VIRTUALIZATION_VM_OTHER;
|
|
|
|
#else
|
|
|
|
return VIRTUALIZATION_NONE;
|
2015-02-04 00:56:06 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
static int detect_vm_dmi(void) {
|
2015-11-03 19:10:13 +01:00
|
|
|
#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
|
2013-11-28 19:34:08 +01:00
|
|
|
|
|
|
|
static const char *const dmi_vendors[] = {
|
2015-11-03 20:31:03 +01:00
|
|
|
"/sys/class/dmi/id/product_name", /* Test this before sys_vendor to detect KVM over QEMU */
|
2013-11-28 19:34:08 +01:00
|
|
|
"/sys/class/dmi/id/sys_vendor",
|
|
|
|
"/sys/class/dmi/id/board_vendor",
|
|
|
|
"/sys/class/dmi/id/bios_vendor"
|
|
|
|
};
|
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
static const struct {
|
|
|
|
const char *vendor;
|
|
|
|
int id;
|
|
|
|
} dmi_vendor_table[] = {
|
2015-11-03 20:31:03 +01:00
|
|
|
{ "KVM", VIRTUALIZATION_KVM },
|
2015-09-07 13:42:47 +02:00
|
|
|
{ "QEMU", VIRTUALIZATION_QEMU },
|
2013-11-28 19:34:08 +01:00
|
|
|
/* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
|
2015-09-07 13:42:47 +02:00
|
|
|
{ "VMware", VIRTUALIZATION_VMWARE },
|
|
|
|
{ "VMW", VIRTUALIZATION_VMWARE },
|
|
|
|
{ "innotek GmbH", VIRTUALIZATION_ORACLE },
|
|
|
|
{ "Xen", VIRTUALIZATION_XEN },
|
|
|
|
{ "Bochs", VIRTUALIZATION_BOCHS },
|
|
|
|
{ "Parallels", VIRTUALIZATION_PARALLELS },
|
|
|
|
};
|
2013-11-28 19:34:08 +01:00
|
|
|
unsigned i;
|
2015-09-07 13:42:47 +02:00
|
|
|
int r;
|
2011-09-23 17:00:33 +02:00
|
|
|
|
|
|
|
for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) {
|
2013-03-07 15:59:26 +01:00
|
|
|
_cleanup_free_ char *s = NULL;
|
2015-09-07 13:42:47 +02:00
|
|
|
unsigned j;
|
2011-09-23 17:00:33 +02:00
|
|
|
|
2013-03-07 15:59:26 +01:00
|
|
|
r = read_one_line_file(dmi_vendors[i], &s);
|
|
|
|
if (r < 0) {
|
2015-09-07 13:42:47 +02:00
|
|
|
if (r == -ENOENT)
|
|
|
|
continue;
|
2011-09-23 17:00:33 +02:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
return r;
|
2011-09-23 17:00:33 +02:00
|
|
|
}
|
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
for (j = 0; j < ELEMENTSOF(dmi_vendor_table); j++)
|
|
|
|
if (startswith(s, dmi_vendor_table[j].vendor))
|
|
|
|
return dmi_vendor_table[j].id;
|
2011-09-23 17:00:33 +02:00
|
|
|
}
|
2013-11-28 19:34:08 +01:00
|
|
|
#endif
|
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
return VIRTUALIZATION_NONE;
|
2013-11-28 19:34:08 +01:00
|
|
|
}
|
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
static int detect_vm_xen(void) {
|
|
|
|
_cleanup_free_ char *domcap = NULL;
|
|
|
|
char *cap, *i;
|
2013-11-28 19:34:08 +01:00
|
|
|
int r;
|
2011-09-23 17:00:33 +02:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
r = read_one_line_file("/proc/xen/capabilities", &domcap);
|
|
|
|
if (r == -ENOENT)
|
|
|
|
return VIRTUALIZATION_NONE;
|
2013-11-28 19:34:08 +01:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
i = domcap;
|
|
|
|
while ((cap = strsep(&i, ",")))
|
|
|
|
if (streq(cap, "control_d"))
|
|
|
|
break;
|
2013-11-28 19:34:08 +01:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
return cap ? VIRTUALIZATION_NONE : VIRTUALIZATION_XEN;
|
|
|
|
}
|
2014-06-06 16:36:45 +02:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
static int detect_vm_hypervisor(void) {
|
|
|
|
_cleanup_free_ char *hvtype = NULL;
|
|
|
|
int r;
|
2014-06-06 16:36:45 +02:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
r = read_one_line_file("/sys/hypervisor/type", &hvtype);
|
|
|
|
if (r == -ENOENT)
|
|
|
|
return VIRTUALIZATION_NONE;
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-06-06 16:36:45 +02:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
if (streq(hvtype, "xen"))
|
|
|
|
return VIRTUALIZATION_XEN;
|
|
|
|
else
|
|
|
|
return VIRTUALIZATION_VM_OTHER;
|
|
|
|
}
|
2014-06-06 16:36:45 +02:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
static int detect_vm_uml(void) {
|
|
|
|
_cleanup_free_ char *cpuinfo_contents = NULL;
|
|
|
|
int r;
|
2014-06-06 16:36:45 +02:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
/* Detect User-Mode Linux by reading /proc/cpuinfo */
|
|
|
|
r = read_full_file("/proc/cpuinfo", &cpuinfo_contents, NULL);
|
|
|
|
if (r < 0)
|
2013-11-28 19:34:08 +01:00
|
|
|
return r;
|
2015-09-07 13:42:47 +02:00
|
|
|
if (strstr(cpuinfo_contents, "\nvendor_id\t: User Mode Linux\n"))
|
|
|
|
return VIRTUALIZATION_UML;
|
2013-11-28 19:34:08 +01:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
return VIRTUALIZATION_NONE;
|
|
|
|
}
|
2015-07-23 21:18:36 +02:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
static int detect_vm_zvm(void) {
|
2013-11-28 19:34:08 +01:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
#if defined(__s390__)
|
|
|
|
_cleanup_free_ char *t = NULL;
|
|
|
|
int r;
|
2015-07-23 21:18:36 +02:00
|
|
|
|
2015-09-30 14:57:55 +02:00
|
|
|
r = get_proc_field("/proc/sysinfo", "VM00 Control Program", WHITESPACE, &t);
|
2015-09-07 13:42:47 +02:00
|
|
|
if (r == -ENOENT)
|
|
|
|
return VIRTUALIZATION_NONE;
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2015-07-23 21:18:36 +02:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
if (streq(t, "z/VM"))
|
|
|
|
return VIRTUALIZATION_ZVM;
|
|
|
|
else
|
|
|
|
return VIRTUALIZATION_KVM;
|
|
|
|
#else
|
|
|
|
return VIRTUALIZATION_NONE;
|
|
|
|
#endif
|
|
|
|
}
|
2015-07-23 21:18:36 +02:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
/* Returns a short identifier for the various VM implementations */
|
|
|
|
int detect_vm(void) {
|
|
|
|
static thread_local int cached_found = _VIRTUALIZATION_INVALID;
|
|
|
|
int r;
|
2015-07-23 21:18:36 +02:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
if (cached_found >= 0)
|
|
|
|
return cached_found;
|
2013-11-28 19:34:08 +01:00
|
|
|
|
2015-11-23 19:15:25 +01:00
|
|
|
/* We have to use the correct order here:
|
|
|
|
* Some virtualization technologies do use KVM hypervisor but are
|
|
|
|
* expected to be detected as something else. So detect DMI first.
|
|
|
|
*
|
|
|
|
* An example is Virtualbox since version 5.0, which uses KVM backend.
|
|
|
|
* Detection via DMI works corretly, the CPU ID would find KVM
|
|
|
|
* only. */
|
2015-11-23 13:55:04 +01:00
|
|
|
r = detect_vm_dmi();
|
2015-09-07 13:42:47 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r != VIRTUALIZATION_NONE)
|
2015-02-04 00:56:06 +01:00
|
|
|
goto finish;
|
|
|
|
|
2015-11-23 13:55:04 +01:00
|
|
|
r = detect_vm_cpuid();
|
2015-09-07 13:42:47 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r != VIRTUALIZATION_NONE)
|
2013-10-31 16:23:06 +01:00
|
|
|
goto finish;
|
2011-09-23 17:00:33 +02:00
|
|
|
|
2015-11-03 21:49:38 +01:00
|
|
|
/* x86 xen will most likely be detected by cpuid. If not (most likely
|
|
|
|
* because we're not an x86 guest), then we should try the xen capabilities
|
|
|
|
* file next. If that's not found, then we check for the high-level
|
|
|
|
* hypervisor sysfs file:
|
|
|
|
*
|
|
|
|
* https://bugs.freedesktop.org/show_bug.cgi?id=77271 */
|
|
|
|
|
|
|
|
r = detect_vm_xen();
|
2013-07-16 13:14:40 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2015-09-07 13:42:47 +02:00
|
|
|
if (r != VIRTUALIZATION_NONE)
|
2013-10-31 16:23:06 +01:00
|
|
|
goto finish;
|
2013-07-16 13:14:40 +02:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
r = detect_vm_hypervisor();
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r != VIRTUALIZATION_NONE)
|
|
|
|
goto finish;
|
2014-07-18 15:13:36 +02:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
r = detect_vm_device_tree();
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r != VIRTUALIZATION_NONE)
|
|
|
|
goto finish;
|
2014-07-18 15:13:36 +02:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
r = detect_vm_uml();
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r != VIRTUALIZATION_NONE)
|
|
|
|
goto finish;
|
2014-07-18 15:13:36 +02:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
r = detect_vm_zvm();
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2013-10-31 16:23:06 +01:00
|
|
|
|
|
|
|
finish:
|
|
|
|
cached_found = r;
|
|
|
|
return r;
|
2011-09-23 17:00:33 +02:00
|
|
|
}
|
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
int detect_container(void) {
|
2013-10-31 16:23:06 +01:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
static const struct {
|
|
|
|
const char *value;
|
|
|
|
int id;
|
|
|
|
} value_table[] = {
|
|
|
|
{ "lxc", VIRTUALIZATION_LXC },
|
|
|
|
{ "lxc-libvirt", VIRTUALIZATION_LXC_LIBVIRT },
|
|
|
|
{ "systemd-nspawn", VIRTUALIZATION_SYSTEMD_NSPAWN },
|
|
|
|
{ "docker", VIRTUALIZATION_DOCKER },
|
2015-11-09 14:37:43 +01:00
|
|
|
{ "rkt", VIRTUALIZATION_RKT },
|
2015-09-07 13:42:47 +02:00
|
|
|
};
|
2013-10-31 16:23:06 +01:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
static thread_local int cached_found = _VIRTUALIZATION_INVALID;
|
2014-05-28 12:37:11 +02:00
|
|
|
_cleanup_free_ char *m = NULL;
|
2015-09-07 13:42:47 +02:00
|
|
|
const char *e = NULL;
|
|
|
|
unsigned j;
|
2012-04-22 14:48:46 +02:00
|
|
|
int r;
|
2011-09-23 17:00:33 +02:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
if (cached_found >= 0)
|
2013-10-31 16:23:06 +01:00
|
|
|
return cached_found;
|
|
|
|
|
2011-09-23 17:00:33 +02:00
|
|
|
/* /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) {
|
2015-09-07 13:42:47 +02:00
|
|
|
r = VIRTUALIZATION_OPENVZ;
|
2013-10-31 16:23:06 +01:00
|
|
|
goto finish;
|
2011-09-23 17:00:33 +02:00
|
|
|
}
|
|
|
|
|
2014-05-28 12:37:11 +02:00
|
|
|
if (getpid() == 1) {
|
|
|
|
/* If we are PID 1 we can just check our own
|
|
|
|
* environment variable */
|
|
|
|
|
|
|
|
e = getenv("container");
|
|
|
|
if (isempty(e)) {
|
2015-09-07 13:42:47 +02:00
|
|
|
r = VIRTUALIZATION_NONE;
|
2014-05-28 12:37:11 +02:00
|
|
|
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) {
|
2014-12-10 13:23:49 +01:00
|
|
|
|
|
|
|
/* Fallback for cases where PID 1 was not
|
|
|
|
* systemd (for example, cases where
|
|
|
|
* init=/bin/sh is used. */
|
|
|
|
|
|
|
|
r = getenv_for_pid(1, "container", &m);
|
|
|
|
if (r <= 0) {
|
|
|
|
|
|
|
|
/* If that didn't work, give up,
|
|
|
|
* assume no container manager.
|
|
|
|
*
|
|
|
|
* Note: This means we still cannot
|
|
|
|
* detect containers if init=/bin/sh
|
|
|
|
* is passed but privileges dropped,
|
|
|
|
* as /proc/1/environ is only readable
|
|
|
|
* with privileges. */
|
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
r = VIRTUALIZATION_NONE;
|
2014-12-10 13:23:49 +01:00
|
|
|
goto finish;
|
|
|
|
}
|
2014-05-28 12:37:11 +02:00
|
|
|
}
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
e = m;
|
|
|
|
}
|
2011-09-23 17:00:33 +02:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
for (j = 0; j < ELEMENTSOF(value_table); j++)
|
|
|
|
if (streq(e, value_table[j].value)) {
|
|
|
|
r = value_table[j].id;
|
|
|
|
goto finish;
|
|
|
|
}
|
2013-10-31 16:23:06 +01:00
|
|
|
|
2015-11-09 23:47:29 +01:00
|
|
|
r = VIRTUALIZATION_CONTAINER_OTHER;
|
2014-05-28 12:37:11 +02:00
|
|
|
|
2013-10-31 16:23:06 +01:00
|
|
|
finish:
|
|
|
|
cached_found = r;
|
2012-04-22 14:48:46 +02:00
|
|
|
return r;
|
2011-09-23 17:00:33 +02:00
|
|
|
}
|
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
int detect_virtualization(void) {
|
2011-09-23 17:00:33 +02:00
|
|
|
int r;
|
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
r = detect_container();
|
|
|
|
if (r != 0)
|
2013-10-31 16:23:06 +01:00
|
|
|
return r;
|
2011-09-23 17:00:33 +02:00
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
return detect_vm();
|
2011-09-23 17:00:33 +02:00
|
|
|
}
|
2015-09-07 13:42:47 +02:00
|
|
|
|
2015-10-27 00:07:27 +01:00
|
|
|
int running_in_chroot(void) {
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = files_same("/proc/1/root", "/");
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return ret == 0;
|
|
|
|
}
|
|
|
|
|
2015-09-07 13:42:47 +02:00
|
|
|
static const char *const virtualization_table[_VIRTUALIZATION_MAX] = {
|
|
|
|
[VIRTUALIZATION_NONE] = "none",
|
|
|
|
[VIRTUALIZATION_KVM] = "kvm",
|
|
|
|
[VIRTUALIZATION_QEMU] = "qemu",
|
|
|
|
[VIRTUALIZATION_BOCHS] = "bochs",
|
|
|
|
[VIRTUALIZATION_XEN] = "xen",
|
|
|
|
[VIRTUALIZATION_UML] = "uml",
|
|
|
|
[VIRTUALIZATION_VMWARE] = "vmware",
|
|
|
|
[VIRTUALIZATION_ORACLE] = "oracle",
|
|
|
|
[VIRTUALIZATION_MICROSOFT] = "microsoft",
|
|
|
|
[VIRTUALIZATION_ZVM] = "zvm",
|
|
|
|
[VIRTUALIZATION_PARALLELS] = "parallels",
|
|
|
|
[VIRTUALIZATION_VM_OTHER] = "vm-other",
|
|
|
|
|
|
|
|
[VIRTUALIZATION_SYSTEMD_NSPAWN] = "systemd-nspawn",
|
|
|
|
[VIRTUALIZATION_LXC_LIBVIRT] = "lxc-libvirt",
|
|
|
|
[VIRTUALIZATION_LXC] = "lxc",
|
|
|
|
[VIRTUALIZATION_OPENVZ] = "openvz",
|
|
|
|
[VIRTUALIZATION_DOCKER] = "docker",
|
2015-11-09 14:37:43 +01:00
|
|
|
[VIRTUALIZATION_RKT] = "rkt",
|
2015-09-07 13:42:47 +02:00
|
|
|
[VIRTUALIZATION_CONTAINER_OTHER] = "container-other",
|
|
|
|
};
|
|
|
|
|
|
|
|
DEFINE_STRING_TABLE_LOOKUP(virtualization, int);
|