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/>.
27 #include "process-util.h"
31 static int detect_vm_cpuid(void) {
33 /* CPUID is an x86 specific interface. */
34 #if defined(__i386__) || defined(__x86_64__)
39 } cpuid_vendor_table[] = {
40 { "XenVMMXenVMM", VIRTUALIZATION_XEN },
41 { "KVMKVMKVM", VIRTUALIZATION_KVM },
42 /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
43 { "VMwareVMware", VIRTUALIZATION_VMWARE },
44 /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */
45 { "Microsoft Hv", VIRTUALIZATION_MICROSOFT },
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);
82 /* There is a hypervisor, see what it is */
84 __asm__ __volatile__ (
85 /* ebx/rbx is being used for PIC! */
86 " push %%"REG_b" \n\t"
91 : "=a" (eax), "=r" (sig.sig32[0]), "=c" (sig.sig32[1]), "=d" (sig.sig32[2])
95 for (j = 0; j < ELEMENTSOF(cpuid_vendor_table); j ++)
96 if (streq(sig.text, cpuid_vendor_table[j].cpuid))
97 return cpuid_vendor_table[j].id;
99 return VIRTUALIZATION_VM_OTHER;
103 return VIRTUALIZATION_NONE;
106 static int detect_vm_device_tree(void) {
107 #if defined(__arm__) || defined(__aarch64__) || defined(__powerpc__) || defined(__powerpc64__)
108 _cleanup_free_ char *hvtype = NULL;
111 r = read_one_line_file("/proc/device-tree/hypervisor/compatible", &hvtype);
113 _cleanup_closedir_ DIR *dir = NULL;
116 dir = opendir("/proc/device-tree");
119 return VIRTUALIZATION_NONE;
123 FOREACH_DIRENT(dent, dir, return -errno)
124 if (strstr(dent->d_name, "fw-cfg"))
125 return VIRTUALIZATION_QEMU;
127 return VIRTUALIZATION_NONE;
131 if (streq(hvtype, "linux,kvm"))
132 return VIRTUALIZATION_KVM;
133 else if (strstr(hvtype, "xen"))
134 return VIRTUALIZATION_XEN;
136 return VIRTUALIZATION_VM_OTHER;
138 return VIRTUALIZATION_NONE;
142 static int detect_vm_dmi(void) {
143 #if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
145 static const char *const dmi_vendors[] = {
146 "/sys/class/dmi/id/sys_vendor",
147 "/sys/class/dmi/id/board_vendor",
148 "/sys/class/dmi/id/bios_vendor"
151 static const struct {
154 } dmi_vendor_table[] = {
155 { "QEMU", VIRTUALIZATION_QEMU },
156 /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
157 { "VMware", VIRTUALIZATION_VMWARE },
158 { "VMW", VIRTUALIZATION_VMWARE },
159 { "innotek GmbH", VIRTUALIZATION_ORACLE },
160 { "Xen", VIRTUALIZATION_XEN },
161 { "Bochs", VIRTUALIZATION_BOCHS },
162 { "Parallels", VIRTUALIZATION_PARALLELS },
167 for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) {
168 _cleanup_free_ char *s = NULL;
171 r = read_one_line_file(dmi_vendors[i], &s);
179 for (j = 0; j < ELEMENTSOF(dmi_vendor_table); j++)
180 if (startswith(s, dmi_vendor_table[j].vendor))
181 return dmi_vendor_table[j].id;
185 return VIRTUALIZATION_NONE;
188 static int detect_vm_xen(void) {
189 _cleanup_free_ char *domcap = NULL;
193 r = read_one_line_file("/proc/xen/capabilities", &domcap);
195 return VIRTUALIZATION_NONE;
198 while ((cap = strsep(&i, ",")))
199 if (streq(cap, "control_d"))
202 return cap ? VIRTUALIZATION_NONE : VIRTUALIZATION_XEN;
205 static int detect_vm_hypervisor(void) {
206 _cleanup_free_ char *hvtype = NULL;
209 r = read_one_line_file("/sys/hypervisor/type", &hvtype);
211 return VIRTUALIZATION_NONE;
215 if (streq(hvtype, "xen"))
216 return VIRTUALIZATION_XEN;
218 return VIRTUALIZATION_VM_OTHER;
221 static int detect_vm_uml(void) {
222 _cleanup_free_ char *cpuinfo_contents = NULL;
225 /* Detect User-Mode Linux by reading /proc/cpuinfo */
226 r = read_full_file("/proc/cpuinfo", &cpuinfo_contents, NULL);
229 if (strstr(cpuinfo_contents, "\nvendor_id\t: User Mode Linux\n"))
230 return VIRTUALIZATION_UML;
232 return VIRTUALIZATION_NONE;
235 static int detect_vm_zvm(void) {
237 #if defined(__s390__)
238 _cleanup_free_ char *t = NULL;
241 r = get_proc_field("/proc/sysinfo", "VM00 Control Program", WHITESPACE, &t);
243 return VIRTUALIZATION_NONE;
247 if (streq(t, "z/VM"))
248 return VIRTUALIZATION_ZVM;
250 return VIRTUALIZATION_KVM;
252 return VIRTUALIZATION_NONE;
256 /* Returns a short identifier for the various VM implementations */
257 int detect_vm(void) {
258 static thread_local int cached_found = _VIRTUALIZATION_INVALID;
261 if (cached_found >= 0)
264 /* Try xen capabilities file first, if not found try
265 * high-level hypervisor sysfs file:
267 * https://bugs.freedesktop.org/show_bug.cgi?id=77271 */
272 if (r != VIRTUALIZATION_NONE)
278 if (r != VIRTUALIZATION_NONE)
281 r = detect_vm_cpuid();
284 if (r != VIRTUALIZATION_NONE)
287 r = detect_vm_hypervisor();
290 if (r != VIRTUALIZATION_NONE)
293 r = detect_vm_device_tree();
296 if (r != VIRTUALIZATION_NONE)
302 if (r != VIRTUALIZATION_NONE)
314 int detect_container(void) {
316 static const struct {
320 { "lxc", VIRTUALIZATION_LXC },
321 { "lxc-libvirt", VIRTUALIZATION_LXC_LIBVIRT },
322 { "systemd-nspawn", VIRTUALIZATION_SYSTEMD_NSPAWN },
323 { "docker", VIRTUALIZATION_DOCKER },
326 static thread_local int cached_found = _VIRTUALIZATION_INVALID;
327 _cleanup_free_ char *m = NULL;
328 const char *e = NULL;
332 if (cached_found >= 0)
335 /* /proc/vz exists in container and outside of the container,
336 * /proc/bc only outside of the container. */
337 if (access("/proc/vz", F_OK) >= 0 &&
338 access("/proc/bc", F_OK) < 0) {
339 r = VIRTUALIZATION_OPENVZ;
344 /* If we are PID 1 we can just check our own
345 * environment variable */
347 e = getenv("container");
349 r = VIRTUALIZATION_NONE;
354 /* Otherwise, PID 1 dropped this information into a
355 * file in /run. This is better than accessing
356 * /proc/1/environ, since we don't need CAP_SYS_PTRACE
359 r = read_one_line_file("/run/systemd/container", &m);
362 /* Fallback for cases where PID 1 was not
363 * systemd (for example, cases where
364 * init=/bin/sh is used. */
366 r = getenv_for_pid(1, "container", &m);
369 /* If that didn't work, give up,
370 * assume no container manager.
372 * Note: This means we still cannot
373 * detect containers if init=/bin/sh
374 * is passed but privileges dropped,
375 * as /proc/1/environ is only readable
376 * with privileges. */
378 r = VIRTUALIZATION_NONE;
388 for (j = 0; j < ELEMENTSOF(value_table); j++)
389 if (streq(e, value_table[j].value)) {
390 r = value_table[j].id;
394 r = VIRTUALIZATION_NONE;
401 /// UNNEEDED by elogind
403 int detect_virtualization(void) {
406 r = detect_container();
414 static const char *const virtualization_table[_VIRTUALIZATION_MAX] = {
415 [VIRTUALIZATION_NONE] = "none",
416 [VIRTUALIZATION_KVM] = "kvm",
417 [VIRTUALIZATION_QEMU] = "qemu",
418 [VIRTUALIZATION_BOCHS] = "bochs",
419 [VIRTUALIZATION_XEN] = "xen",
420 [VIRTUALIZATION_UML] = "uml",
421 [VIRTUALIZATION_VMWARE] = "vmware",
422 [VIRTUALIZATION_ORACLE] = "oracle",
423 [VIRTUALIZATION_MICROSOFT] = "microsoft",
424 [VIRTUALIZATION_ZVM] = "zvm",
425 [VIRTUALIZATION_PARALLELS] = "parallels",
426 [VIRTUALIZATION_VM_OTHER] = "vm-other",
428 [VIRTUALIZATION_SYSTEMD_NSPAWN] = "systemd-nspawn",
429 [VIRTUALIZATION_LXC_LIBVIRT] = "lxc-libvirt",
430 [VIRTUALIZATION_LXC] = "lxc",
431 [VIRTUALIZATION_OPENVZ] = "openvz",
432 [VIRTUALIZATION_DOCKER] = "docker",
433 [VIRTUALIZATION_CONTAINER_OTHER] = "container-other",
436 DEFINE_STRING_TABLE_LOOKUP(virtualization, int);