2 #include <sys/utsname.h>
3 #include <sys/personality.h>
5 #if defined(HAVE_LIBRTAS)
11 #include "fileutils.h"
14 /* Lookup a pattern and get the value for format "<pattern> : <key>"
16 int lookup(char *line
, char *pattern
, char **value
)
19 int len
= strlen(pattern
);
21 /* don't re-fill already found tags, first one wins */
25 if (strncmp(line
, pattern
, len
))
28 for (p
= line
+ len
; isspace(*p
); p
++);
34 for (++p
; isspace(*p
); p
++);
42 len
= strlen(line
) - 1;
43 for (p
= line
+ len
; isspace(*(p
-1)); p
--);
50 struct lscpu_cputype
*lscpu_new_cputype(void)
52 struct lscpu_cputype
*ct
;
54 ct
= xcalloc(1, sizeof(struct lscpu_cputype
));
59 DBG(TYPE
, ul_debugobj(ct
, "alloc"));
63 void lscpu_ref_cputype(struct lscpu_cputype
*ct
)
67 DBG(TYPE
, ul_debugobj(ct
, ">>> ref %d", ct
->refcount
));
71 void lscpu_unref_cputype(struct lscpu_cputype
*ct
)
76 /*DBG(TYPE, ul_debugobj(ct, ">>> unref %d", ct->refcount - 1));*/
78 if (--ct
->refcount
<= 0) {
79 DBG(TYPE
, ul_debugobj(ct
, " freeing %s/%s", ct
->vendor
, ct
->model
));
80 lscpu_cputype_free_topology(ct
);
82 free(ct
->bios_vendor
);
83 free(ct
->machinetype
); /* s390 */
87 free(ct
->bios_modelname
);
88 free(ct
->bios_family
);
89 free(ct
->revision
); /* alternative for model (ppc) */
93 free(ct
->mtid
); /* maximum thread id (s390) */
94 free(ct
->addrsz
); /* address sizes */
96 free(ct
->dynamic_mhz
);
101 struct lscpu_cputype
*lscpu_cputype_get_default(struct lscpu_cxt
*cxt
)
103 return cxt
->cputypes
? cxt
->cputypes
[0] : NULL
;
106 #define match(astr, bstr) \
107 ((!astr && !bstr) || (astr && bstr && strcmp(astr, bstr) == 0))
109 struct lscpu_cputype
*lscpu_add_cputype(struct lscpu_cxt
*cxt
, struct lscpu_cputype
*ct
)
111 DBG(TYPE
, ul_debugobj(ct
, "add new"));
112 cxt
->cputypes
= xrealloc(cxt
->cputypes
, (cxt
->ncputypes
+ 1)
113 * sizeof(struct lscpu_cputype
*));
114 cxt
->cputypes
[cxt
->ncputypes
] = ct
;
116 lscpu_ref_cputype(ct
);
120 static void fprintf_cputypes(FILE *f
, struct lscpu_cxt
*cxt
)
124 for (i
= 0; i
< cxt
->ncputypes
; i
++) {
125 struct lscpu_cputype
*ct
= cxt
->cputypes
[i
];
127 fprintf(f
, "\n vendor: %s\n", ct
->vendor
);
128 fprintf(f
, " machinetype: %s\n", ct
->machinetype
);
129 fprintf(f
, " family: %s\n", ct
->family
);
130 fprintf(f
, " model: %s\n", ct
->model
);
131 fprintf(f
, " modelname: %s\n", ct
->modelname
);
132 fprintf(f
, " revision: %s\n", ct
->revision
);
133 fprintf(f
, " stepping: %s\n", ct
->stepping
);
134 fprintf(f
, " mtid: %s\n", ct
->mtid
);
135 fprintf(f
, " addrsz: %s\n", ct
->addrsz
);
140 CPUINFO_LINE_UNKNOWN
, /* unknown line */
141 CPUINFO_LINE_CPUTYPE
, /* line found in type_patterns[] */
142 CPUINFO_LINE_CPU
, /* line found in cpu_patterns[] */
143 CPUINFO_LINE_CACHE
/* line found in cache_pattern[] */
146 /* Describes /proc/cpuinfo fields */
147 struct cpuinfo_pattern
{
148 int id
; /* field ID */
149 int domain
; /* CPUINFO_LINE_* */
150 const char *pattern
; /* field name as used in /proc/cpuinfo */
151 size_t offset
; /* offset in lscpu_cputype or lscpu_cpu struct */
154 /* field identifiers (field name may be different on different archs) */
157 PAT_BOGOMIPS
, /* global */
158 PAT_BOGOMIPS_CPU
, /* per-cpu */
181 * /proc/cpuinfo to lscpu_cputype conversion
183 #define DEF_PAT_CPUTYPE(_str, _id, _member) \
186 .domain = CPUINFO_LINE_CPUTYPE, \
188 .offset = offsetof(struct lscpu_cputype, _member), \
191 static const struct cpuinfo_pattern type_patterns
[] =
193 /* Sort by fields name! */
194 DEF_PAT_CPUTYPE( "ASEs implemented", PAT_FLAGS
, flags
), /* mips */
195 DEF_PAT_CPUTYPE( "BogoMIPS", PAT_BOGOMIPS
, bogomips
), /* aarch64 */
196 DEF_PAT_CPUTYPE( "CPU implementer", PAT_IMPLEMENTER
,vendor
), /* ARM and aarch64 */
197 DEF_PAT_CPUTYPE( "CPU part", PAT_PART
, model
), /* ARM and aarch64 */
198 DEF_PAT_CPUTYPE( "CPU revision", PAT_REVISION
, revision
), /* aarch64 */
199 DEF_PAT_CPUTYPE( "CPU variant", PAT_VARIANT
, stepping
), /* aarch64 */
200 DEF_PAT_CPUTYPE( "Features", PAT_FEATURES
, flags
), /* aarch64 */
201 DEF_PAT_CPUTYPE( "address sizes", PAT_ADDRESS_SIZES
, addrsz
),/* x86 */
202 DEF_PAT_CPUTYPE( "bogomips per cpu", PAT_BOGOMIPS
, bogomips
), /* s390 */
203 DEF_PAT_CPUTYPE( "cpu", PAT_CPU
, modelname
), /* ppc, sparc */
204 DEF_PAT_CPUTYPE( "cpu family", PAT_FAMILY
, family
),
205 DEF_PAT_CPUTYPE( "cpu model", PAT_MODEL
, model
), /* mips */
206 DEF_PAT_CPUTYPE( "family", PAT_FAMILY
, family
),
207 DEF_PAT_CPUTYPE( "features", PAT_FEATURES
, flags
), /* s390 */
208 DEF_PAT_CPUTYPE( "flags", PAT_FLAGS
, flags
), /* x86 */
209 DEF_PAT_CPUTYPE( "max thread id", PAT_MAX_THREAD_ID
, mtid
), /* s390 */
210 DEF_PAT_CPUTYPE( "model", PAT_MODEL
, model
),
211 DEF_PAT_CPUTYPE( "model name", PAT_MODEL_NAME
, modelname
),
212 DEF_PAT_CPUTYPE( "revision", PAT_REVISION
, revision
),
213 DEF_PAT_CPUTYPE( "stepping", PAT_STEPPING
, stepping
),
214 DEF_PAT_CPUTYPE( "type", PAT_TYPE
, flags
), /* sparc64 */
215 DEF_PAT_CPUTYPE( "vendor", PAT_VENDOR
, vendor
),
216 DEF_PAT_CPUTYPE( "vendor_id", PAT_VENDOR
, vendor
), /* s390 */
220 * /proc/cpuinfo to lscpu_cpu conversion
222 #define DEF_PAT_CPU(_str, _id, _member) \
225 .domain = CPUINFO_LINE_CPU, \
227 .offset = offsetof(struct lscpu_cpu, _member), \
230 static const struct cpuinfo_pattern cpu_patterns
[] =
232 /* Sort by fields name! */
233 DEF_PAT_CPU( "bogomips", PAT_BOGOMIPS_CPU
, bogomips
),
234 DEF_PAT_CPU( "cpu MHz", PAT_MHZ
, mhz
),
235 DEF_PAT_CPU( "cpu MHz dynamic", PAT_MHZ_DYNAMIC
, dynamic_mhz
), /* s390 */
236 DEF_PAT_CPU( "cpu MHz static", PAT_MHZ_STATIC
, static_mhz
), /* s390 */
237 DEF_PAT_CPU( "cpu number", PAT_PROCESSOR
, logical_id
), /* s390 */
238 DEF_PAT_CPU( "processor", PAT_PROCESSOR
, logical_id
),
243 * /proc/cpuinfo to lscpu_cache conversion
245 #define DEF_PAT_CACHE(_str, _id) \
248 .domain = CPUINFO_LINE_CACHE, \
252 static const struct cpuinfo_pattern cache_patterns
[] =
254 /* Sort by fields name! */
255 DEF_PAT_CACHE("cache", PAT_CACHE
),
258 #define CPUTYPE_PATTERN_BUFSZ 32
260 static int cmp_pattern(const void *a0
, const void *b0
)
262 const struct cpuinfo_pattern
263 *a
= (const struct cpuinfo_pattern
*) a0
,
264 *b
= (const struct cpuinfo_pattern
*) b0
;
265 return strcmp(a
->pattern
, b
->pattern
);
268 struct cpuinfo_parser
{
269 struct lscpu_cxt
*cxt
;
270 struct lscpu_cpu
*curr_cpu
;
271 struct lscpu_cputype
*curr_type
;
272 unsigned int curr_type_added
: 1;
275 static int is_different_cputype(struct lscpu_cputype
*ct
, size_t offset
, const char *value
)
278 case offsetof(struct lscpu_cputype
, vendor
):
279 return ct
->vendor
&& value
&& strcmp(ct
->vendor
, value
) != 0;
280 case offsetof(struct lscpu_cputype
, model
):
281 return ct
->model
&& value
&& strcmp(ct
->model
, value
) != 0;
282 case offsetof(struct lscpu_cputype
, modelname
):
283 return ct
->modelname
&& value
&& strcmp(ct
->modelname
, value
) != 0;
284 case offsetof(struct lscpu_cputype
, stepping
):
285 return ct
->stepping
&& value
&& strcmp(ct
->stepping
, value
) != 0;
290 /* canonicalize @str -- remove number at the end return the
291 * number by @keynum. This is usable for example for "processor 5" or "cache1"
293 static char *key_cleanup(char *str
, int *keynum
)
295 size_t sz
= rtrim_whitespace((unsigned char *)str
);
301 for (i
= sz
; i
> 0; i
--) {
302 if (!isdigit(str
[i
- 1]))
307 char *end
= NULL
, *p
= str
+ i
;
311 n
= strtol(p
, &end
, 10);
312 if (errno
|| !end
|| end
== p
)
317 rtrim_whitespace((unsigned char *)str
);
322 static const struct cpuinfo_pattern
*cpuinfo_parse_line(char *str
, char **value
, int *keynum
)
324 struct cpuinfo_pattern key
= { .id
= 0 }, *pat
;
326 char buf
[CPUTYPE_PATTERN_BUFSZ
] = { 0 };
328 DBG(GATHER
, ul_debug("parse \"%s\"", str
));
332 p
= (char *) skip_blank(str
);
340 /* prepare name of the field */
341 xstrncpy(buf
, p
, sizeof(buf
));
346 v
= (char *) skip_space(v
);
350 key
.pattern
= key_cleanup(buf
, keynum
);
352 if ((pat
= bsearch(&key
, type_patterns
,
353 ARRAY_SIZE(type_patterns
),
354 sizeof(struct cpuinfo_pattern
),
359 if ((pat
= bsearch(&key
, cpu_patterns
,
360 ARRAY_SIZE(cpu_patterns
),
361 sizeof(struct cpuinfo_pattern
),
366 if ((pat
= bsearch(&key
, cache_patterns
,
367 ARRAY_SIZE(cache_patterns
),
368 sizeof(struct cpuinfo_pattern
),
374 rtrim_whitespace((unsigned char *) v
);
379 /* Parse extra cache lines contained within /proc/cpuinfo but which are not
380 * part of the cache topology information within the sysfs filesystem. This is
381 * true for all shared caches on e.g. s390. When there are layers of
382 * hypervisors in between it is not knows which CPUs share which caches.
383 * Therefore information about shared caches is only available in
384 * /proc/cpuinfo. Format is:
386 * cache<nr> : level=<lvl> type=<type> scope=<scope> size=<size> line_size=<lsz> associativity=<as>
388 * the cache<nr> part is parsed in cpuinfo_parse_line, in this function parses part after ":".
390 static int cpuinfo_parse_cache(struct lscpu_cxt
*cxt
, int keynum
, char *data
)
392 struct lscpu_cache
*cache
;
396 unsigned int line_size
, associativity
;
398 DBG(GATHER
, ul_debugobj(cxt
, " parse cpuinfo cache '%s'", data
));
400 p
= strstr(data
, "scope=") + 6;
401 /* Skip private caches, also present in sysfs */
402 if (!p
|| strncmp(p
, "Private", 7) == 0)
404 p
= strstr(data
, "level=");
405 if (!p
|| sscanf(p
, "level=%d", &level
) != 1)
407 p
= strstr(data
, "type=") + 5;
411 if (strncmp(p
, "Data", 4) == 0)
413 else if (strncmp(p
, "Instruction", 11) == 0)
415 else if (strncmp(p
, "Unified", 7) == 0)
417 p
= strstr(data
, "size=");
418 if (!p
|| sscanf(p
, "size=%lld", &size
) != 1)
421 p
= strstr(data
, "line_size=");
422 if (!p
|| sscanf(p
, "line_size=%u", &line_size
) != 1)
425 p
= strstr(data
, "associativity=");
426 if (!p
|| sscanf(p
, "associativity=%u", &associativity
) != 1)
430 cxt
->ecaches
= xrealloc(cxt
->ecaches
,
431 cxt
->necaches
* sizeof(struct lscpu_cache
));
432 cache
= &cxt
->ecaches
[cxt
->necaches
- 1];
433 memset(cache
, 0 , sizeof(*cache
));
435 if (type
== 'i' || type
== 'd')
436 xasprintf(&cache
->name
, "L%d%c", level
, type
);
438 xasprintf(&cache
->name
, "L%d", level
);
441 cache
->level
= level
;
442 cache
->size
= size
* 1024;
443 cache
->ways_of_associativity
= associativity
;
444 cache
->coherency_line_size
= line_size
;
445 /* Number of sets for s390. For safety, just check divide by zero */
446 cache
->number_of_sets
= line_size
? (cache
->size
/ line_size
): 0;
447 cache
->number_of_sets
= associativity
? (cache
->number_of_sets
/ associativity
) : 0;
449 cache
->type
= type
== 'i' ? xstrdup("Instruction") :
450 type
== 'd' ? xstrdup("Data") :
451 type
== 'u' ? xstrdup("Unified") : NULL
;
455 int lscpu_read_cpuinfo(struct lscpu_cxt
*cxt
)
460 struct lscpu_cputype
*ct
;
461 struct cpuinfo_parser _pr
= { .cxt
= cxt
}, *pr
= &_pr
;
463 assert(cxt
->npossibles
); /* lscpu_create_cpus() required */
466 DBG(GATHER
, ul_debugobj(cxt
, "reading cpuinfo"));
468 fp
= ul_path_fopen(cxt
->procfs
, "r", "cpuinfo");
470 err(EXIT_FAILURE
, _("cannot open %s"), "/proc/cpuinfo");
474 char *p
= NULL
, *value
= NULL
;
475 const struct cpuinfo_pattern
*pattern
;
477 if (fgets(buf
, sizeof(buf
), fp
) != NULL
)
478 p
= (char *) skip_space(buf
);
480 if (p
== NULL
|| (*buf
&& !*p
)) {
481 /* Blank line separates information */
483 break; /* fgets() returns nothing; EOF */
487 rtrim_whitespace((unsigned char *) buf
);
490 pattern
= cpuinfo_parse_line(p
, &value
, &keynum
);
492 DBG(GATHER
, ul_debug("'%s' not found", buf
));
497 switch (pattern
->domain
) {
498 case CPUINFO_LINE_CPU
:
499 if (pattern
->id
== PAT_PROCESSOR
) {
507 if (ul_strtou32(value
, &n
, 10) == 0)
511 if (pr
->curr_cpu
&& pr
->curr_type
)
512 lscpu_cpu_set_type(pr
->curr_cpu
, pr
->curr_type
);
514 lscpu_unref_cpu(pr
->curr_cpu
);
515 pr
->curr_cpu
= lscpu_get_cpu(cxt
, id
);
518 DBG(GATHER
, ul_debug("*** cpu ID '%d' undefined", id
));
520 DBG(GATHER
, ul_debug(" switch to CPU %d", id
));
521 lscpu_ref_cpu(pr
->curr_cpu
);
525 DBG(GATHER
, ul_debug("*** cpu data before cpu ID"));
527 strdup_to_offset(pr
->curr_cpu
, pattern
->offset
, value
);
529 if (pattern
->id
== PAT_MHZ_DYNAMIC
&& pr
->curr_type
&& !pr
->curr_type
->dynamic_mhz
)
530 pr
->curr_type
->dynamic_mhz
= xstrdup(value
);
531 if (pattern
->id
== PAT_MHZ_STATIC
&& pr
->curr_type
&& !pr
->curr_type
->static_mhz
)
532 pr
->curr_type
->static_mhz
= xstrdup(value
);
533 if (pattern
->id
== PAT_BOGOMIPS_CPU
&& pr
->curr_type
&& !pr
->curr_type
->bogomips
)
534 pr
->curr_type
->bogomips
= xstrdup(value
);
535 if (pattern
->id
== PAT_MHZ
&& pr
->curr_cpu
&& value
) {
537 pr
->curr_cpu
->mhz_cur_freq
= (float) c_strtod(value
, NULL
);
539 pr
->curr_cpu
->mhz_cur_freq
= 0;
542 case CPUINFO_LINE_CPUTYPE
:
543 if (pr
->curr_type
&& is_different_cputype(pr
->curr_type
, pattern
->offset
, value
)) {
544 lscpu_unref_cputype(pr
->curr_type
);
545 pr
->curr_type
= NULL
;
547 if (!pr
->curr_type
) {
548 pr
->curr_type
= lscpu_new_cputype();
549 lscpu_add_cputype(cxt
, pr
->curr_type
);
552 strdup_to_offset(pr
->curr_type
, pattern
->offset
, value
);
554 case CPUINFO_LINE_CACHE
:
555 if (pattern
->id
!= PAT_CACHE
)
557 cpuinfo_parse_cache(cxt
, keynum
, value
);
562 DBG(GATHER
, fprintf_cputypes(stderr
, cxt
));
564 if (pr
->curr_cpu
&& !pr
->curr_cpu
->type
)
565 lscpu_cpu_set_type(pr
->curr_cpu
, pr
->curr_type
);
567 lscpu_unref_cputype(pr
->curr_type
);
568 lscpu_unref_cpu(pr
->curr_cpu
);
571 lscpu_sort_caches(cxt
->ecaches
, cxt
->necaches
);
573 /* Set the default type to CPUs which are missing (or not parsed)
575 ct
= lscpu_cputype_get_default(cxt
);
576 for (i
= 0; ct
&& i
< cxt
->npossibles
; i
++) {
577 struct lscpu_cpu
*cpu
= cxt
->cpus
[i
];
579 if (cpu
&& !cpu
->type
)
580 lscpu_cpu_set_type(cpu
, ct
);
586 struct lscpu_arch
*lscpu_read_architecture(struct lscpu_cxt
*cxt
)
588 struct utsname utsbuf
;
589 struct lscpu_arch
*ar
;
590 struct lscpu_cputype
*ct
;
594 DBG(GATHER
, ul_debug("reading architecture"));
596 if (uname(&utsbuf
) == -1)
597 err(EXIT_FAILURE
, _("error: uname failed"));
599 ar
= xcalloc(1, sizeof(*cxt
->arch
));
600 ar
->name
= xstrdup(utsbuf
.machine
);
603 /* reading info from any /{sys,proc} dump, don't mix it with
604 * information about our real CPU */
607 #if defined(__alpha__) || defined(__ia64__)
608 ar
->bit64
= 1; /* 64bit platforms only */
610 /* platforms with 64bit flag in /proc/cpuinfo, define
611 * 32bit default here */
612 #if defined(__i386__) || defined(__x86_64__) || \
613 defined(__s390x__) || defined(__s390__) || defined(__sparc_v9__)
617 #if defined(__aarch64__)
619 /* personality() is the most reliable way (since 4.7)
620 * to determine aarch32 support */
621 int pers
= personality(PER_LINUX32
);
631 ct
= lscpu_cputype_get_default(cxt
);
632 if (ct
&& ct
->flags
) {
635 snprintf(buf
, sizeof(buf
), " %s ", ct
->flags
);
636 if (strstr(buf
, " lm "))
637 ar
->bit32
= 1, ar
->bit64
= 1; /* x86_64 */
638 if (strstr(buf
, " zarch "))
639 ar
->bit32
= 1, ar
->bit64
= 1; /* s390x */
640 if (strstr(buf
, " sun4v ") || strstr(buf
, " sun4u "))
641 ar
->bit32
= 1, ar
->bit64
= 1; /* sparc64 */
644 if (ar
->name
&& !cxt
->noalive
) {
645 if (strcmp(ar
->name
, "ppc64") == 0)
646 ar
->bit32
= 1, ar
->bit64
= 1;
647 else if (strcmp(ar
->name
, "ppc") == 0)
651 DBG(GATHER
, ul_debugobj(ar
, "arch: name=%s %s %s",
653 ar
->bit64
? "64-bit" : "",
654 ar
->bit64
? "32-bit" : ""));
658 void lscpu_free_architecture(struct lscpu_arch
*ar
)
666 int lscpu_read_cpulists(struct lscpu_cxt
*cxt
)
668 cpu_set_t
*cpuset
= NULL
;
671 DBG(GATHER
, ul_debugobj(cxt
, "reading cpulists"));
673 if (ul_path_read_s32(cxt
->syscpu
, &cxt
->maxcpus
, "kernel_max") == 0)
674 /* note that kernel_max is maximum index [NR_CPUS-1] */
677 else if (!cxt
->noalive
)
678 /* the root is '/' so we are working with data from the current kernel */
679 cxt
->maxcpus
= get_max_number_of_cpus();
681 if (cxt
->maxcpus
<= 0)
682 /* error or we are reading some /sys snapshot instead of the
683 * real /sys, let's use any crazy number... */
686 cxt
->setsize
= CPU_ALLOC_SIZE(cxt
->maxcpus
);
688 /* create CPUs from possible mask */
689 if (ul_path_readf_cpulist(cxt
->syscpu
, &cpuset
, cxt
->maxcpus
, "possible") == 0) {
690 lscpu_create_cpus(cxt
, cpuset
, cxt
->setsize
);
694 err(EXIT_FAILURE
, _("failed to determine number of CPUs: %s"),
695 _PATH_SYS_CPU
"/possible");
698 /* get mask for present CPUs */
699 if (ul_path_readf_cpulist(cxt
->syscpu
, &cxt
->present
, cxt
->maxcpus
, "present") == 0)
700 cxt
->npresents
= CPU_COUNT_S(cxt
->setsize
, cxt
->present
);
702 /* get mask for online CPUs */
703 if (ul_path_readf_cpulist(cxt
->syscpu
, &cxt
->online
, cxt
->maxcpus
, "online") == 0)
704 cxt
->nonlines
= CPU_COUNT_S(cxt
->setsize
, cxt
->online
);
709 #if defined(HAVE_LIBRTAS)
710 # define PROCESSOR_MODULE_INFO 43
711 static int strbe16toh(const char *buf
, int offset
)
713 return (buf
[offset
] << 8) + buf
[offset
+1];
717 /* some extra information for the default CPU type */
718 int lscpu_read_archext(struct lscpu_cxt
*cxt
)
722 struct lscpu_cputype
*ct
;
724 DBG(GATHER
, ul_debugobj(cxt
, "reading extra arch info"));
727 ct
= lscpu_cputype_get_default(cxt
);
731 /* get dispatching mode */
732 if (ul_path_read_s32(cxt
->syscpu
, &ct
->dispatching
, "dispatching") != 0)
733 ct
->dispatching
= -1;
735 /* get cpufreq boost mode */
736 if (ul_path_read_s32(cxt
->syscpu
, &ct
->freqboost
, "cpufreq/boost") != 0)
739 if ((f
= ul_path_fopen(cxt
->procfs
, "r", "sysinfo"))) {
740 while (fgets(buf
, sizeof(buf
), f
) != NULL
) {
741 if (lookup(buf
, "Type", &ct
->machinetype
))
747 #if defined(HAVE_LIBRTAS)
748 /* Get PowerPC specific info */
752 ct
->physsockets
= ct
->physchips
= ct
->physcoresperchip
= 0;
754 rc
= rtas_get_sysparm(PROCESSOR_MODULE_INFO
, sizeof(buf
), buf
);
758 len
= strbe16toh(buf
, 0);
762 ntypes
= strbe16toh(buf
, 2);
766 ct
->physsockets
= strbe16toh(buf
, 4);
767 ct
->physchips
= strbe16toh(buf
, 6);
768 ct
->physcoresperchip
= strbe16toh(buf
, 8);
775 static int cmp_vulnerability_name(const void *a0
, const void *b0
)
777 const struct lscpu_vulnerability
778 *a
= (const struct lscpu_vulnerability
*) a0
,
779 *b
= (const struct lscpu_vulnerability
*) b0
;
780 return strcmp(a
->name
, b
->name
);
783 int lscpu_read_vulnerabilities(struct lscpu_cxt
*cxt
)
791 DBG(GATHER
, ul_debugobj(cxt
, "reading vulnerabilities"));
793 dir
= ul_path_opendir(cxt
->syscpu
, "vulnerabilities");
798 while (xreaddir(dir
))
806 cxt
->vuls
= xcalloc(n
, sizeof(struct lscpu_vulnerability
));
808 while (cxt
->nvuls
< n
&& (d
= xreaddir(dir
))) {
810 struct lscpu_vulnerability
*vu
;
812 #ifdef _DIRENT_HAVE_D_TYPE
813 if (d
->d_type
== DT_DIR
|| d
->d_type
== DT_UNKNOWN
)
816 if (ul_path_readf_string(cxt
->syscpu
, &str
,
817 "vulnerabilities/%s", d
->d_name
) <= 0)
820 vu
= &cxt
->vuls
[cxt
->nvuls
++];
823 vu
->name
= xstrdup(d
->d_name
);
824 *vu
->name
= toupper(*vu
->name
);
825 strrep(vu
->name
, '_', ' ');
829 p
= (char *) startswith(vu
->text
, "Mitigation");
832 strrem(vu
->text
, ':');
837 qsort(cxt
->vuls
, cxt
->nvuls
,
838 sizeof(struct lscpu_vulnerability
), cmp_vulnerability_name
);
843 static inline int is_node_dirent(struct dirent
*d
)
847 #ifdef _DIRENT_HAVE_D_TYPE
848 (d
->d_type
== DT_DIR
|| d
->d_type
== DT_UNKNOWN
) &&
850 strncmp(d
->d_name
, "node", 4) == 0 &&
851 isdigit_string(d
->d_name
+ 4);
854 static int nodecmp(const void *ap
, const void *bp
)
856 int *a
= (int *) ap
, *b
= (int *) bp
;
860 int lscpu_read_numas(struct lscpu_cxt
*cxt
)
865 struct path_cxt
*sys
;
867 assert(!cxt
->nnodes
);
870 sys
= ul_new_path(_PATH_SYS_NODE
);
872 err(EXIT_FAILURE
, _("failed to initialize %s handler"), _PATH_SYS_NODE
);
874 ul_path_set_prefix(sys
, cxt
->prefix
);
876 dir
= ul_path_opendir(sys
, NULL
);
880 while ((d
= readdir(dir
))) {
881 if (is_node_dirent(d
))
890 cxt
->nodemaps
= xcalloc(cxt
->nnodes
, sizeof(cpu_set_t
*));
891 cxt
->idx2nodenum
= xmalloc(cxt
->nnodes
* sizeof(int));
894 for (i
= 0; (d
= readdir(dir
)) && i
< cxt
->nnodes
;) {
895 if (is_node_dirent(d
))
896 cxt
->idx2nodenum
[i
++] = strtol_or_err(((d
->d_name
) + 4),
897 _("Failed to extract the node number"));
900 qsort(cxt
->idx2nodenum
, cxt
->nnodes
, sizeof(int), nodecmp
);
902 /* information about how nodes share different CPUs */
903 for (i
= 0; i
< cxt
->nnodes
; i
++)
904 ul_path_readf_cpuset(sys
, &cxt
->nodemaps
[i
], cxt
->maxcpus
,
905 "node%d/cpumap", cxt
->idx2nodenum
[i
]);
907 DBG(GATHER
, ul_debugobj(cxt
, "read %zu numas", cxt
->nnodes
));