]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/lscpu.c
sys-utils: lscpu segfaults when built with -fsanitize=address
[thirdparty/util-linux.git] / sys-utils / lscpu.c
CommitLineData
5dd7507c
CQ
1/*
2 * lscpu - CPU architecture information helper
3 *
4 * Copyright (C) 2008 Cai Qian <qcai@redhat.com>
5 * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
6 *
80dde62f 7 * This program is free software; you can redistribute it and/or modify
5dd7507c 8 * it under the terms of the GNU General Public License as published by
80dde62f 9 * the Free Software Foundation; either version 2 of the License, or
5dd7507c
CQ
10 * (at your option) any later version.
11 *
80dde62f 12 * This program is distributed in the hope that it would be useful,
5dd7507c
CQ
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
7cebf0bb
SK
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
5dd7507c
CQ
20 */
21
5bd31c6d 22#include <assert.h>
5dd7507c
CQ
23#include <ctype.h>
24#include <dirent.h>
5dd7507c
CQ
25#include <errno.h>
26#include <fcntl.h>
27#include <getopt.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <sys/utsname.h>
32#include <unistd.h>
33#include <stdarg.h>
39561c70
KZ
34#include <sys/types.h>
35#include <sys/stat.h>
5dd7507c 36
a680b2ab 37#if (defined(__x86_64__) || defined(__i386__)) && !defined(__SANITIZE_ADDRESS__)
b7744730
RM
38# define INCLUDE_VMWARE_BDOOR
39#endif
40
41#ifdef INCLUDE_VMWARE_BDOOR
42# include <stdint.h>
43# include <signal.h>
44# include <strings.h>
45# include <setjmp.h>
65322517 46# ifdef HAVE_SYS_IO_H
b7744730
RM
47# include <sys/io.h>
48# endif
49#endif
50
83db4eb2
OO
51#include <libsmartcols.h>
52
7e03f383 53#include "cpuset.h"
5dd7507c 54#include "nls.h"
4581647a 55#include "xalloc.h"
eb76ca98 56#include "c.h"
477251f8
KZ
57#include "strutils.h"
58#include "bitops.h"
8148217b 59#include "path.h"
efb8854f 60#include "closestream.h"
41a8940d 61#include "optutils.h"
fb2627ce 62#include "lscpu.h"
477251f8 63
5dd7507c
CQ
64#define CACHE_MAX 100
65
66/* /sys paths */
d50363cd 67#define _PATH_SYS_SYSTEM "/sys/devices/system"
7e03f383 68#define _PATH_SYS_CPU _PATH_SYS_SYSTEM "/cpu"
e9074a16 69#define _PATH_SYS_NODE _PATH_SYS_SYSTEM "/node"
d50363cd 70#define _PATH_PROC_XEN "/proc/xen"
c8b64f6d 71#define _PATH_PROC_XENCAP _PATH_PROC_XEN "/capabilities"
d50363cd
KZ
72#define _PATH_PROC_CPUINFO "/proc/cpuinfo"
73#define _PATH_PROC_PCIDEVS "/proc/bus/pci/devices"
b8ec7bdf 74#define _PATH_PROC_SYSINFO "/proc/sysinfo"
fb2627ce
OO
75#define _PATH_PROC_STATUS "/proc/self/status"
76#define _PATH_PROC_VZ "/proc/vz"
77#define _PATH_PROC_BC "/proc/bc"
5bd31c6d 78#define _PATH_PROC_DEVICETREE "/proc/device-tree"
fb2627ce 79#define _PATH_DEV_MEM "/dev/mem"
5dd7507c 80
c8b64f6d
KZ
81/* virtualization types */
82enum {
83 VIRT_NONE = 0,
84 VIRT_PARA,
857d9cdf
KZ
85 VIRT_FULL,
86 VIRT_CONT
c8b64f6d
KZ
87};
88const char *virt_types[] = {
89 [VIRT_NONE] = N_("none"),
90 [VIRT_PARA] = N_("para"),
857d9cdf
KZ
91 [VIRT_FULL] = N_("full"),
92 [VIRT_CONT] = N_("container"),
c8b64f6d
KZ
93};
94
c8b64f6d
KZ
95const char *hv_vendors[] = {
96 [HYPER_NONE] = NULL,
97 [HYPER_XEN] = "Xen",
98 [HYPER_KVM] = "KVM",
99fbc877 99 [HYPER_MSHV] = "Microsoft",
b8ec7bdf 100 [HYPER_VMWARE] = "VMware",
fb2627ce
OO
101 [HYPER_IBM] = "IBM",
102 [HYPER_VSERVER] = "Linux-VServer",
103 [HYPER_UML] = "User-mode Linux",
104 [HYPER_INNOTEK] = "Innotek GmbH",
105 [HYPER_HITACHI] = "Hitachi",
96ce475f
RM
106 [HYPER_PARALLELS] = "Parallels",
107 [HYPER_VBOX] = "Oracle",
5bd31c6d
RM
108 [HYPER_OS400] = "OS/400",
109 [HYPER_PHYP] = "pHyp",
4597b692 110 [HYPER_SPAR] = "Unisys s-Par"
96ce475f
RM
111};
112
113const int hv_vendor_pci[] = {
114 [HYPER_NONE] = 0x0000,
115 [HYPER_XEN] = 0x5853,
116 [HYPER_KVM] = 0x0000,
117 [HYPER_MSHV] = 0x1414,
118 [HYPER_VMWARE] = 0x15ad,
119 [HYPER_VBOX] = 0x80ee,
120};
121
122const int hv_graphics_pci[] = {
123 [HYPER_NONE] = 0x0000,
124 [HYPER_XEN] = 0x0001,
125 [HYPER_KVM] = 0x0000,
126 [HYPER_MSHV] = 0x5353,
127 [HYPER_VMWARE] = 0x0710,
128 [HYPER_VBOX] = 0xbeef,
c8b64f6d
KZ
129};
130
f633ad4e 131/* CPU modes */
79e8b41a 132enum {
f633ad4e
KZ
133 MODE_32BIT = (1 << 1),
134 MODE_64BIT = (1 << 2)
79e8b41a 135};
c8b64f6d 136
e8aa16ee
KZ
137/* cache(s) description */
138struct cpu_cache {
7e03f383
KZ
139 char *name;
140 char *size;
141
142 int nsharedmaps;
143 cpu_set_t **sharedmaps;
e8aa16ee
KZ
144};
145
a0fff77e
HC
146/* dispatching modes */
147enum {
148 DISP_HORIZONTAL = 0,
149 DISP_VERTICAL = 1
150};
151
152const char *disp_modes[] = {
153 [DISP_HORIZONTAL] = N_("horizontal"),
154 [DISP_VERTICAL] = N_("vertical")
155};
156
2b8fcb81
HC
157/* cpu polarization */
158enum {
159 POLAR_UNKNOWN = 0,
160 POLAR_VLOW,
161 POLAR_VMEDIUM,
162 POLAR_VHIGH,
163 POLAR_HORIZONTAL
164};
165
8005924a
KZ
166struct polarization_modes {
167 char *parsable;
168 char *readable;
169};
170
171struct polarization_modes polar_modes[] = {
172 [POLAR_UNKNOWN] = {"U", "-"},
173 [POLAR_VLOW] = {"VL", "vert-low"},
174 [POLAR_VMEDIUM] = {"VM", "vert-medium"},
175 [POLAR_VHIGH] = {"VH", "vert-high"},
176 [POLAR_HORIZONTAL] = {"H", "horizontal"},
2b8fcb81
HC
177};
178
e8aa16ee
KZ
179/* global description */
180struct lscpu_desc {
5dd7507c
CQ
181 char *arch;
182 char *vendor;
183 char *family;
184 char *model;
1461094c 185 char *modelname;
c8b64f6d 186 char *virtflag; /* virtualization flag (vmx, svm) */
10829cd7 187 char *hypervisor; /* hypervisor software */
c8b64f6d
KZ
188 int hyper; /* hypervisor vendor ID */
189 int virtype; /* VIRT_PARA|FULL|NONE ? */
5dd7507c 190 char *mhz;
e065a597
DB
191 char **maxmhz; /* maximum mega hertz */
192 char **minmhz; /* minimum mega hertz */
5dd7507c 193 char *stepping;
9b8d4d5f 194 char *bogomips;
5dd7507c 195 char *flags;
a0fff77e 196 int dispatching; /* none, horizontal or vertical */
79e8b41a
KZ
197 int mode; /* rm, lm or/and tm */
198
a5cfffff
TK
199 int ncpuspos; /* maximal possible CPUs */
200 int ncpus; /* number of present CPUs */
201 cpu_set_t *present; /* mask with present CPUs */
aac1e59e 202 cpu_set_t *online; /* mask with online CPUs */
7e03f383 203
4f642863
AT
204 int nthreads; /* number of online threads */
205
206 int ncaches;
207 struct cpu_cache *caches;
208
209 /*
210 * All maps are sequentially indexed (0..ncpuspos), the array index
211 * does not have match with cpuX number as presented by kernel. You
212 * have to use real_cpu_num() to get the real cpuX number.
213 *
214 * For example, the possible system CPUs are: 1,3,5, it means that
215 * ncpuspos=3, so all arrays are in range 0..3.
216 */
217 int *idx2cpunum; /* mapping index to CPU num */
218
7e03f383 219 int nnodes; /* number of NUMA modes */
e9074a16 220 int *idx2nodenum; /* Support for discontinuous nodes */
7e03f383
KZ
221 cpu_set_t **nodemaps; /* array with NUMA nodes */
222
56baaa4e
HC
223 /* books -- based on book_siblings (internal kernel map of cpuX's
224 * hardware threads within the same book */
225 int nbooks; /* number of all online books */
226 cpu_set_t **bookmaps; /* unique book_siblings */
227
7e03f383
KZ
228 /* sockets -- based on core_siblings (internal kernel map of cpuX's
229 * hardware threads within the same physical_package_id (socket)) */
e282eec2 230 int nsockets; /* number of all online sockets */
7e03f383
KZ
231 cpu_set_t **socketmaps; /* unique core_siblings */
232
233 /* cores -- based on thread_siblings (internel kernel map of cpuX's
234 * hardware threads within the same core as cpuX) */
e282eec2 235 int ncores; /* number of all online cores */
7e03f383
KZ
236 cpu_set_t **coremaps; /* unique thread_siblings */
237
2b8fcb81 238 int *polarization; /* cpu polarization */
596b8845 239 int *addresses; /* physical cpu addresses */
d231eea1 240 int *configured; /* cpu configured */
5dd7507c
CQ
241};
242
8005924a
KZ
243enum {
244 OUTPUT_SUMMARY = 0, /* default */
245 OUTPUT_PARSABLE, /* -p */
ba45d8c1 246 OUTPUT_READABLE, /* -e */
8005924a
KZ
247};
248
8148217b
HC
249enum {
250 SYSTEM_LIVE = 0, /* analyzing a live system */
251 SYSTEM_SNAPSHOT, /* analyzing a snapshot of a different system */
252};
253
8005924a 254struct lscpu_modifier {
a7e5300c 255 int mode; /* OUTPUT_* */
8148217b 256 int system; /* SYSTEM_* */
a7e5300c
HC
257 unsigned int hex:1, /* print CPU masks rather than CPU lists */
258 compat:1, /* use backwardly compatible format */
7afc2387
HC
259 online:1, /* print online CPUs */
260 offline:1; /* print offline CPUs */
8005924a
KZ
261};
262
7e03f383 263static int maxcpus; /* size in bits of kernel cpu mask */
5dd7507c 264
aac1e59e 265#define is_cpu_online(_d, _cpu) \
a5cfffff
TK
266 ((_d) && (_d)->online ? \
267 CPU_ISSET_S((_cpu), CPU_ALLOC_SIZE(maxcpus), (_d)->online) : 0)
268#define is_cpu_present(_d, _cpu) \
269 ((_d) && (_d)->present ? \
270 CPU_ISSET_S((_cpu), CPU_ALLOC_SIZE(maxcpus), (_d)->present) : 0)
aac1e59e 271
4f642863
AT
272#define real_cpu_num(_d, _i) ((_d)->idx2cpunum[(_i)])
273
477251f8 274/*
3d27b76a 275 * IDs
477251f8
KZ
276 */
277enum {
278 COL_CPU,
279 COL_CORE,
280 COL_SOCKET,
281 COL_NODE,
282 COL_BOOK,
2b8fcb81 283 COL_CACHE,
596b8845 284 COL_POLARIZATION,
d231eea1
HC
285 COL_ADDRESS,
286 COL_CONFIGURED,
a7e5300c 287 COL_ONLINE,
e065a597
DB
288 COL_MAXMHZ,
289 COL_MINMHZ,
477251f8
KZ
290};
291
3d27b76a
KZ
292/* column description
293 */
294struct lscpu_coldesc {
295 const char *name;
296 const char *help;
297
298 unsigned int is_abbr:1; /* name is abbreviation */
477251f8
KZ
299};
300
3d27b76a
KZ
301static struct lscpu_coldesc coldescs[] =
302{
303 [COL_CPU] = { "CPU", N_("logical CPU number"), 1 },
304 [COL_CORE] = { "CORE", N_("logical core number") },
305 [COL_SOCKET] = { "SOCKET", N_("logical socket number") },
306 [COL_NODE] = { "NODE", N_("logical NUMA node number") },
307 [COL_BOOK] = { "BOOK", N_("logical book number") },
308 [COL_CACHE] = { "CACHE", N_("shows how caches are shared between CPUs") },
309 [COL_POLARIZATION] = { "POLARIZATION", N_("CPU dispatching mode on virtual hardware") },
310 [COL_ADDRESS] = { "ADDRESS", N_("physical address of a CPU") },
311 [COL_CONFIGURED] = { "CONFIGURED", N_("shows if the hypervisor has allocated the CPU") },
44320710 312 [COL_ONLINE] = { "ONLINE", N_("shows if Linux currently makes use of the CPU") },
4df28845
BS
313 [COL_MAXMHZ] = { "MAXMHZ", N_("shows the maximum MHz of the CPU") },
314 [COL_MINMHZ] = { "MINMHZ", N_("shows the minimum MHz of the CPU") }
3d27b76a 315};
477251f8 316
583f14cc
KZ
317static int
318column_name_to_id(const char *name, size_t namesz)
477251f8 319{
329fd1c3 320 size_t i;
477251f8 321
3d27b76a
KZ
322 for (i = 0; i < ARRAY_SIZE(coldescs); i++) {
323 const char *cn = coldescs[i].name;
477251f8
KZ
324
325 if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
326 return i;
327 }
328 warnx(_("unknown column: %s"), name);
329 return -1;
330}
331
5dd7507c
CQ
332/* Lookup a pattern and get the value from cpuinfo.
333 * Format is:
334 *
335 * "<pattern> : <key>"
336 */
583f14cc
KZ
337static int
338lookup(char *line, char *pattern, char **value)
5dd7507c
CQ
339{
340 char *p, *v;
341 int len = strlen(pattern);
342
343 if (!*line)
344 return 0;
345
346 /* pattern */
347 if (strncmp(line, pattern, len))
348 return 0;
349
350 /* white spaces */
351 for (p = line + len; isspace(*p); p++);
352
353 /* separator */
354 if (*p != ':')
355 return 0;
356
357 /* white spaces */
358 for (++p; isspace(*p); p++);
359
360 /* value */
361 if (!*p)
362 return 0;
363 v = p;
364
365 /* end of value */
366 len = strlen(line) - 1;
367 for (p = line + len; isspace(*(p-1)); p--);
368 *p = '\0';
369
370 *value = xstrdup(v);
371 return 1;
372}
373
f633ad4e
KZ
374/* Don't init the mode for platforms where we are not able to
375 * detect that CPU supports 64-bit mode.
376 */
377static int
8148217b 378init_mode(struct lscpu_modifier *mod)
f633ad4e
KZ
379{
380 int m = 0;
381
8148217b 382 if (mod->system == SYSTEM_SNAPSHOT)
4e740fd8
KZ
383 /* reading info from any /{sys,proc} dump, don't mix it with
384 * information about our real CPU */
385 return 0;
386
f633ad4e
KZ
387#if defined(__alpha__) || defined(__ia64__)
388 m |= MODE_64BIT; /* 64bit platforms only */
389#endif
390 /* platforms with 64bit flag in /proc/cpuinfo, define
391 * 32bit default here */
392#if defined(__i386__) || defined(__x86_64__) || \
c487c90c 393 defined(__s390x__) || defined(__s390__) || defined(__sparc_v9__)
f633ad4e
KZ
394 m |= MODE_32BIT;
395#endif
396 return m;
397}
398
5dd7507c 399static void
8148217b 400read_basicinfo(struct lscpu_desc *desc, struct lscpu_modifier *mod)
5dd7507c 401{
d50363cd 402 FILE *fp = path_fopen("r", 1, _PATH_PROC_CPUINFO);
5dd7507c
CQ
403 char buf[BUFSIZ];
404 struct utsname utsbuf;
a5cfffff 405 size_t setsize;
5dd7507c
CQ
406
407 /* architecture */
408 if (uname(&utsbuf) == -1)
409 err(EXIT_FAILURE, _("error: uname failed"));
e8aa16ee 410 desc->arch = xstrdup(utsbuf.machine);
5dd7507c 411
5dd7507c
CQ
412 /* details */
413 while (fgets(buf, sizeof(buf), fp) != NULL) {
e8aa16ee
KZ
414 if (lookup(buf, "vendor", &desc->vendor)) ;
415 else if (lookup(buf, "vendor_id", &desc->vendor)) ;
e8aa16ee
KZ
416 else if (lookup(buf, "family", &desc->family)) ;
417 else if (lookup(buf, "cpu family", &desc->family)) ;
418 else if (lookup(buf, "model", &desc->model)) ;
1461094c 419 else if (lookup(buf, "model name", &desc->modelname)) ;
e8aa16ee
KZ
420 else if (lookup(buf, "stepping", &desc->stepping)) ;
421 else if (lookup(buf, "cpu MHz", &desc->mhz)) ;
f633ad4e
KZ
422 else if (lookup(buf, "flags", &desc->flags)) ; /* x86 */
423 else if (lookup(buf, "features", &desc->flags)) ; /* s390 */
c487c90c 424 else if (lookup(buf, "type", &desc->flags)) ; /* sparc64 */
9b8d4d5f 425 else if (lookup(buf, "bogomips", &desc->bogomips)) ;
abcd6368 426 else if (lookup(buf, "bogomips per cpu", &desc->bogomips)) ; /* s390 */
5dd7507c
CQ
427 else
428 continue;
429 }
c8b64f6d 430
8148217b 431 desc->mode = init_mode(mod);
f633ad4e 432
e8aa16ee
KZ
433 if (desc->flags) {
434 snprintf(buf, sizeof(buf), " %s ", desc->flags);
c8b64f6d 435 if (strstr(buf, " svm "))
8290a249 436 desc->virtflag = xstrdup("svm");
c8b64f6d 437 else if (strstr(buf, " vmx "))
8290a249 438 desc->virtflag = xstrdup("vmx");
79e8b41a 439 if (strstr(buf, " lm "))
f633ad4e
KZ
440 desc->mode |= MODE_32BIT | MODE_64BIT; /* x86_64 */
441 if (strstr(buf, " zarch "))
442 desc->mode |= MODE_32BIT | MODE_64BIT; /* s390x */
c487c90c
KZ
443 if (strstr(buf, " sun4v ") || strstr(buf, " sun4u "))
444 desc->mode |= MODE_32BIT | MODE_64BIT; /* sparc64 */
c8b64f6d
KZ
445 }
446
4581b716
KZ
447 if (desc->arch && mod->system != SYSTEM_SNAPSHOT) {
448 if (strcmp(desc->arch, "ppc64") == 0)
449 desc->mode |= MODE_32BIT | MODE_64BIT;
450 else if (strcmp(desc->arch, "ppc") == 0)
451 desc->mode |= MODE_32BIT;
452 }
453
5dd7507c 454 fclose(fp);
7e03f383 455
1d56b55e 456 if (path_exist(_PATH_SYS_CPU "/kernel_max"))
3d6e5c35 457 /* note that kernel_max is maximum index [NR_CPUS-1] */
1d56b55e 458 maxcpus = path_read_s32(_PATH_SYS_CPU "/kernel_max") + 1;
7e03f383 459
8148217b 460 else if (mod->system == SYSTEM_LIVE)
7e03f383
KZ
461 /* the root is '/' so we are working with data from the current kernel */
462 maxcpus = get_max_number_of_cpus();
701e2b8e
KZ
463
464 if (maxcpus <= 0)
465 /* error or we are reading some /sys snapshot instead of the
466 * real /sys, let's use any crazy number... */
a5cfffff
TK
467 maxcpus = 2048;
468
469 setsize = CPU_ALLOC_SIZE(maxcpus);
470
1d56b55e
RM
471 if (path_exist(_PATH_SYS_CPU "/possible")) {
472 cpu_set_t *tmp = path_read_cpulist(maxcpus, _PATH_SYS_CPU "/possible");
4f642863
AT
473 int num, idx;
474
a5cfffff 475 desc->ncpuspos = CPU_COUNT_S(setsize, tmp);
4f642863
AT
476 desc->idx2cpunum = xcalloc(desc->ncpuspos, sizeof(int));
477
478 for (num = 0, idx = 0; num < maxcpus; num++) {
479 if (CPU_ISSET(num, tmp))
480 desc->idx2cpunum[idx++] = num;
481 }
a5cfffff
TK
482 cpuset_free(tmp);
483 } else
484 err(EXIT_FAILURE, _("failed to determine number of CPUs: %s"),
1d56b55e 485 _PATH_SYS_CPU "/possible");
a5cfffff
TK
486
487
488 /* get mask for present CPUs */
1d56b55e
RM
489 if (path_exist(_PATH_SYS_CPU "/present")) {
490 desc->present = path_read_cpulist(maxcpus, _PATH_SYS_CPU "/present");
a5cfffff
TK
491 desc->ncpus = CPU_COUNT_S(setsize, desc->present);
492 }
aac1e59e
KZ
493
494 /* get mask for online CPUs */
1d56b55e
RM
495 if (path_exist(_PATH_SYS_CPU "/online")) {
496 desc->online = path_read_cpulist(maxcpus, _PATH_SYS_CPU "/online");
e282eec2
KZ
497 desc->nthreads = CPU_COUNT_S(setsize, desc->online);
498 }
a0fff77e
HC
499
500 /* get dispatching mode */
1d56b55e
RM
501 if (path_exist(_PATH_SYS_CPU "/dispatching"))
502 desc->dispatching = path_read_s32(_PATH_SYS_CPU "/dispatching");
a0fff77e
HC
503 else
504 desc->dispatching = -1;
5dd7507c
CQ
505}
506
c8b64f6d 507static int
140014a4 508has_pci_device(unsigned int vendor, unsigned int device)
c8b64f6d
KZ
509{
510 FILE *f;
13cf6fc8 511 unsigned int num, fn, ven, dev;
c8b64f6d
KZ
512 int res = 1;
513
d50363cd 514 f = path_fopen("r", 0, _PATH_PROC_PCIDEVS);
c8b64f6d
KZ
515 if (!f)
516 return 0;
517
518 /* for more details about bus/pci/devices format see
519 * drivers/pci/proc.c in linux kernel
520 */
521 while(fscanf(f, "%02x%02x\t%04x%04x\t%*[^\n]",
522 &num, &fn, &ven, &dev) == 4) {
523
524 if (ven == vendor && dev == device)
525 goto found;
526 }
527
528 res = 0;
529found:
530 fclose(f);
531 return res;
532}
533
534#if defined(__x86_64__) || defined(__i386__)
535
536/*
537 * This CPUID leaf returns the information about the hypervisor.
538 * EAX : maximum input value for CPUID supported by the hypervisor.
539 * EBX, ECX, EDX : Hypervisor vendor ID signature. E.g. VMwareVMware.
540 */
541#define HYPERVISOR_INFO_LEAF 0x40000000
542
543static inline void
544cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx,
545 unsigned int *ecx, unsigned int *edx)
546{
c9239f23
MF
547 __asm__(
548#if defined(__PIC__) && defined(__i386__)
549 /* x86 PIC cannot clobber ebx -- gcc bitches */
7845b91d 550 "xchg %%ebx, %%esi;"
c9239f23 551 "cpuid;"
7845b91d 552 "xchg %%esi, %%ebx;"
c9239f23
MF
553 : "=S" (*ebx),
554#else
555 "cpuid;"
556 : "=b" (*ebx),
557#endif
558 "=a" (*eax),
c8b64f6d
KZ
559 "=c" (*ecx),
560 "=d" (*edx)
bc54770d 561 : "1" (op), "c"(0));
c8b64f6d
KZ
562}
563
564static void
e8aa16ee 565read_hypervisor_cpuid(struct lscpu_desc *desc)
c8b64f6d
KZ
566{
567 unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0;
568 char hyper_vendor_id[13];
569
570 memset(hyper_vendor_id, 0, sizeof(hyper_vendor_id));
571
572 cpuid(HYPERVISOR_INFO_LEAF, &eax, &ebx, &ecx, &edx);
573 memcpy(hyper_vendor_id + 0, &ebx, 4);
574 memcpy(hyper_vendor_id + 4, &ecx, 4);
575 memcpy(hyper_vendor_id + 8, &edx, 4);
576 hyper_vendor_id[12] = '\0';
577
578 if (!hyper_vendor_id[0])
579 return;
580
581 if (!strncmp("XenVMMXenVMM", hyper_vendor_id, 12))
e8aa16ee 582 desc->hyper = HYPER_XEN;
c8b64f6d 583 else if (!strncmp("KVMKVMKVM", hyper_vendor_id, 9))
e8aa16ee 584 desc->hyper = HYPER_KVM;
c8b64f6d 585 else if (!strncmp("Microsoft Hv", hyper_vendor_id, 12))
e8aa16ee 586 desc->hyper = HYPER_MSHV;
99fbc877
SH
587 else if (!strncmp("VMwareVMware", hyper_vendor_id, 12))
588 desc->hyper = HYPER_VMWARE;
4597b692
BR
589 else if (!strncmp("UnisysSpar64", hyper_vendor_id, 12))
590 desc->hyper = HYPER_SPAR;
c8b64f6d
KZ
591}
592
b7744730 593#else /* ! (__x86_64__ || __i386__) */
c8b64f6d 594static void
6d791b4c 595read_hypervisor_cpuid(struct lscpu_desc *desc __attribute__((__unused__)))
c8b64f6d
KZ
596{
597}
598#endif
599
3565bd7a
KZ
600static int is_compatible(const char *path, const char *str)
601{
602 FILE *fd;
603
f93993b7 604 fd = path_fopen("r", 0, "%s", path);
3565bd7a
KZ
605 if (fd) {
606 char buf[256];
607 size_t i, len;
608
609 memset(buf, 0, sizeof(buf));
610 len = fread(buf, 1, sizeof(buf) - 1, fd);
611 fclose(fd);
612
613 for (i = 0; i < len;) {
614 if (!strcmp(&buf[i], str))
615 return 1;
616 i += strlen(&buf[i]);
617 i++;
618 }
619 }
620
621 return 0;
622}
623
5bd31c6d
RM
624static int
625read_hypervisor_powerpc(struct lscpu_desc *desc)
626{
627 assert(!desc->hyper);
628
79738105 629 /* IBM iSeries: legacy, para-virtualized on top of OS/400 */
5bd31c6d
RM
630 if (path_exist("/proc/iSeries")) {
631 desc->hyper = HYPER_OS400;
632 desc->virtype = VIRT_PARA;
79738105
KZ
633
634 /* PowerNV (POWER Non-Virtualized, bare-metal) */
635 } else if (path_exist(_PATH_PROC_DEVICETREE "/compatible")) {
636 if (is_compatible(_PATH_PROC_DEVICETREE "/compatible", "ibm,powernv")) {
d45984be
KZ
637 desc->hyper = HYPER_NONE;
638 desc->virtype = VIRT_NONE;
79738105
KZ
639 }
640
d45984be 641 /* PowerVM (IBM's proprietary hypervisor, aka pHyp) */
5bd31c6d
RM
642 } else if (path_exist(_PATH_PROC_DEVICETREE "/ibm,partition-name")
643 && path_exist(_PATH_PROC_DEVICETREE "/hmc-managed?")
644 && !path_exist(_PATH_PROC_DEVICETREE "/chosen/qemu,graphic-width")) {
645 FILE *fd;
646 desc->hyper = HYPER_PHYP;
647 desc->virtype = VIRT_PARA;
648 fd = path_fopen("r", 0, _PATH_PROC_DEVICETREE "/ibm,partition-name");
649 if (fd) {
650 char buf[256];
6cbf75e5 651 if (fscanf(fd, "%255s", buf) == 1 && !strcmp(buf, "full"))
5bd31c6d
RM
652 desc->virtype = VIRT_NONE;
653 fclose(fd);
654 }
79738105
KZ
655
656 /* Qemu */
3565bd7a
KZ
657 } else if (path_exist(_PATH_PROC_DEVICETREE "/compatible")) {
658 if (is_compatible(_PATH_PROC_DEVICETREE "/compatible", "qemu,pseries")) {
659 desc->hyper = HYPER_KVM;
79738105 660 desc->virtype = VIRT_PARA;
5bd31c6d
RM
661 }
662 }
5bd31c6d
RM
663 return desc->hyper;
664}
665
b7744730
RM
666#ifdef INCLUDE_VMWARE_BDOOR
667
668#define VMWARE_BDOOR_MAGIC 0x564D5868
669#define VMWARE_BDOOR_PORT 0x5658
670#define VMWARE_BDOOR_CMD_GETVERSION 10
671
77242032 672static UL_ASAN_BLACKLIST
7845b91d
MF
673void vmware_bdoor(uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
674{
675 __asm__(
676#if defined(__PIC__) && defined(__i386__)
677 /* x86 PIC cannot clobber ebx -- gcc bitches */
678 "xchg %%ebx, %%esi;"
679 "inl (%%dx), %%eax;"
680 "xchg %%esi, %%ebx;"
681 : "=S" (*ebx),
682#else
683 "inl (%%dx), %%eax;"
684 : "=b" (*ebx),
685#endif
686 "=a" (*eax),
687 "=c" (*ecx),
688 "=d" (*edx)
689 : "0" (VMWARE_BDOOR_MAGIC),
690 "1" (VMWARE_BDOOR_CMD_GETVERSION),
691 "2" (VMWARE_BDOOR_PORT),
692 "3" (0)
693 : "memory");
694}
b7744730
RM
695
696static jmp_buf segv_handler_env;
697
698static void
699segv_handler(__attribute__((__unused__)) int sig,
700 __attribute__((__unused__)) siginfo_t *info,
701 __attribute__((__unused__)) void *ignored)
702{
703 siglongjmp(segv_handler_env, 1);
704}
705
706static int
707is_vmware_platform(void)
708{
709 uint32_t eax, ebx, ecx, edx;
710 struct sigaction act, oact;
711
712 /*
713 * The assembly routine for vmware detection works
714 * fine under vmware, even if ran as regular user. But
715 * on real HW or under other hypervisors, it segfaults (which is
716 * expected). So we temporarily install SIGSEGV handler to catch
717 * the signal. All this magic is needed because lscpu
718 * isn't supposed to require root privileges.
719 */
720 if (sigsetjmp(segv_handler_env, 1))
721 return 0;
722
9dd2d497 723 memset(&act, 0, sizeof(act));
b7744730
RM
724 act.sa_sigaction = segv_handler;
725 act.sa_flags = SA_SIGINFO;
726
727 if (sigaction(SIGSEGV, &act, &oact))
728 err(EXIT_FAILURE, _("error: can not set signal handler"));
729
7845b91d 730 vmware_bdoor(&eax, &ebx, &ecx, &edx);
b7744730
RM
731
732 if (sigaction(SIGSEGV, &oact, NULL))
733 err(EXIT_FAILURE, _("error: can not restore signal handler"));
734
735 return eax != (uint32_t)-1 && ebx == VMWARE_BDOOR_MAGIC;
736}
737
738#else /* ! INCLUDE_VMWARE_BDOOR */
739
740static int
741is_vmware_platform(void)
742{
743 return 0;
744}
745
746#endif /* INCLUDE_VMWARE_BDOOR */
747
c8b64f6d 748static void
eff79ceb 749read_hypervisor(struct lscpu_desc *desc, struct lscpu_modifier *mod)
c8b64f6d 750{
fb2627ce
OO
751 FILE *fd;
752
753 if (mod->system != SYSTEM_SNAPSHOT) {
eff79ceb 754 read_hypervisor_cpuid(desc);
fb2627ce
OO
755 if (!desc->hyper)
756 desc->hyper = read_hypervisor_dmi();
b7744730
RM
757 if (!desc->hyper && is_vmware_platform())
758 desc->hyper = HYPER_VMWARE;
fb2627ce 759 }
c8b64f6d 760
e8aa16ee 761 if (desc->hyper)
e8aa16ee 762 desc->virtype = VIRT_FULL;
c8b64f6d 763
5bd31c6d
RM
764 else if (read_hypervisor_powerpc(desc) > 0) {}
765
fb2627ce 766 /* Xen para-virt or dom0 */
d50363cd 767 else if (path_exist(_PATH_PROC_XEN)) {
c8b64f6d 768 int dom0 = 0;
fb2627ce 769 fd = path_fopen("r", 0, _PATH_PROC_XENCAP);
c8b64f6d
KZ
770
771 if (fd) {
772 char buf[256];
773
6cbf75e5 774 if (fscanf(fd, "%255s", buf) == 1 &&
c8b64f6d
KZ
775 !strcmp(buf, "control_d"))
776 dom0 = 1;
777 fclose(fd);
778 }
e8aa16ee
KZ
779 desc->virtype = dom0 ? VIRT_NONE : VIRT_PARA;
780 desc->hyper = HYPER_XEN;
c8b64f6d 781
fb2627ce 782 /* Xen full-virt on non-x86_64 */
96ce475f 783 } else if (has_pci_device( hv_vendor_pci[HYPER_XEN], hv_graphics_pci[HYPER_XEN])) {
e8aa16ee
KZ
784 desc->hyper = HYPER_XEN;
785 desc->virtype = VIRT_FULL;
96ce475f
RM
786 } else if (has_pci_device( hv_vendor_pci[HYPER_VMWARE], hv_graphics_pci[HYPER_VMWARE])) {
787 desc->hyper = HYPER_VMWARE;
788 desc->virtype = VIRT_FULL;
789 } else if (has_pci_device( hv_vendor_pci[HYPER_VBOX], hv_graphics_pci[HYPER_VBOX])) {
790 desc->hyper = HYPER_VBOX;
791 desc->virtype = VIRT_FULL;
fb2627ce
OO
792
793 /* IBM PR/SM */
b8ec7bdf 794 } else if (path_exist(_PATH_PROC_SYSINFO)) {
145a3ca3 795 FILE *sysinfo_fd = path_fopen("r", 0, _PATH_PROC_SYSINFO);
b8ec7bdf
HC
796 char buf[BUFSIZ];
797
145a3ca3 798 if (!sysinfo_fd)
b3eff5dd 799 return;
b8ec7bdf 800 desc->hyper = HYPER_IBM;
10829cd7 801 desc->hypervisor = "PR/SM";
b8ec7bdf 802 desc->virtype = VIRT_FULL;
145a3ca3 803 while (fgets(buf, sizeof(buf), sysinfo_fd) != NULL) {
10829cd7
HC
804 char *str;
805
b8ec7bdf
HC
806 if (!strstr(buf, "Control Program:"))
807 continue;
808 if (!strstr(buf, "KVM"))
809 desc->hyper = HYPER_IBM;
810 else
811 desc->hyper = HYPER_KVM;
10829cd7
HC
812 str = strchr(buf, ':');
813 if (!str)
814 continue;
9d8537ff
KZ
815 xasprintf(&str, "%s", str + 1);
816
10829cd7
HC
817 /* remove leading, trailing and repeating whitespace */
818 while (*str == ' ')
819 str++;
820 desc->hypervisor = str;
821 str += strlen(str) - 1;
822 while ((*str == '\n') || (*str == ' '))
823 *(str--) = '\0';
824 while ((str = strstr(desc->hypervisor, " ")))
825 memmove(str, str + 1, strlen(str));
b8ec7bdf 826 }
145a3ca3 827 fclose(sysinfo_fd);
c8b64f6d 828 }
fb2627ce
OO
829
830 /* OpenVZ/Virtuozzo - /proc/vz dir should exist
831 * /proc/bc should not */
857d9cdf 832 else if (path_exist(_PATH_PROC_VZ) && !path_exist(_PATH_PROC_BC)) {
fb2627ce 833 desc->hyper = HYPER_PARALLELS;
857d9cdf 834 desc->virtype = VIRT_CONT;
fb2627ce
OO
835
836 /* IBM */
857d9cdf 837 } else if (desc->vendor &&
fb2627ce 838 (strcmp(desc->vendor, "PowerVM Lx86") == 0 ||
857d9cdf 839 strcmp(desc->vendor, "IBM/S390") == 0)) {
fb2627ce 840 desc->hyper = HYPER_IBM;
857d9cdf 841 desc->virtype = VIRT_FULL;
fb2627ce
OO
842
843 /* User-mode-linux */
857d9cdf 844 } else if (desc->modelname && strstr(desc->modelname, "UML")) {
fb2627ce 845 desc->hyper = HYPER_UML;
857d9cdf 846 desc->virtype = VIRT_PARA;
fb2627ce
OO
847
848 /* Linux-VServer */
857d9cdf 849 } else if (path_exist(_PATH_PROC_STATUS)) {
fb2627ce
OO
850 char buf[BUFSIZ];
851 char *val = NULL;
852
dbbf8395 853 fd = path_fopen("r", 1, _PATH_PROC_STATUS);
fb2627ce
OO
854 while (fgets(buf, sizeof(buf), fd) != NULL) {
855 if (lookup(buf, "VxID", &val))
856 break;
857 }
858 fclose(fd);
859
860 if (val) {
861 while (isdigit(*val))
862 ++val;
857d9cdf 863 if (!*val) {
fb2627ce 864 desc->hyper = HYPER_VSERVER;
857d9cdf
KZ
865 desc->virtype = VIRT_CONT;
866 }
fb2627ce
OO
867 }
868 }
c8b64f6d
KZ
869}
870
455fe9a0 871/* add @set to the @ary, unnecessary set is deallocated. */
7e03f383
KZ
872static int add_cpuset_to_array(cpu_set_t **ary, int *items, cpu_set_t *set)
873{
874 int i;
875 size_t setsize = CPU_ALLOC_SIZE(maxcpus);
876
877 if (!ary)
878 return -1;
879
880 for (i = 0; i < *items; i++) {
881 if (CPU_EQUAL_S(setsize, set, ary[i]))
882 break;
883 }
884 if (i == *items) {
885 ary[*items] = set;
886 ++*items;
887 return 0;
888 }
889 CPU_FREE(set);
890 return 1;
891}
892
5dd7507c 893static void
4f642863 894read_topology(struct lscpu_desc *desc, int idx)
5dd7507c 895{
56baaa4e 896 cpu_set_t *thread_siblings, *core_siblings, *book_siblings;
4f642863 897 int num = real_cpu_num(desc, idx);
7e03f383
KZ
898
899 if (!path_exist(_PATH_SYS_CPU "/cpu%d/topology/thread_siblings", num))
900 return;
5dd7507c 901
ca01695b 902 thread_siblings = path_read_cpuset(maxcpus, _PATH_SYS_CPU
7e03f383 903 "/cpu%d/topology/thread_siblings", num);
ca01695b 904 core_siblings = path_read_cpuset(maxcpus, _PATH_SYS_CPU
7e03f383 905 "/cpu%d/topology/core_siblings", num);
56baaa4e 906 book_siblings = NULL;
4f642863 907 if (path_exist(_PATH_SYS_CPU "/cpu%d/topology/book_siblings", num))
ca01695b 908 book_siblings = path_read_cpuset(maxcpus, _PATH_SYS_CPU
56baaa4e 909 "/cpu%d/topology/book_siblings", num);
aac1e59e
KZ
910
911 if (!desc->coremaps) {
56baaa4e 912 int nbooks, nsockets, ncores, nthreads;
7e03f383
KZ
913 size_t setsize = CPU_ALLOC_SIZE(maxcpus);
914
915 /* threads within one core */
916 nthreads = CPU_COUNT_S(setsize, thread_siblings);
d4bfa64d
KZ
917 if (!nthreads)
918 nthreads = 1;
919
7e03f383
KZ
920 /* cores within one socket */
921 ncores = CPU_COUNT_S(setsize, core_siblings) / nthreads;
d4bfa64d
KZ
922 if (!ncores)
923 ncores = 1;
924
925 /* number of sockets within one book. Because of odd /
926 * non-present cpu maps and to keep calculation easy we make
927 * sure that nsockets and nbooks is at least 1.
32a46618 928 */
d4bfa64d
KZ
929 nsockets = desc->ncpus / nthreads / ncores;
930 if (!nsockets)
931 nsockets = 1;
932
56baaa4e 933 /* number of books */
d4bfa64d
KZ
934 nbooks = desc->ncpus / nthreads / ncores / nsockets;
935 if (!nbooks)
936 nbooks = 1;
e282eec2
KZ
937
938 /* all threads, see also read_basicinfo()
32a46618 939 * -- fallback for kernels without
e282eec2
KZ
940 * /sys/devices/system/cpu/online.
941 */
942 if (!desc->nthreads)
32a46618 943 desc->nthreads = nbooks * nsockets * ncores * nthreads;
d4bfa64d 944
a5cfffff 945 /* For each map we make sure that it can have up to ncpuspos
9d1a3a18
HC
946 * entries. This is because we cannot reliably calculate the
947 * number of cores, sockets and books on all architectures.
948 * E.g. completely virtualized architectures like s390 may
949 * have multiple sockets of different sizes.
950 */
a5cfffff
TK
951 desc->coremaps = xcalloc(desc->ncpuspos, sizeof(cpu_set_t *));
952 desc->socketmaps = xcalloc(desc->ncpuspos, sizeof(cpu_set_t *));
08de16d0 953 if (book_siblings)
a5cfffff 954 desc->bookmaps = xcalloc(desc->ncpuspos, sizeof(cpu_set_t *));
7e03f383 955 }
5dd7507c 956
7e03f383
KZ
957 add_cpuset_to_array(desc->socketmaps, &desc->nsockets, core_siblings);
958 add_cpuset_to_array(desc->coremaps, &desc->ncores, thread_siblings);
56baaa4e
HC
959 if (book_siblings)
960 add_cpuset_to_array(desc->bookmaps, &desc->nbooks, book_siblings);
7e03f383 961}
4f642863 962
2b8fcb81 963static void
4f642863 964read_polarization(struct lscpu_desc *desc, int idx)
2b8fcb81
HC
965{
966 char mode[64];
4f642863 967 int num = real_cpu_num(desc, idx);
2b8fcb81
HC
968
969 if (desc->dispatching < 0)
970 return;
971 if (!path_exist(_PATH_SYS_CPU "/cpu%d/polarization", num))
972 return;
973 if (!desc->polarization)
a5cfffff 974 desc->polarization = xcalloc(desc->ncpuspos, sizeof(int));
ca01695b 975 path_read_str(mode, sizeof(mode), _PATH_SYS_CPU "/cpu%d/polarization", num);
2b8fcb81 976 if (strncmp(mode, "vertical:low", sizeof(mode)) == 0)
4f642863 977 desc->polarization[idx] = POLAR_VLOW;
2b8fcb81 978 else if (strncmp(mode, "vertical:medium", sizeof(mode)) == 0)
4f642863 979 desc->polarization[idx] = POLAR_VMEDIUM;
2b8fcb81 980 else if (strncmp(mode, "vertical:high", sizeof(mode)) == 0)
4f642863 981 desc->polarization[idx] = POLAR_VHIGH;
2b8fcb81 982 else if (strncmp(mode, "horizontal", sizeof(mode)) == 0)
4f642863 983 desc->polarization[idx] = POLAR_HORIZONTAL;
2b8fcb81 984 else
4f642863 985 desc->polarization[idx] = POLAR_UNKNOWN;
2b8fcb81 986}
7e03f383 987
596b8845 988static void
4f642863 989read_address(struct lscpu_desc *desc, int idx)
596b8845 990{
4f642863
AT
991 int num = real_cpu_num(desc, idx);
992
596b8845
HC
993 if (!path_exist(_PATH_SYS_CPU "/cpu%d/address", num))
994 return;
995 if (!desc->addresses)
a5cfffff 996 desc->addresses = xcalloc(desc->ncpuspos, sizeof(int));
4f642863 997 desc->addresses[idx] = path_read_s32(_PATH_SYS_CPU "/cpu%d/address", num);
596b8845 998}
7e03f383 999
d231eea1 1000static void
4f642863 1001read_configured(struct lscpu_desc *desc, int idx)
d231eea1 1002{
4f642863
AT
1003 int num = real_cpu_num(desc, idx);
1004
d231eea1
HC
1005 if (!path_exist(_PATH_SYS_CPU "/cpu%d/configure", num))
1006 return;
1007 if (!desc->configured)
a5cfffff 1008 desc->configured = xcalloc(desc->ncpuspos, sizeof(int));
4f642863 1009 desc->configured[idx] = path_read_s32(_PATH_SYS_CPU "/cpu%d/configure", num);
d231eea1
HC
1010}
1011
44320710 1012static void
4f642863 1013read_max_mhz(struct lscpu_desc *desc, int idx)
44320710 1014{
4f642863
AT
1015 int num = real_cpu_num(desc, idx);
1016
44320710
SK
1017 if (!path_exist(_PATH_SYS_CPU "/cpu%d/cpufreq/cpuinfo_max_freq", num))
1018 return;
e065a597
DB
1019 if (!desc->maxmhz)
1020 desc->maxmhz = xcalloc(desc->ncpuspos, sizeof(char *));
4f642863 1021 xasprintf(&(desc->maxmhz[idx]), "%.4f",
44320710
SK
1022 (float)path_read_s32(_PATH_SYS_CPU
1023 "/cpu%d/cpufreq/cpuinfo_max_freq", num) / 1000);
1024}
1025
e065a597 1026static void
4f642863 1027read_min_mhz(struct lscpu_desc *desc, int idx)
e065a597 1028{
4f642863
AT
1029 int num = real_cpu_num(desc, idx);
1030
e065a597
DB
1031 if (!path_exist(_PATH_SYS_CPU "/cpu%d/cpufreq/cpuinfo_min_freq", num))
1032 return;
1033 if (!desc->minmhz)
1034 desc->minmhz = xcalloc(desc->ncpuspos, sizeof(char *));
4f642863 1035 xasprintf(&(desc->minmhz[idx]), "%.4f",
e065a597
DB
1036 (float)path_read_s32(_PATH_SYS_CPU
1037 "/cpu%d/cpufreq/cpuinfo_min_freq", num) / 1000);
1038}
1039
7e03f383
KZ
1040static int
1041cachecmp(const void *a, const void *b)
1042{
1043 struct cpu_cache *c1 = (struct cpu_cache *) a;
1044 struct cpu_cache *c2 = (struct cpu_cache *) b;
1045
1046 return strcmp(c2->name, c1->name);
5dd7507c
CQ
1047}
1048
1049static void
4f642863 1050read_cache(struct lscpu_desc *desc, int idx)
5dd7507c
CQ
1051{
1052 char buf[256];
7e03f383 1053 int i;
4f642863 1054 int num = real_cpu_num(desc, idx);
5dd7507c 1055
aac1e59e 1056 if (!desc->ncaches) {
1d56b55e 1057 while(path_exist(_PATH_SYS_CPU "/cpu%d/cache/index%d",
7e03f383
KZ
1058 num, desc->ncaches))
1059 desc->ncaches++;
5dd7507c 1060
7e03f383
KZ
1061 if (!desc->ncaches)
1062 return;
5dd7507c 1063
08de16d0 1064 desc->caches = xcalloc(desc->ncaches, sizeof(*desc->caches));
7e03f383
KZ
1065 }
1066 for (i = 0; i < desc->ncaches; i++) {
1067 struct cpu_cache *ca = &desc->caches[i];
1068 cpu_set_t *map;
1069
1d56b55e 1070 if (!path_exist(_PATH_SYS_CPU "/cpu%d/cache/index%d",
dcdead42
HC
1071 num, i))
1072 continue;
7e03f383
KZ
1073 if (!ca->name) {
1074 int type, level;
1075
1076 /* cache type */
ca01695b 1077 path_read_str(buf, sizeof(buf),
7e03f383
KZ
1078 _PATH_SYS_CPU "/cpu%d/cache/index%d/type",
1079 num, i);
1080 if (!strcmp(buf, "Data"))
1081 type = 'd';
1082 else if (!strcmp(buf, "Instruction"))
1083 type = 'i';
1084 else
1085 type = 0;
1086
1087 /* cache level */
ca01695b 1088 level = path_read_s32(_PATH_SYS_CPU "/cpu%d/cache/index%d/level",
7e03f383
KZ
1089 num, i);
1090 if (type)
1091 snprintf(buf, sizeof(buf), "L%d%c", level, type);
1092 else
1093 snprintf(buf, sizeof(buf), "L%d", level);
1094
1095 ca->name = xstrdup(buf);
1096
1097 /* cache size */
10d927ab
RM
1098 if (path_exist(_PATH_SYS_CPU "/cpu%d/cache/index%d/size",num, i)) {
1099 path_read_str(buf, sizeof(buf),
1100 _PATH_SYS_CPU "/cpu%d/cache/index%d/size", num, i);
1101 ca->size = xstrdup(buf);
1102 } else {
1103 ca->size = xstrdup("unknown size");
1104 }
7e03f383 1105 }
5dd7507c 1106
7e03f383 1107 /* information about how CPUs share different caches */
ca01695b 1108 map = path_read_cpuset(maxcpus,
8148217b
HC
1109 _PATH_SYS_CPU "/cpu%d/cache/index%d/shared_cpu_map",
1110 num, i);
5dd7507c 1111
08de16d0 1112 if (!ca->sharedmaps)
a5cfffff 1113 ca->sharedmaps = xcalloc(desc->ncpuspos, sizeof(cpu_set_t *));
7e03f383 1114 add_cpuset_to_array(ca->sharedmaps, &ca->nsharedmaps, map);
5dd7507c
CQ
1115 }
1116}
1117
e9074a16
KZ
1118static inline int is_node_dirent(struct dirent *d)
1119{
1120 return
1121 d &&
1122#ifdef _DIRENT_HAVE_D_TYPE
c0cf4ae9 1123 (d->d_type == DT_DIR || d->d_type == DT_UNKNOWN) &&
e9074a16
KZ
1124#endif
1125 strncmp(d->d_name, "node", 4) == 0 &&
1126 isdigit_string(d->d_name + 4);
1127}
1128
39c758d1
KZ
1129static int
1130nodecmp(const void *ap, const void *bp)
1131{
1132 int *a = (int *) ap, *b = (int *) bp;
1133 return *a - *b;
1134}
1135
5dd7507c 1136static void
e8aa16ee 1137read_nodes(struct lscpu_desc *desc)
5dd7507c 1138{
e9074a16
KZ
1139 int i = 0;
1140 DIR *dir;
1141 struct dirent *d;
1142 char *path;
5dd7507c
CQ
1143
1144 /* number of NUMA node */
e9074a16
KZ
1145 path = path_strdup(_PATH_SYS_NODE);
1146 dir = opendir(path);
1147 free(path);
7e03f383 1148
e9074a16
KZ
1149 while (dir && (d = readdir(dir))) {
1150 if (is_node_dirent(d))
1151 desc->nnodes++;
1152 }
1153
1154 if (!desc->nnodes) {
1155 if (dir)
1156 closedir(dir);
7e03f383 1157 return;
e9074a16 1158 }
5dd7507c 1159
08de16d0 1160 desc->nodemaps = xcalloc(desc->nnodes, sizeof(cpu_set_t *));
e9074a16
KZ
1161 desc->idx2nodenum = xmalloc(desc->nnodes * sizeof(int));
1162
1163 if (dir) {
1164 rewinddir(dir);
1165 while ((d = readdir(dir)) && i < desc->nnodes) {
1166 if (is_node_dirent(d))
1167 desc->idx2nodenum[i++] = strtol_or_err(((d->d_name) + 4),
1168 _("Failed to extract the node number"));
1169 }
1170 closedir(dir);
39c758d1 1171 qsort(desc->idx2nodenum, desc->nnodes, sizeof(int), nodecmp);
e9074a16 1172 }
5dd7507c
CQ
1173
1174 /* information about how nodes share different CPUs */
7e03f383 1175 for (i = 0; i < desc->nnodes; i++)
ca01695b 1176 desc->nodemaps[i] = path_read_cpuset(maxcpus,
1d56b55e 1177 _PATH_SYS_NODE "/node%d/cpumap",
e9074a16 1178 desc->idx2nodenum[i]);
5dd7507c
CQ
1179}
1180
e3b3a2f3 1181static char *
4f642863 1182get_cell_data(struct lscpu_desc *desc, int idx, int col,
e3b3a2f3
KZ
1183 struct lscpu_modifier *mod,
1184 char *buf, size_t bufsz)
5dd7507c 1185{
7e03f383 1186 size_t setsize = CPU_ALLOC_SIZE(maxcpus);
4f642863
AT
1187 size_t i;
1188 int cpu = real_cpu_num(desc, idx);
e3b3a2f3
KZ
1189
1190 *buf = '\0';
5dd7507c 1191
477251f8
KZ
1192 switch (col) {
1193 case COL_CPU:
e3b3a2f3 1194 snprintf(buf, bufsz, "%d", cpu);
477251f8
KZ
1195 break;
1196 case COL_CORE:
e9d659ea 1197 if (cpuset_ary_isset(cpu, desc->coremaps,
4f642863 1198 desc->ncores, setsize, &i) == 0)
73f2bec5 1199 snprintf(buf, bufsz, "%zu", i);
477251f8
KZ
1200 break;
1201 case COL_SOCKET:
e9d659ea 1202 if (cpuset_ary_isset(cpu, desc->socketmaps,
4f642863 1203 desc->nsockets, setsize, &i) == 0)
73f2bec5 1204 snprintf(buf, bufsz, "%zu", i);
477251f8
KZ
1205 break;
1206 case COL_NODE:
e9d659ea 1207 if (cpuset_ary_isset(cpu, desc->nodemaps,
4f642863 1208 desc->nnodes, setsize, &i) == 0)
e9074a16 1209 snprintf(buf, bufsz, "%d", desc->idx2nodenum[i]);
477251f8
KZ
1210 break;
1211 case COL_BOOK:
e9d659ea 1212 if (cpuset_ary_isset(cpu, desc->bookmaps,
4f642863 1213 desc->nbooks, setsize, &i) == 0)
73f2bec5 1214 snprintf(buf, bufsz, "%zu", i);
477251f8
KZ
1215 break;
1216 case COL_CACHE:
e3b3a2f3
KZ
1217 {
1218 char *p = buf;
1219 size_t sz = bufsz;
1220 int j;
1221
7e03f383
KZ
1222 for (j = desc->ncaches - 1; j >= 0; j--) {
1223 struct cpu_cache *ca = &desc->caches[j];
e9d659ea
KZ
1224
1225 if (cpuset_ary_isset(cpu, ca->sharedmaps,
4f642863 1226 ca->nsharedmaps, setsize, &i) == 0) {
73f2bec5 1227 int x = snprintf(p, sz, "%zu", i);
e3b3a2f3
KZ
1228 if (x <= 0 || (size_t) x + 2 >= sz)
1229 return NULL;
1230 p += x;
1231 sz -= x;
1232 }
1233 if (j != 0) {
1234 *p++ = mod->compat ? ',' : ':';
1235 *p = '\0';
1236 sz++;
1237 }
5dd7507c 1238 }
477251f8 1239 break;
e3b3a2f3 1240 }
2b8fcb81 1241 case COL_POLARIZATION:
ba45d8c1 1242 if (desc->polarization) {
4f642863 1243 int x = desc->polarization[idx];
ba45d8c1 1244
e3b3a2f3 1245 snprintf(buf, bufsz, "%s",
ba45d8c1
KZ
1246 mod->mode == OUTPUT_PARSABLE ?
1247 polar_modes[x].parsable :
1248 polar_modes[x].readable);
1249 }
2b8fcb81 1250 break;
596b8845
HC
1251 case COL_ADDRESS:
1252 if (desc->addresses)
4f642863 1253 snprintf(buf, bufsz, "%d", desc->addresses[idx]);
596b8845 1254 break;
d231eea1 1255 case COL_CONFIGURED:
e43fc13e
HC
1256 if (!desc->configured)
1257 break;
1258 if (mod->mode == OUTPUT_PARSABLE)
f205c90a 1259 snprintf(buf, bufsz, "%s",
4f642863 1260 desc->configured[idx] ? _("Y") : _("N"));
e43fc13e 1261 else
f205c90a 1262 snprintf(buf, bufsz, "%s",
4f642863 1263 desc->configured[idx] ? _("yes") : _("no"));
d231eea1 1264 break;
a7e5300c 1265 case COL_ONLINE:
e43fc13e
HC
1266 if (!desc->online)
1267 break;
1268 if (mod->mode == OUTPUT_PARSABLE)
f205c90a 1269 snprintf(buf, bufsz, "%s",
e43fc13e
HC
1270 is_cpu_online(desc, cpu) ? _("Y") : _("N"));
1271 else
f205c90a 1272 snprintf(buf, bufsz, "%s",
847b982e 1273 is_cpu_online(desc, cpu) ? _("yes") : _("no"));
a7e5300c 1274 break;
e065a597
DB
1275 case COL_MAXMHZ:
1276 if (desc->maxmhz)
4f642863 1277 xstrncpy(buf, desc->maxmhz[idx], bufsz);
e065a597
DB
1278 break;
1279 case COL_MINMHZ:
1280 if (desc->minmhz)
4f642863 1281 xstrncpy(buf, desc->minmhz[idx], bufsz);
44320710 1282 break;
477251f8 1283 }
e3b3a2f3
KZ
1284 return buf;
1285}
1286
1287static char *
1288get_cell_header(struct lscpu_desc *desc, int col,
1289 struct lscpu_modifier *mod,
1290 char *buf, size_t bufsz)
1291{
1292 *buf = '\0';
1293
1294 if (col == COL_CACHE) {
1295 char *p = buf;
1296 size_t sz = bufsz;
1297 int i;
1298
1299 for (i = desc->ncaches - 1; i >= 0; i--) {
1300 int x = snprintf(p, sz, "%s", desc->caches[i].name);
1301 if (x <= 0 || (size_t) x + 2 > sz)
1302 return NULL;
1303 sz -= x;
1304 p += x;
1305 if (i > 0) {
1306 *p++ = mod->compat ? ',' : ':';
1307 *p = '\0';
1308 sz++;
1309 }
1310 }
1311 if (desc->ncaches)
1312 return buf;
1313 }
756d79cd 1314 snprintf(buf, bufsz, "%s", coldescs[col].name);
e3b3a2f3 1315 return buf;
477251f8
KZ
1316}
1317
1318/*
ba45d8c1 1319 * [-p] backend, we support two parsable formats:
477251f8
KZ
1320 *
1321 * 1) "compatible" -- this format is compatible with the original lscpu(1)
1322 * output and it contains fixed set of the columns. The CACHE columns are at
1323 * the end of the line and the CACHE is not printed if the number of the caches
1324 * is zero. The CACHE columns are separated by two commas, for example:
1325 *
1326 * $ lscpu --parse
1327 * # CPU,Core,Socket,Node,,L1d,L1i,L2
1328 * 0,0,0,0,,0,0,0
1329 * 1,1,0,0,,1,1,0
1330 *
1331 * 2) "user defined output" -- this format prints always all columns without
1332 * special prefix for CACHE column. If there are not CACHEs then the column is
1333 * empty and the header "Cache" is printed rather than a real name of the cache.
1334 * The CACHE columns are separated by ':'.
1335 *
1336 * $ lscpu --parse=CPU,CORE,SOCKET,NODE,CACHE
1337 * # CPU,Core,Socket,Node,L1d:L1i:L2
1338 * 0,0,0,0,0:0:0
1339 * 1,1,0,0,1:1:0
1340 */
1341static void
8005924a
KZ
1342print_parsable(struct lscpu_desc *desc, int cols[], int ncols,
1343 struct lscpu_modifier *mod)
477251f8 1344{
e3b3a2f3
KZ
1345 char buf[BUFSIZ], *data;
1346 int i;
477251f8 1347
e3b3a2f3
KZ
1348 /*
1349 * Header
1350 */
477251f8
KZ
1351 printf(_(
1352 "# The following is the parsable format, which can be fed to other\n"
1353 "# programs. Each different item in every column has an unique ID\n"
1354 "# starting from zero.\n"));
1355
1356 fputs("# ", stdout);
1357 for (i = 0; i < ncols; i++) {
3d27b76a 1358 int col = cols[i];
b9d18bc3 1359
3d27b76a 1360 if (col == COL_CACHE) {
8005924a 1361 if (mod->compat && !desc->ncaches)
477251f8 1362 continue;
8005924a 1363 if (mod->compat && i != 0)
477251f8 1364 putchar(',');
477251f8 1365 }
e3b3a2f3
KZ
1366 if (i > 0)
1367 putchar(',');
1368
3d27b76a 1369 data = get_cell_header(desc, col, mod, buf, sizeof(buf));
b9d18bc3 1370
3d27b76a
KZ
1371 if (data && * data && col != COL_CACHE &&
1372 !coldescs[col].is_abbr) {
1373 /*
1374 * For normal column names use mixed case (e.g. "Socket")
1375 */
1376 char *p = data + 1;
1377
14e8be8a
PU
1378 while (p && *p != '\0') {
1379 *p = tolower((unsigned int) *p);
1380 p++;
1381 }
3d27b76a 1382 }
e3b3a2f3 1383 fputs(data && *data ? data : "", stdout);
477251f8
KZ
1384 }
1385 putchar('\n');
1386
e3b3a2f3
KZ
1387 /*
1388 * Data
1389 */
a5cfffff 1390 for (i = 0; i < desc->ncpuspos; i++) {
e3b3a2f3 1391 int c;
4f642863 1392 int cpu = real_cpu_num(desc, i);
e3b3a2f3 1393
4f642863 1394 if (!mod->offline && desc->online && !is_cpu_online(desc, cpu))
7afc2387 1395 continue;
4f642863 1396 if (!mod->online && desc->online && is_cpu_online(desc, cpu))
477251f8 1397 continue;
4f642863 1398 if (desc->present && !is_cpu_present(desc, cpu))
a5cfffff 1399 continue;
477251f8 1400 for (c = 0; c < ncols; c++) {
8005924a 1401 if (mod->compat && cols[c] == COL_CACHE) {
477251f8
KZ
1402 if (!desc->ncaches)
1403 continue;
1404 if (c > 0)
1405 putchar(',');
1406 }
1407 if (c > 0)
1408 putchar(',');
e3b3a2f3
KZ
1409
1410 data = get_cell_data(desc, i, cols[c], mod,
1411 buf, sizeof(buf));
1412 fputs(data && *data ? data : "", stdout);
477251f8 1413 }
5dd7507c
CQ
1414 putchar('\n');
1415 }
1416}
1417
ba45d8c1
KZ
1418/*
1419 * [-e] backend
1420 */
1421static void
1422print_readable(struct lscpu_desc *desc, int cols[], int ncols,
1423 struct lscpu_modifier *mod)
1424{
1425 int i;
e7213e34
KZ
1426 char buf[BUFSIZ];
1427 const char *data;
710ed55d 1428 struct libscols_table *table;
ba45d8c1 1429
710ed55d
KZ
1430 scols_init_debug(0);
1431
1432 table = scols_new_table();
83db4eb2 1433 if (!table)
ba45d8c1
KZ
1434 err(EXIT_FAILURE, _("failed to initialize output table"));
1435
1436 for (i = 0; i < ncols; i++) {
b9d18bc3 1437 data = get_cell_header(desc, cols[i], mod, buf, sizeof(buf));
83db4eb2 1438 if (!scols_table_new_column(table, xstrdup(data), 0, 0))
e7213e34 1439 err(EXIT_FAILURE, _("failed to initialize output column"));
ba45d8c1
KZ
1440 }
1441
a5cfffff 1442 for (i = 0; i < desc->ncpuspos; i++) {
ba45d8c1 1443 int c;
83db4eb2 1444 struct libscols_line *line;
4f642863 1445 int cpu = real_cpu_num(desc, i);
ba45d8c1 1446
4f642863 1447 if (!mod->offline && desc->online && !is_cpu_online(desc, cpu))
7afc2387 1448 continue;
4f642863 1449 if (!mod->online && desc->online && is_cpu_online(desc, cpu))
ba45d8c1 1450 continue;
4f642863 1451 if (desc->present && !is_cpu_present(desc, cpu))
a5cfffff 1452 continue;
ba45d8c1 1453
83db4eb2 1454 line = scols_table_new_line(table, NULL);
e7213e34
KZ
1455 if (!line)
1456 err(EXIT_FAILURE, _("failed to initialize output line"));
ba45d8c1
KZ
1457
1458 for (c = 0; c < ncols; c++) {
1459 data = get_cell_data(desc, i, cols[c], mod,
1460 buf, sizeof(buf));
e7213e34
KZ
1461 if (!data || !*data)
1462 data = "-";
1463 scols_line_set_data(line, c, data);
ba45d8c1
KZ
1464 }
1465 }
1466
83db4eb2
OO
1467 scols_print_table(table);
1468 scols_unref_table(table);
ba45d8c1 1469}
5dd7507c
CQ
1470
1471/* output formats "<key> <value>"*/
1472#define print_s(_key, _val) printf("%-23s%s\n", _key, _val)
1473#define print_n(_key, _val) printf("%-23s%d\n", _key, _val)
1474
1475static void
4f912c6a
KZ
1476print_cpuset(const char *key, cpu_set_t *set, int hex)
1477{
1478 size_t setsize = CPU_ALLOC_SIZE(maxcpus);
1479 size_t setbuflen = 7 * maxcpus;
1480 char setbuf[setbuflen], *p;
1481
1482 if (hex) {
1483 p = cpumask_create(setbuf, setbuflen, set, setsize);
1484 printf("%-23s0x%s\n", key, p);
1485 } else {
1486 p = cpulist_create(setbuf, setbuflen, set, setsize);
1487 print_s(key, p);
1488 }
1489
1490}
1491
ba45d8c1
KZ
1492/*
1493 * default output
1494 */
4f912c6a 1495static void
8005924a 1496print_summary(struct lscpu_desc *desc, struct lscpu_modifier *mod)
5dd7507c 1497{
7e03f383
KZ
1498 char buf[512];
1499 int i;
aac1e59e 1500 size_t setsize = CPU_ALLOC_SIZE(maxcpus);
7e03f383 1501
e6b0611b 1502 print_s(_("Architecture:"), desc->arch);
79e8b41a 1503
f633ad4e 1504 if (desc->mode) {
2d7bee25 1505 char mbuf[64], *p = mbuf;
79e8b41a 1506
f633ad4e 1507 if (desc->mode & MODE_32BIT) {
79e8b41a
KZ
1508 strcpy(p, "32-bit, ");
1509 p += 8;
1510 }
f633ad4e 1511 if (desc->mode & MODE_64BIT) {
79e8b41a
KZ
1512 strcpy(p, "64-bit, ");
1513 p += 8;
1514 }
1515 *(p - 2) = '\0';
2d7bee25 1516 print_s(_("CPU op-mode(s):"), mbuf);
79e8b41a 1517 }
aabe2441 1518#if !defined(WORDS_BIGENDIAN)
9b8d4d5f
DB
1519 print_s(_("Byte Order:"), "Little Endian");
1520#else
1521 print_s(_("Byte Order:"), "Big Endian");
9b8d4d5f 1522#endif
4a939e04 1523 print_n(_("CPU(s):"), desc->ncpus);
4f912c6a 1524
5d4ba40d 1525 if (desc->online)
8005924a
KZ
1526 print_cpuset(mod->hex ? _("On-line CPU(s) mask:") :
1527 _("On-line CPU(s) list:"),
1528 desc->online, mod->hex);
4f912c6a 1529
5d4ba40d 1530 if (desc->online && CPU_COUNT_S(setsize, desc->online) != desc->ncpus) {
4f912c6a
KZ
1531 cpu_set_t *set;
1532
1533 /* Linux kernel provides cpuset of off-line CPUs that contains
1534 * all configured CPUs (see /sys/devices/system/cpu/offline),
1535 * but want to print real (present in system) off-line CPUs only.
1536 */
1537 set = cpuset_alloc(maxcpus, NULL, NULL);
1538 if (!set)
1539 err(EXIT_FAILURE, _("failed to callocate cpu set"));
1540 CPU_ZERO_S(setsize, set);
a5cfffff 1541 for (i = 0; i < desc->ncpuspos; i++) {
4f642863
AT
1542 int cpu = real_cpu_num(desc, i);
1543 if (!is_cpu_online(desc, cpu) && is_cpu_present(desc, cpu))
1544 CPU_SET_S(cpu, setsize, set);
4f912c6a 1545 }
8005924a
KZ
1546 print_cpuset(mod->hex ? _("Off-line CPU(s) mask:") :
1547 _("Off-line CPU(s) list:"),
1548 set, mod->hex);
4f912c6a
KZ
1549 cpuset_free(set);
1550 }
5dd7507c 1551
7e03f383 1552 if (desc->nsockets) {
8648ca96
HC
1553 int cores_per_socket, sockets_per_book, books;
1554
1555 cores_per_socket = sockets_per_book = books = 0;
1556 /* s390 detects its cpu topology via /proc/sysinfo, if present.
1557 * Using simply the cpu topology masks in sysfs will not give
1558 * usable results since everything is virtualized. E.g.
1559 * virtual core 0 may have only 1 cpu, but virtual core 2 may
1560 * five cpus.
1561 * If the cpu topology is not exported (e.g. 2nd level guest)
1562 * fall back to old calculation scheme.
1563 */
1564 if (path_exist(_PATH_PROC_SYSINFO)) {
1565 FILE *fd = path_fopen("r", 0, _PATH_PROC_SYSINFO);
2d7bee25 1566 char pbuf[BUFSIZ];
8648ca96
HC
1567 int t0, t1, t2;
1568
2d7bee25
SK
1569 while (fd && fgets(pbuf, sizeof(pbuf), fd) != NULL) {
1570 if (sscanf(pbuf, "CPU Topology SW:%d%d%d%d%d%d",
8648ca96
HC
1571 &t0, &t1, &t2, &books, &sockets_per_book,
1572 &cores_per_socket) == 6)
1573 break;
1574 }
ad655c88
KZ
1575 if (fd)
1576 fclose(fd);
8648ca96 1577 }
7e03f383 1578 print_n(_("Thread(s) per core:"), desc->nthreads / desc->ncores);
8648ca96
HC
1579 print_n(_("Core(s) per socket:"),
1580 cores_per_socket ?: desc->ncores / desc->nsockets);
56baaa4e 1581 if (desc->nbooks) {
8648ca96
HC
1582 print_n(_("Socket(s) per book:"),
1583 sockets_per_book ?: desc->nsockets / desc->nbooks);
1584 print_n(_("Book(s):"), books ?: desc->nbooks);
56baaa4e 1585 } else {
8648ca96 1586 print_n(_("Socket(s):"), sockets_per_book ?: desc->nsockets);
56baaa4e 1587 }
5dd7507c 1588 }
7e03f383
KZ
1589 if (desc->nnodes)
1590 print_n(_("NUMA node(s):"), desc->nnodes);
e8aa16ee
KZ
1591 if (desc->vendor)
1592 print_s(_("Vendor ID:"), desc->vendor);
1593 if (desc->family)
1594 print_s(_("CPU family:"), desc->family);
1595 if (desc->model)
1596 print_s(_("Model:"), desc->model);
1461094c
KZ
1597 if (desc->modelname)
1598 print_s(_("Model name:"), desc->modelname);
e8aa16ee
KZ
1599 if (desc->stepping)
1600 print_s(_("Stepping:"), desc->stepping);
1601 if (desc->mhz)
1602 print_s(_("CPU MHz:"), desc->mhz);
e065a597
DB
1603 if (desc->maxmhz)
1604 print_s(_("CPU max MHz:"), desc->maxmhz[0]);
1605 if (desc->minmhz)
1606 print_s(_("CPU min MHz:"), desc->minmhz[0]);
9b8d4d5f
DB
1607 if (desc->bogomips)
1608 print_s(_("BogoMIPS:"), desc->bogomips);
e8aa16ee
KZ
1609 if (desc->virtflag) {
1610 if (!strcmp(desc->virtflag, "svm"))
5dd7507c 1611 print_s(_("Virtualization:"), "AMD-V");
e8aa16ee 1612 else if (!strcmp(desc->virtflag, "vmx"))
5dd7507c
CQ
1613 print_s(_("Virtualization:"), "VT-x");
1614 }
10829cd7
HC
1615 if (desc->hypervisor)
1616 print_s(_("Hypervisor:"), desc->hypervisor);
e8aa16ee
KZ
1617 if (desc->hyper) {
1618 print_s(_("Hypervisor vendor:"), hv_vendors[desc->hyper]);
50c6ee4c 1619 print_s(_("Virtualization type:"), _(virt_types[desc->virtype]));
c8b64f6d 1620 }
a0fff77e 1621 if (desc->dispatching >= 0)
50c6ee4c 1622 print_s(_("Dispatching mode:"), _(disp_modes[desc->dispatching]));
7e03f383 1623 if (desc->ncaches) {
2d7bee25 1624 char cbuf[512];
5dd7507c 1625
7e03f383 1626 for (i = desc->ncaches - 1; i >= 0; i--) {
2d7bee25 1627 snprintf(cbuf, sizeof(cbuf),
7e03f383 1628 _("%s cache:"), desc->caches[i].name);
2d7bee25 1629 print_s(cbuf, desc->caches[i].size);
7e03f383
KZ
1630 }
1631 }
1632
4f912c6a 1633 for (i = 0; i < desc->nnodes; i++) {
e9074a16 1634 snprintf(buf, sizeof(buf), _("NUMA node%d CPU(s):"), desc->idx2nodenum[i]);
8005924a 1635 print_cpuset(buf, desc->nodemaps[i], mod->hex);
5dd7507c 1636 }
ee1f1057
WC
1637
1638 if (desc->flags)
1639 print_s(_("Flags:"), desc->flags);
5dd7507c
CQ
1640}
1641
39561c70 1642static void __attribute__((__noreturn__)) usage(FILE *out)
5dd7507c 1643{
b9d18bc3
KZ
1644 size_t i;
1645
1646 fputs(USAGE_HEADER, out);
c6f095cf 1647 fprintf(out, _(" %s [options]\n"), program_invocation_short_name);
7f1ec5e8 1648
451dbcfa
BS
1649 fputs(USAGE_SEPARATOR, out);
1650 fputs(_("Display information about the CPU architecture.\n"), out);
1651
b9d18bc3 1652 fputs(USAGE_OPTIONS, out);
c6f095cf
BS
1653 fputs(_(" -a, --all print both online and offline CPUs (default for -e)\n"), out);
1654 fputs(_(" -b, --online print online CPUs only (default for -p)\n"), out);
1655 fputs(_(" -c, --offline print offline CPUs only\n"), out);
1656 fputs(_(" -e, --extended[=<list>] print out an extended readable format\n"), out);
1657 fputs(_(" -p, --parse[=<list>] print out a parsable format\n"), out);
1658 fputs(_(" -s, --sysroot <dir> use specified directory as system root\n"), out);
1659 fputs(_(" -x, --hex print hexadecimal masks rather than lists of CPUs\n"), out);
1660 fputs(USAGE_SEPARATOR, out);
1661 fputs(USAGE_HELP, out);
1662 fputs(USAGE_VERSION, out);
b9d18bc3
KZ
1663
1664 fprintf(out, _("\nAvailable columns:\n"));
1665
3d27b76a
KZ
1666 for (i = 0; i < ARRAY_SIZE(coldescs); i++)
1667 fprintf(out, " %13s %s\n", coldescs[i].name, _(coldescs[i].help));
1668
a587cc55 1669 fprintf(out, USAGE_MAN_TAIL("lscpu(1)"));
4f912c6a 1670
39561c70 1671 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
5dd7507c
CQ
1672}
1673
1674int main(int argc, char *argv[])
1675{
8005924a
KZ
1676 struct lscpu_modifier _mod = { .mode = OUTPUT_SUMMARY }, *mod = &_mod;
1677 struct lscpu_desc _desc = { .flags = 0 }, *desc = &_desc;
1678 int c, i;
3d27b76a 1679 int columns[ARRAY_SIZE(coldescs)], ncolumns = 0;
7fc12cd2 1680 int cpu_modifier_specified = 0;
5dd7507c 1681
6c7d5ae9 1682 static const struct option longopts[] = {
0ad29ff6 1683 { "all", no_argument, 0, 'a' },
23e9e95a 1684 { "online", no_argument, 0, 'b' },
7afc2387 1685 { "offline", no_argument, 0, 'c' },
47b6e8b6 1686 { "help", no_argument, 0, 'h' },
ba45d8c1 1687 { "extended", optional_argument, 0, 'e' },
477251f8 1688 { "parse", optional_argument, 0, 'p' },
47b6e8b6 1689 { "sysroot", required_argument, 0, 's' },
4f912c6a 1690 { "hex", no_argument, 0, 'x' },
44de912c 1691 { "version", no_argument, 0, 'V' },
5dd7507c
CQ
1692 { NULL, 0, 0, 0 }
1693 };
1694
8e97eb4b
KZ
1695 static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
1696 { 'a','b','c' },
1697 { 'e','p' },
1698 { 0 }
1699 };
1700 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
1701
2f8f1388 1702 setlocale(LC_ALL, "");
5dd7507c
CQ
1703 bindtextdomain(PACKAGE, LOCALEDIR);
1704 textdomain(PACKAGE);
efb8854f 1705 atexit(close_stdout);
5dd7507c 1706
7afc2387 1707 while ((c = getopt_long(argc, argv, "abce::hp::s:xV", longopts, NULL)) != -1) {
8e97eb4b
KZ
1708
1709 err_exclusive_options(c, longopts, excl, excl_st);
1710
5dd7507c 1711 switch (c) {
0ad29ff6 1712 case 'a':
7afc2387 1713 mod->online = mod->offline = 1;
7fc12cd2 1714 cpu_modifier_specified = 1;
0ad29ff6 1715 break;
23e9e95a
KZ
1716 case 'b':
1717 mod->online = 1;
7fc12cd2 1718 cpu_modifier_specified = 1;
23e9e95a 1719 break;
7afc2387
HC
1720 case 'c':
1721 mod->offline = 1;
7fc12cd2 1722 cpu_modifier_specified = 1;
7afc2387 1723 break;
5dd7507c 1724 case 'h':
39561c70 1725 usage(stdout);
5dd7507c 1726 case 'p':
ba45d8c1 1727 case 'e':
477251f8
KZ
1728 if (optarg) {
1729 if (*optarg == '=')
1730 optarg++;
1731 ncolumns = string_to_idarray(optarg,
1732 columns, ARRAY_SIZE(columns),
1733 column_name_to_id);
1734 if (ncolumns < 0)
1735 return EXIT_FAILURE;
477251f8 1736 }
ba45d8c1 1737 mod->mode = c == 'p' ? OUTPUT_PARSABLE : OUTPUT_READABLE;
5dd7507c 1738 break;
47b6e8b6 1739 case 's':
ca01695b 1740 path_set_prefix(optarg);
8148217b 1741 mod->system = SYSTEM_SNAPSHOT;
47b6e8b6 1742 break;
4f912c6a 1743 case 'x':
8005924a 1744 mod->hex = 1;
4f912c6a 1745 break;
44de912c 1746 case 'V':
f6277500 1747 printf(UTIL_LINUX_VERSION);
44de912c 1748 return EXIT_SUCCESS;
5dd7507c 1749 default:
39561c70 1750 usage(stderr);
5dd7507c
CQ
1751 }
1752 }
7bbb7829 1753
7fc12cd2
HC
1754 if (cpu_modifier_specified && mod->mode == OUTPUT_SUMMARY) {
1755 fprintf(stderr,
1756 _("%s: options --all, --online and --offline may only "
ac56e555 1757 "be used with options --extended or --parse.\n"),
7fc12cd2
HC
1758 program_invocation_short_name);
1759 return EXIT_FAILURE;
1760 }
1761
7bbb7829
HC
1762 if (argc != optind)
1763 usage(stderr);
1764
7afc2387
HC
1765 /* set default cpu display mode if none was specified */
1766 if (!mod->online && !mod->offline) {
1767 mod->online = 1;
1768 mod->offline = mod->mode == OUTPUT_READABLE ? 1 : 0;
1769 }
5dd7507c 1770
8148217b 1771 read_basicinfo(desc, mod);
5dd7507c 1772
a5cfffff 1773 for (i = 0; i < desc->ncpuspos; i++) {
7e03f383
KZ
1774 read_topology(desc, i);
1775 read_cache(desc, i);
2b8fcb81 1776 read_polarization(desc, i);
596b8845 1777 read_address(desc, i);
d231eea1 1778 read_configured(desc, i);
44320710 1779 read_max_mhz(desc, i);
e065a597 1780 read_min_mhz(desc, i);
47b6e8b6 1781 }
7e03f383 1782
960bf130
KZ
1783 if (desc->caches)
1784 qsort(desc->caches, desc->ncaches,
1785 sizeof(struct cpu_cache), cachecmp);
7e03f383
KZ
1786
1787 read_nodes(desc);
eff79ceb 1788 read_hypervisor(desc, mod);
c8b64f6d 1789
8005924a 1790 switch(mod->mode) {
ba45d8c1
KZ
1791 case OUTPUT_SUMMARY:
1792 print_summary(desc, mod);
1793 break;
1794 case OUTPUT_PARSABLE:
1795 if (!ncolumns) {
1796 columns[ncolumns++] = COL_CPU;
1797 columns[ncolumns++] = COL_CORE;
1798 columns[ncolumns++] = COL_SOCKET;
1799 columns[ncolumns++] = COL_NODE;
1800 columns[ncolumns++] = COL_CACHE;
1801 mod->compat = 1;
1802 }
1803 print_parsable(desc, columns, ncolumns, mod);
1804 break;
1805 case OUTPUT_READABLE:
1806 if (!ncolumns) {
1807 /* No list was given. Just print whatever is there. */
1808 columns[ncolumns++] = COL_CPU;
1809 if (desc->nodemaps)
8005924a 1810 columns[ncolumns++] = COL_NODE;
ba45d8c1
KZ
1811 if (desc->bookmaps)
1812 columns[ncolumns++] = COL_BOOK;
1813 if (desc->socketmaps)
1814 columns[ncolumns++] = COL_SOCKET;
1815 if (desc->coremaps)
1816 columns[ncolumns++] = COL_CORE;
1817 if (desc->caches)
8005924a 1818 columns[ncolumns++] = COL_CACHE;
a7e5300c
HC
1819 if (desc->online)
1820 columns[ncolumns++] = COL_ONLINE;
d231eea1
HC
1821 if (desc->configured)
1822 columns[ncolumns++] = COL_CONFIGURED;
ba45d8c1
KZ
1823 if (desc->polarization)
1824 columns[ncolumns++] = COL_POLARIZATION;
1825 if (desc->addresses)
1826 columns[ncolumns++] = COL_ADDRESS;
e065a597
DB
1827 if (desc->maxmhz)
1828 columns[ncolumns++] = COL_MAXMHZ;
1829 if (desc->minmhz)
1830 columns[ncolumns++] = COL_MINMHZ;
ba45d8c1
KZ
1831 }
1832 print_readable(desc, columns, ncolumns, mod);
1833 break;
8005924a 1834 }
5dd7507c 1835
cf474aac 1836 return EXIT_SUCCESS;
5dd7507c 1837}