Update to upstream util-linux 2.20.1
[framework/base/util-linux-ng.git] / sys-utils / lscpu.c
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  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it would be useful,
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  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software Foundation,
19  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <ctype.h>
23 #include <dirent.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <getopt.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/utsname.h>
31 #include <unistd.h>
32 #include <stdarg.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35
36 #include "cpuset.h"
37 #include "nls.h"
38 #include "xalloc.h"
39 #include "c.h"
40 #include "strutils.h"
41 #include "bitops.h"
42
43
44 #define CACHE_MAX 100
45
46 /* /sys paths */
47 #define _PATH_SYS_SYSTEM        "/sys/devices/system"
48 #define _PATH_SYS_CPU           _PATH_SYS_SYSTEM "/cpu"
49 #define _PATH_PROC_XEN          "/proc/xen"
50 #define _PATH_PROC_XENCAP       _PATH_PROC_XEN "/capabilities"
51 #define _PATH_PROC_CPUINFO      "/proc/cpuinfo"
52 #define _PATH_PROC_PCIDEVS      "/proc/bus/pci/devices"
53 #define _PATH_PROC_SYSINFO      "/proc/sysinfo"
54
55 /* virtualization types */
56 enum {
57         VIRT_NONE       = 0,
58         VIRT_PARA,
59         VIRT_FULL
60 };
61 const char *virt_types[] = {
62         [VIRT_NONE]     = N_("none"),
63         [VIRT_PARA]     = N_("para"),
64         [VIRT_FULL]     = N_("full")
65 };
66
67 /* hypervisor vendors */
68 enum {
69         HYPER_NONE      = 0,
70         HYPER_XEN,
71         HYPER_KVM,
72         HYPER_MSHV,
73         HYPER_VMWARE
74 };
75 const char *hv_vendors[] = {
76         [HYPER_NONE]    = NULL,
77         [HYPER_XEN]     = "Xen",
78         [HYPER_KVM]     = "KVM",
79         [HYPER_MSHV]    = "Microsoft",
80         [HYPER_VMWARE]  = "VMware"
81 };
82
83 /* CPU modes */
84 enum {
85         MODE_32BIT      = (1 << 1),
86         MODE_64BIT      = (1 << 2)
87 };
88
89 /* cache(s) description */
90 struct cpu_cache {
91         char            *name;
92         char            *size;
93
94         int             nsharedmaps;
95         cpu_set_t       **sharedmaps;
96 };
97
98 /* global description */
99 struct lscpu_desc {
100         char    *arch;
101         char    *vendor;
102         char    *family;
103         char    *model;
104         char    *virtflag;      /* virtualization flag (vmx, svm) */
105         int     hyper;          /* hypervisor vendor ID */
106         int     virtype;        /* VIRT_PARA|FULL|NONE ? */
107         char    *mhz;
108         char    *stepping;
109         char    *bogomips;
110         char    *flags;
111         int     mode;           /* rm, lm or/and tm */
112
113         int             ncpus;          /* number of CPUs */
114         cpu_set_t       *online;        /* mask with online CPUs */
115
116         int             nnodes;         /* number of NUMA modes */
117         cpu_set_t       **nodemaps;     /* array with NUMA nodes */
118
119         /* books -- based on book_siblings (internal kernel map of cpuX's
120          * hardware threads within the same book */
121         int             nbooks;         /* number of all online books */
122         cpu_set_t       **bookmaps;     /* unique book_siblings */
123
124         /* sockets -- based on core_siblings (internal kernel map of cpuX's
125          * hardware threads within the same physical_package_id (socket)) */
126         int             nsockets;       /* number of all online sockets */
127         cpu_set_t       **socketmaps;   /* unique core_siblings */
128
129         /* cores -- based on thread_siblings (internel kernel map of cpuX's
130          * hardware threads within the same core as cpuX) */
131         int             ncores;         /* number of all online cores */
132         cpu_set_t       **coremaps;     /* unique thread_siblings */
133
134         int             nthreads;       /* number of online threads */
135
136         int             ncaches;
137         struct cpu_cache *caches;
138 };
139
140 static size_t sysrootlen;
141 static char pathbuf[PATH_MAX];
142 static int maxcpus;             /* size in bits of kernel cpu mask */
143
144 #define is_cpu_online(_d, _cpu) \
145                 ((_d) && (_d)->online ? \
146                         CPU_ISSET_S((_cpu), CPU_ALLOC_SIZE(maxcpus), (_d)->online) : 0)
147
148 static FILE *path_fopen(const char *mode, int exit_on_err, const char *path, ...)
149                 __attribute__ ((__format__ (__printf__, 3, 4)));
150 static void path_getstr(char *result, size_t len, const char *path, ...)
151                 __attribute__ ((__format__ (__printf__, 3, 4)));
152 static int path_getnum(const char *path, ...)
153                 __attribute__ ((__format__ (__printf__, 1, 2)));
154 static int path_exist(const char *path, ...)
155                 __attribute__ ((__format__ (__printf__, 1, 2)));
156 static cpu_set_t *path_cpuset(const char *path, ...)
157                 __attribute__ ((__format__ (__printf__, 1, 2)));
158
159 /*
160  * Parsable output
161  */
162 enum {
163         COL_CPU,
164         COL_CORE,
165         COL_SOCKET,
166         COL_NODE,
167         COL_BOOK,
168         COL_CACHE
169 };
170
171 static const char *colnames[] =
172 {
173         [COL_CPU] = "CPU",
174         [COL_CORE] = "Core",
175         [COL_SOCKET] = "Socket",
176         [COL_NODE] = "Node",
177         [COL_BOOK] = "Book",
178         [COL_CACHE] = "Cache"
179 };
180
181
182 static int column_name_to_id(const char *name, size_t namesz)
183 {
184         size_t i;
185
186         for (i = 0; i < ARRAY_SIZE(colnames); i++) {
187                 const char *cn = colnames[i];
188
189                 if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
190                         return i;
191         }
192         warnx(_("unknown column: %s"), name);
193         return -1;
194 }
195
196 static const char *
197 path_vcreate(const char *path, va_list ap)
198 {
199         if (sysrootlen)
200                 vsnprintf(pathbuf + sysrootlen,
201                           sizeof(pathbuf) - sysrootlen, path, ap);
202         else
203                 vsnprintf(pathbuf, sizeof(pathbuf), path, ap);
204         return pathbuf;
205 }
206
207 static FILE *
208 path_vfopen(const char *mode, int exit_on_error, const char *path, va_list ap)
209 {
210         FILE *f;
211         const char *p = path_vcreate(path, ap);
212
213         f = fopen(p, mode);
214         if (!f && exit_on_error)
215                 err(EXIT_FAILURE, _("error: cannot open %s"), p);
216         return f;
217 }
218
219 static FILE *
220 path_fopen(const char *mode, int exit_on_error, const char *path, ...)
221 {
222         FILE *fd;
223         va_list ap;
224
225         va_start(ap, path);
226         fd = path_vfopen(mode, exit_on_error, path, ap);
227         va_end(ap);
228
229         return fd;
230 }
231
232 static void
233 path_getstr(char *result, size_t len, const char *path, ...)
234 {
235         FILE *fd;
236         va_list ap;
237
238         va_start(ap, path);
239         fd = path_vfopen("r", 1, path, ap);
240         va_end(ap);
241
242         if (!fgets(result, len, fd))
243                 err(EXIT_FAILURE, _("failed to read: %s"), pathbuf);
244         fclose(fd);
245
246         len = strlen(result);
247         if (result[len - 1] == '\n')
248                 result[len - 1] = '\0';
249 }
250
251 static int
252 path_getnum(const char *path, ...)
253 {
254         FILE *fd;
255         va_list ap;
256         int result;
257
258         va_start(ap, path);
259         fd = path_vfopen("r", 1, path, ap);
260         va_end(ap);
261
262         if (fscanf(fd, "%d", &result) != 1) {
263                 if (ferror(fd))
264                         err(EXIT_FAILURE, _("failed to read: %s"), pathbuf);
265                 else
266                         errx(EXIT_FAILURE, _("parse error: %s"), pathbuf);
267         }
268         fclose(fd);
269         return result;
270 }
271
272 static int
273 path_exist(const char *path, ...)
274 {
275         va_list ap;
276         const char *p;
277
278         va_start(ap, path);
279         p = path_vcreate(path, ap);
280         va_end(ap);
281
282         return access(p, F_OK) == 0;
283 }
284
285 static cpu_set_t *
286 path_cpuparse(int islist, const char *path, va_list ap)
287 {
288         FILE *fd;
289         cpu_set_t *set;
290         size_t setsize, len = maxcpus * 7;
291         char buf[len];
292
293         fd = path_vfopen("r", 1, path, ap);
294
295         if (!fgets(buf, len, fd))
296                 err(EXIT_FAILURE, _("failed to read: %s"), pathbuf);
297         fclose(fd);
298
299         len = strlen(buf);
300         if (buf[len - 1] == '\n')
301                 buf[len - 1] = '\0';
302
303         set = cpuset_alloc(maxcpus, &setsize, NULL);
304         if (!set)
305                 err(EXIT_FAILURE, _("failed to callocate cpu set"));
306
307         if (islist) {
308                 if (cpulist_parse(buf, set, setsize))
309                         errx(EXIT_FAILURE, _("failed to parse CPU list %s"), buf);
310         } else {
311                 if (cpumask_parse(buf, set, setsize))
312                         errx(EXIT_FAILURE, _("failed to parse CPU mask %s"), buf);
313         }
314         return set;
315 }
316
317 static cpu_set_t *
318 path_cpuset(const char *path, ...)
319 {
320         va_list ap;
321         cpu_set_t *set;
322
323         va_start(ap, path);
324         set = path_cpuparse(0, path, ap);
325         va_end(ap);
326
327         return set;
328 }
329
330 static cpu_set_t *
331 path_cpulist(const char *path, ...)
332 {
333         va_list ap;
334         cpu_set_t *set;
335
336         va_start(ap, path);
337         set = path_cpuparse(1, path, ap);
338         va_end(ap);
339
340         return set;
341 }
342
343 /* Lookup a pattern and get the value from cpuinfo.
344  * Format is:
345  *
346  *      "<pattern>   : <key>"
347  */
348 int lookup(char *line, char *pattern, char **value)
349 {
350         char *p, *v;
351         int len = strlen(pattern);
352
353         if (!*line)
354                 return 0;
355
356         /* pattern */
357         if (strncmp(line, pattern, len))
358                 return 0;
359
360         /* white spaces */
361         for (p = line + len; isspace(*p); p++);
362
363         /* separator */
364         if (*p != ':')
365                 return 0;
366
367         /* white spaces */
368         for (++p; isspace(*p); p++);
369
370         /* value */
371         if (!*p)
372                 return 0;
373         v = p;
374
375         /* end of value */
376         len = strlen(line) - 1;
377         for (p = line + len; isspace(*(p-1)); p--);
378         *p = '\0';
379
380         *value = xstrdup(v);
381         return 1;
382 }
383
384 /* Don't init the mode for platforms where we are not able to
385  * detect that CPU supports 64-bit mode.
386  */
387 static int
388 init_mode(void)
389 {
390         int m = 0;
391
392         if (sysrootlen)
393                 /* reading info from any /{sys,proc} dump, don't mix it with
394                  * information about our real CPU */
395                 return 0;
396
397 #if defined(__alpha__) || defined(__ia64__)
398         m |= MODE_64BIT;        /* 64bit platforms only */
399 #endif
400         /* platforms with 64bit flag in /proc/cpuinfo, define
401          * 32bit default here */
402 #if defined(__i386__) || defined(__x86_64__) || \
403     defined(__s390x__) || defined(__s390__) || defined(__sparc_v9__)
404         m |= MODE_32BIT;
405 #endif
406         return m;
407 }
408
409 static void
410 read_basicinfo(struct lscpu_desc *desc)
411 {
412         FILE *fp = path_fopen("r", 1, _PATH_PROC_CPUINFO);
413         char buf[BUFSIZ];
414         struct utsname utsbuf;
415
416         /* architecture */
417         if (uname(&utsbuf) == -1)
418                 err(EXIT_FAILURE, _("error: uname failed"));
419         desc->arch = xstrdup(utsbuf.machine);
420
421         /* count CPU(s) */
422         while(path_exist(_PATH_SYS_SYSTEM "/cpu/cpu%d", desc->ncpus))
423                 desc->ncpus++;
424
425         /* details */
426         while (fgets(buf, sizeof(buf), fp) != NULL) {
427                 if (lookup(buf, "vendor", &desc->vendor)) ;
428                 else if (lookup(buf, "vendor_id", &desc->vendor)) ;
429                 else if (lookup(buf, "family", &desc->family)) ;
430                 else if (lookup(buf, "cpu family", &desc->family)) ;
431                 else if (lookup(buf, "model", &desc->model)) ;
432                 else if (lookup(buf, "stepping", &desc->stepping)) ;
433                 else if (lookup(buf, "cpu MHz", &desc->mhz)) ;
434                 else if (lookup(buf, "flags", &desc->flags)) ;          /* x86 */
435                 else if (lookup(buf, "features", &desc->flags)) ;       /* s390 */
436                 else if (lookup(buf, "type", &desc->flags)) ;           /* sparc64 */
437                 else if (lookup(buf, "bogomips", &desc->bogomips)) ;
438                 else if (lookup(buf, "bogomips per cpu", &desc->bogomips)) ; /* s390 */
439                 else
440                         continue;
441         }
442
443         desc->mode = init_mode();
444
445         if (desc->flags) {
446                 snprintf(buf, sizeof(buf), " %s ", desc->flags);
447                 if (strstr(buf, " svm "))
448                         desc->virtflag = strdup("svm");
449                 else if (strstr(buf, " vmx "))
450                         desc->virtflag = strdup("vmx");
451                 if (strstr(buf, " lm "))
452                         desc->mode |= MODE_32BIT | MODE_64BIT;          /* x86_64 */
453                 if (strstr(buf, " zarch "))
454                         desc->mode |= MODE_32BIT | MODE_64BIT;          /* s390x */
455                 if (strstr(buf, " sun4v ") || strstr(buf, " sun4u "))
456                         desc->mode |= MODE_32BIT | MODE_64BIT;          /* sparc64 */
457         }
458
459         fclose(fp);
460
461         if (path_exist(_PATH_SYS_SYSTEM "/cpu/kernel_max"))
462                 /* note that kernel_max is maximum index [NR_CPUS-1] */
463                 maxcpus = path_getnum(_PATH_SYS_SYSTEM "/cpu/kernel_max") + 1;
464
465         else if (!sysrootlen)
466                 /* the root is '/' so we are working with data from the current kernel */
467                 maxcpus = get_max_number_of_cpus();
468         else
469                 /* we are reading some /sys snapshot instead of the real /sys,
470                  * let's use any crazy number... */
471                 maxcpus = desc->ncpus > 2048 ? desc->ncpus : 2048;
472
473         /* get mask for online CPUs */
474         if (path_exist(_PATH_SYS_SYSTEM "/cpu/online")) {
475                 size_t setsize = CPU_ALLOC_SIZE(maxcpus);
476                 desc->online = path_cpulist(_PATH_SYS_SYSTEM "/cpu/online");
477                 desc->nthreads = CPU_COUNT_S(setsize, desc->online);
478         }
479 }
480
481 static int
482 has_pci_device(int vendor, int device)
483 {
484         FILE *f;
485         int num, fn, ven, dev;
486         int res = 1;
487
488         f = path_fopen("r", 0, _PATH_PROC_PCIDEVS);
489         if (!f)
490                 return 0;
491
492          /* for more details about bus/pci/devices format see
493           * drivers/pci/proc.c in linux kernel
494           */
495         while(fscanf(f, "%02x%02x\t%04x%04x\t%*[^\n]",
496                         &num, &fn, &ven, &dev) == 4) {
497
498                 if (ven == vendor && dev == device)
499                         goto found;
500         }
501
502         res = 0;
503 found:
504         fclose(f);
505         return res;
506 }
507
508 #if defined(__x86_64__) || defined(__i386__)
509
510 /*
511  * This CPUID leaf returns the information about the hypervisor.
512  * EAX : maximum input value for CPUID supported by the hypervisor.
513  * EBX, ECX, EDX : Hypervisor vendor ID signature. E.g. VMwareVMware.
514  */
515 #define HYPERVISOR_INFO_LEAF   0x40000000
516
517 static inline void
518 cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx,
519                          unsigned int *ecx, unsigned int *edx)
520 {
521         __asm__(
522 #if defined(__PIC__) && defined(__i386__)
523                 /* x86 PIC cannot clobber ebx -- gcc bitches */
524                 "pushl %%ebx;"
525                 "cpuid;"
526                 "movl %%ebx, %%esi;"
527                 "popl %%ebx;"
528                 : "=S" (*ebx),
529 #else
530                 "cpuid;"
531                 : "=b" (*ebx),
532 #endif
533                   "=a" (*eax),
534                   "=c" (*ecx),
535                   "=d" (*edx)
536                 : "1" (op), "c"(0));
537 }
538
539 static void
540 read_hypervisor_cpuid(struct lscpu_desc *desc)
541 {
542         unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0;
543         char hyper_vendor_id[13];
544
545         memset(hyper_vendor_id, 0, sizeof(hyper_vendor_id));
546
547         cpuid(HYPERVISOR_INFO_LEAF, &eax, &ebx, &ecx, &edx);
548         memcpy(hyper_vendor_id + 0, &ebx, 4);
549         memcpy(hyper_vendor_id + 4, &ecx, 4);
550         memcpy(hyper_vendor_id + 8, &edx, 4);
551         hyper_vendor_id[12] = '\0';
552
553         if (!hyper_vendor_id[0])
554                 return;
555
556         if (!strncmp("XenVMMXenVMM", hyper_vendor_id, 12))
557                 desc->hyper = HYPER_XEN;
558         else if (!strncmp("KVMKVMKVM", hyper_vendor_id, 9))
559                 desc->hyper = HYPER_KVM;
560         else if (!strncmp("Microsoft Hv", hyper_vendor_id, 12))
561                 desc->hyper = HYPER_MSHV;
562         else if (!strncmp("VMwareVMware", hyper_vendor_id, 12))
563                 desc->hyper = HYPER_VMWARE;
564 }
565
566 #else   /* ! __x86_64__ */
567 static void
568 read_hypervisor_cpuid(struct lscpu_desc *desc)
569 {
570 }
571 #endif
572
573 static void
574 read_hypervisor(struct lscpu_desc *desc)
575 {
576         read_hypervisor_cpuid(desc);
577
578         if (desc->hyper)
579                 /* hvm */
580                 desc->virtype = VIRT_FULL;
581
582         else if (path_exist(_PATH_PROC_XEN)) {
583                 /* Xen para-virt or dom0 */
584                 FILE *fd = path_fopen("r", 0, _PATH_PROC_XENCAP);
585                 int dom0 = 0;
586
587                 if (fd) {
588                         char buf[256];
589
590                         if (fscanf(fd, "%s", buf) == 1 &&
591                             !strcmp(buf, "control_d"))
592                                 dom0 = 1;
593                         fclose(fd);
594                 }
595                 desc->virtype = dom0 ? VIRT_NONE : VIRT_PARA;
596                 desc->hyper = HYPER_XEN;
597
598         } else if (has_pci_device(0x5853, 0x0001)) {
599                 /* Xen full-virt on non-x86_64 */
600                 desc->hyper = HYPER_XEN;
601                 desc->virtype = VIRT_FULL;
602         }
603 }
604
605 /* add @set to the @ary, unnecesary set is deallocated. */
606 static int add_cpuset_to_array(cpu_set_t **ary, int *items, cpu_set_t *set)
607 {
608         int i;
609         size_t setsize = CPU_ALLOC_SIZE(maxcpus);
610
611         if (!ary)
612                 return -1;
613
614         for (i = 0; i < *items; i++) {
615                 if (CPU_EQUAL_S(setsize, set, ary[i]))
616                         break;
617         }
618         if (i == *items) {
619                 ary[*items] = set;
620                 ++*items;
621                 return 0;
622         }
623         CPU_FREE(set);
624         return 1;
625 }
626
627 static void
628 read_topology(struct lscpu_desc *desc, int num)
629 {
630         cpu_set_t *thread_siblings, *core_siblings, *book_siblings;
631
632         if (!path_exist(_PATH_SYS_CPU "/cpu%d/topology/thread_siblings", num))
633                 return;
634
635         thread_siblings = path_cpuset(_PATH_SYS_CPU
636                                         "/cpu%d/topology/thread_siblings", num);
637         core_siblings = path_cpuset(_PATH_SYS_CPU
638                                         "/cpu%d/topology/core_siblings", num);
639         book_siblings = NULL;
640         if (path_exist(_PATH_SYS_CPU "/cpu%d/topology/book_siblings", num)) {
641                 book_siblings = path_cpuset(_PATH_SYS_CPU
642                                             "/cpu%d/topology/book_siblings", num);
643         }
644
645         if (!desc->coremaps) {
646                 int nbooks, nsockets, ncores, nthreads;
647                 size_t setsize = CPU_ALLOC_SIZE(maxcpus);
648
649                 /* threads within one core */
650                 nthreads = CPU_COUNT_S(setsize, thread_siblings);
651                 /* cores within one socket */
652                 ncores = CPU_COUNT_S(setsize, core_siblings) / nthreads;
653                 /* number of sockets within one book.
654                  * Because of odd / non-present cpu maps and to keep
655                  * calculation easy we make sure that nsockets and
656                  * nbooks is at least 1.
657                  */
658                 nsockets = desc->ncpus / nthreads / ncores ?: 1;
659                 /* number of books */
660                 nbooks = desc->ncpus / nthreads / ncores / nsockets ?: 1;
661
662                 /* all threads, see also read_basicinfo()
663                  * -- fallback for kernels without
664                  *    /sys/devices/system/cpu/online.
665                  */
666                 if (!desc->nthreads)
667                         desc->nthreads = nbooks * nsockets * ncores * nthreads;
668                 /* For each map we make sure that it can have up to ncpus
669                  * entries. This is because we cannot reliably calculate the
670                  * number of cores, sockets and books on all architectures.
671                  * E.g. completely virtualized architectures like s390 may
672                  * have multiple sockets of different sizes.
673                  */
674                 desc->coremaps = xcalloc(desc->ncpus, sizeof(cpu_set_t *));
675                 desc->socketmaps = xcalloc(desc->ncpus, sizeof(cpu_set_t *));
676                 if (book_siblings)
677                         desc->bookmaps = xcalloc(desc->ncpus, sizeof(cpu_set_t *));
678         }
679
680         add_cpuset_to_array(desc->socketmaps, &desc->nsockets, core_siblings);
681         add_cpuset_to_array(desc->coremaps, &desc->ncores, thread_siblings);
682         if (book_siblings)
683                 add_cpuset_to_array(desc->bookmaps, &desc->nbooks, book_siblings);
684 }
685
686 static int
687 cachecmp(const void *a, const void *b)
688 {
689         struct cpu_cache *c1 = (struct cpu_cache *) a;
690         struct cpu_cache *c2 = (struct cpu_cache *) b;
691
692         return strcmp(c2->name, c1->name);
693 }
694
695 static void
696 read_cache(struct lscpu_desc *desc, int num)
697 {
698         char buf[256];
699         int i;
700
701         if (!desc->ncaches) {
702                 while(path_exist(_PATH_SYS_SYSTEM "/cpu/cpu%d/cache/index%d",
703                                         num, desc->ncaches))
704                         desc->ncaches++;
705
706                 if (!desc->ncaches)
707                         return;
708
709                 desc->caches = xcalloc(desc->ncaches, sizeof(*desc->caches));
710         }
711         for (i = 0; i < desc->ncaches; i++) {
712                 struct cpu_cache *ca = &desc->caches[i];
713                 cpu_set_t *map;
714
715                 if (!path_exist(_PATH_SYS_SYSTEM "/cpu/cpu%d/cache/index%d",
716                                 num, i))
717                         continue;
718                 if (!ca->name) {
719                         int type, level;
720
721                         /* cache type */
722                         path_getstr(buf, sizeof(buf),
723                                         _PATH_SYS_CPU "/cpu%d/cache/index%d/type",
724                                         num, i);
725                         if (!strcmp(buf, "Data"))
726                                 type = 'd';
727                         else if (!strcmp(buf, "Instruction"))
728                                 type = 'i';
729                         else
730                                 type = 0;
731
732                         /* cache level */
733                         level = path_getnum(_PATH_SYS_CPU "/cpu%d/cache/index%d/level",
734                                         num, i);
735                         if (type)
736                                 snprintf(buf, sizeof(buf), "L%d%c", level, type);
737                         else
738                                 snprintf(buf, sizeof(buf), "L%d", level);
739
740                         ca->name = xstrdup(buf);
741
742                         /* cache size */
743                         path_getstr(buf, sizeof(buf),
744                                         _PATH_SYS_CPU "/cpu%d/cache/index%d/size",
745                                         num, i);
746                         ca->size = xstrdup(buf);
747                 }
748
749                 /* information about how CPUs share different caches */
750                 map = path_cpuset(_PATH_SYS_CPU "/cpu%d/cache/index%d/shared_cpu_map",
751                                 num, i);
752
753                 if (!ca->sharedmaps)
754                         ca->sharedmaps = xcalloc(desc->ncpus, sizeof(cpu_set_t *));
755                 add_cpuset_to_array(ca->sharedmaps, &ca->nsharedmaps, map);
756         }
757 }
758
759 static void
760 read_nodes(struct lscpu_desc *desc)
761 {
762         int i;
763
764         /* number of NUMA node */
765         while (path_exist(_PATH_SYS_SYSTEM "/node/node%d", desc->nnodes))
766                 desc->nnodes++;
767
768         if (!desc->nnodes)
769                 return;
770
771         desc->nodemaps = xcalloc(desc->nnodes, sizeof(cpu_set_t *));
772
773         /* information about how nodes share different CPUs */
774         for (i = 0; i < desc->nnodes; i++)
775                 desc->nodemaps[i] = path_cpuset(
776                                         _PATH_SYS_SYSTEM "/node/node%d/cpumap",
777                                         i);
778 }
779
780 static void
781 print_parsable_cell(struct lscpu_desc *desc, int i, int col, int compatible)
782 {
783         int j;
784         size_t setsize = CPU_ALLOC_SIZE(maxcpus);
785
786         switch (col) {
787         case COL_CPU:
788                 printf("%d", i);
789                 break;
790         case COL_CORE:
791                 for (j = 0; j < desc->ncores; j++) {
792                         if (CPU_ISSET_S(i, setsize, desc->coremaps[j])) {
793                                 printf("%d", j);
794                                 break;
795                         }
796                 }
797                 break;
798         case COL_SOCKET:
799                 for (j = 0; j < desc->nsockets; j++) {
800                         if (CPU_ISSET_S(i, setsize, desc->socketmaps[j])) {
801                                 printf("%d", j);
802                                 break;
803                         }
804                 }
805                 break;
806         case COL_NODE:
807                 for (j = 0; j < desc->nnodes; j++) {
808                         if (CPU_ISSET_S(i, setsize, desc->nodemaps[j])) {
809                                 printf("%d", j);
810                                 break;
811                         }
812                 }
813                 break;
814         case COL_BOOK:
815                 for (j = 0; j < desc->nbooks; j++) {
816                         if (CPU_ISSET_S(i, setsize, desc->bookmaps[j])) {
817                                 printf("%d", j);
818                                 break;
819                         }
820                 }
821                 break;
822         case COL_CACHE:
823                 for (j = desc->ncaches - 1; j >= 0; j--) {
824                         struct cpu_cache *ca = &desc->caches[j];
825                         int x;
826
827                         for (x = 0; x < ca->nsharedmaps; x++) {
828                                 if (CPU_ISSET_S(i, setsize, ca->sharedmaps[x])) {
829                                         printf("%d", x);
830                                         break;
831                                 }
832                         }
833                         if (j != 0)
834                                 putchar(compatible ? ',' : ':');
835                 }
836                 break;
837         }
838 }
839
840 /*
841  * We support two formats:
842  *
843  * 1) "compatible" -- this format is compatible with the original lscpu(1)
844  * output and it contains fixed set of the columns. The CACHE columns are at
845  * the end of the line and the CACHE is not printed if the number of the caches
846  * is zero. The CACHE columns are separated by two commas, for example:
847  *
848  *    $ lscpu --parse
849  *    # CPU,Core,Socket,Node,,L1d,L1i,L2
850  *    0,0,0,0,,0,0,0
851  *    1,1,0,0,,1,1,0
852  *
853  * 2) "user defined output" -- this format prints always all columns without
854  * special prefix for CACHE column. If there are not CACHEs then the column is
855  * empty and the header "Cache" is printed rather than a real name of the cache.
856  * The CACHE columns are separated by ':'.
857  *
858  *      $ lscpu --parse=CPU,CORE,SOCKET,NODE,CACHE
859  *      # CPU,Core,Socket,Node,L1d:L1i:L2
860  *      0,0,0,0,0:0:0
861  *      1,1,0,0,1:1:0
862  */
863 static void
864 print_parsable(struct lscpu_desc *desc, int cols[], int ncols, int compatible)
865 {
866         int i, c;
867
868         printf(_(
869         "# The following is the parsable format, which can be fed to other\n"
870         "# programs. Each different item in every column has an unique ID\n"
871         "# starting from zero.\n"));
872
873         fputs("# ", stdout);
874         for (i = 0; i < ncols; i++) {
875                 if (cols[i] == COL_CACHE) {
876                         if (compatible && !desc->ncaches)
877                                 continue;
878                         if (i > 0)
879                                 putchar(',');
880                         if (compatible && i != 0)
881                                 putchar(',');
882                         for (c = desc->ncaches - 1; c >= 0; c--) {
883                                 printf("%s", desc->caches[c].name);
884                                 if (c > 0)
885                                         putchar(compatible ? ',' : ':');
886                         }
887                         if (!desc->ncaches)
888                                 fputs(colnames[cols[i]], stdout);
889                 } else {
890                         if (i > 0)
891                                 putchar(',');
892                         fputs(colnames[cols[i]], stdout);
893                 }
894         }
895         putchar('\n');
896
897         for (i = 0; i < desc->ncpus; i++) {
898                 if (desc->online && !is_cpu_online(desc, i))
899                         continue;
900                 for (c = 0; c < ncols; c++) {
901                         if (compatible && cols[c] == COL_CACHE) {
902                                 if (!desc->ncaches)
903                                         continue;
904                                 if (c > 0)
905                                         putchar(',');
906                         }
907                         if (c > 0)
908                                 putchar(',');
909                         print_parsable_cell(desc, i, cols[c], compatible);
910                 }
911                 putchar('\n');
912         }
913 }
914
915
916 /* output formats "<key>  <value>"*/
917 #define print_s(_key, _val)     printf("%-23s%s\n", _key, _val)
918 #define print_n(_key, _val)     printf("%-23s%d\n", _key, _val)
919
920 static void
921 print_cpuset(const char *key, cpu_set_t *set, int hex)
922 {
923         size_t setsize = CPU_ALLOC_SIZE(maxcpus);
924         size_t setbuflen = 7 * maxcpus;
925         char setbuf[setbuflen], *p;
926
927         if (hex) {
928                 p = cpumask_create(setbuf, setbuflen, set, setsize);
929                 printf("%-23s0x%s\n", key, p);
930         } else {
931                 p = cpulist_create(setbuf, setbuflen, set, setsize);
932                 print_s(key, p);
933         }
934
935 }
936
937 static void
938 print_readable(struct lscpu_desc *desc, int hex)
939 {
940         char buf[512];
941         int i;
942         size_t setsize = CPU_ALLOC_SIZE(maxcpus);
943
944         print_s(_("Architecture:"), desc->arch);
945
946         if (desc->mode) {
947                 char buf[64], *p = buf;
948
949                 if (desc->mode & MODE_32BIT) {
950                         strcpy(p, "32-bit, ");
951                         p += 8;
952                 }
953                 if (desc->mode & MODE_64BIT) {
954                         strcpy(p, "64-bit, ");
955                         p += 8;
956                 }
957                 *(p - 2) = '\0';
958                 print_s(_("CPU op-mode(s):"), buf);
959         }
960 #if !defined(WORDS_BIGENDIAN)
961         print_s(_("Byte Order:"), "Little Endian");
962 #else
963         print_s(_("Byte Order:"), "Big Endian");
964 #endif
965         print_n(_("CPU(s):"), desc->ncpus);
966
967         if (desc->online)
968                 print_cpuset(hex ? _("On-line CPU(s) mask:") :
969                                    _("On-line CPU(s) list:"),
970                                 desc->online, hex);
971
972         if (desc->online && CPU_COUNT_S(setsize, desc->online) != desc->ncpus) {
973                 cpu_set_t *set;
974
975                 /* Linux kernel provides cpuset of off-line CPUs that contains
976                  * all configured CPUs (see /sys/devices/system/cpu/offline),
977                  * but want to print real (present in system) off-line CPUs only.
978                  */
979                 set = cpuset_alloc(maxcpus, NULL, NULL);
980                 if (!set)
981                         err(EXIT_FAILURE, _("failed to callocate cpu set"));
982                 CPU_ZERO_S(setsize, set);
983                 for (i = 0; i < desc->ncpus; i++) {
984                         if (!is_cpu_online(desc, i))
985                                 CPU_SET_S(i, setsize, set);
986                 }
987                 print_cpuset(hex ? _("Off-line CPU(s) mask:") :
988                                    _("Off-line CPU(s) list:"),
989                              set, hex);
990                 cpuset_free(set);
991         }
992
993         if (desc->nsockets) {
994                 int cores_per_socket, sockets_per_book, books;
995
996                 cores_per_socket = sockets_per_book = books = 0;
997                 /* s390 detects its cpu topology via /proc/sysinfo, if present.
998                  * Using simply the cpu topology masks in sysfs will not give
999                  * usable results since everything is virtualized. E.g.
1000                  * virtual core 0 may have only 1 cpu, but virtual core 2 may
1001                  * five cpus.
1002                  * If the cpu topology is not exported (e.g. 2nd level guest)
1003                  * fall back to old calculation scheme.
1004                  */
1005                 if (path_exist(_PATH_PROC_SYSINFO)) {
1006                         FILE *fd = path_fopen("r", 0, _PATH_PROC_SYSINFO);
1007                         char buf[BUFSIZ];
1008                         int t0, t1, t2;
1009
1010                         while (fgets(buf, sizeof(buf), fd) != NULL) {
1011                                 if (sscanf(buf, "CPU Topology SW:%d%d%d%d%d%d",
1012                                            &t0, &t1, &t2, &books, &sockets_per_book,
1013                                            &cores_per_socket) == 6)
1014                                         break;
1015                         }
1016                 }
1017                 print_n(_("Thread(s) per core:"), desc->nthreads / desc->ncores);
1018                 print_n(_("Core(s) per socket:"),
1019                         cores_per_socket ?: desc->ncores / desc->nsockets);
1020                 if (desc->nbooks) {
1021                         print_n(_("Socket(s) per book:"),
1022                                 sockets_per_book ?: desc->nsockets / desc->nbooks);
1023                         print_n(_("Book(s):"), books ?: desc->nbooks);
1024                 } else {
1025                         print_n(_("Socket(s):"), sockets_per_book ?: desc->nsockets);
1026                 }
1027         }
1028         if (desc->nnodes)
1029                 print_n(_("NUMA node(s):"), desc->nnodes);
1030         if (desc->vendor)
1031                 print_s(_("Vendor ID:"), desc->vendor);
1032         if (desc->family)
1033                 print_s(_("CPU family:"), desc->family);
1034         if (desc->model)
1035                 print_s(_("Model:"), desc->model);
1036         if (desc->stepping)
1037                 print_s(_("Stepping:"), desc->stepping);
1038         if (desc->mhz)
1039                 print_s(_("CPU MHz:"), desc->mhz);
1040         if (desc->bogomips)
1041                 print_s(_("BogoMIPS:"), desc->bogomips);
1042         if (desc->virtflag) {
1043                 if (!strcmp(desc->virtflag, "svm"))
1044                         print_s(_("Virtualization:"), "AMD-V");
1045                 else if (!strcmp(desc->virtflag, "vmx"))
1046                         print_s(_("Virtualization:"), "VT-x");
1047         }
1048         if (desc->hyper) {
1049                 print_s(_("Hypervisor vendor:"), hv_vendors[desc->hyper]);
1050                 print_s(_("Virtualization type:"), virt_types[desc->virtype]);
1051         }
1052         if (desc->ncaches) {
1053                 char buf[512];
1054                 int i;
1055
1056                 for (i = desc->ncaches - 1; i >= 0; i--) {
1057                         snprintf(buf, sizeof(buf),
1058                                         _("%s cache:"), desc->caches[i].name);
1059                         print_s(buf, desc->caches[i].size);
1060                 }
1061         }
1062
1063         for (i = 0; i < desc->nnodes; i++) {
1064                 snprintf(buf, sizeof(buf), _("NUMA node%d CPU(s):"), i);
1065                 print_cpuset(buf, desc->nodemaps[i], hex);
1066         }
1067 }
1068
1069 static void __attribute__((__noreturn__)) usage(FILE *out)
1070 {
1071         fputs(_("\nUsage:\n"), out);
1072         fprintf(out,
1073               _(" %s [options]\n"), program_invocation_short_name);
1074
1075         fputs(_("\nOptions:\n"), out);
1076         fputs(_(" -h, --help          print this help\n"
1077                 " -p, --parse <list>  print out a parsable instead of a readable format\n"
1078                 " -s, --sysroot <dir> use directory DIR as system root\n"
1079                 " -x, --hex           print hexadecimal masks rather than lists of CPUs\n\n"), out);
1080
1081         exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
1082 }
1083
1084 int main(int argc, char *argv[])
1085 {
1086         struct lscpu_desc _desc, *desc = &_desc;
1087         int parsable = 0, c, i, hex = 0;
1088         int columns[ARRAY_SIZE(colnames)], ncolumns = 0;
1089         int compatible = 0;
1090
1091         static const struct option longopts[] = {
1092                 { "help",       no_argument,       0, 'h' },
1093                 { "parse",      optional_argument, 0, 'p' },
1094                 { "sysroot",    required_argument, 0, 's' },
1095                 { "hex",        no_argument,       0, 'x' },
1096                 { NULL,         0, 0, 0 }
1097         };
1098
1099         setlocale(LC_ALL, "");
1100         bindtextdomain(PACKAGE, LOCALEDIR);
1101         textdomain(PACKAGE);
1102
1103         while ((c = getopt_long(argc, argv, "hp::s:x", longopts, NULL)) != -1) {
1104                 switch (c) {
1105                 case 'h':
1106                         usage(stdout);
1107                 case 'p':
1108                         parsable = 1;
1109                         if (optarg) {
1110                                 if (*optarg == '=')
1111                                         optarg++;
1112                                 ncolumns = string_to_idarray(optarg,
1113                                                 columns, ARRAY_SIZE(columns),
1114                                                 column_name_to_id);
1115                                 if (ncolumns < 0)
1116                                         return EXIT_FAILURE;
1117                         } else {
1118                                 columns[ncolumns++] = COL_CPU;
1119                                 columns[ncolumns++] = COL_CORE;
1120                                 columns[ncolumns++] = COL_SOCKET;
1121                                 columns[ncolumns++] = COL_NODE;
1122                                 columns[ncolumns++] = COL_CACHE;
1123                                 compatible = 1;
1124                         }
1125                         break;
1126                 case 's':
1127                         sysrootlen = strlen(optarg);
1128                         strncpy(pathbuf, optarg, sizeof(pathbuf));
1129                         pathbuf[sizeof(pathbuf) - 1] = '\0';
1130                         break;
1131                 case 'x':
1132                         hex = 1;
1133                         break;
1134                 default:
1135                         usage(stderr);
1136                 }
1137         }
1138
1139         memset(desc, 0, sizeof(*desc));
1140
1141         read_basicinfo(desc);
1142
1143         for (i = 0; i < desc->ncpus; i++) {
1144                 if (desc->online && !is_cpu_online(desc, i))
1145                         continue;
1146                 read_topology(desc, i);
1147                 read_cache(desc, i);
1148         }
1149
1150         qsort(desc->caches, desc->ncaches, sizeof(struct cpu_cache), cachecmp);
1151
1152         read_nodes(desc);
1153
1154         read_hypervisor(desc);
1155
1156         /* Show time! */
1157         if (parsable)
1158                 print_parsable(desc, columns, ncolumns, compatible);
1159         else
1160                 print_readable(desc, hex);
1161
1162         return EXIT_SUCCESS;
1163 }