]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/lscpu.c
Merge branch 'patch-23' of https://github.com/mariobl/util-linux
[thirdparty/util-linux.git] / sys-utils / lscpu.c
CommitLineData
5dd7507c 1/*
9abd5e4b 2 * SPDX-License-Identifier: GPL-2.0-or-later
5dd7507c 3 *
80dde62f 4 * This program is free software; you can redistribute it and/or modify
5dd7507c 5 * it under the terms of the GNU General Public License as published by
80dde62f 6 * the Free Software Foundation; either version 2 of the License, or
5dd7507c
CQ
7 * (at your option) any later version.
8 *
9abd5e4b
KZ
9 * Copyright (C) 2008 Cai Qian <qcai@redhat.com>
10 * Copyright (C) 2008-2023 Karel Zak <kzak@redhat.com>
5dd7507c 11 *
9abd5e4b 12 * lscpu - CPU architecture information helper
5dd7507c 13 */
5bd31c6d 14#include <assert.h>
5dd7507c
CQ
15#include <ctype.h>
16#include <dirent.h>
5dd7507c
CQ
17#include <errno.h>
18#include <fcntl.h>
19#include <getopt.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <sys/utsname.h>
24#include <unistd.h>
25#include <stdarg.h>
39561c70
KZ
26#include <sys/types.h>
27#include <sys/stat.h>
32865bd5 28#include <sys/personality.h>
5dd7507c 29
83db4eb2
OO
30#include <libsmartcols.h>
31
efb8854f 32#include "closestream.h"
41a8940d 33#include "optutils.h"
aff94add 34#include "c_strtod.h"
0e3858fc 35#include "sysfs.h"
71061694 36
fb2627ce 37#include "lscpu.h"
0ebbe9f1 38
2ba641e5 39static const char *virt_types[] = {
7454b598
KZ
40 [VIRT_TYPE_NONE] = N_("none"),
41 [VIRT_TYPE_PARA] = N_("para"),
42 [VIRT_TYPE_FULL] = N_("full"),
43 [VIRT_TYPE_CONTAINER] = N_("container"),
c8b64f6d
KZ
44};
45
2ba641e5 46static const char *hv_vendors[] = {
7454b598
KZ
47 [VIRT_VENDOR_NONE] = NULL,
48 [VIRT_VENDOR_XEN] = "Xen",
49 [VIRT_VENDOR_KVM] = "KVM",
50 [VIRT_VENDOR_MSHV] = "Microsoft",
f2aadc11 51 [VIRT_VENDOR_VMWARE] = "VMware",
7454b598
KZ
52 [VIRT_VENDOR_IBM] = "IBM",
53 [VIRT_VENDOR_VSERVER] = "Linux-VServer",
54 [VIRT_VENDOR_UML] = "User-mode Linux",
55 [VIRT_VENDOR_INNOTEK] = "Innotek GmbH",
56 [VIRT_VENDOR_HITACHI] = "Hitachi",
f2aadc11 57 [VIRT_VENDOR_PARALLELS] = "Parallels",
7454b598
KZ
58 [VIRT_VENDOR_VBOX] = "Oracle",
59 [VIRT_VENDOR_OS400] = "OS/400",
60 [VIRT_VENDOR_PHYP] = "pHyp",
61 [VIRT_VENDOR_SPAR] = "Unisys s-Par",
62 [VIRT_VENDOR_WSL] = "Windows Subsystem for Linux"
96ce475f
RM
63};
64
a0fff77e 65/* dispatching modes */
2ba641e5 66static const char *disp_modes[] = {
a0fff77e
HC
67 [DISP_HORIZONTAL] = N_("horizontal"),
68 [DISP_VERTICAL] = N_("vertical")
69};
70
f9ac0210
KZ
71struct polarization_modes {
72 char *parsable;
73 char *readable;
74};
75
2ba641e5 76static struct polarization_modes polar_modes[] = {
0a0af616
KZ
77 [POLAR_UNKNOWN] = {"U", "-"},
78 [POLAR_VLOW] = {"VL", "vert-low"},
79 [POLAR_VMEDIUM] = {"VM", "vert-medium"},
80 [POLAR_VHIGH] = {"VH", "vert-high"},
8005924a 81 [POLAR_HORIZONTAL] = {"H", "horizontal"},
2b8fcb81
HC
82};
83
477251f8 84/*
3d27b76a 85 * IDs
477251f8
KZ
86 */
87enum {
cc94324e 88 COL_CPU_BOGOMIPS,
cc07239d
KZ
89 COL_CPU_CPU,
90 COL_CPU_CORE,
91 COL_CPU_SOCKET,
73c0a766 92 COL_CPU_CLUSTER,
cc07239d
KZ
93 COL_CPU_NODE,
94 COL_CPU_BOOK,
95 COL_CPU_DRAWER,
96 COL_CPU_CACHE,
97 COL_CPU_POLARIZATION,
98 COL_CPU_ADDRESS,
99 COL_CPU_CONFIGURED,
100 COL_CPU_ONLINE,
6d880d3d 101 COL_CPU_MHZ,
9b9e4f5d 102 COL_CPU_SCALMHZ,
cc07239d
KZ
103 COL_CPU_MAXMHZ,
104 COL_CPU_MINMHZ,
1d956847 105 COL_CPU_MODELNAME,
477251f8
KZ
106};
107
0e86bc84
KZ
108enum {
109 COL_CACHE_ALLSIZE,
110 COL_CACHE_LEVEL,
111 COL_CACHE_NAME,
112 COL_CACHE_ONESIZE,
113 COL_CACHE_TYPE,
114 COL_CACHE_WAYS,
cf3b6b71
KZ
115 COL_CACHE_ALLOCPOL,
116 COL_CACHE_WRITEPOL,
117 COL_CACHE_PHYLINE,
118 COL_CACHE_SETS,
119 COL_CACHE_COHERENCYSIZE
0e86bc84
KZ
120};
121
122
3d27b76a
KZ
123/* column description
124 */
125struct lscpu_coldesc {
126 const char *name;
127 const char *help;
128
0e86bc84 129 int flags;
3d27b76a 130 unsigned int is_abbr:1; /* name is abbreviation */
17353ee0 131 int json_type;
477251f8
KZ
132};
133
cc07239d 134static struct lscpu_coldesc coldescs_cpu[] =
3d27b76a 135{
17353ee0
TW
136 [COL_CPU_BOGOMIPS] = { "BOGOMIPS", N_("crude measurement of CPU speed"), SCOLS_FL_RIGHT, 1, SCOLS_JSON_NUMBER },
137 [COL_CPU_CPU] = { "CPU", N_("logical CPU number"), SCOLS_FL_RIGHT, 1, SCOLS_JSON_NUMBER },
138 [COL_CPU_CORE] = { "CORE", N_("logical core number"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER },
139 [COL_CPU_CLUSTER] = { "CLUSTER", N_("logical cluster number"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER },
140 [COL_CPU_SOCKET] = { "SOCKET", N_("logical socket number"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER },
141 [COL_CPU_NODE] = { "NODE", N_("logical NUMA node number"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER },
142 [COL_CPU_BOOK] = { "BOOK", N_("logical book number"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER },
143 [COL_CPU_DRAWER] = { "DRAWER", N_("logical drawer number"), SCOLS_FL_RIGHT, SCOLS_JSON_NUMBER },
cc07239d
KZ
144 [COL_CPU_CACHE] = { "CACHE", N_("shows how caches are shared between CPUs") },
145 [COL_CPU_POLARIZATION] = { "POLARIZATION", N_("CPU dispatching mode on virtual hardware") },
146 [COL_CPU_ADDRESS] = { "ADDRESS", N_("physical address of a CPU") },
87579a96
TW
147 [COL_CPU_CONFIGURED] = { "CONFIGURED", N_("shows if the hypervisor has allocated the CPU"), 0, 0, SCOLS_JSON_BOOLEAN_OPTIONAL },
148 [COL_CPU_ONLINE] = { "ONLINE", N_("shows if Linux currently makes use of the CPU"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_BOOLEAN_OPTIONAL },
79884c5d 149 [COL_CPU_MHZ] = { "MHZ", N_("shows the currently MHz of the CPU"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER },
17353ee0
TW
150 [COL_CPU_SCALMHZ] = { "SCALMHZ%", N_("shows scaling percentage of the CPU frequency"), SCOLS_FL_RIGHT, SCOLS_JSON_NUMBER },
151 [COL_CPU_MAXMHZ] = { "MAXMHZ", N_("shows the maximum MHz of the CPU"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER },
1d956847
KZ
152 [COL_CPU_MINMHZ] = { "MINMHZ", N_("shows the minimum MHz of the CPU"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER },
153 [COL_CPU_MODELNAME] = { "MODELNAME", N_("shows CPU model name"), 0, 0, SCOLS_JSON_STRING }
0e86bc84
KZ
154};
155
156static struct lscpu_coldesc coldescs_cache[] =
157{
158 [COL_CACHE_ALLSIZE] = { "ALL-SIZE", N_("size of all system caches"), SCOLS_FL_RIGHT },
17353ee0 159 [COL_CACHE_LEVEL] = { "LEVEL", N_("cache level"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER },
0e86bc84
KZ
160 [COL_CACHE_NAME] = { "NAME", N_("cache name") },
161 [COL_CACHE_ONESIZE] = { "ONE-SIZE", N_("size of one cache"), SCOLS_FL_RIGHT },
162 [COL_CACHE_TYPE] = { "TYPE", N_("cache type") },
17353ee0 163 [COL_CACHE_WAYS] = { "WAYS", N_("ways of associativity"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER },
cf3b6b71
KZ
164 [COL_CACHE_ALLOCPOL] = { "ALLOC-POLICY", N_("allocation policy") },
165 [COL_CACHE_WRITEPOL] = { "WRITE-POLICY", N_("write policy") },
b956bc86 166 [COL_CACHE_PHYLINE] = { "PHY-LINE", N_("number of physical cache line per cache tag"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER },
17353ee0
TW
167 [COL_CACHE_SETS] = { "SETS", N_("number of sets in the cache; set lines has the same cache index"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER },
168 [COL_CACHE_COHERENCYSIZE] = { "COHERENCY-SIZE", N_("minimum amount of data in bytes transferred from memory to cache"), SCOLS_FL_RIGHT, 0, SCOLS_JSON_NUMBER }
3d27b76a 169};
477251f8 170
c9121791 171static int hierarchic = -1;
91eef60c 172
43715b4e
KZ
173UL_DEBUG_DEFINE_MASK(lscpu);
174UL_DEBUG_DEFINE_MASKNAMES(lscpu) = UL_DEBUG_EMPTY_MASKNAMES;
175
176static void lscpu_init_debug(void)
177{
178 __UL_INIT_DEBUG_FROM_ENV(lscpu, LSCPU_DEBUG_, 0, LSCPU_DEBUG);
179}
180
583f14cc 181static int
cc07239d 182cpu_column_name_to_id(const char *name, size_t namesz)
477251f8 183{
329fd1c3 184 size_t i;
477251f8 185
cc07239d
KZ
186 for (i = 0; i < ARRAY_SIZE(coldescs_cpu); i++) {
187 const char *cn = coldescs_cpu[i].name;
477251f8
KZ
188
189 if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
190 return i;
191 }
192 warnx(_("unknown column: %s"), name);
193 return -1;
194}
195
0e86bc84
KZ
196static int
197cache_column_name_to_id(const char *name, size_t namesz)
198{
199 size_t i;
200
201 for (i = 0; i < ARRAY_SIZE(coldescs_cache); i++) {
202 const char *cn = coldescs_cache[i].name;
203
204 if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
205 return i;
206 }
207 warnx(_("unknown column: %s"), name);
208 return -1;
209}
210
27c349f9
KZ
211static void lscpu_context_init_paths(struct lscpu_cxt *cxt)
212{
213 DBG(MISC, ul_debugobj(cxt, "initialize paths"));
214 ul_path_init_debug();
215
f145492f
TW
216 /* / */
217 cxt->rootfs = NULL;
218 if (cxt->prefix) {
219 cxt->rootfs = ul_new_path("/");
220 if (!cxt->rootfs)
221 err(EXIT_FAILURE, _("failed to initialize rootfs handler"));
222 ul_path_set_prefix(cxt->rootfs, cxt->prefix);
223 }
224
27c349f9
KZ
225 /* /sys/devices/system/cpu */
226 cxt->syscpu = ul_new_path(_PATH_SYS_CPU);
227 if (!cxt->syscpu)
228 err(EXIT_FAILURE, _("failed to initialize CPUs sysfs handler"));
229 if (cxt->prefix)
230 ul_path_set_prefix(cxt->syscpu, cxt->prefix);
231
232 /* /proc */
233 cxt->procfs = ul_new_path("/proc");
234 if (!cxt->procfs)
235 err(EXIT_FAILURE, _("failed to initialize procfs handler"));
236 if (cxt->prefix)
237 ul_path_set_prefix(cxt->procfs, cxt->prefix);
238}
239
240static struct lscpu_cxt *lscpu_new_context(void)
241{
242 return xcalloc(1, sizeof(struct lscpu_cxt));
243}
244
245static void lscpu_free_context(struct lscpu_cxt *cxt)
246{
247 size_t i;
248
249 if (!cxt)
250 return;
251
252 DBG(MISC, ul_debugobj(cxt, "freeing context"));
253
254 DBG(MISC, ul_debugobj(cxt, " de-initialize paths"));
255 ul_unref_path(cxt->syscpu);
256 ul_unref_path(cxt->procfs);
f145492f 257 ul_unref_path(cxt->rootfs);
27c349f9
KZ
258
259 DBG(MISC, ul_debugobj(cxt, " freeing cpus"));
260 for (i = 0; i < cxt->npossibles; i++) {
261 lscpu_unref_cpu(cxt->cpus[i]);
262 cxt->cpus[i] = NULL;
263 }
264 DBG(MISC, ul_debugobj(cxt, " freeing types"));
265 for (i = 0; i < cxt->ncputypes; i++) {
266 lscpu_unref_cputype(cxt->cputypes[i]);
267 cxt->cputypes[i] = NULL;
268 }
269
270 free(cxt->present);
271 free(cxt->online);
272 free(cxt->cputypes);
273 free(cxt->cpus);
274
275 for (i = 0; i < cxt->nvuls; i++) {
276 free(cxt->vuls[i].name);
277 free(cxt->vuls[i].text);
278 }
279 free(cxt->vuls);
280
281 for (i = 0; i < cxt->nnodes; i++)
282 free(cxt->nodemaps[i]);
283
284 free(cxt->nodemaps);
285 free(cxt->idx2nodenum);
286
287 lscpu_free_virtualization(cxt->virt);
288 lscpu_free_architecture(cxt->arch);
6fbb5328 289
27c349f9 290 lscpu_free_caches(cxt->ecaches, cxt->necaches);
6fbb5328 291 lscpu_free_caches(cxt->caches, cxt->ncaches);
27c349f9
KZ
292
293 free(cxt);
294}
295
63c5e7f8
KZ
296static void __fill_id( struct lscpu_cxt *cxt,
297 struct lscpu_cpu *cpu,
298 int id, cpu_set_t **map,
299 size_t nitems,
300 char *buf, size_t bufsz)
301{
302 *buf = '\0';
303
304 if (cxt->show_physical) {
305 if (id < 0)
306 snprintf(buf, bufsz, "-");
307 else
308 snprintf(buf, bufsz, "%d", id);
309 } else if (map) {
310 size_t i;
311
312 if (cpuset_ary_isset(cpu->logical_id, map, nitems,
313 cxt->setsize, &i) == 0)
314 snprintf(buf, bufsz, "%zu", i);
315 }
316}
5dd7507c 317
17353ee0
TW
318static void get_cell_boolean(
319 struct lscpu_cxt *cxt,
320 int has_data, int data,
321 char *buf, size_t bufsz)
322{
323 if (!has_data)
324 return;
325
326 if (cxt->mode == LSCPU_OUTPUT_PARSABLE || cxt->json)
327 snprintf(buf, bufsz, "%s",
328 data ? _("Y") : _("N"));
329 else
330 snprintf(buf, bufsz, "%s",
331 data ? _("yes") : _("no"));
332}
333
63c5e7f8
KZ
334#define fill_id(_cxt, _cpu, NAME, _buf, _bufsz) \
335 __fill_id(_cxt, (_cpu), \
336 (_cpu)-> NAME ## id, \
337 (_cpu)->type-> NAME ## maps, \
338 (_cpu)->type->n ## NAME ## s, \
339 _buf, _bufsz)
340
341static char *get_cell_data(
342 struct lscpu_cxt *cxt,
343 struct lscpu_cpu *cpu, int col,
344 char *buf, size_t bufsz)
5dd7507c 345{
4f642863 346 size_t i;
e3b3a2f3
KZ
347
348 *buf = '\0';
5dd7507c 349
63c5e7f8
KZ
350 if (!cpu->type)
351 return NULL;
352
477251f8 353 switch (col) {
cc07239d 354 case COL_CPU_CPU:
63c5e7f8 355 snprintf(buf, bufsz, "%d", cpu->logical_id);
477251f8 356 break;
cc94324e 357 case COL_CPU_BOGOMIPS:
aff94add
KZ
358 if (!cpu->bogomips && !cpu->type->bogomips)
359 break;
360 snprintf(buf, bufsz, "%.2f", (float) c_strtod(
361 cpu->bogomips ? : cpu->type->bogomips, NULL));
cc94324e 362 break;
cc07239d 363 case COL_CPU_CORE:
63c5e7f8 364 fill_id(cxt, cpu, core, buf, bufsz);
477251f8 365 break;
cc07239d 366 case COL_CPU_SOCKET:
63c5e7f8 367 fill_id(cxt, cpu, socket, buf, bufsz);
477251f8 368 break;
73c0a766
MM
369 case COL_CPU_CLUSTER:
370 if (cxt->is_cluster)
371 fill_id(cxt, cpu, socket, buf, bufsz);
372 break;
cc07239d 373 case COL_CPU_DRAWER:
63c5e7f8 374 fill_id(cxt, cpu, drawer, buf, bufsz);
b3adf6ef 375 break;
cc07239d 376 case COL_CPU_BOOK:
63c5e7f8
KZ
377 fill_id(cxt, cpu, book, buf, bufsz);
378 break;
379 case COL_CPU_NODE:
380 if (cpuset_ary_isset(cpu->logical_id, cxt->nodemaps,
381 cxt->nnodes, cxt->setsize, &i) == 0)
382 snprintf(buf, bufsz, "%d", cxt->idx2nodenum[i]);
477251f8 383 break;
cc07239d 384 case COL_CPU_CACHE:
e3b3a2f3 385 {
63c5e7f8 386 const char *last = NULL;
e3b3a2f3
KZ
387 char *p = buf;
388 size_t sz = bufsz;
e3b3a2f3 389
63c5e7f8
KZ
390 for (i = 0; i < cxt->ncaches; i++) {
391 int x;
392 struct lscpu_cache *ca;
393 const char *name = cxt->caches[i].name;
e9d659ea 394
63c5e7f8
KZ
395 if (last && strcmp(last, name) == 0)
396 continue;
397 last = name;
398 ca = lscpu_cpu_get_cache(cxt, cpu, name);
399 if (!ca)
400 continue;
401 x = snprintf(p, sz, "%d", ca->id);
402 if (x < 0 || (size_t) x >= sz)
403 return NULL;
404 p += x;
405 sz -= x;
e07cca6b
KZ
406 if (sz < 2)
407 return NULL;
408 *p++ = cxt->show_compatible ? ',' : ':';
409 *p = '\0';
410 sz--;
5dd7507c 411 }
e07cca6b
KZ
412 if (p > buf && (*(p - 1) == ',' || *(p - 1) == ':'))
413 *(p - 1) = '\0';
477251f8 414 break;
e3b3a2f3 415 }
cc07239d 416 case COL_CPU_POLARIZATION:
63c5e7f8
KZ
417 if (cpu->polarization < 0)
418 break;
419 snprintf(buf, bufsz, "%s",
420 cxt->mode == LSCPU_OUTPUT_PARSABLE ?
421 polar_modes[cpu->polarization].parsable :
422 polar_modes[cpu->polarization].readable);
2b8fcb81 423 break;
cc07239d 424 case COL_CPU_ADDRESS:
63c5e7f8
KZ
425 if (cpu->address < 0)
426 break;
427 snprintf(buf, bufsz, "%d", cpu->address);
596b8845 428 break;
cc07239d 429 case COL_CPU_CONFIGURED:
17353ee0 430 get_cell_boolean(cxt, cpu->configured >= 0, cpu->configured, buf, bufsz);
d231eea1 431 break;
cc07239d 432 case COL_CPU_ONLINE:
17353ee0 433 get_cell_boolean(cxt, !!cxt->online, is_cpu_online(cxt, cpu), buf, bufsz);
a7e5300c 434 break;
6d880d3d 435 case COL_CPU_MHZ:
ff6513c7
KZ
436 if (cpu->mhz_cur_freq)
437 snprintf(buf, bufsz, "%.4f", cpu->mhz_cur_freq);
6d880d3d 438 break;
9b9e4f5d
KZ
439 case COL_CPU_SCALMHZ:
440 if (cpu->mhz_cur_freq && cpu->mhz_max_freq)
441 snprintf(buf, bufsz, "%.0f%%", cpu->mhz_cur_freq / cpu->mhz_max_freq * 100);
6d880d3d 442 break;
cc07239d 443 case COL_CPU_MAXMHZ:
63c5e7f8
KZ
444 if (cpu->mhz_max_freq)
445 snprintf(buf, bufsz, "%.4f", cpu->mhz_max_freq);
e065a597 446 break;
cc07239d 447 case COL_CPU_MINMHZ:
63c5e7f8
KZ
448 if (cpu->mhz_min_freq)
449 snprintf(buf, bufsz, "%.4f", cpu->mhz_min_freq);
44320710 450 break;
1d956847
KZ
451 case COL_CPU_MODELNAME:
452 if (cpu->type && cpu->type->modelname)
453 xstrncpy(buf, cpu->type->modelname, bufsz);
454 break;
477251f8 455 }
e3b3a2f3
KZ
456 return buf;
457}
458
63c5e7f8
KZ
459static char *get_cell_header(
460 struct lscpu_cxt *cxt, int col,
461 char *buf, size_t bufsz)
e3b3a2f3
KZ
462{
463 *buf = '\0';
464
cc07239d 465 if (col == COL_CPU_CACHE) {
63c5e7f8 466 const char *last = NULL;
e3b3a2f3
KZ
467 char *p = buf;
468 size_t sz = bufsz;
63c5e7f8
KZ
469 size_t i;
470
471 for (i = 0; i < cxt->ncaches; i++) {
472 struct lscpu_cache *ca = &cxt->caches[i];
473 int x;
474
475 if (last && strcmp(last, ca->name) == 0)
476 continue;
477 last = ca->name;
e3b3a2f3 478
63c5e7f8 479 x = snprintf(p, sz, "%s", ca->name);
06fa5817 480 if (x < 0 || (size_t) x >= sz)
e3b3a2f3
KZ
481 return NULL;
482 sz -= x;
483 p += x;
e07cca6b
KZ
484 if (sz < 2)
485 return NULL;
486 *p++ = cxt->show_compatible ? ',' : ':';
487 *p = '\0';
488 sz--;
e3b3a2f3 489 }
e07cca6b
KZ
490 if (p > buf && (*(p - 1) == ',' || *(p - 1) == ':'))
491 *(p - 1) = '\0';
63c5e7f8 492 if (cxt->ncaches)
e3b3a2f3
KZ
493 return buf;
494 }
cc07239d 495 snprintf(buf, bufsz, "%s", coldescs_cpu[col].name);
e3b3a2f3 496 return buf;
477251f8
KZ
497}
498
1766641a 499
9d480e57
KZ
500static void caches_add_line(struct lscpu_cxt *cxt,
501 struct libscols_table *tb,
502 struct lscpu_cache *ca,
503 int cols[], size_t ncols)
504{
505 struct libscols_line *ln;
506 size_t c;
507
508 ln = scols_table_new_line(tb, NULL);
509 if (!ln)
510 err(EXIT_FAILURE, _("failed to allocate output line"));
511
512 for (c = 0; c < ncols; c++) {
513 char *data = NULL;
514 int col = cols[c];
515
516 switch (col) {
517 case COL_CACHE_NAME:
518 if (ca->name)
519 data = xstrdup(ca->name);
520 break;
521 case COL_CACHE_ONESIZE:
522 if (!ca->size)
523 break;
524 if (cxt->bytes)
525 xasprintf(&data, "%" PRIu64, ca->size);
526 else
527 data = size_to_human_string(SIZE_SUFFIX_1LETTER, ca->size);
528 break;
529 case COL_CACHE_ALLSIZE:
530 {
b9b28b64
KZ
531 uint64_t sz = 0;
532 if (ca->name)
9dadd3e6 533 sz = lscpu_get_cache_full_size(cxt, ca->name, NULL);
9d480e57
KZ
534 if (!sz)
535 break;
536 if (cxt->bytes)
537 xasprintf(&data, "%" PRIu64, sz);
538 else
539 data = size_to_human_string(SIZE_SUFFIX_1LETTER, sz);
540 break;
541 }
542 case COL_CACHE_WAYS:
543 if (ca->ways_of_associativity)
544 xasprintf(&data, "%u", ca->ways_of_associativity);
545 break;
546
547 case COL_CACHE_TYPE:
548 if (ca->type)
549 data = xstrdup(ca->type);
550 break;
551 case COL_CACHE_LEVEL:
552 if (ca->level)
553 xasprintf(&data, "%d", ca->level);
554 break;
555 case COL_CACHE_ALLOCPOL:
556 if (ca->allocation_policy)
557 data = xstrdup(ca->allocation_policy);
558 break;
559 case COL_CACHE_WRITEPOL:
560 if (ca->write_policy)
561 data = xstrdup(ca->write_policy);
562 break;
563 case COL_CACHE_PHYLINE:
564 if (ca->physical_line_partition)
565 xasprintf(&data, "%u", ca->physical_line_partition);
566 break;
567 case COL_CACHE_SETS:
568 if (ca->number_of_sets)
569 xasprintf(&data, "%u", ca->number_of_sets);
570 break;
571 case COL_CACHE_COHERENCYSIZE:
572 if (ca->coherency_line_size)
573 xasprintf(&data, "%u", ca->coherency_line_size);
574 break;
575 }
576
577 if (data && scols_line_refer_data(ln, c, data))
578 err(EXIT_FAILURE, _("failed to add output data"));
579 }
580}
581
582
0e86bc84
KZ
583/*
584 * [-C] backend
585 */
1766641a 586static void print_caches_readable(struct lscpu_cxt *cxt, int cols[], size_t ncols)
0e86bc84 587{
1766641a
KZ
588 size_t i;
589 struct libscols_table *tb;
590 const char *last = NULL;
0e86bc84
KZ
591
592 scols_init_debug(0);
593
1766641a
KZ
594 tb = scols_new_table();
595 if (!tb)
0e86bc84 596 err(EXIT_FAILURE, _("failed to allocate output table"));
1766641a
KZ
597 if (cxt->json) {
598 scols_table_enable_json(tb, 1);
599 scols_table_set_name(tb, "caches");
0e86bc84
KZ
600 }
601
602 for (i = 0; i < ncols; i++) {
603 struct lscpu_coldesc *cd = &coldescs_cache[cols[i]];
17353ee0
TW
604 struct libscols_column *cl;
605
606 cl = scols_table_new_column(tb, cd->name, 0, cd->flags);
17353ee0 607 if (cl == NULL)
0e86bc84 608 err(EXIT_FAILURE, _("failed to allocate output column"));
17353ee0
TW
609 if (cxt->json)
610 scols_column_set_json_type(cl, cd->json_type);
0e86bc84
KZ
611 }
612
9d480e57 613 /* standard caches */
1766641a
KZ
614 for (i = 0; i < cxt->ncaches; i++) {
615 struct lscpu_cache *ca = &cxt->caches[i];
0e86bc84 616
1766641a
KZ
617 if (last && strcmp(last, ca->name) == 0)
618 continue;
1766641a 619 last = ca->name;
9d480e57
KZ
620 caches_add_line(cxt, tb, ca, cols, ncols);
621 }
1766641a 622
9d480e57
KZ
623 /* extra caches */
624 for (i = 0; i < cxt->necaches; i++) {
625 struct lscpu_cache *ca = &cxt->ecaches[i];
318542e0 626
9d480e57
KZ
627 if (last && strcmp(last, ca->name) == 0)
628 continue;
629 last = ca->name;
630 caches_add_line(cxt, tb, ca, cols, ncols);
0e86bc84
KZ
631 }
632
1766641a
KZ
633 scols_print_table(tb);
634 scols_unref_table(tb);
0e86bc84
KZ
635}
636
477251f8 637/*
ba45d8c1 638 * [-p] backend, we support two parsable formats:
477251f8
KZ
639 *
640 * 1) "compatible" -- this format is compatible with the original lscpu(1)
641 * output and it contains fixed set of the columns. The CACHE columns are at
642 * the end of the line and the CACHE is not printed if the number of the caches
643 * is zero. The CACHE columns are separated by two commas, for example:
644 *
645 * $ lscpu --parse
646 * # CPU,Core,Socket,Node,,L1d,L1i,L2
647 * 0,0,0,0,,0,0,0
648 * 1,1,0,0,,1,1,0
649 *
650 * 2) "user defined output" -- this format prints always all columns without
651 * special prefix for CACHE column. If there are not CACHEs then the column is
652 * empty and the header "Cache" is printed rather than a real name of the cache.
653 * The CACHE columns are separated by ':'.
654 *
655 * $ lscpu --parse=CPU,CORE,SOCKET,NODE,CACHE
656 * # CPU,Core,Socket,Node,L1d:L1i:L2
657 * 0,0,0,0,0:0:0
658 * 1,1,0,0,1:1:0
659 */
0710bb13 660static void print_cpus_parsable(struct lscpu_cxt *cxt, int cols[], size_t ncols)
477251f8 661{
e3b3a2f3 662 char buf[BUFSIZ], *data;
0710bb13 663 size_t i;
477251f8 664
e3b3a2f3
KZ
665 /*
666 * Header
667 */
477251f8
KZ
668 printf(_(
669 "# The following is the parsable format, which can be fed to other\n"
670 "# programs. Each different item in every column has an unique ID\n"
6321d34f 671 "# starting usually from zero.\n"));
477251f8
KZ
672
673 fputs("# ", stdout);
674 for (i = 0; i < ncols; i++) {
3d27b76a 675 int col = cols[i];
b9d18bc3 676
cc07239d 677 if (col == COL_CPU_CACHE) {
0710bb13 678 if (cxt->show_compatible && !cxt->ncaches)
477251f8 679 continue;
0710bb13 680 if (cxt->show_compatible && i != 0)
477251f8 681 putchar(',');
477251f8 682 }
e3b3a2f3
KZ
683 if (i > 0)
684 putchar(',');
685
0710bb13 686 data = get_cell_header(cxt, col, buf, sizeof(buf));
cc07239d
KZ
687 if (data && * data && col != COL_CPU_CACHE &&
688 !coldescs_cpu[col].is_abbr) {
3d27b76a
KZ
689 /*
690 * For normal column names use mixed case (e.g. "Socket")
691 */
692 char *p = data + 1;
693
14e8be8a
PU
694 while (p && *p != '\0') {
695 *p = tolower((unsigned int) *p);
696 p++;
697 }
3d27b76a 698 }
e3b3a2f3 699 fputs(data && *data ? data : "", stdout);
477251f8
KZ
700 }
701 putchar('\n');
702
e3b3a2f3
KZ
703 /*
704 * Data
705 */
0710bb13
KZ
706 for (i = 0; i < cxt->npossibles; i++) {
707 struct lscpu_cpu *cpu = cxt->cpus[i];
708 size_t c;
e3b3a2f3 709
0710bb13
KZ
710 if (cxt->online) {
711 if (!cxt->show_offline && !is_cpu_online(cxt, cpu))
6dd7b74b 712 continue;
0710bb13 713 if (!cxt->show_online && is_cpu_online(cxt, cpu))
6dd7b74b
SK
714 continue;
715 }
0710bb13 716 if (cxt->present && !is_cpu_present(cxt, cpu))
a5cfffff 717 continue;
0710bb13 718
477251f8 719 for (c = 0; c < ncols; c++) {
0710bb13
KZ
720 if (cxt->show_compatible && cols[c] == COL_CPU_CACHE) {
721 if (!cxt->ncaches)
477251f8
KZ
722 continue;
723 if (c > 0)
724 putchar(',');
725 }
726 if (c > 0)
727 putchar(',');
e3b3a2f3 728
0710bb13 729 data = get_cell_data(cxt, cpu, cols[c], buf, sizeof(buf));
e3b3a2f3 730 fputs(data && *data ? data : "", stdout);
bdda3543 731 *buf = '\0';
477251f8 732 }
5dd7507c
CQ
733 putchar('\n');
734 }
735}
736
ba45d8c1
KZ
737/*
738 * [-e] backend
739 */
63c5e7f8 740static void print_cpus_readable(struct lscpu_cxt *cxt, int cols[], size_t ncols)
ba45d8c1 741{
63c5e7f8 742 size_t i;
e7213e34
KZ
743 char buf[BUFSIZ];
744 const char *data;
63c5e7f8 745 struct libscols_table *tb;
ba45d8c1 746
710ed55d
KZ
747 scols_init_debug(0);
748
63c5e7f8
KZ
749 tb = scols_new_table();
750 if (!tb)
780ce22c 751 err(EXIT_FAILURE, _("failed to allocate output table"));
63c5e7f8
KZ
752 if (cxt->json) {
753 scols_table_enable_json(tb, 1);
754 scols_table_set_name(tb, "cpus");
19a5510b 755 }
ba45d8c1
KZ
756
757 for (i = 0; i < ncols; i++) {
63c5e7f8 758 data = get_cell_header(cxt, cols[i], buf, sizeof(buf));
17353ee0
TW
759 struct lscpu_coldesc *cd = &coldescs_cpu[cols[i]];
760 struct libscols_column *cl;
761
762 cl = scols_table_new_column(tb, data, 0, cd->flags);
763 if (cl == NULL)
780ce22c 764 err(EXIT_FAILURE, _("failed to allocate output column"));
17353ee0
TW
765 if (cxt->json)
766 scols_column_set_json_type(cl, cd->json_type);
ba45d8c1
KZ
767 }
768
63c5e7f8
KZ
769 for (i = 0; i < cxt->npossibles; i++) {
770 size_t c;
771 struct libscols_line *ln;
772 struct lscpu_cpu *cpu = cxt->cpus[i];
ba45d8c1 773
63c5e7f8
KZ
774 if (cxt->online) {
775 if (!cxt->show_offline && !is_cpu_online(cxt, cpu))
6dd7b74b 776 continue;
63c5e7f8 777 if (!cxt->show_online && is_cpu_online(cxt, cpu))
6dd7b74b
SK
778 continue;
779 }
63c5e7f8
KZ
780
781 if (cxt->present && !is_cpu_present(cxt, cpu))
a5cfffff 782 continue;
ba45d8c1 783
63c5e7f8
KZ
784 ln = scols_table_new_line(tb, NULL);
785 if (!ln)
780ce22c 786 err(EXIT_FAILURE, _("failed to allocate output line"));
ba45d8c1
KZ
787
788 for (c = 0; c < ncols; c++) {
63c5e7f8 789 data = get_cell_data(cxt, cpu, cols[c], buf, sizeof(buf));
e7213e34
KZ
790 if (!data || !*data)
791 data = "-";
63c5e7f8 792 if (scols_line_set_data(ln, c, data))
780ce22c 793 err(EXIT_FAILURE, _("failed to add output data"));
ba45d8c1
KZ
794 }
795 }
796
63c5e7f8
KZ
797 scols_print_table(tb);
798 scols_unref_table(tb);
ba45d8c1 799}
5dd7507c 800
e3f21318 801static struct libscols_line *
91eef60c 802 __attribute__ ((__format__(printf, 4, 5)))
c82b12a0 803 add_summary_sprint(struct libscols_table *tb,
e3f21318 804 struct libscols_line *sec,
c82b12a0
KZ
805 const char *txt,
806 const char *fmt,
807 ...)
808{
91eef60c 809 struct libscols_line *ln;
c82b12a0
KZ
810 va_list args;
811
c9121791
KZ
812 /* Don't print section lines without data */
813 if (!hierarchic && fmt == NULL)
91eef60c
KZ
814 return NULL;
815
816 ln = scols_table_new_line(tb, sec);
c82b12a0 817 if (!ln)
780ce22c 818 err(EXIT_FAILURE, _("failed to allocate output line"));
c82b12a0
KZ
819
820 /* description column */
a0661407
KZ
821 if (txt && scols_line_set_data(ln, 0, txt))
822 err(EXIT_FAILURE, _("failed to add output data"));
c82b12a0
KZ
823
824 /* data column */
91eef60c
KZ
825 if (fmt) {
826 char *data;
827 va_start(args, fmt);
828 xvasprintf(&data, fmt, args);
829 va_end(args);
830
831 if (data && scols_line_refer_data(ln, 1, data))
832 err(EXIT_FAILURE, _("failed to add output data"));
833 }
e3f21318
KZ
834
835 return ln;
c82b12a0
KZ
836}
837
91eef60c 838#define add_summary_e(tb, sec, txt) add_summary_sprint(tb, sec, txt, NULL)
e3f21318
KZ
839#define add_summary_n(tb, sec, txt, num) add_summary_sprint(tb, sec, txt, "%zu", num)
840#define add_summary_s(tb, sec, txt, str) add_summary_sprint(tb, sec, txt, "%s", str)
841#define add_summary_x(tb, sec, txt, fmt, x) add_summary_sprint(tb, sec, txt, fmt, x)
5dd7507c
CQ
842
843static void
d8813bb3
KZ
844print_cpuset(struct lscpu_cxt *cxt,
845 struct libscols_table *tb,
91eef60c 846 struct libscols_line *sec,
d8813bb3 847 const char *key, cpu_set_t *set)
4f912c6a 848{
d8813bb3 849 size_t setbuflen = 7 * cxt->maxcpus;
b6f635ef 850 char *setbuf, *p;
4f912c6a 851
93a1bb10
KZ
852 assert(set);
853 assert(key);
854 assert(tb);
855 assert(cxt);
856
b6f635ef
TW
857 setbuf = xmalloc(setbuflen);
858
d8813bb3
KZ
859 if (cxt->hex) {
860 p = cpumask_create(setbuf, setbuflen, set, cxt->setsize);
91eef60c 861 add_summary_s(tb, sec, key, p);
4f912c6a 862 } else {
d8813bb3 863 p = cpulist_create(setbuf, setbuflen, set, cxt->setsize);
91eef60c 864 add_summary_s(tb, sec, key, p);
4f912c6a 865 }
b6f635ef
TW
866
867 free(setbuf);
4f912c6a
KZ
868}
869
2f5e2730
KZ
870static void
871print_summary_cputype(struct lscpu_cxt *cxt,
872 struct lscpu_cputype *ct,
91eef60c
KZ
873 struct libscols_table *tb,
874 struct libscols_line *sec)
5dd7507c 875{
38e93216 876 sec = add_summary_s(tb, sec, _("Model name:"), ct->modelname ? ct->modelname : "-");
8014104b
MM
877 if (ct->bios_modelname)
878 add_summary_s(tb, sec, _("BIOS Model name:"), ct->bios_modelname);
4cae2104
HS
879 if (ct->bios_family)
880 add_summary_s(tb, sec, _("BIOS CPU family:"), ct->bios_family);
2f5e2730 881 if (ct->machinetype)
91eef60c 882 add_summary_s(tb, sec, _("Machine type:"), ct->machinetype);
2f5e2730 883 if (ct->family)
91eef60c 884 add_summary_s(tb, sec, _("CPU family:"), ct->family);
2f5e2730 885 if (ct->model || ct->revision)
91eef60c 886 add_summary_s(tb, sec, _("Model:"), ct->revision ? ct->revision : ct->model);
2f5e2730 887
91eef60c 888 add_summary_n(tb, sec, _("Thread(s) per core:"), ct->nthreads_per_core);
73c0a766
MM
889 if (cxt->is_cluster)
890 add_summary_n(tb, sec, _("Core(s) per cluster:"), ct->ncores_per_socket);
891 else
892 add_summary_n(tb, sec, _("Core(s) per socket:"), ct->ncores_per_socket);
19ddc05e 893
2f5e2730 894 if (ct->nbooks) {
91eef60c 895 add_summary_n(tb, sec, _("Socket(s) per book:"), ct->nsockets_per_book);
19ddc05e 896 if (ct->ndrawers_per_system || ct->ndrawers) {
91eef60c 897 add_summary_n(tb, sec, _("Book(s) per drawer:"), ct->nbooks_per_drawer);
19ddc05e 898 add_summary_n(tb, sec, _("Drawer(s):"), ct->ndrawers_per_system ?: ct->ndrawers);
2f5e2730 899 } else
19ddc05e 900 add_summary_n(tb, sec, _("Book(s):"), ct->nbooks_per_drawer ?: ct->nbooks);
73c0a766 901 } else {
f42f105b
MM
902 if (cxt->is_cluster) {
903 if (ct->nr_socket_on_cluster > 0)
904 add_summary_n(tb, sec, _("Socket(s):"), ct->nr_socket_on_cluster);
905 else
906 add_summary_s(tb, sec, _("Socket(s):"), "-");
907
73c0a766
MM
908 add_summary_n(tb, sec, _("Cluster(s):"),
909 ct->nsockets_per_book ?: ct->nsockets);
f42f105b 910 } else
73c0a766
MM
911 add_summary_n(tb, sec, _("Socket(s):"),
912 ct->nsockets_per_book ?: ct->nsockets);
913 }
2f5e2730 914
93a1bb10 915 if (ct->stepping)
91eef60c 916 add_summary_s(tb, sec, _("Stepping:"), ct->stepping);
93a1bb10 917 if (ct->freqboost >= 0)
91eef60c 918 add_summary_s(tb, sec, _("Frequency boost:"), ct->freqboost ?
16ca0551 919 _("enabled") : _("disabled"));
01bea871
KZ
920
921 /* s390 -- from the first CPU where is dynamic/static MHz */
93a1bb10 922 if (ct->dynamic_mhz)
91eef60c 923 add_summary_s(tb, sec, _("CPU dynamic MHz:"), ct->dynamic_mhz);
93a1bb10 924 if (ct->static_mhz)
91eef60c 925 add_summary_s(tb, sec, _("CPU static MHz:"), ct->static_mhz);
01bea871 926
93a1bb10 927 if (ct->has_freq) {
9b9e4f5d
KZ
928 float scal = lsblk_cputype_get_scalmhz(cxt, ct);
929 if (scal > 0.0)
930 add_summary_x(tb, sec, _("CPU(s) scaling MHz:"), "%.0f%%", scal);
91eef60c
KZ
931 add_summary_x(tb, sec, _("CPU max MHz:"), "%.4f", lsblk_cputype_get_maxmhz(cxt, ct));
932 add_summary_x(tb, sec, _("CPU min MHz:"), "%.4f", lsblk_cputype_get_minmhz(cxt, ct));
bd9b94d1 933 }
93a1bb10 934 if (ct->bogomips)
aff94add 935 add_summary_x(tb, sec, _("BogoMIPS:"), "%.2f", (float) c_strtod(ct->bogomips, NULL));
91eef60c 936
93a1bb10 937 if (ct->dispatching >= 0)
91eef60c 938 add_summary_s(tb, sec, _("Dispatching mode:"), _(disp_modes[ct->dispatching]));
93a1bb10
KZ
939
940 if (ct->physsockets) {
91eef60c
KZ
941 add_summary_n(tb, sec, _("Physical sockets:"), ct->physsockets);
942 add_summary_n(tb, sec, _("Physical chips:"), ct->physchips);
943 add_summary_n(tb, sec, _("Physical cores/chip:"), ct->physcoresperchip);
639eeb28
KZ
944 }
945
93a1bb10 946 if (ct->flags)
91eef60c 947 add_summary_s(tb, sec, _("Flags:"), ct->flags);
2f5e2730
KZ
948}
949
950/*
951 * default output
952 */
953static void print_summary(struct lscpu_cxt *cxt)
954{
955 struct lscpu_cputype *ct;
91eef60c 956 char field[256];
2f5e2730
KZ
957 size_t i = 0;
958 struct libscols_table *tb;
f46c685b 959 struct libscols_line *sec;
071d3135 960 int hdr_caches = 0;
2f5e2730
KZ
961
962 scols_init_debug(0);
963
964 tb = scols_new_table();
965 if (!tb)
966 err(EXIT_FAILURE, _("failed to allocate output table"));
967
968 scols_table_enable_noheadings(tb, 1);
969 if (cxt->json) {
970 scols_table_enable_json(tb, 1);
971 scols_table_set_name(tb, "lscpu");
c9121791 972 } else if (hierarchic) {
91eef60c
KZ
973 struct libscols_symbols *sy = scols_new_symbols();
974
975 if (!sy)
976 err_oom();
977 scols_symbols_set_branch(sy, " ");
978 scols_symbols_set_vertical(sy, " ");
979 scols_symbols_set_right(sy, " ");
980 scols_table_set_symbols(tb, sy);
d4cb6a03 981 scols_unref_symbols(sy);
2f5e2730
KZ
982 }
983
c9121791 984 if (scols_table_new_column(tb, "field", 0, hierarchic ? SCOLS_FL_TREE : 0) == NULL ||
2f5e2730
KZ
985 scols_table_new_column(tb, "data", 0, SCOLS_FL_NOEXTREMES | SCOLS_FL_WRAP) == NULL)
986 err(EXIT_FAILURE, _("failed to initialize output column"));
987
988 ct = lscpu_cputype_get_default(cxt);
989
91eef60c 990 /* Section: architecture */
f46c685b
TW
991 sec = add_summary_s(tb, NULL, _("Architecture:"), cxt->arch->name);
992 if (cxt->arch->bit32 || cxt->arch->bit64) {
2f5e2730
KZ
993 char buf[32], *p = buf;
994
995 if (cxt->arch->bit32) {
996 strcpy(p, "32-bit, ");
997 p += 8;
998 }
999 if (cxt->arch->bit64) {
1000 strcpy(p, "64-bit, ");
1001 p += 8;
1002 }
1003 *(p - 2) = '\0';
e3f21318 1004 add_summary_s(tb, sec, _("CPU op-mode(s):"), buf);
2f5e2730 1005 }
0d7cef3d 1006 if (ct && ct->addrsz)
e3f21318 1007 add_summary_s(tb, sec, _("Address sizes:"), ct->addrsz);
0e3858fc 1008
f145492f 1009 if (sysfs_get_byteorder(cxt->rootfs) == SYSFS_BYTEORDER_LITTLE)
0e3858fc
TW
1010 add_summary_s(tb, sec, _("Byte Order:"), "Little Endian");
1011 else
1012 add_summary_s(tb, sec, _("Byte Order:"), "Big Endian");
91eef60c
KZ
1013
1014 /* Section: CPU lists */
1015 sec = add_summary_n(tb, NULL, _("CPU(s):"), cxt->npresents);
1016
2f5e2730 1017 if (cxt->online)
91eef60c 1018 print_cpuset(cxt, tb, sec,
2f5e2730
KZ
1019 cxt->hex ? _("On-line CPU(s) mask:") :
1020 _("On-line CPU(s) list:"),
1021 cxt->online);
1022
1023 if (cxt->online && cxt->nonlines != cxt->npresents) {
1024 cpu_set_t *set;
1025
1026 /* Linux kernel provides cpuset of off-line CPUs that contains
1027 * all configured CPUs (see /sys/devices/system/cpu/offline),
1028 * but want to print real (present in system) off-line CPUs only.
1029 */
1030 set = cpuset_alloc(cxt->maxcpus, NULL, NULL);
1031 if (!set)
1032 err(EXIT_FAILURE, _("failed to callocate cpu set"));
1033 CPU_ZERO_S(cxt->setsize, set);
1034 for (i = 0; i < cxt->npossibles; i++) {
1035 struct lscpu_cpu *cpu = cxt->cpus[i];
1036
1037 if (cpu && is_cpu_present(cxt, cpu) && !is_cpu_online(cxt, cpu))
1038 CPU_SET_S(cpu->logical_id, cxt->setsize, set);
1039 }
91eef60c 1040 print_cpuset(cxt, tb, sec,
2f5e2730
KZ
1041 cxt->hex ? _("Off-line CPU(s) mask:") :
1042 _("Off-line CPU(s) list:"), set);
1043 cpuset_free(set);
1044 }
8014104b 1045 sec = NULL;
2f5e2730 1046
91eef60c 1047 /* Section: cpu type description */
0d7cef3d 1048 if (ct && ct->vendor)
91eef60c 1049 sec = add_summary_s(tb, NULL, _("Vendor ID:"), ct->vendor);
0d7cef3d 1050 if (ct && ct->bios_vendor)
8014104b 1051 add_summary_s(tb, sec, _("BIOS Vendor ID:"), ct->bios_vendor);
91eef60c 1052
8014104b
MM
1053 for (i = 0; i < cxt->ncputypes; i++)
1054 print_summary_cputype(cxt, cxt->cputypes[i], tb, sec);
91eef60c 1055 sec = NULL;
2f5e2730 1056
91eef60c 1057 /* Section: vitualiazation */
93a1bb10 1058 if (cxt->virt) {
91eef60c 1059 sec = add_summary_e(tb, NULL, _("Virtualization features:"));
01bea871 1060 if (cxt->virt->cpuflag && !strcmp(cxt->virt->cpuflag, "svm"))
e3f21318 1061 add_summary_s(tb, sec, _("Virtualization:"), "AMD-V");
01bea871 1062 else if (cxt->virt->cpuflag && !strcmp(cxt->virt->cpuflag, "vmx"))
e3f21318 1063 add_summary_s(tb, sec, _("Virtualization:"), "VT-x");
93a1bb10
KZ
1064
1065 if (cxt->virt->hypervisor)
e3f21318 1066 add_summary_s(tb, sec, _("Hypervisor:"), cxt->virt->hypervisor);
93a1bb10 1067 if (cxt->virt->vendor) {
e3f21318
KZ
1068 add_summary_s(tb, sec, _("Hypervisor vendor:"), hv_vendors[cxt->virt->vendor]);
1069 add_summary_s(tb, sec, _("Virtualization type:"), _(virt_types[cxt->virt->type]));
93a1bb10 1070 }
e3f21318 1071 sec = NULL;
93a1bb10 1072 }
91eef60c
KZ
1073
1074 /* Section: caches */
01bea871
KZ
1075 if (cxt->ncaches) {
1076 const char *last = NULL;
93a1bb10 1077
01bea871
KZ
1078 /* The caches are sorted by name, cxt->caches[] may contains
1079 * multiple instances for the same name.
1080 */
1081 for (i = 0; i < cxt->ncaches; i++) {
1082 const char *name = cxt->caches[i].name;
1083 uint64_t sz;
9dadd3e6 1084 int n = 0;
93a1bb10 1085
01bea871 1086 if (last && strcmp(last, name) == 0)
93a1bb10 1087 continue;
9dadd3e6 1088 sz = lscpu_get_cache_full_size(cxt, name, &n);
01bea871 1089 if (!sz)
93a1bb10 1090 continue;
071d3135
KZ
1091 if (!hdr_caches) {
1092 sec = add_summary_e(tb, NULL, _("Caches (sum of all):"));
1093 hdr_caches = 1;
1094 }
1095
c9121791 1096 snprintf(field, sizeof(field), hierarchic ? _("%s:") : _("%s cache:"), name);
01bea871 1097 if (cxt->bytes)
9dadd3e6
KZ
1098 add_summary_sprint(tb, sec, field,
1099 P_("%" PRIu64 " (%d instance)",
1100 "%" PRIu64 " (%d instances)", n),
1101 sz, n);
01bea871
KZ
1102 else {
1103 char *tmp = size_to_human_string(
1104 SIZE_SUFFIX_3LETTER |
1105 SIZE_SUFFIX_SPACE,
1106 sz);
9dadd3e6
KZ
1107 add_summary_sprint(tb, sec, field,
1108 P_("%s (%d instance)",
1109 "%s (%d instances)", n),
1110 tmp, n);
01bea871
KZ
1111 free(tmp);
1112 }
1113 last = name;
93a1bb10
KZ
1114 }
1115 }
01bea871 1116
071d3135
KZ
1117 for (i = 0; i < cxt->necaches; i++) {
1118 struct lscpu_cache *ca = &cxt->ecaches[i];
93a1bb10 1119
071d3135
KZ
1120 if (ca->size == 0)
1121 continue;
1122 if (!hdr_caches) {
1123 sec = add_summary_e(tb, NULL, _("Caches:"));
1124 hdr_caches = 1;
1125 }
c9121791 1126 snprintf(field, sizeof(field), hierarchic ? _("%s:") : _("%s cache:"), ca->name);
071d3135
KZ
1127 if (cxt->bytes)
1128 add_summary_x(tb, sec, field, "%" PRIu64, ca->size);
1129 else {
1130 char *tmp = size_to_human_string(
1131 SIZE_SUFFIX_3LETTER |
1132 SIZE_SUFFIX_SPACE,
1133 ca->size);
1134 add_summary_s(tb, sec, field, tmp);
1135 free(tmp);
01bea871
KZ
1136 }
1137 }
7155a57d 1138 sec = NULL;
01bea871 1139
91eef60c 1140 /* Section: NUMA modes */
01bea871 1141 if (cxt->nnodes) {
91eef60c 1142 sec = add_summary_e(tb, NULL, _("NUMA:"));
e3f21318
KZ
1143
1144 add_summary_n(tb, sec,_("NUMA node(s):"), cxt->nnodes);
01bea871 1145 for (i = 0; i < cxt->nnodes; i++) {
91eef60c
KZ
1146 snprintf(field, sizeof(field), _("NUMA node%d CPU(s):"), cxt->idx2nodenum[i]);
1147 print_cpuset(cxt, tb, sec, field, cxt->nodemaps[i]);
93a1bb10 1148 }
e3f21318 1149 sec = NULL;
93a1bb10
KZ
1150 }
1151
91eef60c 1152 /* Section: Vulnerabilities */
01bea871 1153 if (cxt->vuls) {
91eef60c 1154 sec = add_summary_e(tb, NULL, _("Vulnerabilities:"));
e3f21318 1155
01bea871 1156 for (i = 0; i < cxt->nvuls; i++) {
c9121791 1157 snprintf(field, sizeof(field), hierarchic ?
91eef60c
KZ
1158 _("%s:") : _("Vulnerability %s:"), cxt->vuls[i].name);
1159 add_summary_s(tb, sec, field, cxt->vuls[i].text);
93a1bb10 1160 }
e3f21318 1161 sec = NULL;
93a1bb10 1162 }
c82b12a0
KZ
1163 scols_print_table(tb);
1164 scols_unref_table(tb);
5dd7507c
CQ
1165}
1166
6e1eda6f 1167static void __attribute__((__noreturn__)) usage(void)
5dd7507c 1168{
6e1eda6f 1169 FILE *out = stdout;
b9d18bc3
KZ
1170 size_t i;
1171
1172 fputs(USAGE_HEADER, out);
c6f095cf 1173 fprintf(out, _(" %s [options]\n"), program_invocation_short_name);
7f1ec5e8 1174
451dbcfa
BS
1175 fputs(USAGE_SEPARATOR, out);
1176 fputs(_("Display information about the CPU architecture.\n"), out);
1177
b9d18bc3 1178 fputs(USAGE_OPTIONS, out);
c6f095cf
BS
1179 fputs(_(" -a, --all print both online and offline CPUs (default for -e)\n"), out);
1180 fputs(_(" -b, --online print online CPUs only (default for -p)\n"), out);
2011528b 1181 fputs(_(" -B, --bytes print sizes in bytes rather than in human readable format\n"), out);
0e86bc84 1182 fputs(_(" -C, --caches[=<list>] info about caches in extended readable format\n"), out);
c6f095cf 1183 fputs(_(" -c, --offline print offline CPUs only\n"), out);
19a5510b 1184 fputs(_(" -J, --json use JSON for default or extended format\n"), out);
c6f095cf
BS
1185 fputs(_(" -e, --extended[=<list>] print out an extended readable format\n"), out);
1186 fputs(_(" -p, --parse[=<list>] print out a parsable format\n"), out);
1187 fputs(_(" -s, --sysroot <dir> use specified directory as system root\n"), out);
1188 fputs(_(" -x, --hex print hexadecimal masks rather than lists of CPUs\n"), out);
0d2b5d2a 1189 fputs(_(" -y, --physical print physical instead of logical IDs\n"), out);
c9121791 1190 fputs(_(" --hierarchic[=when] use subsections in summary (auto, never, always)\n"), out);
0a31a242 1191 fputs(_(" --output-all print all available columns for -e, -p or -C\n"), out);
c6f095cf 1192 fputs(USAGE_SEPARATOR, out);
bad4c729 1193 fprintf(out, USAGE_HELP_OPTIONS(25));
b9d18bc3 1194
cc07239d
KZ
1195 fputs(_("\nAvailable output columns for -e or -p:\n"), out);
1196 for (i = 0; i < ARRAY_SIZE(coldescs_cpu); i++)
1197 fprintf(out, " %13s %s\n", coldescs_cpu[i].name, _(coldescs_cpu[i].help));
3d27b76a 1198
0e86bc84
KZ
1199 fputs(_("\nAvailable output columns for -C:\n"), out);
1200 for (i = 0; i < ARRAY_SIZE(coldescs_cache); i++)
1201 fprintf(out, " %13s %s\n", coldescs_cache[i].name, _(coldescs_cache[i].help));
1202
bad4c729 1203 fprintf(out, USAGE_MAN_TAIL("lscpu(1)"));
4f912c6a 1204
6e1eda6f 1205 exit(EXIT_SUCCESS);
5dd7507c
CQ
1206}
1207
1208int main(int argc, char *argv[])
1209{
27c349f9 1210 struct lscpu_cxt *cxt;
b73d38b1 1211 int c, all = 0;
b4f60062 1212 int columns[ARRAY_SIZE(coldescs_cpu)];
7fc12cd2 1213 int cpu_modifier_specified = 0;
1242c3fd 1214 char *outarg = NULL;
b4f60062 1215 size_t i, ncolumns = 0;
fbf0619b
SK
1216 enum {
1217 OPT_OUTPUT_ALL = CHAR_MAX + 1,
c9121791 1218 OPT_HIERARCHIC,
fbf0619b 1219 };
6c7d5ae9 1220 static const struct option longopts[] = {
87918040
SK
1221 { "all", no_argument, NULL, 'a' },
1222 { "online", no_argument, NULL, 'b' },
2011528b 1223 { "bytes", no_argument, NULL, 'B' },
0e86bc84 1224 { "caches", optional_argument, NULL, 'C' },
87918040
SK
1225 { "offline", no_argument, NULL, 'c' },
1226 { "help", no_argument, NULL, 'h' },
1227 { "extended", optional_argument, NULL, 'e' },
19a5510b 1228 { "json", no_argument, NULL, 'J' },
87918040
SK
1229 { "parse", optional_argument, NULL, 'p' },
1230 { "sysroot", required_argument, NULL, 's' },
1231 { "physical", no_argument, NULL, 'y' },
1232 { "hex", no_argument, NULL, 'x' },
1233 { "version", no_argument, NULL, 'V' },
fbf0619b 1234 { "output-all", no_argument, NULL, OPT_OUTPUT_ALL },
c9121791 1235 { "hierarchic", optional_argument, NULL, OPT_HIERARCHIC },
87918040 1236 { NULL, 0, NULL, 0 }
5dd7507c
CQ
1237 };
1238
8e97eb4b 1239 static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
0e86bc84 1240 { 'C','e','p' },
a44cd891 1241 { 'a','b','c' },
8e97eb4b
KZ
1242 { 0 }
1243 };
1244 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
1245
2f8f1388 1246 setlocale(LC_ALL, "");
5dd7507c
CQ
1247 bindtextdomain(PACKAGE, LOCALEDIR);
1248 textdomain(PACKAGE);
25b7045e 1249 close_stdout_atexit();
5dd7507c 1250
b73d38b1
KZ
1251 cxt = lscpu_new_context();
1252
2011528b 1253 while ((c = getopt_long(argc, argv, "aBbC::ce::hJp::s:xyV", longopts, NULL)) != -1) {
8e97eb4b
KZ
1254
1255 err_exclusive_options(c, longopts, excl, excl_st);
1256
5dd7507c 1257 switch (c) {
0ad29ff6 1258 case 'a':
b73d38b1 1259 cxt->show_online = cxt->show_offline = 1;
7fc12cd2 1260 cpu_modifier_specified = 1;
0ad29ff6 1261 break;
2011528b 1262 case 'B':
b73d38b1 1263 cxt->bytes = 1;
2011528b 1264 break;
23e9e95a 1265 case 'b':
b73d38b1 1266 cxt->show_online = 1;
7fc12cd2 1267 cpu_modifier_specified = 1;
23e9e95a 1268 break;
7afc2387 1269 case 'c':
b73d38b1 1270 cxt->show_offline = 1;
7fc12cd2 1271 cpu_modifier_specified = 1;
7afc2387 1272 break;
0e86bc84
KZ
1273 case 'C':
1274 if (optarg) {
1275 if (*optarg == '=')
1276 optarg++;
1242c3fd 1277 outarg = optarg;
0e86bc84 1278 }
b73d38b1 1279 cxt->mode = LSCPU_OUTPUT_CACHES;
0e86bc84 1280 break;
19a5510b 1281 case 'J':
b73d38b1 1282 cxt->json = 1;
19a5510b 1283 break;
5dd7507c 1284 case 'p':
ba45d8c1 1285 case 'e':
477251f8
KZ
1286 if (optarg) {
1287 if (*optarg == '=')
1288 optarg++;
1242c3fd 1289 outarg = optarg;
477251f8 1290 }
b73d38b1 1291 cxt->mode = c == 'p' ? LSCPU_OUTPUT_PARSABLE : LSCPU_OUTPUT_READABLE;
5dd7507c 1292 break;
47b6e8b6 1293 case 's':
b73d38b1
KZ
1294 cxt->prefix = optarg;
1295 cxt->noalive = 1;
47b6e8b6 1296 break;
4f912c6a 1297 case 'x':
b73d38b1 1298 cxt->hex = 1;
4f912c6a 1299 break;
0d2b5d2a 1300 case 'y':
b73d38b1 1301 cxt->show_physical = 1;
0d2b5d2a 1302 break;
fbf0619b 1303 case OPT_OUTPUT_ALL:
0e86bc84 1304 all = 1;
fbf0619b 1305 break;
c9121791
KZ
1306 case OPT_HIERARCHIC:
1307 if (optarg) {
1308 if (strcmp(optarg, "auto") == 0)
1309 hierarchic = -1;
1310 else if (strcmp(optarg, "never") == 0)
1311 hierarchic = 0;
1312 else if (strcmp(optarg, "always") == 0)
1313 hierarchic = 1;
1314 else
1315 errx(EXIT_FAILURE, _("unsupported --flat argument"));
1316 } else
1317 hierarchic = 1;
1318 break;
2c308875
KZ
1319 case 'h':
1320 usage();
1321 case 'V':
1322 print_version(EXIT_SUCCESS);
5dd7507c 1323 default:
677ec86c 1324 errtryhelp(EXIT_FAILURE);
5dd7507c
CQ
1325 }
1326 }
7bbb7829 1327
0a31a242 1328 if (all && ncolumns == 0) {
b73d38b1 1329 size_t maxsz = cxt->mode == LSCPU_OUTPUT_CACHES ?
0e86bc84
KZ
1330 ARRAY_SIZE(coldescs_cache) :
1331 ARRAY_SIZE(coldescs_cpu);
1332
b73d38b1
KZ
1333 for (i = 0; i < maxsz; i++)
1334 columns[ncolumns++] = i;
0e86bc84
KZ
1335 }
1336
b73d38b1 1337 if (cpu_modifier_specified && cxt->mode == LSCPU_OUTPUT_SUMMARY) {
7fc12cd2
HC
1338 fprintf(stderr,
1339 _("%s: options --all, --online and --offline may only "
ac56e555 1340 "be used with options --extended or --parse.\n"),
7fc12cd2
HC
1341 program_invocation_short_name);
1342 return EXIT_FAILURE;
1343 }
1344
6e1eda6f
RM
1345 if (argc != optind) {
1346 warnx(_("bad usage"));
1347 errtryhelp(EXIT_FAILURE);
1348 }
7bbb7829 1349
7afc2387 1350 /* set default cpu display mode if none was specified */
b73d38b1
KZ
1351 if (!cxt->show_online && !cxt->show_offline) {
1352 cxt->show_online = 1;
1353 cxt->show_offline = cxt->mode == LSCPU_OUTPUT_READABLE ? 1 : 0;
7afc2387 1354 }
6e509042 1355
91eef60c 1356
4b9cbc38 1357 lscpu_init_debug();
6e509042 1358
4b9cbc38 1359 lscpu_context_init_paths(cxt);
5dd7507c 1360
4b9cbc38
KZ
1361 lscpu_read_cpulists(cxt);
1362 lscpu_read_cpuinfo(cxt);
1363 cxt->arch = lscpu_read_architecture(cxt);
538b50cb 1364
4b9cbc38
KZ
1365 lscpu_read_archext(cxt);
1366 lscpu_read_vulnerabilities(cxt);
1367 lscpu_read_numas(cxt);
1368 lscpu_read_topology(cxt);
7e03f383 1369
4b9cbc38 1370 lscpu_decode_arm(cxt);
28b1658f 1371
4b9cbc38 1372 cxt->virt = lscpu_read_virtualization(cxt);
c8b64f6d 1373
c9121791
KZ
1374 if (hierarchic == -1)
1375 hierarchic = isatty(STDOUT_FILENO); /* default */
1376
d8813bb3 1377 switch(cxt->mode) {
30b912d3 1378 case LSCPU_OUTPUT_SUMMARY:
d8813bb3 1379 print_summary(cxt);
ba45d8c1 1380 break;
30b912d3 1381 case LSCPU_OUTPUT_CACHES:
0e86bc84
KZ
1382 if (!ncolumns) {
1383 columns[ncolumns++] = COL_CACHE_NAME;
1384 columns[ncolumns++] = COL_CACHE_ONESIZE;
1385 columns[ncolumns++] = COL_CACHE_ALLSIZE;
1386 columns[ncolumns++] = COL_CACHE_WAYS;
1387 columns[ncolumns++] = COL_CACHE_TYPE;
1388 columns[ncolumns++] = COL_CACHE_LEVEL;
cf3b6b71
KZ
1389 columns[ncolumns++] = COL_CACHE_SETS;
1390 columns[ncolumns++] = COL_CACHE_PHYLINE;
1391 columns[ncolumns++] = COL_CACHE_COHERENCYSIZE;
0e86bc84 1392 }
1242c3fd
KZ
1393 if (outarg && string_add_to_idarray(outarg, columns,
1394 ARRAY_SIZE(columns),
1395 &ncolumns, cache_column_name_to_id) < 0)
1396 return EXIT_FAILURE;
1397
1766641a 1398 print_caches_readable(cxt, columns, ncolumns);
0e86bc84 1399 break;
30b912d3 1400 case LSCPU_OUTPUT_READABLE:
ba45d8c1
KZ
1401 if (!ncolumns) {
1402 /* No list was given. Just print whatever is there. */
63c5e7f8
KZ
1403 struct lscpu_cputype *ct = lscpu_cputype_get_default(cxt);
1404
cc07239d 1405 columns[ncolumns++] = COL_CPU_CPU;
63c5e7f8 1406 if (cxt->nnodes)
cc07239d 1407 columns[ncolumns++] = COL_CPU_NODE;
63c5e7f8 1408 if (ct && ct->ndrawers)
cc07239d 1409 columns[ncolumns++] = COL_CPU_DRAWER;
63c5e7f8 1410 if (ct && ct->nbooks)
cc07239d 1411 columns[ncolumns++] = COL_CPU_BOOK;
73c0a766
MM
1412 if (ct && ct->nsockets) {
1413 if (cxt->is_cluster)
1414 columns[ncolumns++] = COL_CPU_CLUSTER;
1415 else
1416 columns[ncolumns++] = COL_CPU_SOCKET;
1417 }
63c5e7f8 1418 if (ct && ct->ncores)
cc07239d 1419 columns[ncolumns++] = COL_CPU_CORE;
63c5e7f8 1420 if (cxt->ncaches)
cc07239d 1421 columns[ncolumns++] = COL_CPU_CACHE;
63c5e7f8 1422 if (cxt->online)
cc07239d 1423 columns[ncolumns++] = COL_CPU_ONLINE;
63c5e7f8 1424 if (ct && ct->has_configured)
cc07239d 1425 columns[ncolumns++] = COL_CPU_CONFIGURED;
63c5e7f8 1426 if (ct && ct->has_polarization)
cc07239d 1427 columns[ncolumns++] = COL_CPU_POLARIZATION;
63c5e7f8 1428 if (ct && ct->has_addresses)
cc07239d 1429 columns[ncolumns++] = COL_CPU_ADDRESS;
63c5e7f8 1430 if (ct && ct->has_freq) {
cc07239d 1431 columns[ncolumns++] = COL_CPU_MAXMHZ;
cc07239d 1432 columns[ncolumns++] = COL_CPU_MINMHZ;
aa049eab 1433 columns[ncolumns++] = COL_CPU_MHZ;
63c5e7f8 1434 }
ba45d8c1 1435 }
1242c3fd
KZ
1436 if (outarg && string_add_to_idarray(outarg, columns,
1437 ARRAY_SIZE(columns),
1438 &ncolumns, cpu_column_name_to_id) < 0)
1439 return EXIT_FAILURE;
63c5e7f8
KZ
1440 print_cpus_readable(cxt, columns, ncolumns);
1441 break;
63c5e7f8 1442 case LSCPU_OUTPUT_PARSABLE:
0da947eb 1443 cxt->show_compatible = 1;
63c5e7f8
KZ
1444 if (!ncolumns) {
1445 columns[ncolumns++] = COL_CPU_CPU;
1446 columns[ncolumns++] = COL_CPU_CORE;
73c0a766
MM
1447 if (cxt->is_cluster)
1448 columns[ncolumns++] = COL_CPU_CLUSTER;
1449 else
1450 columns[ncolumns++] = COL_CPU_SOCKET;
63c5e7f8
KZ
1451 columns[ncolumns++] = COL_CPU_NODE;
1452 columns[ncolumns++] = COL_CPU_CACHE;
63c5e7f8 1453 }
369c89e7
KZ
1454 if (outarg) {
1455 if (string_add_to_idarray(outarg, columns,
1242c3fd
KZ
1456 ARRAY_SIZE(columns),
1457 &ncolumns, cpu_column_name_to_id) < 0)
369c89e7
KZ
1458 return EXIT_FAILURE;
1459 cxt->show_compatible = 0;
1460 }
1242c3fd 1461
0710bb13 1462 print_cpus_parsable(cxt, columns, ncolumns);
ba45d8c1 1463 break;
8005924a 1464 }
5dd7507c 1465
27c349f9
KZ
1466 lscpu_free_context(cxt);
1467
cf474aac 1468 return EXIT_SUCCESS;
5dd7507c 1469}