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/>.
26 #include "alloc-util.h"
27 #include "dirent-util.h"
30 #include "process-util.h"
31 #include "stat-util.h"
32 #include "string-table.h"
33 #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 r
= detect_vm_cpuid();
275 if (r
!= VIRTUALIZATION_NONE
)
281 if (r
!= VIRTUALIZATION_NONE
)
284 /* x86 xen will most likely be detected by cpuid. If not (most likely
285 * because we're not an x86 guest), then we should try the xen capabilities
286 * file next. If that's not found, then we check for the high-level
287 * hypervisor sysfs file:
289 * https://bugs.freedesktop.org/show_bug.cgi?id=77271 */
294 if (r
!= VIRTUALIZATION_NONE
)
297 r
= detect_vm_hypervisor();
300 if (r
!= VIRTUALIZATION_NONE
)
303 r
= detect_vm_device_tree();
306 if (r
!= VIRTUALIZATION_NONE
)
312 if (r
!= VIRTUALIZATION_NONE
)
324 int detect_container(void) {
326 static const struct {
330 { "lxc", VIRTUALIZATION_LXC
},
331 { "lxc-libvirt", VIRTUALIZATION_LXC_LIBVIRT
},
332 { "systemd-nspawn", VIRTUALIZATION_SYSTEMD_NSPAWN
},
333 { "docker", VIRTUALIZATION_DOCKER
},
334 { "rkt", VIRTUALIZATION_RKT
},
337 static thread_local
int cached_found
= _VIRTUALIZATION_INVALID
;
338 _cleanup_free_
char *m
= NULL
;
339 const char *e
= NULL
;
343 if (cached_found
>= 0)
346 /* /proc/vz exists in container and outside of the container,
347 * /proc/bc only outside of the container. */
348 if (access("/proc/vz", F_OK
) >= 0 &&
349 access("/proc/bc", F_OK
) < 0) {
350 r
= VIRTUALIZATION_OPENVZ
;
355 /* If we are PID 1 we can just check our own
356 * environment variable */
358 e
= getenv("container");
360 r
= VIRTUALIZATION_NONE
;
365 /* Otherwise, PID 1 dropped this information into a
366 * file in /run. This is better than accessing
367 * /proc/1/environ, since we don't need CAP_SYS_PTRACE
370 r
= read_one_line_file("/run/systemd/container", &m
);
373 /* Fallback for cases where PID 1 was not
374 * systemd (for example, cases where
375 * init=/bin/sh is used. */
377 r
= getenv_for_pid(1, "container", &m
);
380 /* If that didn't work, give up,
381 * assume no container manager.
383 * Note: This means we still cannot
384 * detect containers if init=/bin/sh
385 * is passed but privileges dropped,
386 * as /proc/1/environ is only readable
387 * with privileges. */
389 r
= VIRTUALIZATION_NONE
;
399 for (j
= 0; j
< ELEMENTSOF(value_table
); j
++)
400 if (streq(e
, value_table
[j
].value
)) {
401 r
= value_table
[j
].id
;
405 r
= VIRTUALIZATION_CONTAINER_OTHER
;
412 int detect_virtualization(void) {
415 r
= detect_container();
422 int running_in_chroot(void) {
425 ret
= files_same("/proc/1/root", "/");
432 static const char *const virtualization_table
[_VIRTUALIZATION_MAX
] = {
433 [VIRTUALIZATION_NONE
] = "none",
434 [VIRTUALIZATION_KVM
] = "kvm",
435 [VIRTUALIZATION_QEMU
] = "qemu",
436 [VIRTUALIZATION_BOCHS
] = "bochs",
437 [VIRTUALIZATION_XEN
] = "xen",
438 [VIRTUALIZATION_UML
] = "uml",
439 [VIRTUALIZATION_VMWARE
] = "vmware",
440 [VIRTUALIZATION_ORACLE
] = "oracle",
441 [VIRTUALIZATION_MICROSOFT
] = "microsoft",
442 [VIRTUALIZATION_ZVM
] = "zvm",
443 [VIRTUALIZATION_PARALLELS
] = "parallels",
444 [VIRTUALIZATION_VM_OTHER
] = "vm-other",
446 [VIRTUALIZATION_SYSTEMD_NSPAWN
] = "systemd-nspawn",
447 [VIRTUALIZATION_LXC_LIBVIRT
] = "lxc-libvirt",
448 [VIRTUALIZATION_LXC
] = "lxc",
449 [VIRTUALIZATION_OPENVZ
] = "openvz",
450 [VIRTUALIZATION_DOCKER
] = "docker",
451 [VIRTUALIZATION_RKT
] = "rkt",
452 [VIRTUALIZATION_CONTAINER_OTHER
] = "container-other",
455 DEFINE_STRING_TABLE_LOOKUP(virtualization
, int);