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(const char **_id) {
33 /* Both CPUID and DMI are x86 specific interfaces... */
34 #if defined(__i386__) || defined(__x86_64__)
36 static const char cpuid_vendor_table[] =
37 "XenVMMXenVMM\0" "xen\0"
39 /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
40 "VMwareVMware\0" "vmware\0"
41 /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */
42 "Microsoft Hv\0" "microsoft\0";
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);
78 /* There is a hypervisor, see what it is */
80 __asm__ __volatile__ (
81 /* ebx/rbx is being used for PIC! */
82 " push %%"REG_b" \n\t"
87 : "=a" (eax), "=r" (sig.sig32[0]), "=c" (sig.sig32[1]), "=d" (sig.sig32[2])
91 NULSTR_FOREACH_PAIR(j, k, cpuid_vendor_table)
92 if (streq(sig.text, j)) {
105 static int detect_vm_devicetree(const char **_id) {
106 #if defined(__arm__) || defined(__aarch64__) || defined(__powerpc__) || defined(__powerpc64__)
107 _cleanup_free_ char *hvtype = NULL;
110 r = read_one_line_file("/proc/device-tree/hypervisor/compatible", &hvtype);
112 if (streq(hvtype, "linux,kvm")) {
115 } else if (strstr(hvtype, "xen")) {
119 } else if (r == -ENOENT) {
120 _cleanup_closedir_ DIR *dir = NULL;
123 dir = opendir("/proc/device-tree");
130 FOREACH_DIRENT(dent, dir, return -errno) {
131 if (strstr(dent->d_name, "fw-cfg")) {
141 static int detect_vm_dmi(const char **_id) {
143 /* Both CPUID and DMI are x86 specific interfaces... */
144 #if defined(__i386__) || defined(__x86_64__)
146 static const char *const dmi_vendors[] = {
147 "/sys/class/dmi/id/sys_vendor",
148 "/sys/class/dmi/id/board_vendor",
149 "/sys/class/dmi/id/bios_vendor"
152 static const char dmi_vendor_table[] =
154 /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
155 "VMware\0" "vmware\0"
157 "innotek GmbH\0" "oracle\0"
160 "Parallels\0" "parallels\0";
163 for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) {
164 _cleanup_free_ char *s = NULL;
168 r = read_one_line_file(dmi_vendors[i], &s);
176 NULSTR_FOREACH_PAIR(j, k, dmi_vendor_table)
177 if (startswith(s, j)) {
187 /* Returns a short identifier for the various VM implementations */
188 int detect_vm(const char **id) {
189 _cleanup_free_ char *domcap = NULL, *cpuinfo_contents = NULL;
190 static thread_local int cached_found = -1;
191 static thread_local const char *cached_id = NULL;
192 const char *_id = NULL, *_id_cpuid = NULL;
195 if (_likely_(cached_found >= 0)) {
203 /* Try xen capabilities file first, if not found try high-level hypervisor sysfs file:
205 * https://bugs.freedesktop.org/show_bug.cgi?id=77271 */
206 r = read_one_line_file("/proc/xen/capabilities", &domcap);
208 char *cap, *i = domcap;
210 while ((cap = strsep(&i, ",")))
211 if (streq(cap, "control_d"))
221 } else if (r == -ENOENT) {
222 _cleanup_free_ char *hvtype = NULL;
224 r = read_one_line_file("/sys/hypervisor/type", &hvtype);
226 if (streq(hvtype, "xen")) {
231 } else if (r != -ENOENT)
236 /* this will set _id to "other" and return 0 for unknown hypervisors */
237 r = detect_vm_cpuid(&_id);
239 /* finish when found a known hypervisor other than kvm */
240 if (r < 0 || (r > 0 && !streq(_id, "kvm")))
245 r = detect_vm_dmi(&_id);
247 /* kvm with and without Virtualbox */
248 /* Parallels exports KVMKVMKVM leaf */
249 if (streq_ptr(_id_cpuid, "kvm")) {
250 if (r > 0 && (streq(_id, "oracle") || streq(_id, "parallels")))
258 /* information from dmi */
262 r = detect_vm_devicetree(&_id);
272 /* Detect User-Mode Linux by reading /proc/cpuinfo */
273 r = read_full_file("/proc/cpuinfo", &cpuinfo_contents, NULL);
276 if (strstr(cpuinfo_contents, "\nvendor_id\t: User Mode Linux\n")) {
282 #if defined(__s390__)
284 _cleanup_free_ char *t = NULL;
286 r = get_status_field("/proc/sysinfo", "VM00 Control Program:", &t);
288 if (streq(t, "z/VM"))
311 int detect_container(const char **id) {
313 static thread_local int cached_found = -1;
314 static thread_local const char *cached_id = NULL;
316 _cleanup_free_ char *m = NULL;
317 const char *_id = NULL, *e = NULL;
320 if (_likely_(cached_found >= 0)) {
328 /* /proc/vz exists in container and outside of the container,
329 * /proc/bc only outside of the container. */
330 if (access("/proc/vz", F_OK) >= 0 &&
331 access("/proc/bc", F_OK) < 0) {
338 /* If we are PID 1 we can just check our own
339 * environment variable */
341 e = getenv("container");
348 /* Otherwise, PID 1 dropped this information into a
349 * file in /run. This is better than accessing
350 * /proc/1/environ, since we don't need CAP_SYS_PTRACE
353 r = read_one_line_file("/run/systemd/container", &m);
356 /* Fallback for cases where PID 1 was not
357 * systemd (for example, cases where
358 * init=/bin/sh is used. */
360 r = getenv_for_pid(1, "container", &m);
363 /* If that didn't work, give up,
364 * assume no container manager.
366 * Note: This means we still cannot
367 * detect containers if init=/bin/sh
368 * is passed but privileges dropped,
369 * as /proc/1/environ is only readable
370 * with privileges. */
382 /* We only recognize a selected few here, since we want to
383 * enforce a redacted namespace */
386 else if (streq(e, "lxc-libvirt"))
388 else if (streq(e, "systemd-nspawn"))
389 _id = "systemd-nspawn";
390 else if (streq(e, "docker"))
407 /// UNNEEDED by elogind
409 /* Returns a short identifier for the various VM/container implementations */
410 int detect_virtualization(const char **id) {
413 r = detect_container(id);
417 return VIRTUALIZATION_CONTAINER;
423 return VIRTUALIZATION_VM;
425 return VIRTUALIZATION_NONE;