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"
28 #include "string-util.h"
32 static int detect_vm_cpuid(void) {
34 /* Both CPUID and DMI are x86 specific interfaces... */
35 #if defined(__i386__) || defined(__x86_64__)
40 } cpuid_vendor_table
[] = {
41 { "XenVMMXenVMM", VIRTUALIZATION_XEN
},
42 { "KVMKVMKVM", VIRTUALIZATION_KVM
},
43 /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
44 { "VMwareVMware", VIRTUALIZATION_VMWARE
},
45 /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */
46 { "Microsoft Hv", VIRTUALIZATION_MICROSOFT
},
52 /* http://lwn.net/Articles/301888/ */
54 #if defined (__i386__)
57 #elif defined (__amd64__)
62 /* First detect whether there is a hypervisor */
64 __asm__
__volatile__ (
65 /* ebx/rbx is being used for PIC! */
66 " push %%"REG_b
" \n\t"
70 : "=a" (eax
), "=c" (ecx
)
74 hypervisor
= !!(ecx
& 0x80000000U
);
83 /* There is a hypervisor, see what it is */
85 __asm__
__volatile__ (
86 /* ebx/rbx is being used for PIC! */
87 " push %%"REG_b
" \n\t"
92 : "=a" (eax
), "=r" (sig
.sig32
[0]), "=c" (sig
.sig32
[1]), "=d" (sig
.sig32
[2])
96 for (j
= 0; j
< ELEMENTSOF(cpuid_vendor_table
); j
++)
97 if (streq(sig
.text
, cpuid_vendor_table
[j
].cpuid
))
98 return cpuid_vendor_table
[j
].id
;
100 return VIRTUALIZATION_VM_OTHER
;
104 return VIRTUALIZATION_NONE
;
107 static int detect_vm_device_tree(void) {
108 #if defined(__arm__) || defined(__aarch64__) || defined(__powerpc__) || defined(__powerpc64__)
109 _cleanup_free_
char *hvtype
= NULL
;
112 r
= read_one_line_file("/proc/device-tree/hypervisor/compatible", &hvtype
);
114 _cleanup_closedir_
DIR *dir
= NULL
;
117 dir
= opendir("/proc/device-tree");
120 return VIRTUALIZATION_NONE
;
124 FOREACH_DIRENT(dent
, dir
, return -errno
)
125 if (strstr(dent
->d_name
, "fw-cfg"))
126 return VIRTUALIZATION_QEMU
;
128 return VIRTUALIZATION_NONE
;
132 if (streq(hvtype
, "linux,kvm"))
133 return VIRTUALIZATION_KVM
;
134 else if (strstr(hvtype
, "xen"))
135 return VIRTUALIZATION_XEN
;
137 return VIRTUALIZATION_VM_OTHER
;
139 return VIRTUALIZATION_NONE
;
143 static int detect_vm_dmi(void) {
145 /* Both CPUID and DMI are x86 specific interfaces... */
146 #if defined(__i386__) || defined(__x86_64__)
148 static const char *const dmi_vendors
[] = {
149 "/sys/class/dmi/id/sys_vendor",
150 "/sys/class/dmi/id/board_vendor",
151 "/sys/class/dmi/id/bios_vendor"
154 static const struct {
157 } dmi_vendor_table
[] = {
158 { "QEMU", VIRTUALIZATION_QEMU
},
159 /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
160 { "VMware", VIRTUALIZATION_VMWARE
},
161 { "VMW", VIRTUALIZATION_VMWARE
},
162 { "innotek GmbH", VIRTUALIZATION_ORACLE
},
163 { "Xen", VIRTUALIZATION_XEN
},
164 { "Bochs", VIRTUALIZATION_BOCHS
},
165 { "Parallels", VIRTUALIZATION_PARALLELS
},
170 for (i
= 0; i
< ELEMENTSOF(dmi_vendors
); i
++) {
171 _cleanup_free_
char *s
= NULL
;
174 r
= read_one_line_file(dmi_vendors
[i
], &s
);
182 for (j
= 0; j
< ELEMENTSOF(dmi_vendor_table
); j
++)
183 if (startswith(s
, dmi_vendor_table
[j
].vendor
))
184 return dmi_vendor_table
[j
].id
;
188 return VIRTUALIZATION_NONE
;
191 static int detect_vm_xen(void) {
192 _cleanup_free_
char *domcap
= NULL
;
196 r
= read_one_line_file("/proc/xen/capabilities", &domcap
);
198 return VIRTUALIZATION_NONE
;
201 while ((cap
= strsep(&i
, ",")))
202 if (streq(cap
, "control_d"))
205 return cap
? VIRTUALIZATION_NONE
: VIRTUALIZATION_XEN
;
208 static int detect_vm_hypervisor(void) {
209 _cleanup_free_
char *hvtype
= NULL
;
212 r
= read_one_line_file("/sys/hypervisor/type", &hvtype
);
214 return VIRTUALIZATION_NONE
;
218 if (streq(hvtype
, "xen"))
219 return VIRTUALIZATION_XEN
;
221 return VIRTUALIZATION_VM_OTHER
;
224 static int detect_vm_uml(void) {
225 _cleanup_free_
char *cpuinfo_contents
= NULL
;
228 /* Detect User-Mode Linux by reading /proc/cpuinfo */
229 r
= read_full_file("/proc/cpuinfo", &cpuinfo_contents
, NULL
);
232 if (strstr(cpuinfo_contents
, "\nvendor_id\t: User Mode Linux\n"))
233 return VIRTUALIZATION_UML
;
235 return VIRTUALIZATION_NONE
;
238 static int detect_vm_zvm(void) {
240 #if defined(__s390__)
241 _cleanup_free_
char *t
= NULL
;
244 r
= get_proc_field("/proc/sysinfo", "VM00 Control Program", WHITESPACE
, &t
);
246 return VIRTUALIZATION_NONE
;
250 if (streq(t
, "z/VM"))
251 return VIRTUALIZATION_ZVM
;
253 return VIRTUALIZATION_KVM
;
255 return VIRTUALIZATION_NONE
;
259 /* Returns a short identifier for the various VM implementations */
260 int detect_vm(void) {
261 static thread_local
int cached_found
= _VIRTUALIZATION_INVALID
;
264 if (cached_found
>= 0)
267 /* Try xen capabilities file first, if not found try
268 * high-level hypervisor sysfs file:
270 * https://bugs.freedesktop.org/show_bug.cgi?id=77271 */
275 if (r
!= VIRTUALIZATION_NONE
)
281 if (r
!= VIRTUALIZATION_NONE
)
284 r
= detect_vm_cpuid();
287 if (r
!= VIRTUALIZATION_NONE
)
290 r
= detect_vm_hypervisor();
293 if (r
!= VIRTUALIZATION_NONE
)
296 r
= detect_vm_device_tree();
299 if (r
!= VIRTUALIZATION_NONE
)
305 if (r
!= VIRTUALIZATION_NONE
)
317 int detect_container(void) {
319 static const struct {
323 { "lxc", VIRTUALIZATION_LXC
},
324 { "lxc-libvirt", VIRTUALIZATION_LXC_LIBVIRT
},
325 { "systemd-nspawn", VIRTUALIZATION_SYSTEMD_NSPAWN
},
326 { "docker", VIRTUALIZATION_DOCKER
},
329 static thread_local
int cached_found
= _VIRTUALIZATION_INVALID
;
330 _cleanup_free_
char *m
= NULL
;
331 const char *e
= NULL
;
335 if (cached_found
>= 0)
338 /* /proc/vz exists in container and outside of the container,
339 * /proc/bc only outside of the container. */
340 if (access("/proc/vz", F_OK
) >= 0 &&
341 access("/proc/bc", F_OK
) < 0) {
342 r
= VIRTUALIZATION_OPENVZ
;
347 /* If we are PID 1 we can just check our own
348 * environment variable */
350 e
= getenv("container");
352 r
= VIRTUALIZATION_NONE
;
357 /* Otherwise, PID 1 dropped this information into a
358 * file in /run. This is better than accessing
359 * /proc/1/environ, since we don't need CAP_SYS_PTRACE
362 r
= read_one_line_file("/run/systemd/container", &m
);
365 /* Fallback for cases where PID 1 was not
366 * systemd (for example, cases where
367 * init=/bin/sh is used. */
369 r
= getenv_for_pid(1, "container", &m
);
372 /* If that didn't work, give up,
373 * assume no container manager.
375 * Note: This means we still cannot
376 * detect containers if init=/bin/sh
377 * is passed but privileges dropped,
378 * as /proc/1/environ is only readable
379 * with privileges. */
381 r
= VIRTUALIZATION_NONE
;
391 for (j
= 0; j
< ELEMENTSOF(value_table
); j
++)
392 if (streq(e
, value_table
[j
].value
)) {
393 r
= value_table
[j
].id
;
397 r
= VIRTUALIZATION_NONE
;
404 int detect_virtualization(void) {
407 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);