2 This file is part of systemd.
4 Copyright 2011 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include "alloc-util.h"
27 #include "dirent-util.h"
31 #include "process-util.h"
32 #include "stat-util.h"
33 #include "string-table.h"
34 #include "string-util.h"
37 static int detect_vm_cpuid(void) {
39 /* CPUID is an x86 specific interface. */
40 #if defined(__i386__) || defined(__x86_64__)
45 } cpuid_vendor_table
[] = {
46 { "XenVMMXenVMM", VIRTUALIZATION_XEN
},
47 { "KVMKVMKVM", VIRTUALIZATION_KVM
},
48 /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
49 { "VMwareVMware", VIRTUALIZATION_VMWARE
},
50 /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */
51 { "Microsoft Hv", VIRTUALIZATION_MICROSOFT
},
57 /* http://lwn.net/Articles/301888/ */
59 #if defined (__i386__)
62 #elif defined (__amd64__)
67 /* First detect whether there is a hypervisor */
69 __asm__
__volatile__ (
70 /* ebx/rbx is being used for PIC! */
71 " push %%"REG_b
" \n\t"
75 : "=a" (eax
), "=c" (ecx
)
79 hypervisor
= !!(ecx
& 0x80000000U
);
88 /* There is a hypervisor, see what it is */
90 __asm__
__volatile__ (
91 /* ebx/rbx is being used for PIC! */
92 " push %%"REG_b
" \n\t"
97 : "=a" (eax
), "=r" (sig
.sig32
[0]), "=c" (sig
.sig32
[1]), "=d" (sig
.sig32
[2])
101 for (j
= 0; j
< ELEMENTSOF(cpuid_vendor_table
); j
++)
102 if (streq(sig
.text
, cpuid_vendor_table
[j
].cpuid
))
103 return cpuid_vendor_table
[j
].id
;
105 return VIRTUALIZATION_VM_OTHER
;
109 return VIRTUALIZATION_NONE
;
112 static int detect_vm_device_tree(void) {
113 #if defined(__arm__) || defined(__aarch64__) || defined(__powerpc__) || defined(__powerpc64__)
114 _cleanup_free_
char *hvtype
= NULL
;
117 r
= read_one_line_file("/proc/device-tree/hypervisor/compatible", &hvtype
);
119 _cleanup_closedir_
DIR *dir
= NULL
;
122 dir
= opendir("/proc/device-tree");
125 return VIRTUALIZATION_NONE
;
129 FOREACH_DIRENT(dent
, dir
, return -errno
)
130 if (strstr(dent
->d_name
, "fw-cfg"))
131 return VIRTUALIZATION_QEMU
;
133 return VIRTUALIZATION_NONE
;
137 if (streq(hvtype
, "linux,kvm"))
138 return VIRTUALIZATION_KVM
;
139 else if (strstr(hvtype
, "xen"))
140 return VIRTUALIZATION_XEN
;
142 return VIRTUALIZATION_VM_OTHER
;
144 return VIRTUALIZATION_NONE
;
148 static int detect_vm_dmi(void) {
149 #if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
151 static const char *const dmi_vendors
[] = {
152 "/sys/class/dmi/id/product_name", /* Test this before sys_vendor to detect KVM over QEMU */
153 "/sys/class/dmi/id/sys_vendor",
154 "/sys/class/dmi/id/board_vendor",
155 "/sys/class/dmi/id/bios_vendor"
158 static const struct {
161 } dmi_vendor_table
[] = {
162 { "KVM", VIRTUALIZATION_KVM
},
163 { "QEMU", VIRTUALIZATION_QEMU
},
164 /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
165 { "VMware", VIRTUALIZATION_VMWARE
},
166 { "VMW", VIRTUALIZATION_VMWARE
},
167 { "innotek GmbH", VIRTUALIZATION_ORACLE
},
168 { "Xen", VIRTUALIZATION_XEN
},
169 { "Bochs", VIRTUALIZATION_BOCHS
},
170 { "Parallels", VIRTUALIZATION_PARALLELS
},
175 for (i
= 0; i
< ELEMENTSOF(dmi_vendors
); i
++) {
176 _cleanup_free_
char *s
= NULL
;
179 r
= read_one_line_file(dmi_vendors
[i
], &s
);
187 for (j
= 0; j
< ELEMENTSOF(dmi_vendor_table
); j
++)
188 if (startswith(s
, dmi_vendor_table
[j
].vendor
))
189 return dmi_vendor_table
[j
].id
;
193 return VIRTUALIZATION_NONE
;
196 static int detect_vm_xen(void) {
197 _cleanup_free_
char *domcap
= NULL
;
201 r
= read_one_line_file("/proc/xen/capabilities", &domcap
);
203 return VIRTUALIZATION_NONE
;
206 while ((cap
= strsep(&i
, ",")))
207 if (streq(cap
, "control_d"))
210 return cap
? VIRTUALIZATION_NONE
: VIRTUALIZATION_XEN
;
213 static int detect_vm_hypervisor(void) {
214 _cleanup_free_
char *hvtype
= NULL
;
217 r
= read_one_line_file("/sys/hypervisor/type", &hvtype
);
219 return VIRTUALIZATION_NONE
;
223 if (streq(hvtype
, "xen"))
224 return VIRTUALIZATION_XEN
;
226 return VIRTUALIZATION_VM_OTHER
;
229 static int detect_vm_uml(void) {
230 _cleanup_free_
char *cpuinfo_contents
= NULL
;
233 /* Detect User-Mode Linux by reading /proc/cpuinfo */
234 r
= read_full_file("/proc/cpuinfo", &cpuinfo_contents
, NULL
);
237 if (strstr(cpuinfo_contents
, "\nvendor_id\t: User Mode Linux\n"))
238 return VIRTUALIZATION_UML
;
240 return VIRTUALIZATION_NONE
;
243 static int detect_vm_zvm(void) {
245 #if defined(__s390__)
246 _cleanup_free_
char *t
= NULL
;
249 r
= get_proc_field("/proc/sysinfo", "VM00 Control Program", WHITESPACE
, &t
);
251 return VIRTUALIZATION_NONE
;
255 if (streq(t
, "z/VM"))
256 return VIRTUALIZATION_ZVM
;
258 return VIRTUALIZATION_KVM
;
260 return VIRTUALIZATION_NONE
;
264 /* Returns a short identifier for the various VM implementations */
265 int detect_vm(void) {
266 static thread_local
int cached_found
= _VIRTUALIZATION_INVALID
;
269 if (cached_found
>= 0)
272 /* We have to use the correct order here:
273 * Some virtualization technologies do use KVM hypervisor but are
274 * expected to be detected as something else. So detect DMI first.
276 * An example is Virtualbox since version 5.0, which uses KVM backend.
277 * Detection via DMI works corretly, the CPU ID would find KVM
282 if (r
!= VIRTUALIZATION_NONE
)
285 r
= detect_vm_cpuid();
288 if (r
!= VIRTUALIZATION_NONE
)
291 /* x86 xen will most likely be detected by cpuid. If not (most likely
292 * because we're not an x86 guest), then we should try the xen capabilities
293 * file next. If that's not found, then we check for the high-level
294 * hypervisor sysfs file:
296 * https://bugs.freedesktop.org/show_bug.cgi?id=77271 */
301 if (r
!= VIRTUALIZATION_NONE
)
304 r
= detect_vm_hypervisor();
307 if (r
!= VIRTUALIZATION_NONE
)
310 r
= detect_vm_device_tree();
313 if (r
!= VIRTUALIZATION_NONE
)
319 if (r
!= VIRTUALIZATION_NONE
)
331 int detect_container(void) {
333 static const struct {
337 { "lxc", VIRTUALIZATION_LXC
},
338 { "lxc-libvirt", VIRTUALIZATION_LXC_LIBVIRT
},
339 { "systemd-nspawn", VIRTUALIZATION_SYSTEMD_NSPAWN
},
340 { "docker", VIRTUALIZATION_DOCKER
},
341 { "rkt", VIRTUALIZATION_RKT
},
344 static thread_local
int cached_found
= _VIRTUALIZATION_INVALID
;
345 _cleanup_free_
char *m
= NULL
;
346 const char *e
= NULL
;
350 if (cached_found
>= 0)
353 /* /proc/vz exists in container and outside of the container,
354 * /proc/bc only outside of the container. */
355 if (access("/proc/vz", F_OK
) >= 0 &&
356 access("/proc/bc", F_OK
) < 0) {
357 r
= VIRTUALIZATION_OPENVZ
;
362 /* If we are PID 1 we can just check our own
363 * environment variable */
365 e
= getenv("container");
367 r
= VIRTUALIZATION_NONE
;
372 /* Otherwise, PID 1 dropped this information into a
373 * file in /run. This is better than accessing
374 * /proc/1/environ, since we don't need CAP_SYS_PTRACE
377 r
= read_one_line_file("/run/systemd/container", &m
);
380 /* Fallback for cases where PID 1 was not
381 * systemd (for example, cases where
382 * init=/bin/sh is used. */
384 r
= getenv_for_pid(1, "container", &m
);
387 /* If that didn't work, give up,
388 * assume no container manager.
390 * Note: This means we still cannot
391 * detect containers if init=/bin/sh
392 * is passed but privileges dropped,
393 * as /proc/1/environ is only readable
394 * with privileges. */
396 r
= VIRTUALIZATION_NONE
;
406 for (j
= 0; j
< ELEMENTSOF(value_table
); j
++)
407 if (streq(e
, value_table
[j
].value
)) {
408 r
= value_table
[j
].id
;
412 r
= VIRTUALIZATION_CONTAINER_OTHER
;
419 int detect_virtualization(void) {
422 r
= detect_container();
429 int running_in_chroot(void) {
432 ret
= files_same("/proc/1/root", "/");
439 static const char *const virtualization_table
[_VIRTUALIZATION_MAX
] = {
440 [VIRTUALIZATION_NONE
] = "none",
441 [VIRTUALIZATION_KVM
] = "kvm",
442 [VIRTUALIZATION_QEMU
] = "qemu",
443 [VIRTUALIZATION_BOCHS
] = "bochs",
444 [VIRTUALIZATION_XEN
] = "xen",
445 [VIRTUALIZATION_UML
] = "uml",
446 [VIRTUALIZATION_VMWARE
] = "vmware",
447 [VIRTUALIZATION_ORACLE
] = "oracle",
448 [VIRTUALIZATION_MICROSOFT
] = "microsoft",
449 [VIRTUALIZATION_ZVM
] = "zvm",
450 [VIRTUALIZATION_PARALLELS
] = "parallels",
451 [VIRTUALIZATION_VM_OTHER
] = "vm-other",
453 [VIRTUALIZATION_SYSTEMD_NSPAWN
] = "systemd-nspawn",
454 [VIRTUALIZATION_LXC_LIBVIRT
] = "lxc-libvirt",
455 [VIRTUALIZATION_LXC
] = "lxc",
456 [VIRTUALIZATION_OPENVZ
] = "openvz",
457 [VIRTUALIZATION_DOCKER
] = "docker",
458 [VIRTUALIZATION_RKT
] = "rkt",
459 [VIRTUALIZATION_CONTAINER_OTHER
] = "container-other",
462 DEFINE_STRING_TABLE_LOOKUP(virtualization
, int);