virt.c revision d84248ebec77d7d22c2035c786437d0c58641a6b
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering/***
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering This file is part of systemd.
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering Copyright 2011 Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart 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
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
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***/
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include <string.h>
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include <errno.h>
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include <unistd.h>
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include "util.h"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include "process-util.h"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include "virt.h"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include "fileio.h"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
9eb977db5b89b44f254ab40c1876a76b7d7ea2d0Kay Sieversstatic int detect_vm_cpuid(const char **_id) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* Both CPUID and DMI are x86 specific interfaces... */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#if defined(__i386__) || defined(__x86_64__)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
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";
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering uint32_t eax, ecx;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering union {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering uint32_t sig32[3];
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering char text[13];
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering } sig = {};
9eb977db5b89b44f254ab40c1876a76b7d7ea2d0Kay Sievers const char *j, *k;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering bool hypervisor;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* http://lwn.net/Articles/301888/ */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#if defined (__i386__)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#define REG_a "eax"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#define REG_b "ebx"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#elif defined (__amd64__)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#define REG_a "rax"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#define REG_b "rbx"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#endif
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* First detect whether there is a hypervisor */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering eax = 1;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering __asm__ __volatile__ (
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* ebx/rbx is being used for PIC! */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering " push %%"REG_b" \n\t"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering " cpuid \n\t"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering " pop %%"REG_b" \n\t"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering : "=a" (eax), "=c" (ecx)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering : "0" (eax)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering );
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering hypervisor = !!(ecx & 0x80000000U);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (hypervisor) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* There is a hypervisor, see what it is */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering eax = 0x40000000U;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering __asm__ __volatile__ (
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* ebx/rbx is being used for PIC! */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering " push %%"REG_b" \n\t"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering " cpuid \n\t"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering " mov %%ebx, %1 \n\t"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering " pop %%"REG_b" \n\t"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
d2e54fae5ca7a0f71b5ac8b356a589ff0a09ea0aKay Sievers : "=a" (eax), "=r" (sig.sig32[0]), "=c" (sig.sig32[1]), "=d" (sig.sig32[2])
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering : "0" (eax)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering );
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering NULSTR_FOREACH_PAIR(j, k, cpuid_vendor_table)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (streq(sig.text, j)) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering *_id = k;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return 1;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering *_id = "other";
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return 0;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering#endif
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return 0;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering}
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringstatic int detect_vm_devicetree(const char **_id) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#if defined(__arm__) || defined(__aarch64__) || defined(__powerpc__) || defined(__powerpc64__)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering _cleanup_free_ char *hvtype = NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering int r;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = read_one_line_file("/proc/device-tree/hypervisor/compatible", &hvtype);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (r >= 0) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (streq(hvtype, "linux,kvm")) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering *_id = "kvm";
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return 1;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering } else if (strstr(hvtype, "xen")) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering *_id = "xen";
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return 1;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering } else if (r == -ENOENT) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering _cleanup_closedir_ DIR *dir = NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering struct dirent *dent;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering dir = opendir("/proc/device-tree");
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (!dir) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (errno == ENOENT)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return 0;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return -errno;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering FOREACH_DIRENT(dent, dir, return -errno) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (strstr(dent->d_name, "fw-cfg")) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering *_id = "qemu";
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return 1;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#endif
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return 0;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering}
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringstatic int detect_vm_dmi(const char **_id) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* Both CPUID and DMI are x86 specific interfaces... */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#if defined(__i386__) || defined(__x86_64__)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering static const char *const dmi_vendors[] = {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "/sys/class/dmi/id/sys_vendor",
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "/sys/class/dmi/id/board_vendor",
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering "/sys/class/dmi/id/bios_vendor"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering };
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
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 unsigned i;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering _cleanup_free_ char *s = NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering const char *j, *k;
d889a2069a87e4617b32ddbdeace5a53a12c699dLennart Poettering int r;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = read_one_line_file(dmi_vendors[i], &s);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (r < 0) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (r != -ENOENT)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return r;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering continue;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering NULSTR_FOREACH_PAIR(j, k, dmi_vendor_table)
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering if (startswith(s, j)) {
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering *_id = k;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return 1;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#endif
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return 0;
d889a2069a87e4617b32ddbdeace5a53a12c699dLennart Poettering}
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering/* Returns a short identifier for the various VM implementations */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringint detect_vm(const char **id) {
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 int r;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (_likely_(cached_found >= 0)) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (id)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering *id = cached_id;
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering return cached_found;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* Try xen capabilities file first, if not found try high-level hypervisor sysfs file:
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering *
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering * https://bugs.freedesktop.org/show_bug.cgi?id=77271 */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = read_one_line_file("/proc/xen/capabilities", &domcap);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (r >= 0) {
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering char *cap, *i = domcap;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering while ((cap = strsep(&i, ",")))
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (streq(cap, "control_d"))
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering break;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering if (!cap) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering _id = "xen";
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = 1;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering goto finish;
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering } else if (r == -ENOENT) {
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering _cleanup_free_ char *hvtype = NULL;
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering r = read_one_line_file("/sys/hypervisor/type", &hvtype);
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering if (r >= 0) {
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering if (streq(hvtype, "xen")) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering _id = "xen";
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = 1;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering goto finish;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering } else if (r != -ENOENT)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return r;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering } else
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return r;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* this will set _id to "other" and return 0 for unknown hypervisors */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = detect_vm_cpuid(&_id);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* finish when found a known hypervisor other than kvm */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (r < 0 || (r > 0 && !streq(_id, "kvm")))
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering goto finish;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering _id_cpuid = _id;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = detect_vm_dmi(&_id);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* kvm with and without Virtualbox */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* Parallels exports KVMKVMKVM leaf */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (streq_ptr(_id_cpuid, "kvm")) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (r > 0 && (streq(_id, "oracle") || streq(_id, "parallels")))
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering goto finish;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering _id = _id_cpuid;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = 1;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering goto finish;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* information from dmi */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (r != 0)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering goto finish;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = detect_vm_devicetree(&_id);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (r != 0)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering goto finish;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (_id) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* "other" */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = 1;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering goto finish;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* Detect User-Mode Linux by reading /proc/cpuinfo */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = read_full_file("/proc/cpuinfo", &cpuinfo_contents, NULL);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (r < 0)
d2e54fae5ca7a0f71b5ac8b356a589ff0a09ea0aKay Sievers return r;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (strstr(cpuinfo_contents, "\nvendor_id\t: User Mode Linux\n")) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering _id = "uml";
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = 1;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering goto finish;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#if defined(__s390__)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering _cleanup_free_ char *t = NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = get_status_field("/proc/sysinfo", "VM00 Control Program:", &t);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (r >= 0) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (streq(t, "z/VM"))
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering _id = "zvm";
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering else
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering _id = "kvm";
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = 1;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering goto finish;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#endif
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = 0;
069cfc85f876bb6966cb5a9bbe0235f5064622cdLennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringfinish:
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering cached_found = r;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering cached_id = _id;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (id)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering *id = _id;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return r;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering}
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringint detect_container(const char **id) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering static thread_local int cached_found = -1;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering static thread_local const char *cached_id = NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering _cleanup_free_ char *m = NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering const char *_id = NULL, *e = NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering int r;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (_likely_(cached_found >= 0)) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (id)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering *id = cached_id;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return cached_found;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* /proc/vz exists in container and outside of the container,
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering * /proc/bc only outside of the container. */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (access("/proc/vz", F_OK) >= 0 &&
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering access("/proc/bc", F_OK) < 0) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering _id = "openvz";
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = 1;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering goto finish;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (getpid() == 1) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* If we are PID 1 we can just check our own
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering * environment variable */
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering e = getenv("container");
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (isempty(e)) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = 0;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering goto finish;
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering }
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering } else {
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering
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
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering r = read_one_line_file("/run/systemd/container", &m);
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering if (r == -ENOENT) {
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering /* Fallback for cases where PID 1 was not
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering * systemd (for example, cases where
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering * init=/bin/sh is used. */
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering r = getenv_for_pid(1, "container", &m);
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering if (r <= 0) {
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering /* If that didn't work, give up,
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering * assume no container manager.
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering *
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. */
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering r = 0;
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering goto finish;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (r < 0)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return r;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
4943c1c94ba751c98763f4232b4350481b22c90aLennart Poettering e = m;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
4943c1c94ba751c98763f4232b4350481b22c90aLennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* We only recognize a selected few here, since we want to
4943c1c94ba751c98763f4232b4350481b22c90aLennart Poettering * enforce a redacted namespace */
4943c1c94ba751c98763f4232b4350481b22c90aLennart Poettering if (streq(e, "lxc"))
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering _id ="lxc";
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering else if (streq(e, "lxc-libvirt"))
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering _id = "lxc-libvirt";
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering else if (streq(e, "systemd-nspawn"))
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering _id = "systemd-nspawn";
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering else if (streq(e, "docker"))
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering _id = "docker";
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering else
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering _id = "other";
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = 1;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringfinish:
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering cached_found = r;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering cached_id = _id;
4943c1c94ba751c98763f4232b4350481b22c90aLennart Poettering if (id)
4943c1c94ba751c98763f4232b4350481b22c90aLennart Poettering *id = _id;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return r;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering}
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering/* Returns a short identifier for the various VM/container implementations */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringint detect_virtualization(const char **id) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering int r;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = detect_container(id);
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering if (r < 0)
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering return r;
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering if (r > 0)
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering return VIRTUALIZATION_CONTAINER;
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering r = detect_vm(id);
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering if (r < 0)
return r;
if (r > 0)
return VIRTUALIZATION_VM;
return VIRTUALIZATION_NONE;
}