]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/lscpu-virt.c
sys-utils: cleanup license lines, add SPDX
[thirdparty/util-linux.git] / sys-utils / lscpu-virt.c
CommitLineData
9abd5e4b
KZ
1/*
2 * SPDX-License-Identifier: GPL-2.0-or-later
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * Copyright (C) 2008 Cai Qian <qcai@redhat.com>
10 * Copyright (C) 2008-2023 Karel Zak <kzak@redhat.com>
11 */
909d3575
KZ
12#include <errno.h>
13#include <stdlib.h>
14#include <sys/types.h>
15#include <sys/stat.h>
16#include <fcntl.h>
17#include <unistd.h>
18#include <string.h>
19#include <stdio.h>
20
095be2c2 21#include "lscpu.h"
909d3575 22
3d590f8e
KZ
23#if (defined(__x86_64__) || defined(__i386__))
24# define INCLUDE_VMWARE_BDOOR
25#endif
26
27#ifdef INCLUDE_VMWARE_BDOOR
28# include <stdint.h>
29# include <signal.h>
30# include <strings.h>
31# include <setjmp.h>
32# ifdef HAVE_SYS_IO_H
33# include <sys/io.h>
34# endif
35#endif
36
909d3575
KZ
37/* Xen Domain feature flag used for /sys/hypervisor/properties/features */
38#define XENFEAT_supervisor_mode_kernel 3
39#define XENFEAT_mmu_pt_update_preserve_ad 5
40#define XENFEAT_hvm_callback_vector 8
41
42#define XEN_FEATURES_PV_MASK (1U << XENFEAT_mmu_pt_update_preserve_ad)
43#define XEN_FEATURES_PVH_MASK ( (1U << XENFEAT_supervisor_mode_kernel) \
44 | (1U << XENFEAT_hvm_callback_vector) )
45static const int hv_vendor_pci[] = {
46 [VIRT_VENDOR_NONE] = 0x0000,
47 [VIRT_VENDOR_XEN] = 0x5853,
48 [VIRT_VENDOR_KVM] = 0x0000,
49 [VIRT_VENDOR_MSHV] = 0x1414,
50 [VIRT_VENDOR_VMWARE] = 0x15ad,
51 [VIRT_VENDOR_VBOX] = 0x80ee,
52};
53
54static const int hv_graphics_pci[] = {
55 [VIRT_VENDOR_NONE] = 0x0000,
56 [VIRT_VENDOR_XEN] = 0x0001,
57 [VIRT_VENDOR_KVM] = 0x0000,
58 [VIRT_VENDOR_MSHV] = 0x5353,
59 [VIRT_VENDOR_VMWARE] = 0x0710,
60 [VIRT_VENDOR_VBOX] = 0xbeef,
61};
62
63#define WORD(x) (uint16_t)(*(const uint16_t *)(x))
64#define DWORD(x) (uint32_t)(*(const uint32_t *)(x))
65
3cd676f5 66void *get_mem_chunk(size_t base, size_t len, const char *devmem)
909d3575
KZ
67{
68 void *p = NULL;
69 int fd;
70
71 if ((fd = open(devmem, O_RDONLY)) < 0)
72 return NULL;
73
74 if (!(p = malloc(len)))
75 goto nothing;
76 if (lseek(fd, base, SEEK_SET) == -1)
77 goto nothing;
78 if (read_all(fd, p, len) == -1)
79 goto nothing;
80
81 close(fd);
82 return p;
83
84nothing:
85 free(p);
86 close(fd);
87 return NULL;
88}
89
b04ab8dd
MM
90static int hypervisor_from_dmi_table(uint32_t base, uint16_t len,
91 uint16_t num, const char *devmem)
92{
93 uint8_t *data;
94 int rc = VIRT_VENDOR_NONE;
95 struct dmi_info di;
96
97 data = get_mem_chunk(base, len, devmem);
98 if (!data)
99 return rc;
100
101 memset(&di, 0, sizeof(struct dmi_info));
102 rc = parse_dmi_table(len, num, data, &di);
103 if (rc < 0)
104 goto done;
105
106 if (di.manufacturer && !strcmp(di.manufacturer, "innotek GmbH"))
909d3575 107 rc = VIRT_VENDOR_INNOTEK;
b04ab8dd
MM
108 else if (di.manufacturer && strstr(di.manufacturer, "HITACHI") &&
109 di.product && strstr(di.product, "LPAR"))
909d3575 110 rc = VIRT_VENDOR_HITACHI;
b04ab8dd 111 else if (di.vendor && !strcmp(di.vendor, "Parallels"))
909d3575
KZ
112 rc = VIRT_VENDOR_PARALLELS;
113done:
b04ab8dd 114 free(data);
909d3575
KZ
115 return rc;
116}
117
118static int checksum(const uint8_t *buf, size_t len)
119{
120 uint8_t sum = 0;
121 size_t a;
122
123 for (a = 0; a < len; a++)
124 sum += buf[a];
125 return (sum == 0);
126}
127
128#if defined(__x86_64__) || defined(__i386__)
129static int hypervisor_decode_legacy(uint8_t *buf, const char *devmem)
130{
131 if (!checksum(buf, 0x0F))
132 return -1;
133
134 return hypervisor_from_dmi_table(DWORD(buf + 0x08), WORD(buf + 0x06),
135 WORD(buf + 0x0C),
136 devmem);
137}
138#endif
139
140static int hypervisor_decode_smbios(uint8_t *buf, const char *devmem)
141{
142 if (!checksum(buf, buf[0x05])
143 || memcmp(buf + 0x10, "_DMI_", 5) != 0
144 || !checksum(buf + 0x10, 0x0F))
145 return -1;
146
147 return hypervisor_from_dmi_table(DWORD(buf + 0x18), WORD(buf + 0x16),
148 WORD(buf + 0x1C),
149 devmem);
150}
151
152/*
153 * Probe for EFI interface
154 */
155#define EFI_NOT_FOUND (-1)
156#define EFI_NO_SMBIOS (-2)
157static int address_from_efi(size_t *address)
158{
159 FILE *tab;
160 char linebuf[64];
161 int ret;
162
163 *address = 0; /* Prevent compiler warning */
164
165 /*
166 * Linux up to 2.6.6: /proc/efi/systab
167 * Linux 2.6.7 and up: /sys/firmware/efi/systab
168 */
169 if (!(tab = fopen("/sys/firmware/efi/systab", "r")) &&
170 !(tab = fopen("/proc/efi/systab", "r")))
171 return EFI_NOT_FOUND; /* No EFI interface */
172
173 ret = EFI_NO_SMBIOS;
174 while ((fgets(linebuf, sizeof(linebuf) - 1, tab)) != NULL) {
175 char *addrp = strchr(linebuf, '=');
176 if (!addrp)
177 continue;
178 *(addrp++) = '\0';
179 if (strcmp(linebuf, "SMBIOS") == 0) {
35d45870 180 errno = 0;
909d3575 181 *address = strtoul(addrp, NULL, 0);
35d45870
KZ
182 if (errno)
183 continue;
909d3575
KZ
184 ret = 0;
185 break;
186 }
187 }
188
189 fclose(tab);
190 return ret;
191}
192
193static int read_hypervisor_dmi_from_devmem(void)
194{
195 int rc = VIRT_VENDOR_NONE;
196 uint8_t *buf = NULL;
197 size_t fp = 0;
198
199 /* First try EFI (ia64, Intel-based Mac) */
200 switch (address_from_efi(&fp)) {
201 case EFI_NOT_FOUND:
202 goto memory_scan;
203 case EFI_NO_SMBIOS:
204 goto done;
205 }
206
207 buf = get_mem_chunk(fp, 0x20, _PATH_DEV_MEM);
208 if (!buf)
209 goto done;
210
211 rc = hypervisor_decode_smbios(buf, _PATH_DEV_MEM);
212 if (rc >= VIRT_VENDOR_NONE)
213 goto done;
214
215 free(buf);
216 buf = NULL;
217memory_scan:
218#if defined(__x86_64__) || defined(__i386__)
219 /* Fallback to memory scan (x86, x86_64) */
220 buf = get_mem_chunk(0xF0000, 0x10000, _PATH_DEV_MEM);
221 if (!buf)
222 goto done;
223
224 for (fp = 0; fp <= 0xFFF0; fp += 16) {
225 if (memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0) {
226 rc = hypervisor_decode_smbios(buf + fp, _PATH_DEV_MEM);
227 if (rc < 0)
228 fp += 16;
229
230 } else if (memcmp(buf + fp, "_DMI_", 5) == 0)
231 rc = hypervisor_decode_legacy(buf + fp, _PATH_DEV_MEM);
232
233 if (rc >= VIRT_VENDOR_NONE)
234 break;
235 }
236#endif
237done:
238 free(buf);
239 return rc;
240}
241
242static int read_hypervisor_dmi_from_sysfw(void)
243{
244 static char const sys_fw_dmi_tables[] = _PATH_SYS_DMI;
245 struct stat st;
246
247 if (stat(sys_fw_dmi_tables, &st))
248 return -1;
249
250 return hypervisor_from_dmi_table(0, st.st_size, st.st_size / 4,
251 sys_fw_dmi_tables);
252}
253
254static int read_hypervisor_dmi(void)
255{
256 int rc;
257
258 if (sizeof(uint8_t) != 1
259 || sizeof(uint16_t) != 2
260 || sizeof(uint32_t) != 4
261 || '\0' != 0)
262 return VIRT_VENDOR_NONE;
263
264 /* -1 : no DMI in /sys,
265 * 0 : DMI exist, nothing detected (VIRT_VENDOR_NONE)
266 * >0 : hypervisor detected
267 */
268 rc = read_hypervisor_dmi_from_sysfw();
269 if (rc < 0)
270 rc = read_hypervisor_dmi_from_devmem();
271
272 return rc < 0 ? VIRT_VENDOR_NONE : rc;
273}
274
275static int has_pci_device(struct lscpu_cxt *cxt,
276 unsigned int vendor, unsigned int device)
277{
278 FILE *f;
279 unsigned int num, fn, ven, dev;
280 int res = 1;
281
282 f = ul_path_fopen(cxt->procfs, "r", "bus/pci/devices");
283 if (!f)
284 return 0;
285
286 /* for more details about bus/pci/devices format see
287 * drivers/pci/proc.c in linux kernel
288 */
289 while(fscanf(f, "%02x%02x\t%04x%04x\t%*[^\n]",
290 &num, &fn, &ven, &dev) == 4) {
291
292 if (ven == vendor && dev == device)
293 goto found;
294 }
295
296 res = 0;
297found:
298 fclose(f);
299 return res;
300}
301
302#if defined(__x86_64__) || defined(__i386__)
303/*
304 * This CPUID leaf returns the information about the hypervisor.
305 * EAX : maximum input value for CPUID supported by the hypervisor.
306 * EBX, ECX, EDX : Hypervisor vendor ID signature. E.g. VMwareVMware.
307 */
308#define HYPERVISOR_INFO_LEAF 0x40000000
309
310static inline void cpuid(unsigned int op, unsigned int *eax,
311 unsigned int *ebx, unsigned int *ecx,
312 unsigned int *edx)
313{
314 __asm__(
315#if defined(__PIC__) && defined(__i386__)
316 /* x86 PIC cannot clobber ebx -- gcc bitches */
317 "xchg %%ebx, %%esi;"
318 "cpuid;"
319 "xchg %%esi, %%ebx;"
320 : "=S" (*ebx),
321#else
322 "cpuid;"
323 : "=b" (*ebx),
324#endif
325 "=a" (*eax),
326 "=c" (*ecx),
327 "=d" (*edx)
328 : "1" (op), "c"(0));
329}
330
331static int read_hypervisor_cpuid(void)
332{
333 unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0;
334 char hyper_vendor_id[13] = { 0 };
335
336 cpuid(HYPERVISOR_INFO_LEAF, &eax, &ebx, &ecx, &edx);
337 memcpy(hyper_vendor_id + 0, &ebx, 4);
338 memcpy(hyper_vendor_id + 4, &ecx, 4);
339 memcpy(hyper_vendor_id + 8, &edx, 4);
340 hyper_vendor_id[12] = '\0';
341
342 if (!hyper_vendor_id[0])
343 goto none;
344
345 if (!strncmp("XenVMMXenVMM", hyper_vendor_id, 12))
346 return VIRT_VENDOR_XEN;
347 else if (!strncmp("KVMKVMKVM", hyper_vendor_id, 9))
348 return VIRT_VENDOR_KVM;
349 else if (!strncmp("Microsoft Hv", hyper_vendor_id, 12))
350 return VIRT_VENDOR_MSHV;
351 else if (!strncmp("VMwareVMware", hyper_vendor_id, 12))
352 return VIRT_VENDOR_VMWARE;
353 else if (!strncmp("UnisysSpar64", hyper_vendor_id, 12))
354 return VIRT_VENDOR_SPAR;
355none:
356 return VIRT_VENDOR_NONE;
357}
358
359#else /* ! (__x86_64__ || __i386__) */
b3ea5aaa 360static int read_hypervisor_cpuid(void)
909d3575 361{
b3ea5aaa 362 return 0;
909d3575
KZ
363}
364#endif
365
366static int is_devtree_compatible(struct lscpu_cxt *cxt, const char *str)
367{
368 FILE *fd = ul_path_fopen(cxt->procfs, "r", "device-tree/compatible");
369
370 if (fd) {
371 char buf[256];
372 size_t i, len;
373
374 memset(buf, 0, sizeof(buf));
375 len = fread(buf, 1, sizeof(buf) - 1, fd);
376 fclose(fd);
377
378 for (i = 0; i < len;) {
379 if (!strcmp(&buf[i], str))
380 return 1;
381 i += strlen(&buf[i]);
382 i++;
383 }
384 }
385
386 return 0;
387}
388
389static int read_hypervisor_powerpc(struct lscpu_cxt *cxt, int *type)
390{
391 int vendor = VIRT_VENDOR_NONE;
392
393 *type = VIRT_TYPE_NONE;
394
395 /* IBM iSeries: legacy, para-virtualized on top of OS/400 */
396 if (ul_path_access(cxt->procfs, F_OK, "iSeries") == 0) {
397 vendor = VIRT_VENDOR_OS400;
398 *type = VIRT_TYPE_PARA;
399
400 /* PowerNV (POWER Non-Virtualized, bare-metal) */
401 } else if (is_devtree_compatible(cxt, "ibm,powernv") != 0) {
402 ;
403
404 /* PowerVM (IBM's proprietary hypervisor, aka pHyp) */
405 } else if (ul_path_access(cxt->procfs, F_OK, "device-tree/ibm,partition-name") == 0
406 && ul_path_access(cxt->procfs, F_OK, "device-tree/hmc-managed?") == 0
407 && ul_path_access(cxt->procfs, F_OK, "device-tree/chosen/qemu,graphic-width") != 0) {
408
9fa970fb 409 char buf[256];
909d3575
KZ
410 vendor = VIRT_VENDOR_PHYP;
411 *type = VIRT_TYPE_PARA;
412
9fa970fb
TS
413 if (ul_path_scanf(cxt->procfs, "device-tree/ibm,partition-name", "%255s", buf) == 1 &&
414 !strcmp(buf, "full"))
415 *type = VIRT_TYPE_NONE;
909d3575
KZ
416
417 /* Qemu */
418 } else if (is_devtree_compatible(cxt, "qemu,pseries")) {
419 vendor = VIRT_VENDOR_KVM;
420 *type = VIRT_TYPE_PARA;
421 }
422
423 return vendor;
424}
425
426#ifdef INCLUDE_VMWARE_BDOOR
427
428#define VMWARE_BDOOR_MAGIC 0x564D5868
429#define VMWARE_BDOOR_PORT 0x5658
430#define VMWARE_BDOOR_CMD_GETVERSION 10
431
432static UL_ASAN_BLACKLIST
433void vmware_bdoor(uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
434{
435 __asm__(
436#if defined(__PIC__) && defined(__i386__)
437 /* x86 PIC cannot clobber ebx -- gcc bitches */
438 "xchg %%ebx, %%esi;"
439 "inl (%%dx), %%eax;"
440 "xchg %%esi, %%ebx;"
441 : "=S" (*ebx),
442#else
443 "inl (%%dx), %%eax;"
444 : "=b" (*ebx),
445#endif
446 "=a" (*eax),
447 "=c" (*ecx),
448 "=d" (*edx)
449 : "0" (VMWARE_BDOOR_MAGIC),
450 "1" (VMWARE_BDOOR_CMD_GETVERSION),
451 "2" (VMWARE_BDOOR_PORT),
452 "3" (0)
453 : "memory");
454}
455
456static jmp_buf segv_handler_env;
457
458static void
459segv_handler(__attribute__((__unused__)) int sig,
460 __attribute__((__unused__)) siginfo_t *info,
461 __attribute__((__unused__)) void *ignored)
462{
463 siglongjmp(segv_handler_env, 1);
464}
465
466static int is_vmware_platform(void)
467{
468 uint32_t eax, ebx, ecx, edx;
469 struct sigaction act, oact;
470
471 /*
472 * FIXME: Not reliable for non-root users. Note it works as expected if
473 * vmware_bdoor() is not optimized for PIE, but then it fails to build
474 * on 32bit x86 systems. See lscpu git log for more details (commit
475 * 7845b91dbc7690064a2be6df690e4aaba728fb04). kzak [3-Nov-2016]
476 */
477 if (getuid() != 0)
478 return 0;
479
480 /*
481 * The assembly routine for vmware detection works
482 * fine under vmware, even if ran as regular user. But
483 * on real HW or under other hypervisors, it segfaults (which is
484 * expected). So we temporarily install SIGSEGV handler to catch
485 * the signal. All this magic is needed because lscpu
486 * isn't supposed to require root privileges.
487 */
488 if (sigsetjmp(segv_handler_env, 1))
489 return 0;
490
491 memset(&act, 0, sizeof(act));
492 act.sa_sigaction = segv_handler;
493 act.sa_flags = SA_SIGINFO;
494
495 if (sigaction(SIGSEGV, &act, &oact))
496 err(EXIT_FAILURE, _("cannot set signal handler"));
497
498 vmware_bdoor(&eax, &ebx, &ecx, &edx);
499
500 if (sigaction(SIGSEGV, &oact, NULL))
501 err(EXIT_FAILURE, _("cannot restore signal handler"));
502
503 return eax != (uint32_t)-1 && ebx == VMWARE_BDOOR_MAGIC;
504}
505
506#else /* ! INCLUDE_VMWARE_BDOOR */
507
508static int is_vmware_platform(void)
509{
510 return 0;
511}
512
513#endif /* INCLUDE_VMWARE_BDOOR */
514struct lscpu_virt *lscpu_read_virtualization(struct lscpu_cxt *cxt)
515{
516 char buf[BUFSIZ];
517 struct lscpu_cputype *ct;
518 struct lscpu_virt *virt;
519 FILE *fd;
520
521 DBG(VIRT, ul_debug("reading virtualization"));
522 virt = xcalloc(1, sizeof(*virt));
523
524 /* CPU flags */
525 ct = lscpu_cputype_get_default(cxt);
526 if (ct && ct->flags) {
527 snprintf(buf, sizeof(buf), " %s ", ct->flags);
528 if (strstr(buf, " svm "))
529 virt->cpuflag = xstrdup("svm");
530 else if (strstr(buf, " vmx "))
531 virt->cpuflag = xstrdup("vmx");
532 }
533
534
535 /* We have to detect WSL first. is_vmware_platform() crashes on Windows 10. */
536 fd = ul_path_fopen(cxt->procfs, "r", "sys/kernel/osrelease");
537 if (fd) {
538 if (fgets(buf, sizeof(buf), fd) && strstr(buf, "Microsoft")) {
539 virt->vendor = VIRT_VENDOR_WSL;
540 virt->type = VIRT_TYPE_CONTAINER;
541 }
542 fclose(fd);
543 if (virt->type)
544 goto done;
545 }
546
547 if (!cxt->noalive) {
548 virt->vendor = read_hypervisor_cpuid();
549 if (!virt->vendor)
550 virt->vendor = read_hypervisor_dmi();
551 if (!virt->vendor && is_vmware_platform())
552 virt->vendor = VIRT_VENDOR_VMWARE;
553 }
554
555 if (virt->vendor) {
556 virt->type = VIRT_TYPE_FULL;
557
558 if (virt->vendor == VIRT_VENDOR_XEN) {
559 uint32_t features;
560
9fa970fb 561 if (ul_path_scanf(cxt->rootfs, _PATH_SYS_HYP_FEATURES, "%x", &features) == 1) {
909d3575
KZ
562 /* Xen PV domain */
563 if (features & XEN_FEATURES_PV_MASK)
564 virt->type = VIRT_TYPE_PARA;
565 /* Xen PVH domain */
566 else if ((features & XEN_FEATURES_PVH_MASK)
567 == XEN_FEATURES_PVH_MASK)
568 virt->type = VIRT_TYPE_PARA;
569 }
909d3575
KZ
570 }
571 } else if ((virt->vendor = read_hypervisor_powerpc(cxt, &virt->type))) {
572 ;
573
574 /* Xen para-virt or dom0 */
575 } else if (ul_path_access(cxt->procfs, F_OK, "xen") == 0) {
9fa970fb 576 char xenbuf[256];
909d3575
KZ
577 int dom0 = 0;
578
9fa970fb
TS
579 if (ul_path_scanf(cxt->procfs, "xen/capabilities", "%255s", xenbuf) == 1 &&
580 !strcmp(xenbuf, "control_d"))
581 dom0 = 1;
909d3575
KZ
582 virt->type = dom0 ? VIRT_TYPE_NONE : VIRT_TYPE_PARA;
583 virt->vendor = VIRT_VENDOR_XEN;
584
585 /* Xen full-virt on non-x86_64 */
586 } else if (has_pci_device(cxt, hv_vendor_pci[VIRT_VENDOR_XEN], hv_graphics_pci[VIRT_VENDOR_XEN])) {
587 virt->vendor = VIRT_VENDOR_XEN;
588 virt->type = VIRT_TYPE_FULL;
589 } else if (has_pci_device(cxt, hv_vendor_pci[VIRT_VENDOR_VMWARE], hv_graphics_pci[VIRT_VENDOR_VMWARE])) {
590 virt->vendor = VIRT_VENDOR_VMWARE;
591 virt->type = VIRT_TYPE_FULL;
592 } else if (has_pci_device(cxt, hv_vendor_pci[VIRT_VENDOR_VBOX], hv_graphics_pci[VIRT_VENDOR_VBOX])) {
593 virt->vendor = VIRT_VENDOR_VBOX;
594 virt->type = VIRT_TYPE_FULL;
595
596 /* IBM PR/SM */
597 } else if ((fd = ul_path_fopen(cxt->procfs, "r", "sysinfo"))) {
598
599 virt->vendor = VIRT_VENDOR_IBM;
600 virt->hypervisor = "PR/SM";
601 virt->type = VIRT_TYPE_FULL;
602
603 while (fgets(buf, sizeof(buf), fd) != NULL) {
909d3575
KZ
604 if (!strstr(buf, "Control Program:"))
605 continue;
606 virt->vendor = strstr(buf, "KVM") ? VIRT_VENDOR_KVM : VIRT_VENDOR_IBM;
9aa82cd7
KZ
607 virt->hypervisor = strchr(buf, ':');
608
609 if (virt->hypervisor) {
610 virt->hypervisor++;
611 normalize_whitespace((unsigned char *) virt->hypervisor);
612 break;
613 }
909d3575 614 }
021d0b3d
KZ
615 if (virt->hypervisor)
616 virt->hypervisor = xstrdup(virt->hypervisor);
909d3575
KZ
617 fclose(fd);
618 }
619
620 /* OpenVZ/Virtuozzo - /proc/vz dir should exist
621 * /proc/bc should not */
622 else if (ul_path_access(cxt->procfs, F_OK, "vz") == 0 &&
623 ul_path_access(cxt->procfs, F_OK, "bc") != 0) {
624 virt->vendor = VIRT_VENDOR_PARALLELS;
625 virt->type = VIRT_TYPE_CONTAINER;
626
627 /* IBM */
628 } else if (virt->hypervisor &&
629 (strcmp(virt->hypervisor, "PowerVM Lx86") == 0 ||
630 strcmp(virt->hypervisor, "IBM/S390") == 0)) {
631 virt->vendor = VIRT_VENDOR_IBM;
632 virt->type = VIRT_TYPE_FULL;
633
634 /* User-mode-linux */
635 } else if (ct && ct->modelname && strstr(ct->modelname, "UML")) {
636 virt->vendor = VIRT_VENDOR_UML;
637 virt->type = VIRT_TYPE_PARA;
638
639 /* Linux-VServer */
640 } else if ((fd = ul_path_fopen(cxt->procfs, "r", "self/status"))) {
641 char *val = NULL;
642
643 while (fgets(buf, sizeof(buf), fd) != NULL) {
644 if (lookup(buf, "VxID", &val))
645 break;
646 }
647 fclose(fd);
648
649 if (val) {
650 char *org = val;
651
652 while (isdigit(*val))
653 ++val;
654 if (!*val) {
655 virt->vendor = VIRT_VENDOR_VSERVER;
656 virt->type = VIRT_TYPE_CONTAINER;
657 }
658 free(org);
659 }
660 }
661done:
9aa82cd7 662 DBG(VIRT, ul_debugobj(virt, "virt: cpu='%s' hypervisor='%s' vendor=%d type=%d",
909d3575
KZ
663 virt->cpuflag,
664 virt->hypervisor,
665 virt->vendor,
666 virt->type));
91eef60c
KZ
667
668 if (!virt->cpuflag && !virt->hypervisor && !virt->vendor && !virt->type) {
669 lscpu_free_virtualization(virt);
670 virt = NULL;
671 }
909d3575
KZ
672 return virt;
673}
674
a94bb435 675void lscpu_free_virtualization(struct lscpu_virt *virt)
909d3575
KZ
676{
677 if (!virt)
678 return;
679
680 free(virt->cpuflag);
681 free(virt->hypervisor);
682 free(virt);
683}
684