virt.c revision d7832d2c6e0ef5f2839a2296c1cc2fc85c7d9632
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2011 Lennart Poettering
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(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
General Public License for more details.
You should have received a copy of the GNU General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "util.h"
#include "virt.h"
/* Returns a short identifier for the various VM implementations */
#if defined(__i386__) || defined(__x86_64__)
/* 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"
"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";
static const char cpuid_vendor_table[] =
"XenVMMXenVMM\0" "xen\0"
"KVMKVMKVM\0" "kvm\0"
"VMwareVMware\0" "vmware\0"
"Microsoft Hv\0" "microsoft\0";
union {
char text[13];
} sig;
unsigned i;
const char *j, *k;
bool hypervisor;
#if defined (__i386__)
#define REG_a "eax"
#define REG_b "ebx"
#define REG_a "rax"
#define REG_b "rbx"
#endif
/* First detect whether there is a hypervisor */
eax = 1;
" cpuid \n\t"
: "0" (eax)
);
if (hypervisor) {
/* There is a hypervisor, see what it is */
eax = 0x40000000U;
" cpuid \n\t"
" mov %%ebx, %1 \n\t"
: "0" (eax)
);
if (id)
*id = k;
return 1;
}
}
for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) {
char *s;
int r;
if ((r = read_one_line_file(dmi_vendors[i], &s)) < 0) {
if (r != -ENOENT)
return r;
continue;
}
if (startswith(s, j))
found = k;
free(s);
if (found) {
if (id)
return 1;
}
}
if (hypervisor) {
if (id)
*id = "other";
return 1;
}
#endif
return 0;
}
int detect_container(const char **id) {
FILE *f;
/* Unfortunately many of these operations require root access
* in one way or another */
if (geteuid() != 0)
return -EPERM;
if (running_in_chroot() > 0) {
if (id)
*id = "chroot";
return 1;
}
if (id)
*id = "openvz";
return 1;
}
if (f) {
bool done = false;
do {
unsigned i;
for (i = 0; i < sizeof(line)-1; i++) {
int c;
c = getc(f);
if (_unlikely_(c == EOF)) {
done = true;
break;
} else if (c == 0)
break;
line[i] = c;
}
line[i] = 0;
fclose(f);
if (id)
*id = "lxc";
return 1;
fclose(f);
if (id)
*id = "lxc-libvirt";
return 1;
fclose(f);
if (id)
*id = "systemd-nspawn";
return 1;
fclose(f);
if (id)
*id = "other";
return 1;
}
} while (!done);
fclose(f);
}
return 0;
}
const char *_id;
int r;
if (_likely_(cached_virt >= 0)) {
if (id && cached_virt > 0)
return cached_virt;
}
r = detect_container(&_id);
if (r < 0) {
v = r;
goto finish;
} else if (r > 0) {
goto finish;
}
if (r < 0) {
v = r;
goto finish;
} else if (r > 0) {
v = VIRTUALIZATION_VM;
goto finish;
}
v = VIRTUALIZATION_NONE;
if (v > 0) {
if (id)
}
if (v >= 0)
cached_virt = v;
return v;
}