]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/virt.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / basic / virt.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
b52aae1d
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2011 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
b52aae1d
LP
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 15 Lesser General Public License for more details.
b52aae1d 16
5430f7f2 17 You should have received a copy of the GNU Lesser General Public License
b52aae1d
LP
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
b52aae1d 21#include <errno.h>
11c3a366
TA
22#include <stdint.h>
23#include <stdlib.h>
07630cea 24#include <string.h>
b52aae1d
LP
25#include <unistd.h>
26
b5efdb8a 27#include "alloc-util.h"
ade61d3b 28#include "dirent-util.h"
295ee984 29#include "env-util.h"
ade61d3b 30#include "fd-util.h"
07630cea 31#include "fileio.h"
11c3a366 32#include "macro.h"
93cc7779 33#include "process-util.h"
b5efdb8a 34#include "stat-util.h"
8b43440b 35#include "string-table.h"
07630cea 36#include "string-util.h"
b52aae1d
LP
37#include "virt.h"
38
75f86906 39static int detect_vm_cpuid(void) {
b52aae1d 40
2ef8a4c4 41 /* CPUID is an x86 specific interface. */
bdb628ee 42#if defined(__i386__) || defined(__x86_64__)
b52aae1d 43
75f86906
LP
44 static const struct {
45 const char *cpuid;
46 int id;
47 } cpuid_vendor_table[] = {
48 { "XenVMMXenVMM", VIRTUALIZATION_XEN },
49 { "KVMKVMKVM", VIRTUALIZATION_KVM },
5588612e 50 { "TCGTCGTCGTCG", VIRTUALIZATION_QEMU },
b52aae1d 51 /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
75f86906 52 { "VMwareVMware", VIRTUALIZATION_VMWARE },
ff85f271 53 /* https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs */
75f86906 54 { "Microsoft Hv", VIRTUALIZATION_MICROSOFT },
aa0c3427
LBS
55 /* https://wiki.freebsd.org/bhyve */
56 { "bhyve bhyve ", VIRTUALIZATION_BHYVE },
75f86906 57 };
b52aae1d
LP
58
59 uint32_t eax, ecx;
b52aae1d
LP
60 bool hypervisor;
61
62 /* http://lwn.net/Articles/301888/ */
b52aae1d
LP
63
64#if defined (__i386__)
65#define REG_a "eax"
66#define REG_b "ebx"
67#elif defined (__amd64__)
68#define REG_a "rax"
69#define REG_b "rbx"
70#endif
71
72 /* First detect whether there is a hypervisor */
73 eax = 1;
74 __asm__ __volatile__ (
75 /* ebx/rbx is being used for PIC! */
76 " push %%"REG_b" \n\t"
77 " cpuid \n\t"
78 " pop %%"REG_b" \n\t"
79
80 : "=a" (eax), "=c" (ecx)
81 : "0" (eax)
82 );
83
84 hypervisor = !!(ecx & 0x80000000U);
85
86 if (hypervisor) {
75f86906
LP
87 union {
88 uint32_t sig32[3];
89 char text[13];
90 } sig = {};
91 unsigned j;
b52aae1d
LP
92
93 /* There is a hypervisor, see what it is */
94 eax = 0x40000000U;
95 __asm__ __volatile__ (
96 /* ebx/rbx is being used for PIC! */
97 " push %%"REG_b" \n\t"
98 " cpuid \n\t"
99 " mov %%ebx, %1 \n\t"
100 " pop %%"REG_b" \n\t"
101
102 : "=a" (eax), "=r" (sig.sig32[0]), "=c" (sig.sig32[1]), "=d" (sig.sig32[2])
103 : "0" (eax)
104 );
105
9f63a08d
SS
106 log_debug("Virtualization found, CPUID=%s", sig.text);
107
75f86906
LP
108 for (j = 0; j < ELEMENTSOF(cpuid_vendor_table); j ++)
109 if (streq(sig.text, cpuid_vendor_table[j].cpuid))
110 return cpuid_vendor_table[j].id;
bdb628ee 111
75f86906 112 return VIRTUALIZATION_VM_OTHER;
b52aae1d 113 }
bdb628ee 114#endif
9f63a08d 115 log_debug("No virtualization found in CPUID");
bdb628ee 116
75f86906 117 return VIRTUALIZATION_NONE;
bdb628ee
ZJS
118}
119
75f86906 120static int detect_vm_device_tree(void) {
db6a8689 121#if defined(__arm__) || defined(__aarch64__) || defined(__powerpc__) || defined(__powerpc64__)
d831deb5
CA
122 _cleanup_free_ char *hvtype = NULL;
123 int r;
124
b8f1df82 125 r = read_one_line_file("/proc/device-tree/hypervisor/compatible", &hvtype);
75f86906 126 if (r == -ENOENT) {
ce09c71d
AJ
127 _cleanup_closedir_ DIR *dir = NULL;
128 struct dirent *dent;
129
130 dir = opendir("/proc/device-tree");
131 if (!dir) {
9f63a08d
SS
132 if (errno == ENOENT) {
133 log_debug_errno(errno, "/proc/device-tree: %m");
75f86906 134 return VIRTUALIZATION_NONE;
9f63a08d 135 }
ce09c71d
AJ
136 return -errno;
137 }
138
75f86906 139 FOREACH_DIRENT(dent, dir, return -errno)
9f63a08d
SS
140 if (strstr(dent->d_name, "fw-cfg")) {
141 log_debug("Virtualization QEMU: \"fw-cfg\" present in /proc/device-tree/%s", dent->d_name);
75f86906 142 return VIRTUALIZATION_QEMU;
9f63a08d 143 }
75f86906 144
9f63a08d 145 log_debug("No virtualization found in /proc/device-tree/*");
75f86906
LP
146 return VIRTUALIZATION_NONE;
147 } else if (r < 0)
148 return r;
149
9f63a08d 150 log_debug("Virtualization %s found in /proc/device-tree/hypervisor/compatible", hvtype);
75f86906
LP
151 if (streq(hvtype, "linux,kvm"))
152 return VIRTUALIZATION_KVM;
153 else if (strstr(hvtype, "xen"))
154 return VIRTUALIZATION_XEN;
155 else
156 return VIRTUALIZATION_VM_OTHER;
157#else
9f63a08d 158 log_debug("This platform does not support /proc/device-tree");
75f86906 159 return VIRTUALIZATION_NONE;
d831deb5 160#endif
d831deb5
CA
161}
162
75f86906 163static int detect_vm_dmi(void) {
2ef8a4c4 164#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
bdb628ee
ZJS
165
166 static const char *const dmi_vendors[] = {
3728dcde 167 "/sys/class/dmi/id/product_name", /* Test this before sys_vendor to detect KVM over QEMU */
bdb628ee
ZJS
168 "/sys/class/dmi/id/sys_vendor",
169 "/sys/class/dmi/id/board_vendor",
170 "/sys/class/dmi/id/bios_vendor"
171 };
172
75f86906
LP
173 static const struct {
174 const char *vendor;
175 int id;
176 } dmi_vendor_table[] = {
3728dcde 177 { "KVM", VIRTUALIZATION_KVM },
75f86906 178 { "QEMU", VIRTUALIZATION_QEMU },
bdb628ee 179 /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
75f86906
LP
180 { "VMware", VIRTUALIZATION_VMWARE },
181 { "VMW", VIRTUALIZATION_VMWARE },
182 { "innotek GmbH", VIRTUALIZATION_ORACLE },
183 { "Xen", VIRTUALIZATION_XEN },
184 { "Bochs", VIRTUALIZATION_BOCHS },
185 { "Parallels", VIRTUALIZATION_PARALLELS },
aa0c3427
LBS
186 /* https://wiki.freebsd.org/bhyve */
187 { "BHYVE", VIRTUALIZATION_BHYVE },
75f86906 188 };
bdb628ee 189 unsigned i;
75f86906 190 int r;
b52aae1d
LP
191
192 for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) {
b1b8e816 193 _cleanup_free_ char *s = NULL;
75f86906 194 unsigned j;
b52aae1d 195
b1b8e816
LP
196 r = read_one_line_file(dmi_vendors[i], &s);
197 if (r < 0) {
75f86906
LP
198 if (r == -ENOENT)
199 continue;
b52aae1d 200
75f86906 201 return r;
b52aae1d
LP
202 }
203
9f63a08d
SS
204
205
75f86906 206 for (j = 0; j < ELEMENTSOF(dmi_vendor_table); j++)
9f63a08d
SS
207 if (startswith(s, dmi_vendor_table[j].vendor)) {
208 log_debug("Virtualization %s found in DMI (%s)", s, dmi_vendors[i]);
75f86906 209 return dmi_vendor_table[j].id;
9f63a08d 210 }
b52aae1d 211 }
bdb628ee
ZJS
212#endif
213
9f63a08d
SS
214 log_debug("No virtualization found in DMI");
215
75f86906 216 return VIRTUALIZATION_NONE;
bdb628ee
ZJS
217}
218
75f86906 219static int detect_vm_xen(void) {
45e1c7d5 220
3f61278b
SS
221 /* Check for Dom0 will be executed later in detect_vm_xen_dom0
222 Thats why we dont check the content of /proc/xen/capabilities here. */
223 if (access("/proc/xen/capabilities", F_OK) < 0) {
224 log_debug("Virtualization XEN not found, /proc/xen/capabilities does not exist");
225 return VIRTUALIZATION_NONE;
226 }
227
228 log_debug("Virtualization XEN found (/proc/xen/capabilities exists)");
45e1c7d5 229 return VIRTUALIZATION_XEN;
3f61278b
SS
230}
231
232static bool detect_vm_xen_dom0(void) {
75f86906
LP
233 _cleanup_free_ char *domcap = NULL;
234 char *cap, *i;
bdb628ee 235 int r;
b52aae1d 236
75f86906 237 r = read_one_line_file("/proc/xen/capabilities", &domcap);
9f63a08d
SS
238 if (r == -ENOENT) {
239 log_debug("Virtualization XEN not found, /proc/xen/capabilities does not exist");
3f61278b 240 return false;
9f63a08d 241 }
d5b687e7
LP
242 if (r < 0)
243 return r;
bdb628ee 244
75f86906
LP
245 i = domcap;
246 while ((cap = strsep(&i, ",")))
247 if (streq(cap, "control_d"))
248 break;
9f63a08d
SS
249 if (!cap) {
250 log_debug("Virtualization XEN DomU found (/proc/xen/capabilites)");
3f61278b 251 return false;
9f63a08d
SS
252 }
253
254 log_debug("Virtualization XEN Dom0 ignored (/proc/xen/capabilities)");
3f61278b 255 return true;
75f86906 256}
37287585 257
75f86906
LP
258static int detect_vm_hypervisor(void) {
259 _cleanup_free_ char *hvtype = NULL;
260 int r;
37287585 261
75f86906
LP
262 r = read_one_line_file("/sys/hypervisor/type", &hvtype);
263 if (r == -ENOENT)
264 return VIRTUALIZATION_NONE;
265 if (r < 0)
266 return r;
37287585 267
9f63a08d
SS
268 log_debug("Virtualization %s found in /sys/hypervisor/type", hvtype);
269
75f86906
LP
270 if (streq(hvtype, "xen"))
271 return VIRTUALIZATION_XEN;
272 else
273 return VIRTUALIZATION_VM_OTHER;
274}
37287585 275
75f86906
LP
276static int detect_vm_uml(void) {
277 _cleanup_free_ char *cpuinfo_contents = NULL;
278 int r;
37287585 279
75f86906
LP
280 /* Detect User-Mode Linux by reading /proc/cpuinfo */
281 r = read_full_file("/proc/cpuinfo", &cpuinfo_contents, NULL);
282 if (r < 0)
bdb628ee 283 return r;
9f63a08d
SS
284
285 if (strstr(cpuinfo_contents, "\nvendor_id\t: User Mode Linux\n")) {
286 log_debug("UML virtualization found in /proc/cpuinfo");
75f86906 287 return VIRTUALIZATION_UML;
9f63a08d 288 }
bdb628ee 289
82f8bae2 290 log_debug("No virtualization found in /proc/cpuinfo.");
75f86906
LP
291 return VIRTUALIZATION_NONE;
292}
e32886e0 293
75f86906 294static int detect_vm_zvm(void) {
bdb628ee 295
75f86906
LP
296#if defined(__s390__)
297 _cleanup_free_ char *t = NULL;
298 int r;
e32886e0 299
c4cd1d4d 300 r = get_proc_field("/proc/sysinfo", "VM00 Control Program", WHITESPACE, &t);
75f86906
LP
301 if (r == -ENOENT)
302 return VIRTUALIZATION_NONE;
303 if (r < 0)
304 return r;
e32886e0 305
9f63a08d 306 log_debug("Virtualization %s found in /proc/sysinfo", t);
75f86906
LP
307 if (streq(t, "z/VM"))
308 return VIRTUALIZATION_ZVM;
309 else
310 return VIRTUALIZATION_KVM;
311#else
9f63a08d 312 log_debug("This platform does not support /proc/sysinfo");
75f86906
LP
313 return VIRTUALIZATION_NONE;
314#endif
315}
e32886e0 316
75f86906
LP
317/* Returns a short identifier for the various VM implementations */
318int detect_vm(void) {
319 static thread_local int cached_found = _VIRTUALIZATION_INVALID;
28b1a3ea 320 int r, dmi;
530c1c30 321 bool other = false;
e32886e0 322
75f86906
LP
323 if (cached_found >= 0)
324 return cached_found;
bdb628ee 325
f6875b0a 326 /* We have to use the correct order here:
f6875b0a 327 *
28b1a3ea
CH
328 * -> First try to detect Oracle Virtualbox, even if it uses KVM.
329 * -> Second try to detect from cpuid, this will report KVM for
330 * whatever software is used even if info in dmi is overwritten.
331 * -> Third try to detect from dmi. */
5f1c788c 332
28b1a3ea 333 dmi = detect_vm_dmi();
2f8e375d
BR
334 if (dmi == VIRTUALIZATION_ORACLE) {
335 r = dmi;
336 goto finish;
337 }
5f1c788c 338
28b1a3ea 339 r = detect_vm_cpuid();
75f86906
LP
340 if (r < 0)
341 return r;
530c1c30
RC
342 if (r != VIRTUALIZATION_NONE) {
343 if (r == VIRTUALIZATION_VM_OTHER)
344 other = true;
345 else
346 goto finish;
347 }
d831deb5 348
28b1a3ea 349 r = dmi;
75f86906
LP
350 if (r < 0)
351 return r;
530c1c30
RC
352 if (r != VIRTUALIZATION_NONE) {
353 if (r == VIRTUALIZATION_VM_OTHER)
354 other = true;
355 else
356 goto finish;
357 }
b52aae1d 358
42685451
AJ
359 /* x86 xen will most likely be detected by cpuid. If not (most likely
360 * because we're not an x86 guest), then we should try the xen capabilities
361 * file next. If that's not found, then we check for the high-level
362 * hypervisor sysfs file:
363 *
364 * https://bugs.freedesktop.org/show_bug.cgi?id=77271 */
365
366 r = detect_vm_xen();
7080ea16
RR
367 if (r < 0)
368 return r;
530c1c30
RC
369 if (r != VIRTUALIZATION_NONE) {
370 if (r == VIRTUALIZATION_VM_OTHER)
371 other = true;
372 else
373 goto finish;
374 }
7080ea16 375
75f86906
LP
376 r = detect_vm_hypervisor();
377 if (r < 0)
378 return r;
530c1c30
RC
379 if (r != VIRTUALIZATION_NONE) {
380 if (r == VIRTUALIZATION_VM_OTHER)
381 other = true;
382 else
383 goto finish;
384 }
f41925b4 385
75f86906
LP
386 r = detect_vm_device_tree();
387 if (r < 0)
388 return r;
530c1c30
RC
389 if (r != VIRTUALIZATION_NONE) {
390 if (r == VIRTUALIZATION_VM_OTHER)
391 other = true;
392 else
393 goto finish;
394 }
f41925b4 395
75f86906
LP
396 r = detect_vm_uml();
397 if (r < 0)
398 return r;
530c1c30
RC
399 if (r != VIRTUALIZATION_NONE) {
400 if (r == VIRTUALIZATION_VM_OTHER)
401 other = true;
402 else
403 goto finish;
404 }
f41925b4 405
75f86906
LP
406 r = detect_vm_zvm();
407 if (r < 0)
408 return r;
0fb533a5
LP
409
410finish:
3f61278b
SS
411 /* x86 xen Dom0 is detected as XEN in hypervisor and maybe others.
412 * In order to detect the Dom0 as not virtualization we need to
413 * double-check it */
414 if (r == VIRTUALIZATION_XEN && detect_vm_xen_dom0())
415 r = VIRTUALIZATION_NONE;
530c1c30
RC
416 else if (r == VIRTUALIZATION_NONE && other)
417 r = VIRTUALIZATION_VM_OTHER;
3f61278b 418
0fb533a5 419 cached_found = r;
9f63a08d 420 log_debug("Found VM virtualization %s", virtualization_to_string(r));
0fb533a5 421 return r;
b52aae1d
LP
422}
423
75f86906 424int detect_container(void) {
0fb533a5 425
75f86906
LP
426 static const struct {
427 const char *value;
428 int id;
429 } value_table[] = {
430 { "lxc", VIRTUALIZATION_LXC },
431 { "lxc-libvirt", VIRTUALIZATION_LXC_LIBVIRT },
432 { "systemd-nspawn", VIRTUALIZATION_SYSTEMD_NSPAWN },
433 { "docker", VIRTUALIZATION_DOCKER },
9fb16425 434 { "rkt", VIRTUALIZATION_RKT },
75f86906 435 };
0fb533a5 436
75f86906 437 static thread_local int cached_found = _VIRTUALIZATION_INVALID;
fdd25311 438 _cleanup_free_ char *m = NULL;
75f86906
LP
439 const char *e = NULL;
440 unsigned j;
ab94af92 441 int r;
b52aae1d 442
75f86906 443 if (cached_found >= 0)
0fb533a5 444 return cached_found;
0fb533a5 445
8d6e8034 446 /* /proc/vz exists in container and outside of the container, /proc/bc only outside of the container. */
b52aae1d
LP
447 if (access("/proc/vz", F_OK) >= 0 &&
448 access("/proc/bc", F_OK) < 0) {
75f86906 449 r = VIRTUALIZATION_OPENVZ;
0fb533a5 450 goto finish;
b52aae1d
LP
451 }
452
df0ff127 453 if (getpid_cached() == 1) {
8d6e8034 454 /* If we are PID 1 we can just check our own environment variable, and that's authoritative. */
fdd25311
LP
455
456 e = getenv("container");
457 if (isempty(e)) {
75f86906 458 r = VIRTUALIZATION_NONE;
fdd25311
LP
459 goto finish;
460 }
fdd25311 461
8d6e8034
LP
462 goto translate_name;
463 }
464
465 /* Otherwise, PID 1 might have dropped this information into a file in /run. This is better than accessing
466 * /proc/1/environ, since we don't need CAP_SYS_PTRACE for that. */
467 r = read_one_line_file("/run/systemd/container", &m);
468 if (r >= 0) {
469 e = m;
470 goto translate_name;
471 }
472 if (r != -ENOENT)
473 return log_debug_errno(r, "Failed to read /run/systemd/container: %m");
474
475 /* Fallback for cases where PID 1 was not systemd (for example, cases where init=/bin/sh is used. */
476 r = getenv_for_pid(1, "container", &m);
477 if (r > 0) {
fdd25311 478 e = m;
8d6e8034 479 goto translate_name;
fdd25311 480 }
8d6e8034
LP
481 if (r < 0) /* This only works if we have CAP_SYS_PTRACE, hence let's better ignore failures here */
482 log_debug_errno(r, "Failed to read $container of PID 1, ignoring: %m");
483
484 /* Interestingly /proc/1/sched actually shows the host's PID for what we see as PID 1. Hence, if the PID shown
485 * there is not 1, we know we are in a PID namespace. and hence a container. */
486 r = read_one_line_file("/proc/1/sched", &m);
487 if (r >= 0) {
488 const char *t;
489
490 t = strrchr(m, '(');
491 if (!t)
492 return -EIO;
493
494 if (!startswith(t, "(1,")) {
495 r = VIRTUALIZATION_CONTAINER_OTHER;
496 goto finish;
497 }
498 } else if (r != -ENOENT)
499 return r;
500
501 /* If that didn't work, give up, assume no container manager. */
502 r = VIRTUALIZATION_NONE;
503 goto finish;
b52aae1d 504
8d6e8034 505translate_name:
75f86906
LP
506 for (j = 0; j < ELEMENTSOF(value_table); j++)
507 if (streq(e, value_table[j].value)) {
508 r = value_table[j].id;
509 goto finish;
510 }
0fb533a5 511
f499daf4 512 r = VIRTUALIZATION_CONTAINER_OTHER;
fdd25311 513
0fb533a5 514finish:
8d6e8034 515 log_debug("Found container virtualization %s.", virtualization_to_string(r));
0fb533a5 516 cached_found = r;
ab94af92 517 return r;
b52aae1d
LP
518}
519
75f86906 520int detect_virtualization(void) {
b52aae1d 521 int r;
b52aae1d 522
75f86906 523 r = detect_container();
9f63a08d
SS
524 if (r == 0)
525 r = detect_vm();
b52aae1d 526
9f63a08d 527 return r;
b52aae1d 528}
75f86906 529
299a34c1
ZJS
530static int userns_has_mapping(const char *name) {
531 _cleanup_fclose_ FILE *f = NULL;
532 _cleanup_free_ char *buf = NULL;
533 size_t n_allocated = 0;
534 ssize_t n;
535 uint32_t a, b, c;
536 int r;
537
538 f = fopen(name, "re");
539 if (!f) {
540 log_debug_errno(errno, "Failed to open %s: %m", name);
abd67ce7 541 return errno == ENOENT ? false : -errno;
299a34c1
ZJS
542 }
543
544 n = getline(&buf, &n_allocated, f);
545 if (n < 0) {
546 if (feof(f)) {
547 log_debug("%s is empty, we're in an uninitialized user namespace", name);
548 return true;
549 }
550
551 return log_debug_errno(errno, "Failed to read %s: %m", name);
552 }
553
554 r = sscanf(buf, "%"PRIu32" %"PRIu32" %"PRIu32, &a, &b, &c);
555 if (r < 3)
556 return log_debug_errno(errno, "Failed to parse %s: %m", name);
557
558 if (a == 0 && b == 0 && c == UINT32_MAX) {
559 /* The kernel calls mappings_overlap() and does not allow overlaps */
560 log_debug("%s has a full 1:1 mapping", name);
561 return false;
562 }
563
564 /* Anything else implies that we are in a user namespace */
565 log_debug("Mapping found in %s, we're in a user namespace", name);
566 return true;
567}
568
569int running_in_userns(void) {
570 _cleanup_free_ char *line = NULL;
571 int r;
572
573 r = userns_has_mapping("/proc/self/uid_map");
574 if (r != 0)
575 return r;
576
577 r = userns_has_mapping("/proc/self/gid_map");
578 if (r != 0)
579 return r;
580
581 /* "setgroups" file was added in kernel v3.18-rc6-15-g9cc46516dd. It is also
582 * possible to compile a kernel without CONFIG_USER_NS, in which case "setgroups"
583 * also does not exist. We cannot distinguish those two cases, so assume that
584 * we're running on a stripped-down recent kernel, rather than on an old one,
585 * and if the file is not found, return false.
586 */
587 r = read_one_line_file("/proc/self/setgroups", &line);
588 if (r < 0) {
589 log_debug_errno(r, "/proc/self/setgroups: %m");
590 return r == -ENOENT ? false : r;
591 }
592
593 truncate_nl(line);
594 r = streq(line, "deny");
595 /* See user_namespaces(7) for a description of this "setgroups" contents. */
596 log_debug("/proc/self/setgroups contains \"%s\", %s user namespace", line, r ? "in" : "not in");
597 return r;
598}
599
7f4b3c5e 600int running_in_chroot(void) {
d6d0473d 601 int ret;
7f4b3c5e 602
08a28eec
LN
603 if (getenv_bool("SYSTEMD_IGNORE_CHROOT") > 0)
604 return 0;
605
e3f791a2 606 ret = files_same("/proc/1/root", "/", 0);
d6d0473d
LP
607 if (ret < 0)
608 return ret;
7f4b3c5e 609
d6d0473d 610 return ret == 0;
7f4b3c5e
LP
611}
612
75f86906
LP
613static const char *const virtualization_table[_VIRTUALIZATION_MAX] = {
614 [VIRTUALIZATION_NONE] = "none",
615 [VIRTUALIZATION_KVM] = "kvm",
616 [VIRTUALIZATION_QEMU] = "qemu",
617 [VIRTUALIZATION_BOCHS] = "bochs",
618 [VIRTUALIZATION_XEN] = "xen",
619 [VIRTUALIZATION_UML] = "uml",
620 [VIRTUALIZATION_VMWARE] = "vmware",
621 [VIRTUALIZATION_ORACLE] = "oracle",
622 [VIRTUALIZATION_MICROSOFT] = "microsoft",
623 [VIRTUALIZATION_ZVM] = "zvm",
624 [VIRTUALIZATION_PARALLELS] = "parallels",
aa0c3427 625 [VIRTUALIZATION_BHYVE] = "bhyve",
75f86906
LP
626 [VIRTUALIZATION_VM_OTHER] = "vm-other",
627
628 [VIRTUALIZATION_SYSTEMD_NSPAWN] = "systemd-nspawn",
629 [VIRTUALIZATION_LXC_LIBVIRT] = "lxc-libvirt",
630 [VIRTUALIZATION_LXC] = "lxc",
631 [VIRTUALIZATION_OPENVZ] = "openvz",
632 [VIRTUALIZATION_DOCKER] = "docker",
9fb16425 633 [VIRTUALIZATION_RKT] = "rkt",
75f86906
LP
634 [VIRTUALIZATION_CONTAINER_OTHER] = "container-other",
635};
636
637DEFINE_STRING_TABLE_LOOKUP(virtualization, int);