File util-linux-2.14.1-lscpu.patch of Package util-linux

commit 5dd7507c18fa3d739266aeda4847be41e0613fad
Author: Cai Qian <qcai@redhat.com>
Date:   Thu Jul 17 14:19:40 2008 +0200

    lscpu: new command
    
    Add a lscpu(1) utility program.
    
    [kzak@redhat.com:
    	- indent by linux-2.6/scripts/Lindent
    	- add lscpu.{c,1} to sys-utils/Makefile.am
    	- add NLS suport
    	- complete code refactoring
    ]
    
    Co-Author: Karel Zak <kzak@redhat.com>
    Signed-off-by: Cai Qian <qcai@redhat.com>
    Signed-off-by: Karel Zak <kzak@redhat.com>

Index: util-linux-ng-2.14.1/README.licensing
===================================================================
--- util-linux-ng-2.14.1.orig/README.licensing	2008-09-10 11:02:42.000000000 +0200
+++ util-linux-ng-2.14.1/README.licensing	2008-10-01 17:18:31.000000000 +0200
@@ -2,6 +2,8 @@
 The project utils-linux-ng doesn't use same license for all code. There are
 code with:
 
+   * GPLv3+ (GNU General Public License version 3, or any later version)
+
    * GPLv2+ (GNU General Public License version 2, or any later version)
 
    * GPLv2 (GNU General Public License version 2)
Index: util-linux-ng-2.14.1/po/POTFILES.in
===================================================================
--- util-linux-ng-2.14.1.orig/po/POTFILES.in	2008-09-10 11:02:43.000000000 +0200
+++ util-linux-ng-2.14.1/po/POTFILES.in	2008-10-01 17:18:31.000000000 +0200
@@ -98,6 +98,7 @@ sys-utils/flock.c
 sys-utils/ipcrm.c
 sys-utils/ipcs.c
 sys-utils/ldattach.c
+sys-utils/lscpu.c
 sys-utils/rdev.c
 sys-utils/readprofile.c
 sys-utils/renice.c
Index: util-linux-ng-2.14.1/sys-utils/Makefile.am
===================================================================
--- util-linux-ng-2.14.1.orig/sys-utils/Makefile.am	2008-09-10 11:02:43.000000000 +0200
+++ util-linux-ng-2.14.1/sys-utils/Makefile.am	2008-10-01 17:19:50.000000000 +0200
@@ -11,11 +11,11 @@ dist_man_MANS = flock.1 ipcrm.1 ipcs.1 r
 if LINUX
 bin_PROGRAMS += dmesg
 sbin_PROGRAMS += ctrlaltdel
-usrbinexec_PROGRAMS += cytune setarch
+usrbinexec_PROGRAMS += cytune setarch lscpu
 usrsbinexec_PROGRAMS += tunelp rtcwake
 
 dist_man_MANS += dmesg.1 ctrlaltdel.8 cytune.8 setarch.8 \
-		tunelp.8 rtcwake.8
+		tunelp.8 rtcwake.8 lscpu.1
 endif
 
 cytune_SOURCES = cytune.c cyclades.h
Index: util-linux-ng-2.14.1/sys-utils/lscpu.1
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ util-linux-ng-2.14.1/sys-utils/lscpu.1	2008-10-01 17:18:31.000000000 +0200
@@ -0,0 +1,29 @@
+.\" Process this file with
+.\" groff -man -Tascii lscpu.1
+.\"
+.TH LSCPU 1 "JULY 2008" Linux "User Manuals"
+.SH NAME
+lscpu \- CPU architecture information helper
+.SH SYNOPSIS
+.B lscpu [-hp]
+.SH DESCRIPTION
+.B lscpu
+gathers CPU architecture information like number of CPUs, threads,
+cores, sockets, NUMA nodes, information about CPU caches, CPU family,
+model and stepping from sysfs and /proc/cpuinfo, and prints it in
+human-readable format. Alternatively, it can print out in parsable
+format including how different caches are shared by different CPUs,
+which can also be fed to other programs.
+.SH OPTIONS
+.IP -h, --help
+Print a help message.
+.IP -p, --parse
+Print out in parsable instead of printable format.
+.SH BUGS
+The program at the moment does not handle the system installed with
+different types of physical processors.
+.SH AUTHOR
+Cai Qian <qcai@redhat.com>
+.SH AVAILABILITY
+The setarch command is part of the util-linux-ng package and is available from
+ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/.
Index: util-linux-ng-2.14.1/sys-utils/lscpu.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ util-linux-ng-2.14.1/sys-utils/lscpu.c	2008-10-01 17:18:31.000000000 +0200
@@ -0,0 +1,529 @@
+/*
+ * lscpu - CPU architecture information helper
+ *
+ * Copyright (C) 2008 Cai Qian <qcai@redhat.com>
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <ctype.h>
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+#include "nls.h"
+
+#define CACHE_MAX 100
+
+/* /sys paths */
+#define _PATH_SYS_SYSTEM	"/sys/devices/system"
+#define _PATH_SYS_CPU0		_PATH_SYS_SYSTEM "/cpu/cpu0"
+#define _PATH_PROC_XENCAP	"/proc/xen/capabilities"
+#define _PATH_PROC_CPUINFO	"/proc/cpuinfo"
+
+int have_topology;
+int have_cache;
+int have_node;
+
+/* CPU(s) description */
+struct cpu_decs {
+	/* counters */
+	int	ct_cpu;
+	int	ct_thread;
+	int	ct_core;
+	int	ct_socket;
+	int	ct_node;
+	int	ct_cache;
+
+	/* who is who */
+	char	*arch;
+	char	*vendor;
+	char	*family;
+	char	*model;
+
+	/* caches */
+	char	*caname[CACHE_MAX];
+	char	*casize[CACHE_MAX];
+	int	camap[CACHE_MAX];
+
+	/* misc */
+	char	*mhz;
+	char	*stepping;
+	char	*flags;
+
+	/* NUMA */
+	int	*nodecpu;
+};
+
+char pathbuf[PATH_MAX];
+
+static void path_scanstr(char *result, const char *path, ...)
+		__attribute__ ((__format__ (__printf__, 2, 3)));
+static int path_exist(const char *path, ...)
+		__attribute__ ((__format__ (__printf__, 1, 2)));
+static int path_sibling(const char *path, ...)
+		__attribute__ ((__format__ (__printf__, 1, 2)));
+
+static FILE *
+xfopen(const char *path, const char *mode)
+{
+	FILE *fd = fopen(path, mode);
+	if (!fd)
+		err(EXIT_FAILURE, _("error: %s"), path);
+	return fd;
+}
+
+static FILE *
+path_vfopen(const char *mode, const char *path, va_list ap)
+{
+	vsnprintf(pathbuf, sizeof(pathbuf), path, ap);
+	return xfopen(pathbuf, mode);
+}
+
+static void
+path_scanstr(char *result, const char *path, ...)
+{
+	FILE *fd;
+	va_list ap;
+
+	va_start(ap, path);
+	fd = path_vfopen("r", path, ap);
+	va_end(ap);
+
+	if (fscanf(fd, "%s", result) != 1) {
+		if (ferror(fd))
+			err(EXIT_FAILURE, _("error: %s"), pathbuf);
+		else
+			errx(EXIT_FAILURE, _("error parse: %s"), pathbuf);
+	}
+	fclose(fd);
+}
+
+static int
+path_exist(const char *path, ...)
+{
+	va_list ap;
+
+	va_start(ap, path);
+	vsnprintf(pathbuf, sizeof(pathbuf), path, ap);
+	va_end(ap);
+
+	return access(pathbuf, F_OK) == 0;
+}
+
+char *
+xstrdup(const char *str)
+{
+	char *s = strdup(str);
+	if (!s)
+		err(EXIT_FAILURE, _("error: strdup failed"));
+	return s;
+}
+
+/* count the set bit in a mapping file */
+static int
+path_sibling(const char *path, ...)
+{
+	int c, n;
+	int result = 0;
+	char s[2];
+	FILE *fp;
+	va_list ap;
+
+	va_start(ap, path);
+	fp = path_vfopen("r", path, ap);
+	va_end(ap);
+
+	while ((c = fgetc(fp)) != EOF) {
+		if (isxdigit(c)) {
+			s[0] = c;
+			s[1] = '\0';
+			for (n = strtol(s, NULL, 16); n > 0; n /= 2) {
+				if (n % 2)
+					result++;
+			}
+		}
+	}
+	fclose(fp);
+
+	return result;
+}
+
+/* Lookup a pattern and get the value from cpuinfo.
+ * Format is:
+ *
+ *	"<pattern>   : <key>"
+ */
+int lookup(char *line, char *pattern, char **value)
+{
+	char *p, *v;
+	int len = strlen(pattern);
+
+	if (!*line)
+		return 0;
+
+	/* pattern */
+	if (strncmp(line, pattern, len))
+		return 0;
+
+	/* white spaces */
+	for (p = line + len; isspace(*p); p++);
+
+	/* separator */
+	if (*p != ':')
+		return 0;
+
+	/* white spaces */
+	for (++p; isspace(*p); p++);
+
+	/* value */
+	if (!*p)
+		return 0;
+	v = p;
+
+	/* end of value */
+	len = strlen(line) - 1;
+	for (p = line + len; isspace(*(p-1)); p--);
+	*p = '\0';
+
+	*value = xstrdup(v);
+	return 1;
+}
+
+static void
+read_basicinfo(struct cpu_decs *cpu)
+{
+	FILE *fp = xfopen(_PATH_PROC_CPUINFO, "r");
+	char buf[BUFSIZ];
+	struct utsname utsbuf;
+
+	/* architecture */
+	if (uname(&utsbuf) == -1)
+		err(EXIT_FAILURE, _("error: uname failed"));
+	cpu->arch = xstrdup(utsbuf.machine);
+
+	/* count CPU(s) */
+	while(path_exist(_PATH_SYS_SYSTEM "/cpu/cpu%d", cpu->ct_cpu))
+		cpu->ct_cpu++;
+
+	/* details */
+	while (fgets(buf, sizeof(buf), fp) != NULL) {
+		/* IA64 */
+		if (lookup(buf, "vendor", &cpu->vendor)) ;
+		else if (lookup(buf, "vendor_id", &cpu->vendor)) ;
+		/* IA64 */
+		else if (lookup(buf, "family", &cpu->family)) ;
+		else if (lookup(buf, "cpu family", &cpu->family)) ;
+		else if (lookup(buf, "model", &cpu->model)) ;
+		else if (lookup(buf, "stepping", &cpu->stepping)) ;
+		else if (lookup(buf, "cpu MHz", &cpu->mhz)) ;
+		else if (lookup(buf, "flags", &cpu->flags)) ;
+		else
+			continue;
+	}
+	fclose(fp);
+}
+
+static void
+read_topology(struct cpu_decs *cpu)
+{
+	/* number of threads */
+	cpu->ct_thread = path_sibling(
+				_PATH_SYS_CPU0 "/topology/thread_siblings");
+
+	/* number of cores */
+	cpu->ct_core = path_sibling(
+				_PATH_SYS_CPU0 "/topology/core_siblings")
+			/ cpu->ct_thread;
+
+	/* number of sockets */
+	cpu->ct_socket = cpu->ct_cpu / cpu->ct_core / cpu->ct_thread;
+}
+
+static void
+read_cache(struct cpu_decs *cpu)
+{
+	char buf[256];
+	DIR *dp;
+	struct dirent *dir;
+	int level, type;
+
+	dp = opendir(_PATH_SYS_CPU0 "/cache");
+	if (dp == NULL)
+		err(EXIT_FAILURE, _("error: %s"), _PATH_SYS_CPU0 "/cache");
+
+	while ((dir = readdir(dp)) != NULL) {
+		if (!strcmp(dir->d_name, ".")
+		    || !strcmp(dir->d_name, ".."))
+			continue;
+
+		/* cache type */
+		path_scanstr(buf, _PATH_SYS_CPU0 "/cache/%s/type", dir->d_name);
+		if (!strcmp(buf, "Data"))
+			type = 'd';
+		else if (!strcmp(buf, "Instruction"))
+			type = 'i';
+		else
+			type = 0;
+
+		/* cache level */
+		path_scanstr(buf, _PATH_SYS_CPU0 "/cache/%s/level", dir->d_name);
+		level = atoi(buf);
+
+		if (type)
+			snprintf(buf, sizeof(buf), "L%d%c", level, type);
+		else
+			snprintf(buf, sizeof(buf), "L%d", level);
+
+		cpu->caname[cpu->ct_cache] = xstrdup(buf);
+
+		/* cache size */
+		path_scanstr(buf, _PATH_SYS_CPU0 "/cache/%s/size", dir->d_name);
+		cpu->casize[cpu->ct_cache] = xstrdup(buf);
+
+		/* information about how CPUs share different caches */
+		cpu->camap[cpu->ct_cache] = path_sibling(
+				_PATH_SYS_CPU0 "/cache/%s/shared_cpu_map",
+				dir->d_name);
+		cpu->ct_cache++;
+	}
+}
+
+static void
+read_nodes(struct cpu_decs *cpu)
+{
+	int i;
+
+	/* number of NUMA node */
+	while (path_exist(_PATH_SYS_SYSTEM "/node/node%d", cpu->ct_node))
+		cpu->ct_node++;
+
+	cpu->nodecpu = (int *) malloc(cpu->ct_node * sizeof(int));
+	if (!cpu->nodecpu)
+		err(EXIT_FAILURE, _("error: malloc failed"));
+
+	/* information about how nodes share different CPUs */
+	for (i = 0; i < cpu->ct_node; i++)
+		cpu->nodecpu[i] = path_sibling(
+					_PATH_SYS_SYSTEM "/node/node%d/cpumap",
+					i);
+}
+
+static void
+check_system(void)
+{
+	FILE *fd;
+	char buf[256];
+
+	/* Dom0 Kernel gives wrong information. */
+	fd = fopen(_PATH_PROC_XENCAP, "r");
+	if (fd) {
+		if (fscanf(fd, "%s", buf) == 1 && !strcmp(buf, "control_d"))
+			errx(EXIT_FAILURE,
+			     _("error: Dom0 Kernel is unsupported."));
+		fclose(fd);
+	}
+
+	/* Read through sysfs. */
+	if (access(_PATH_SYS_SYSTEM, F_OK))
+		errx(1, _("error: /sys filesystem is not accessable."));
+
+	if (!access(_PATH_SYS_SYSTEM "/node", F_OK))
+		have_node = 1;
+
+	if (!access(_PATH_SYS_CPU0 "/topology/thread_siblings", F_OK))
+		have_topology = 1;
+
+	if (!access(_PATH_SYS_CPU0 "/cache", F_OK))
+		have_cache = 1;
+}
+
+static void
+print_parsable(struct cpu_decs *cpu)
+{
+	int i, j;
+
+	puts(
+	"# The following is the parsable format, which can be fed to other\n"
+	"# programs. Each different item in every column has a unique ID\n"
+	"# starting from zero.\n"
+	"# CPU,Core,Socket,Node");
+
+	if (have_cache) {
+		/* separator between CPU topology and cache information */
+		putchar(',');
+
+		for (i = cpu->ct_cache - 1; i >= 0; i--)
+			printf(",%s", cpu->caname[i]);
+	}
+	putchar('\n');
+
+	for (i = 0; i < cpu->ct_cpu; i++) {
+		printf("%d", i);
+
+		if (have_topology)
+			printf(",%d,%d",
+				i / cpu->ct_thread,
+			        i / cpu->ct_core / cpu->ct_thread);
+		else
+			printf(",,");
+
+		if (have_node) {
+			int c = 0;
+
+			for (j = 0; j < cpu->ct_node; j++) {
+				c += cpu->nodecpu[j];
+				if (i < c) {
+					printf(",%d", j);
+					break;
+				}
+			}
+		} else
+			putchar(',');
+
+		if (have_cache) {
+			putchar(',');
+
+			for (j = cpu->ct_cache - 1; j >= 0; j--) {
+				/* If shared_cpu_map is 0, all CPUs share the same
+				   cache. */
+				if (cpu->camap[j] == 0)
+					cpu->camap[j] = cpu->ct_core *
+							cpu->ct_thread;
+
+				printf(",%d", i / cpu->camap[j]);
+			}
+		}
+		putchar('\n');
+	}
+}
+
+
+/* output formats "<key>  <value>"*/
+#define print_s(_key, _val)	printf("%-23s%s\n", _key, _val)
+#define print_n(_key, _val)	printf("%-23s%d\n", _key, _val)
+
+static void
+print_readable(struct cpu_decs *cpu)
+{
+	char buf[BUFSIZ];
+
+	print_s("Architecture:", cpu->arch);
+	print_n("CPU(s):", cpu->ct_cpu);
+
+	if (have_topology) {
+		print_n(_("Thread(s) per core:"), cpu->ct_thread);
+		print_n(_("Core(s) per socket:"), cpu->ct_core);
+		print_n(_("CPU socket(s):"), cpu->ct_socket);
+	}
+
+	if (have_node)
+		print_n(_("NUMA node(s):"), cpu->ct_node);
+	if (cpu->vendor)
+		print_s(_("Vendor ID:"), cpu->vendor);
+	if (cpu->family)
+		print_s(_("CPU family:"), cpu->family);
+	if (cpu->model)
+		print_s(_("Model:"), cpu->model);
+	if (cpu->stepping)
+		print_s(_("Stepping:"), cpu->stepping);
+	if (cpu->mhz)
+		print_s(_("CPU MHz:"), cpu->mhz);
+	if (cpu->flags) {
+		snprintf(buf, sizeof(buf), " %s ", cpu->flags);
+		if (strstr(buf, " svm "))
+			print_s(_("Virtualization:"), "AMD-V");
+		else if (strstr(buf, " vmx "))
+			print_s(_("Virtualization:"), "VT-x");
+	}
+
+	if (have_cache) {
+		int i;
+
+		for (i = cpu->ct_cache - 1; i >= 0; i--) {
+			snprintf(buf, sizeof(buf),
+					_("%s cache:"), cpu->caname[i]);
+			print_s(buf, cpu->casize[i]);
+		}
+	}
+}
+
+void usage(int rc)
+{
+	printf(_("Usage: %s [option]\n"),
+			program_invocation_short_name);
+
+	puts(_(	"CPU architecture information helper\n\n"
+		"  -h, --help     usage information\n"
+		"  -p, --parse    print out in parsable instead of printable format.\n"));
+	exit(rc);
+}
+
+int main(int argc, char *argv[])
+{
+	struct cpu_decs _cpu, *cpu = &_cpu;
+	int parsable = 0, c;
+
+	struct option longopts[] = {
+		{ "help",	no_argument, 0, 'h' },
+		{ "parse",	no_argument, 0, 'p' },
+		{ NULL,		0, 0, 0 }
+	};
+
+	setlocale(LC_MESSAGES, "");
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+
+	while((c = getopt_long(argc, argv, "hp", longopts, NULL)) != -1) {
+		switch (c) {
+		case 'h':
+			usage(EXIT_SUCCESS);
+		case 'p':
+			parsable = 1;
+			break;
+		default:
+			usage(EXIT_FAILURE);
+		}
+	}
+
+	memset(cpu, 0, sizeof(*cpu));
+
+	check_system();
+
+	read_basicinfo(cpu);
+
+	if (have_topology)
+		read_topology(cpu);
+	if (have_cache)
+		read_cache(cpu);
+	if (have_node)
+		read_nodes(cpu);
+
+	/* Show time! */
+	if (parsable)
+		print_parsable(cpu);
+	else
+		print_readable(cpu);
+
+	return EXIT_FAILURE;
+}
openSUSE Build Service is sponsored by