1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
30 static int detect_vm_cpuid(const char **_id) {
32 /* Both CPUID and DMI are x86 specific interfaces... */
33 #if defined(__i386__) || defined(__x86_64__)
35 static const char cpuid_vendor_table[] =
36 "XenVMMXenVMM\0" "xen\0"
38 /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
39 "VMwareVMware\0" "vmware\0"
40 /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */
41 "Microsoft Hv\0" "microsoft\0";
51 /* http://lwn.net/Articles/301888/ */
53 #if defined (__i386__)
56 #elif defined (__amd64__)
61 /* First detect whether there is a hypervisor */
63 __asm__ __volatile__ (
64 /* ebx/rbx is being used for PIC! */
65 " push %%"REG_b" \n\t"
69 : "=a" (eax), "=c" (ecx)
73 hypervisor = !!(ecx & 0x80000000U);
77 /* There is a hypervisor, see what it is */
79 __asm__ __volatile__ (
80 /* ebx/rbx is being used for PIC! */
81 " push %%"REG_b" \n\t"
86 : "=a" (eax), "=r" (sig.sig32[0]), "=c" (sig.sig32[1]), "=d" (sig.sig32[2])
90 NULSTR_FOREACH_PAIR(j, k, cpuid_vendor_table)
91 if (streq(sig.text, j)) {
104 static int detect_vm_dmi(const char **_id) {
106 /* Both CPUID and DMI are x86 specific interfaces... */
107 #if defined(__i386__) || defined(__x86_64__)
109 static const char *const dmi_vendors[] = {
110 "/sys/class/dmi/id/sys_vendor",
111 "/sys/class/dmi/id/board_vendor",
112 "/sys/class/dmi/id/bios_vendor"
115 static const char dmi_vendor_table[] =
117 /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
118 "VMware\0" "vmware\0"
120 "Microsoft Corporation\0" "microsoft\0"
121 "innotek GmbH\0" "oracle\0"
126 for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) {
127 _cleanup_free_ char *s = NULL;
131 r = read_one_line_file(dmi_vendors[i], &s);
139 NULSTR_FOREACH_PAIR(j, k, dmi_vendor_table)
140 if (startswith(s, j)) {
150 /* Returns a short identifier for the various VM implementations */
151 int detect_vm(const char **id) {
152 _cleanup_free_ char *hvtype = NULL, *cpuinfo_contents = NULL;
153 static thread_local int cached_found = -1;
154 static thread_local const char *cached_id = NULL;
155 const char *_id = NULL;
158 if (_likely_(cached_found >= 0)) {
166 /* Try high-level hypervisor sysfs file first:
168 * https://bugs.freedesktop.org/show_bug.cgi?id=61491 */
169 r = read_one_line_file("/sys/hypervisor/type", &hvtype);
171 if (streq(hvtype, "xen")) {
176 } else if (r != -ENOENT)
179 /* this will set _id to "other" and return 0 for unknown hypervisors */
180 r = detect_vm_cpuid(&_id);
184 r = detect_vm_dmi(&_id);
194 /* Detect User-Mode Linux by reading /proc/cpuinfo */
195 r = read_full_file("/proc/cpuinfo", &cpuinfo_contents, NULL);
198 if (strstr(cpuinfo_contents, "\nvendor_id\t: User Mode Linux\n")) {
216 int detect_container(const char **id) {
218 static thread_local int cached_found = -1;
219 static thread_local const char *cached_id = NULL;
221 _cleanup_free_ char *e = NULL;
222 const char *_id = NULL;
225 if (_likely_(cached_found >= 0)) {
233 /* Unfortunately many of these operations require root access
234 * in one way or another */
236 r = running_in_chroot();
244 /* /proc/vz exists in container and outside of the container,
245 * /proc/bc only outside of the container. */
246 if (access("/proc/vz", F_OK) >= 0 &&
247 access("/proc/bc", F_OK) < 0) {
253 r = getenv_for_pid(1, "container", &e);
259 /* We only recognize a selected few here, since we want to
260 * enforce a redacted namespace */
263 else if (streq(e, "lxc-libvirt"))
265 else if (streq(e, "systemd-nspawn"))
266 _id = "systemd-nspawn";
280 /* Returns a short identifier for the various VM/container implementations */
281 int detect_virtualization(const char **id) {
284 r = detect_container(id);
288 return VIRTUALIZATION_CONTAINER;
294 return VIRTUALIZATION_VM;
296 return VIRTUALIZATION_NONE;