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