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 /* Both CPUID and DMI are x86 specific interfaces... */
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) {
144 /* Both CPUID and DMI are x86 specific interfaces... */
145 #if defined(__i386__) || defined(__x86_64__)
147 static const char *const dmi_vendors[] = {
148 "/sys/class/dmi/id/sys_vendor",
149 "/sys/class/dmi/id/board_vendor",
150 "/sys/class/dmi/id/bios_vendor"
153 static const struct {
156 } dmi_vendor_table[] = {
157 { "QEMU", VIRTUALIZATION_QEMU },
158 /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
159 { "VMware", VIRTUALIZATION_VMWARE },
160 { "VMW", VIRTUALIZATION_VMWARE },
161 { "innotek GmbH", VIRTUALIZATION_ORACLE },
162 { "Xen", VIRTUALIZATION_XEN },
163 { "Bochs", VIRTUALIZATION_BOCHS },
164 { "Parallels", VIRTUALIZATION_PARALLELS },
169 for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) {
170 _cleanup_free_ char *s = NULL;
173 r = read_one_line_file(dmi_vendors[i], &s);
181 for (j = 0; j < ELEMENTSOF(dmi_vendor_table); j++)
182 if (startswith(s, dmi_vendor_table[j].vendor))
183 return dmi_vendor_table[j].id;
187 return VIRTUALIZATION_NONE;
190 static int detect_vm_xen(void) {
191 _cleanup_free_ char *domcap = NULL;
195 r = read_one_line_file("/proc/xen/capabilities", &domcap);
197 return VIRTUALIZATION_NONE;
200 while ((cap = strsep(&i, ",")))
201 if (streq(cap, "control_d"))
204 return cap ? VIRTUALIZATION_NONE : VIRTUALIZATION_XEN;
207 static int detect_vm_hypervisor(void) {
208 _cleanup_free_ char *hvtype = NULL;
211 r = read_one_line_file("/sys/hypervisor/type", &hvtype);
213 return VIRTUALIZATION_NONE;
217 if (streq(hvtype, "xen"))
218 return VIRTUALIZATION_XEN;
220 return VIRTUALIZATION_VM_OTHER;
223 static int detect_vm_uml(void) {
224 _cleanup_free_ char *cpuinfo_contents = NULL;
227 /* Detect User-Mode Linux by reading /proc/cpuinfo */
228 r = read_full_file("/proc/cpuinfo", &cpuinfo_contents, NULL);
231 if (strstr(cpuinfo_contents, "\nvendor_id\t: User Mode Linux\n"))
232 return VIRTUALIZATION_UML;
234 return VIRTUALIZATION_NONE;
237 static int detect_vm_zvm(void) {
239 #if defined(__s390__)
240 _cleanup_free_ char *t = NULL;
243 r = get_proc_field("/proc/sysinfo", "VM00 Control Program", WHITESPACE, &t);
245 return VIRTUALIZATION_NONE;
249 if (streq(t, "z/VM"))
250 return VIRTUALIZATION_ZVM;
252 return VIRTUALIZATION_KVM;
254 return VIRTUALIZATION_NONE;
258 /* Returns a short identifier for the various VM implementations */
259 int detect_vm(void) {
260 static thread_local int cached_found = _VIRTUALIZATION_INVALID;
263 if (cached_found >= 0)
266 /* Try xen capabilities file first, if not found try
267 * high-level hypervisor sysfs file:
269 * https://bugs.freedesktop.org/show_bug.cgi?id=77271 */
274 if (r != VIRTUALIZATION_NONE)
280 if (r != VIRTUALIZATION_NONE)
283 r = detect_vm_cpuid();
286 if (r != VIRTUALIZATION_NONE)
289 r = detect_vm_hypervisor();
292 if (r != VIRTUALIZATION_NONE)
295 r = detect_vm_device_tree();
298 if (r != VIRTUALIZATION_NONE)
304 if (r != VIRTUALIZATION_NONE)
316 int detect_container(void) {
318 static const struct {
322 { "lxc", VIRTUALIZATION_LXC },
323 { "lxc-libvirt", VIRTUALIZATION_LXC_LIBVIRT },
324 { "systemd-nspawn", VIRTUALIZATION_SYSTEMD_NSPAWN },
325 { "docker", VIRTUALIZATION_DOCKER },
328 static thread_local int cached_found = _VIRTUALIZATION_INVALID;
329 _cleanup_free_ char *m = NULL;
330 const char *e = NULL;
334 if (cached_found >= 0)
337 /* /proc/vz exists in container and outside of the container,
338 * /proc/bc only outside of the container. */
339 if (access("/proc/vz", F_OK) >= 0 &&
340 access("/proc/bc", F_OK) < 0) {
341 r = VIRTUALIZATION_OPENVZ;
346 /* If we are PID 1 we can just check our own
347 * environment variable */
349 e = getenv("container");
351 r = VIRTUALIZATION_NONE;
356 /* Otherwise, PID 1 dropped this information into a
357 * file in /run. This is better than accessing
358 * /proc/1/environ, since we don't need CAP_SYS_PTRACE
361 r = read_one_line_file("/run/systemd/container", &m);
364 /* Fallback for cases where PID 1 was not
365 * systemd (for example, cases where
366 * init=/bin/sh is used. */
368 r = getenv_for_pid(1, "container", &m);
371 /* If that didn't work, give up,
372 * assume no container manager.
374 * Note: This means we still cannot
375 * detect containers if init=/bin/sh
376 * is passed but privileges dropped,
377 * as /proc/1/environ is only readable
378 * with privileges. */
380 r = VIRTUALIZATION_NONE;
390 for (j = 0; j < ELEMENTSOF(value_table); j++)
391 if (streq(e, value_table[j].value)) {
392 r = value_table[j].id;
396 r = VIRTUALIZATION_NONE;
403 /// UNNEEDED by elogind
405 int detect_virtualization(void) {
408 r = detect_container();
416 static const char *const virtualization_table[_VIRTUALIZATION_MAX] = {
417 [VIRTUALIZATION_NONE] = "none",
418 [VIRTUALIZATION_KVM] = "kvm",
419 [VIRTUALIZATION_QEMU] = "qemu",
420 [VIRTUALIZATION_BOCHS] = "bochs",
421 [VIRTUALIZATION_XEN] = "xen",
422 [VIRTUALIZATION_UML] = "uml",
423 [VIRTUALIZATION_VMWARE] = "vmware",
424 [VIRTUALIZATION_ORACLE] = "oracle",
425 [VIRTUALIZATION_MICROSOFT] = "microsoft",
426 [VIRTUALIZATION_ZVM] = "zvm",
427 [VIRTUALIZATION_PARALLELS] = "parallels",
428 [VIRTUALIZATION_VM_OTHER] = "vm-other",
430 [VIRTUALIZATION_SYSTEMD_NSPAWN] = "systemd-nspawn",
431 [VIRTUALIZATION_LXC_LIBVIRT] = "lxc-libvirt",
432 [VIRTUALIZATION_LXC] = "lxc",
433 [VIRTUALIZATION_OPENVZ] = "openvz",
434 [VIRTUALIZATION_DOCKER] = "docker",
435 [VIRTUALIZATION_CONTAINER_OTHER] = "container-other",
438 DEFINE_STRING_TABLE_LOOKUP(virtualization, int);