ACK: [PATCH 2/2] lib: fwts_hwinfo: don't use external utils for H/W checks (LP: #1246646)

Alex Hung alex.hung at canonical.com
Mon Nov 11 03:02:09 UTC 2013


On 11/08/2013 03:33 AM, Colin King wrote:
> From: Colin Ian King <colin.king at canonical.com>
>
> The original bug requested that we remove the dependancy on lspci.
> I've re-worked this code now to remove dependancies on several external
> tools that were being used to check for H/W changes over S3 or S4 cycles.
>
> Changes are:
>
> PCI: Re-work fwts_hwinfo to make compare and dump more generic and add in
> helpers to get and dump PCI specific data using the raw config data from
> sysfs. This allows us to remove the need to execute lspci.
>
> Network: We can just interrogate each device and compare address and
> H/W address rather than rely on messing around with the ifconfig and
> iwconfig output.
>
> Input: The old code was crufty and relied on xinput, which is an awful
> dependancy especially for non-X based systems.  So remove that and
> just sanity check the devices in /sys/class/input
>
> Audio: We need a better solution to this rather than looking at
> pulse audio source and sinks.  Until I can figure out a way that
> does not use pulse audio I'm going to remove this as it isn't used
> much at all (I've never seen anyone file any bugs on pulse audio
> failures caused by S3 or S4 and detected by fwts).
>
> Bluetooth: Examine bluetooth settings from /sys/class/bluetooth
> rather than relying on the bluetooth userspace tools
>
> Tested on several machines with:
>
>          sudo fwts s3 --s3-device-check
>
> Signed-off-by: Colin Ian King <colin.king at canonical.com>
> ---
>   src/lib/include/fwts_hwinfo.h |  13 +-
>   src/lib/src/fwts_hwinfo.c     | 672 ++++++++++++++++++++++++++++++++++++------
>   2 files changed, 581 insertions(+), 104 deletions(-)
>
> diff --git a/src/lib/include/fwts_hwinfo.h b/src/lib/include/fwts_hwinfo.h
> index dd67a8b..2b9bad6 100644
> --- a/src/lib/include/fwts_hwinfo.h
> +++ b/src/lib/include/fwts_hwinfo.h
> @@ -23,14 +23,11 @@
>   #include "fwts.h"
>
>   typedef struct {
> -	fwts_list *network;
> -	fwts_list *ethernet;
> -	fwts_list *ifconfig;
> -	fwts_list *iwconfig;
> -	fwts_list *hciconfig;
> -	fwts_list *videocard;
> -	fwts_list *xinput;
> -	fwts_list *pactl;
> +	fwts_list network;	/* PCI network config */
> +	fwts_list videocard;	/* PCI video card config */
> +	fwts_list netdevs;	/* Network devices */
> +	fwts_list input;	/* Input device config */
> +	fwts_list bluetooth;	/* Bluetooth config */
>   } fwts_hwinfo;
>
>   int fwts_hwinfo_get(fwts_framework *fw, fwts_hwinfo *hwinfo);
> diff --git a/src/lib/src/fwts_hwinfo.c b/src/lib/src/fwts_hwinfo.c
> index 1809a78..cb70f98 100644
> --- a/src/lib/src/fwts_hwinfo.c
> +++ b/src/lib/src/fwts_hwinfo.c
> @@ -18,6 +18,20 @@
>    */
>
>   #include <stdlib.h>
> +#include <stdint.h>
> +#include <errno.h>
> +#include <inttypes.h>
> +#include <dirent.h>
> +#include <limits.h>
> +#include <fcntl.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/ioctl.h>
> +#include <sys/types.h>
> +#include <sys/socket.h>
> +#include <net/if.h>
> +#include <netinet/ether.h>
> +#include <arpa/inet.h>
>
>   #include "fwts.h"
>
> @@ -25,96 +39,549 @@
>   #define FWTS_HWINFO_LISTS_DIFFER	(1)
>   #define FWTS_HWINFO_LISTS_OUT_OF_MEMORY	(-1)
>
> +#define FWTS_HWINFO_SYS_NET		"/sys/class/net"
> +#define FWTS_HWINFO_SYS_INPUT		"/sys/class/input"
> +#define FWTS_HWINFO_SYS_BLUETOOTH	"/sys/class/bluetooth"
> +
> +typedef struct {
> +	char name[NAME_MAX + 1];	/* PCI name */
> +	uint8_t	config[64];		/* PCI config data */
> +	ssize_t config_len;		/* Length of config data */
> +} fwts_pci_config;
> +
> +typedef struct {
> +	char *name;			/* Network device name */
> +	char *addr;			/* Address */
> +	char *hw_addr;			/* H/W MAC address */
> +} fwts_net_config;
> +
> +typedef struct {
> +	char *name;			/* Input class name */
> +	char *dev_name;			/* Input device name */
> +	char *phys;			/* Physical name */
> +} fwts_input_config;
> +
> +typedef struct {
> +	char *name;			/* class name */
> +	char *bt_name;			/* BT name */
> +	char *address;			/* BT address */
> +	char *bus;			/* Bus device is on */
> +	char *type;			/* Type info */
> +} fwts_bluetooth_config;
> +
> +/* compare H/W info */
> +typedef int (*hwinfo_cmp)(void *data1, void *data2);
> +
> +/* dump H/W info */
> +typedef void (*hwinfo_dump)(fwts_framework *fw, fwts_list *list);
> +
> +static char *fwts_hwinfo_data_get(const char *sys, const char *dev, const char *file)
> +{
> +	char path[PATH_MAX];
> +	char *data;
> +
> +	snprintf(path, sizeof(path), "%s/%s/%s", sys, dev, file);
> +	if ((data = fwts_get(path)) == NULL)
> +		return strdup("");
> +
> +	fwts_chop_newline(data);
> +	return data;
> +}
> +
> +
>   /*
> - *  fwts_hwinfo_get()
> - *	gather H/W information
> + *  fwts_hwinfo_bluetooth_free()
> + *	free bluetooth data
>    */
> -int fwts_hwinfo_get(fwts_framework *fw, fwts_hwinfo *hwinfo)
> +static void fwts_hwinfo_bluetooth_free(void *data)
>   {
> -	FWTS_UNUSED(fw);
> +	fwts_bluetooth_config *config = (fwts_bluetooth_config *)data;
> +
> +	free(config->name);
> +	free(config->bt_name);
> +	free(config->address);
> +	free(config->bus);
> +	free(config->type);
> +	free(config);
> +}
> +
> +/*
> + *  fwts_hwinfo_bluetooth_name_cmp()
> + *	compare bluetooth config device name for sorting purposes
> + */
> +static int fwts_hwinfo_bluetooth_name_cmp(void *data1, void *data2)
> +{
> +	fwts_bluetooth_config *config1 = (fwts_bluetooth_config *)data1;
> +	fwts_bluetooth_config *config2 = (fwts_bluetooth_config *)data2;
> +
> +	return strcmp(config1->name, config2->name);
> +}
> +
> +/*
> + *  fwts_hwinfo_bluetooth_cmp()
> + *	compare bluetooth config data
> + */
> +static int fwts_hwinfo_bluetooth_config_cmp(void *data1, void *data2)
> +{
> +	fwts_bluetooth_config *config1 = (fwts_bluetooth_config *)data1;
> +	fwts_bluetooth_config *config2 = (fwts_bluetooth_config *)data2;
> +
> +	return strcmp(config1->name, config2->name) ||
> +	       strcmp(config1->bt_name, config2->bt_name) ||
> +	       strcmp(config1->address, config2->address) ||
> +	       strcmp(config1->bus, config2->bus) ||
> +	       strcmp(config1->type, config2->type);
> +}
> +
> +/*
> + *  fwts_hwinfo_bluetooth_get()
> + * 	read a specific input device config
> + */
> +static int fwts_hwinfo_bluetooth_get(
> +	fwts_framework *fw,
> +	fwts_list *devices)
> +{
> +	DIR *dp;
> +	struct dirent *d;
> +
> +	fwts_list_init(devices);
> +	if ((dp = opendir(FWTS_HWINFO_SYS_BLUETOOTH)) == NULL) {
> +		fwts_log_error(fw, "Cannot open %s to scan network devices.", FWTS_HWINFO_SYS_BLUETOOTH);
> +		return FWTS_ERROR;
> +	}
>
> -	int status;
> +	while ((d = readdir(dp)) != NULL) {
> +		fwts_bluetooth_config *bluetooth_config;
>
> -	fwts_pipe_exec("lspci | grep Network", &hwinfo->network, &status);
> -	fwts_pipe_exec("lspci | grep Ethernet", &hwinfo->ethernet, &status);
> -	fwts_pipe_exec("ifconfig -a | grep -A1 '^\\w'", &hwinfo->ifconfig, &status);
> -	fwts_pipe_exec("iwconfig | grep -A1 '^\\w'", &hwinfo->iwconfig, &status);
> -	fwts_pipe_exec("hciconfig -a | grep -A2 '^\\w", &hwinfo->hciconfig, &status);
> -	fwts_pipe_exec("lspci | grep VGA", &hwinfo->videocard, &status);
> -	fwts_pipe_exec("xinput list", &hwinfo->xinput, &status);
> -	fwts_pipe_exec("pactl list | grep Sink | grep -v Latency", &hwinfo->pactl, &status);
> -	fwts_pipe_exec("pactl list | grep Source | grep -v Latency", &hwinfo->pactl, &status);
> +		if (d->d_name[0] == '.')
> +			continue;
>
> +		if ((bluetooth_config = calloc(1, sizeof(*bluetooth_config))) == NULL) {
> +			fwts_log_error(fw, "Cannot allocate bluetooth config data.");
> +			break;
> +		}
> +		bluetooth_config->name = strdup(d->d_name);
> +		bluetooth_config->bt_name = fwts_hwinfo_data_get(FWTS_HWINFO_SYS_BLUETOOTH, d->d_name, "name");
> +		bluetooth_config->address = fwts_hwinfo_data_get(FWTS_HWINFO_SYS_BLUETOOTH, d->d_name, "address");
> +		bluetooth_config->bus = fwts_hwinfo_data_get(FWTS_HWINFO_SYS_BLUETOOTH, d->d_name, "bus");
> +		bluetooth_config->type = fwts_hwinfo_data_get(FWTS_HWINFO_SYS_BLUETOOTH, d->d_name, "type");
> +
> +		if (bluetooth_config->name == NULL ||
> +		    bluetooth_config->bt_name == NULL ||
> +		    bluetooth_config->address == NULL ||
> +		    bluetooth_config->bus == NULL ||
> +		    bluetooth_config->type == NULL) {
> +			fwts_log_error(fw, "Cannot allocate bluetooth device attributes.");
> +			fwts_hwinfo_bluetooth_free(bluetooth_config);
> +			break;
> +		}
> +		fwts_list_add_ordered(devices, bluetooth_config, fwts_hwinfo_bluetooth_name_cmp);
> +	}
> +	closedir(dp);
>   	return FWTS_OK;
>   }
>
>   /*
> - *  fwts_hwinfo_list_dump()
> - *	dump out a list
> + *  fwts_hwinfo_bluetooth_dump()
> + *	simple bluetooth config dump
>    */
> -static void fwts_hwinfo_list_dump(fwts_framework *fw, fwts_list *list)
> +static void fwts_hwinfo_bluetooth_dump(fwts_framework *fw, fwts_list *devices)
>   {
>   	fwts_list_link *item;
>
> -	if (list == NULL)
> -		fwts_log_info_verbatum(fw, "  (null)");
> -	else  {
> -		fwts_list_foreach(item, list) {
> -			char *text = fwts_list_data(char *, item);
> -			fwts_log_info_verbatum(fw, "  %s", text);
> +	fwts_list_foreach(item, devices) {
> +		fwts_bluetooth_config *bluetooth_config = fwts_list_data(fwts_bluetooth_config *, item);
> +
> +		fwts_log_info_verbatum(fw, "  Device:  %s", bluetooth_config->name);
> +		fwts_log_info_verbatum(fw, "  Name:    %s", bluetooth_config->bt_name);
> +		fwts_log_info_verbatum(fw, "  Address: %s", bluetooth_config->address);
> +		fwts_log_info_verbatum(fw, "  Bus:     %s", bluetooth_config->bus);
> +		fwts_log_info_verbatum(fw, "  Type:    %s", bluetooth_config->type);
> +		fwts_log_nl(fw);
> +	}
> +}
> +
> +/*
> + *  fwts_hwinfo_input_free()
> + *	free input data
> + */
> +static void fwts_hwinfo_input_free(void *data)
> +{
> +	fwts_input_config *config = (fwts_input_config *)data;
> +
> +	free(config->name);
> +	free(config->dev_name);
> +	free(config->phys);
> +	free(config);
> +}
> +
> +/*
> + *  fwts_hwinfo_input_name_cmp()
> + *	compare input config device class name for sorting purposes
> + */
> +static int fwts_hwinfo_input_name_cmp(void *data1, void *data2)
> +{
> +	fwts_input_config *config1 = (fwts_input_config *)data1;
> +	fwts_input_config *config2 = (fwts_input_config *)data2;
> +
> +	return strcmp(config1->name, config2->name);
> +}
> +
> +/*
> + *  fwts_hwinfo_input_cmp()
> + *	compare input config data
> + */
> +static int fwts_hwinfo_input_config_cmp(void *data1, void *data2)
> +{
> +	fwts_input_config *config1 = (fwts_input_config *)data1;
> +	fwts_input_config *config2 = (fwts_input_config *)data2;
> +
> +	return strcmp(config1->name, config2->name) ||
> +	       strcmp(config1->dev_name, config2->dev_name) ||
> +	       strcmp(config1->phys, config2->phys);
> +}
> +
> +/*
> + *  fwts_hwinfo_input_get()
> + * 	read a specific input device config
> + */
> +static int fwts_hwinfo_input_get(
> +	fwts_framework *fw,
> +	fwts_list *devices)
> +{
> +	DIR *dp;
> +	struct dirent *d;
> +
> +	fwts_list_init(devices);
> +	if ((dp = opendir(FWTS_HWINFO_SYS_INPUT)) == NULL) {
> +		fwts_log_error(fw, "Cannot open %s to scan network devices.", FWTS_HWINFO_SYS_INPUT);
> +		return FWTS_ERROR;
> +	}
> +
> +	while ((d = readdir(dp)) != NULL) {
> +		fwts_input_config *input_config;
> +
> +		if (d->d_name[0] == '.')
> +			continue;
> +		if (!strncmp(d->d_name, "input", 5)) {
> +			if ((input_config = calloc(1, sizeof(*input_config))) == NULL) {
> +				fwts_log_error(fw, "Cannot allocate input config data.");
> +				break;
> +			}
> +			input_config->dev_name = fwts_hwinfo_data_get(FWTS_HWINFO_SYS_INPUT, d->d_name, "name");
> +			input_config->phys = fwts_hwinfo_data_get(FWTS_HWINFO_SYS_INPUT, d->d_name, "phys");
> +		} else if (!strncmp(d->d_name, "event", 5) ||
> +			   !strncmp(d->d_name, "mouse", 5)) {
> +			if ((input_config = calloc(1, sizeof(*input_config))) == NULL) {
> +				fwts_log_error(fw, "Cannot allocate input config data.");
> +				break;
> +			}
> +			input_config->dev_name = fwts_hwinfo_data_get(FWTS_HWINFO_SYS_INPUT, d->d_name, "device/name");
> +			input_config->phys = fwts_hwinfo_data_get(FWTS_HWINFO_SYS_INPUT, d->d_name, "device/phys");
> +		} else {
> +			/* Don't know what type it is, ignore */
> +			continue;
> +		}
> +
> +		input_config->name = strdup(d->d_name);
> +
> +		if (input_config->name == NULL ||
> +		    input_config->dev_name == NULL ||
> +		    input_config->phys == NULL) {
> +			fwts_log_error(fw, "Cannot allocate input device attributes.");
> +			fwts_hwinfo_input_free(input_config);
> +			break;
>   		}
> +		fwts_list_add_ordered(devices, input_config, fwts_hwinfo_input_name_cmp);
>   	}
> +	closedir(dp);
> +	return FWTS_OK;
>   }
>
>   /*
> - *  fwts_hwinfo_lists_dump()
> - *	dump out contents of two different lists
> + *  fwts_hwinfo_input_dump()
> + *	simple input config dump
>    */
> -static void fwts_hwinfo_lists_dump(
> +static void fwts_hwinfo_input_dump(fwts_framework *fw, fwts_list *devices)
> +{
> +	fwts_list_link *item;
> +
> +	fwts_list_foreach(item, devices) {
> +		fwts_input_config *input_config = fwts_list_data(fwts_input_config *, item);
> +
> +		fwts_log_info_verbatum(fw, "  Device:      %s", input_config->name);
> +		fwts_log_info_verbatum(fw, "  Device Name: %s", input_config->dev_name);
> +		fwts_log_info_verbatum(fw, "  Phy:         %s", input_config->phys);
> +		fwts_log_nl(fw);
> +	}
> +}
> +
> +/*
> + *  fwts_hwinfo_net_free()
> + *	free net config data
> + */
> +static void fwts_hwinfo_net_free(void *data)
> +{
> +	fwts_net_config *config = (fwts_net_config *)data;
> +
> +	free(config->name);
> +	free(config->addr);
> +	free(config->hw_addr);
> +	free(config);
> +}
> +
> +/*
> + *  fwts_hwinfo_net_name_cmp()
> + *	compare net config device name for sorting purposes
> + */
> +static int fwts_hwinfo_net_name_cmp(void *data1, void *data2)
> +{
> +	fwts_net_config *config1 = (fwts_net_config *)data1;
> +	fwts_net_config *config2 = (fwts_net_config *)data2;
> +
> +	return strcmp(config1->name, config2->name);
> +}
> +
> +/*
> + *  fwts_hwinfo_net_cmp()
> + *	compare net config data
> + */
> +static int fwts_hwinfo_net_cmp(void *data1, void *data2)
> +{
> +	fwts_net_config *config1 = (fwts_net_config *)data1;
> +	fwts_net_config *config2 = (fwts_net_config *)data2;
> +
> +	return strcmp(config1->name, config2->name) ||
> +	       strcmp(config1->addr, config2->addr) ||
> +	       strcmp(config1->hw_addr, config2->hw_addr);
> +}
> +
> +/*
> + *  fwts_hwinfo_new_get()
> + * 	read a specific network interface config
> + */
> +static int fwts_hwinfo_net_get(
>   	fwts_framework *fw,
> -	fwts_list *l1,
> -	fwts_list *l2,
> -	const char *message)
> +	fwts_list *devices)
>   {
> -	fwts_log_info(fw, "%s configurations differ, before:", message);
> -	fwts_hwinfo_list_dump(fw, l1);
> -	fwts_log_info(fw, "versus after:");
> -	fwts_hwinfo_list_dump(fw, l2);
> -	fwts_log_nl(fw);
> +	DIR *dp;
> +	struct dirent *d;
> +	int sock;
> +
> +	fwts_list_init(devices);
> +	if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
> +		fwts_log_error(fw, "Cannot open socket to interrogate network devices.");
> +		return FWTS_ERROR;
> +	}
> +
> +	if ((dp = opendir(FWTS_HWINFO_SYS_NET)) == NULL) {
> +		fwts_log_error(fw, "Cannot open %s to scan network devices.", FWTS_HWINFO_SYS_NET);
> +		close(sock);
> +		return FWTS_ERROR;
> +	}
> +
> +	while ((d = readdir(dp)) != NULL) {
> +		struct	ifreq buf;
> +		fwts_net_config *net_config;
> +
> +		if (d->d_name[0] == '.')
> +			continue;
> +		if ((net_config = calloc(1, sizeof(*net_config))) == NULL) {
> +			fwts_log_error(fw, "Cannot allocate net config data.");
> +			break;
> +		}
> +		net_config->name = strdup(d->d_name);
> +		if (net_config->name == NULL) {
> +			fwts_log_error(fw, "Cannot allocate net config name.");
> +			fwts_hwinfo_net_free(net_config);
> +			break;
> +		}
> +		memset(&buf, 0, sizeof(buf));
> +		strncpy(buf.ifr_name, d->d_name, sizeof(buf.ifr_name));
> +		if (ioctl(sock, SIOCGIFHWADDR, &buf) < 0) {
> +			fwts_log_error(fw, "Cannot get network information for device %s.", d->d_name);
> +			fwts_hwinfo_net_free(net_config);
> +			continue;
> +		}
> +		net_config->hw_addr = strdup(ether_ntoa(((struct ether_addr *)&buf.ifr_hwaddr.sa_data)));
> +		if (net_config->hw_addr == NULL) {
> +			fwts_log_error(fw, "Cannot allocate net config address.");
> +			fwts_hwinfo_net_free(net_config);
> +			break;
> +		}
> +		memset(&buf, 0, sizeof(buf));
> +		strncpy(buf.ifr_name, d->d_name, sizeof(buf.ifr_name));
> +		if (ioctl(sock, SIOCGIFADDR, &buf) < 0) {
> +			if (errno != EADDRNOTAVAIL)
> +				fwts_log_error(fw, "Cannot get address for device %s.", d->d_name);
> +		}
> +		net_config->addr = strdup(inet_ntoa(((struct sockaddr_in *)&buf.ifr_addr)->sin_addr));
> +		if (net_config->addr == NULL) {
> +			fwts_log_error(fw, "Cannot allocate net config H/W address.");
> +			fwts_hwinfo_net_free(net_config);
> +			break;
> +		}
> +		fwts_list_add_ordered(devices, net_config, fwts_hwinfo_net_name_cmp);
> +	}
> +	closedir(dp);
> +	close(sock);
> +
> +	return FWTS_OK;
> +}
> +
> +/*
> + *  fwts_hwinfo_net_dump()
> + *	simple net config dump
> + */
> +static void fwts_hwinfo_net_dump(fwts_framework *fw, fwts_list *devices)
> +{
> +	fwts_list_link *item;
> +
> +	fwts_list_foreach(item, devices) {
> +		fwts_net_config *net_config = fwts_list_data(fwts_net_config *, item);
> +
> +		fwts_log_info_verbatum(fw, "  Device:      %s", net_config->name);
> +		fwts_log_info_verbatum(fw, "  Address:     %s", net_config->addr);
> +		fwts_log_info_verbatum(fw, "  H/W Address: %s", net_config->hw_addr);
> +		fwts_log_nl(fw);
> +	}
> +}
> +
> +/*
> + *  fwts_hwinfo_pci_get()
> + * 	read a specific PCI config based on class code,
> + *	retuning matching PCI configs into the configs list
> + */
> +static int fwts_hwinfo_pci_get(
> +	fwts_framework *fw,
> +	const uint8_t class_code,
> +	fwts_list *configs)
> +{
> +	DIR *pci;
> +	struct dirent *d;
> +
> +	fwts_list_init(configs);
> +	if ((pci = opendir(FWTS_PCI_DEV_PATH)) == NULL) {
> +		fwts_log_error(fw, "Cannot open %s to scan PCI devices.", FWTS_PCI_DEV_PATH);
> +		return FWTS_ERROR;
> +	}
> +
> +	while ((d = readdir(pci)) != NULL) {
> +		ssize_t	n;
> +		int	fd;
> +		fwts_pci_config *pci_config;
> +		uint8_t	config[64];
> +		char 	path[PATH_MAX];
> +
> +		if (d->d_name[0] == '.')
> +			continue;
> +		snprintf(path, sizeof(path), FWTS_PCI_DEV_PATH "/%s/config", d->d_name);
> +
> +		if ((fd = open(path, O_RDONLY)) < 0) {
> +			fwts_log_error(fw, "Cannot open PCI config from %s.", d->d_name);
> +			continue;
> +		}
> +
> +		if ((n = read(fd, config, sizeof(config))) < 0) {
> +			fwts_log_error(fw, "Cannot read PCI config from %s.", d->d_name);
> +			close(fd);
> +			continue;
> +		}
> +		close(fd);
> +
> +		if (config[FWTS_PCI_CONFIG_CLASS_CODE] != class_code)
> +			continue;
> +
> +		if ((pci_config = (fwts_pci_config *)calloc(1, sizeof(*pci_config))) == NULL) {
> +			fwts_log_error(fw, "Cannot allocate PCI config.");
> +			continue;
> +		}
> +		memcpy(pci_config->config, config, n);
> +		pci_config->config_len = n;
> +		strncpy(pci_config->name, d->d_name, NAME_MAX);
> +
> +		fwts_list_append(configs, pci_config);
> +	}
> +	closedir(pci);
> +
> +	return FWTS_OK;
>   }
>
>   /*
> - *  fwts_hwinfo_alpha_compare()
> - *	alphanumeric sort compare function
> + *  fwts_hwinfo_pci_config_cmp()
> + *	compare PCI configs
>    */
> -static int fwts_hwinfo_alpha_compare(void *data1, void *data2)
> +static int fwts_hwinfo_pci_config_cmp(void *data1, void *data2)
>   {
> -        return strcmp((char *)data1, (char*)data2);
> +	fwts_pci_config *pci_config1 = (fwts_pci_config *)data1;
> +	fwts_pci_config *pci_config2 = (fwts_pci_config *)data2;
> +
> +	return (pci_config1->config_len != pci_config2->config_len ||
> +	    memcmp(pci_config1->config, pci_config2->config, pci_config1->config_len) ||
> +	    strcmp(pci_config1->name, pci_config2->name));
>   }
>
>   /*
> - *  fwts_hwinfo_list_sort_alpha()
> - *	clone the contents of the given list and return an
> - *	alphanumerically sorted version of the list. This
> - *	list has cloned contents of the original, so it has
> - *	to be free'd with fwts_list_free(list, NULL) since
> - *	we don't want to free the cloned items and ruin the
> - *	original list
> + *  fwts_hwinfo_pci_dump()
> + *	simple PCI config dump
>    */
> -static fwts_list *fwts_hwinfo_list_sort_alpha(fwts_list *list)
> +static void fwts_hwinfo_pci_dump(fwts_framework *fw, fwts_list *configs)
>   {
>   	fwts_list_link *item;
> -	fwts_list *sorted;
> -	
> -	if ((sorted = fwts_list_new()) == NULL)
> -		return NULL;
> -
> -	fwts_list_foreach(item, list) {
> -		char *str = fwts_list_data(char *, item);
> -		fwts_list_add_ordered(sorted, str, fwts_hwinfo_alpha_compare);
> +
> +	fwts_list_foreach(item, configs) {
> +		ssize_t n;
> +
> +		fwts_pci_config *pci_config = fwts_list_data(fwts_pci_config *, item);
> +		fwts_log_info_verbatum(fw, "  PCI: %s, VID: %2.2" PRIx8 ":%2.2" PRIx8
> +			", Class: %2.2" PRIx8 ":%2.2" PRIx8 " (%s)",
> +			pci_config->name,
> +			pci_config->config[FWTS_PCI_CONFIG_VENDOR_ID],
> +			pci_config->config[FWTS_PCI_CONFIG_DEVICE_ID],
> +			pci_config->config[FWTS_PCI_CONFIG_CLASS_CODE],
> +			pci_config->config[FWTS_PCI_CONFIG_SUBCLASS],
> +			fwts_pci_description(pci_config->config[FWTS_PCI_CONFIG_CLASS_CODE],
> +				pci_config->config[FWTS_PCI_CONFIG_SUBCLASS]));
> +		fwts_log_info_verbatum(fw, "  Config:");
> +
> +		/* and do a raw hex dump of the config space */
> +		for (n = 0; n < pci_config->config_len; n += 16) {
> +			ssize_t left = pci_config->config_len - n;
> +			char buffer[128];
> +
> +			fwts_dump_raw_data(buffer, sizeof(buffer), pci_config->config + n,
> +				n, left > 16 ? 16 : left);
> +			fwts_log_info_verbatum(fw, "  %s", buffer);
> +		}
> +		fwts_log_nl(fw);
>   	}
> +}
>
> -	return sorted;
> +
> +/*
> + *  fwts_hwinfo_lists_dump()
> + *	dump out contents of two different lists
> + */
> +static void fwts_hwinfo_lists_dump(
> +	fwts_framework *fw,
> +	hwinfo_dump dump,
> +	fwts_list *l1,
> +	fwts_list *l2,
> +	const char *message)
> +{
> +	fwts_log_info(fw, "%s configurations differ, before:", message);
> +	if (fwts_list_len(l1))
> +		dump(fw, l1);
> +	else
> +		fwts_log_info(fw, "  (empty)");
> +
> +	fwts_log_info(fw, "versus after:");
> +	if (fwts_list_len(l2))
> +		dump(fw, l2);
> +	else
> +		fwts_log_info(fw, "  (empty)");
> +
> +	fwts_log_nl(fw);
>   }
>
>   /*
> @@ -122,12 +589,13 @@ static fwts_list *fwts_hwinfo_list_sort_alpha(fwts_list *list)
>    *	check lists to see if their contents differ, return 1 for differ, 0 for match,
>    *	-1 for out of memory error
>    */
> -static int fwts_hwinfo_lists_differ(fwts_list *l1, fwts_list *l2)
> +static int fwts_hwinfo_lists_differ(
> +	hwinfo_cmp cmp,
> +	fwts_list *l1,
> +	fwts_list *l2)
>   {
>   	fwts_list_link *item1;
>   	fwts_list_link *item2;
> -	
> -	fwts_list *sorted1, *sorted2;
>
>   	/* Both null - both the same then */
>   	if ((l1 == NULL) && (l2 == NULL))
> @@ -141,33 +609,16 @@ static int fwts_hwinfo_lists_differ(fwts_list *l1, fwts_list *l2)
>   	if (fwts_list_len(l1) != fwts_list_len(l2))
>   		return FWTS_HWINFO_LISTS_DIFFER;
>
> -	if ((sorted1 = fwts_hwinfo_list_sort_alpha(l1)) == NULL)
> -		return FWTS_HWINFO_LISTS_OUT_OF_MEMORY;
> -		
> -	if ((sorted2 = fwts_hwinfo_list_sort_alpha(l2)) == NULL) {
> -		fwts_list_free(sorted1, NULL);
> -		return FWTS_HWINFO_LISTS_OUT_OF_MEMORY;
> -	}
> -
> -	item1 = fwts_list_head(sorted1);
> -	item2 = fwts_list_head(sorted2);
> +	item1 = fwts_list_head(l1);
> +	item2 = fwts_list_head(l2);
>
>   	while ((item1 != NULL) && (item2 != NULL)) {
> -		char *str1 = fwts_list_data(char *, item1);
> -		char *str2 = fwts_list_data(char *, item2);
> -
> -		if (strcmp(str1, str2)) {
> -			fwts_list_free(sorted1, NULL);
> -			fwts_list_free(sorted2, NULL);
> +		if (cmp(fwts_list_data(void *, item1), fwts_list_data(void *, item2)))
>   			return FWTS_HWINFO_LISTS_DIFFER;
> -		}
>   		item1 = fwts_list_next(item1);
>   		item2 = fwts_list_next(item2);
>   	}
>
> -	fwts_list_free(sorted1, NULL);
> -	fwts_list_free(sorted2, NULL);
> -
>   	if ((item1 == NULL) && (item2 == NULL))
>   		return FWTS_HWINFO_LISTS_SAME;
>   	else
> @@ -180,18 +631,40 @@ static int fwts_hwinfo_lists_differ(fwts_list *l1, fwts_list *l2)
>    */
>   static void fwts_hwinfo_lists_compare(
>   	fwts_framework *fw,
> +	hwinfo_cmp cmp,
> +	hwinfo_dump dump,
>   	fwts_list *l1,
>   	fwts_list *l2,
>   	const char *message,
>   	int *differences)
>   {
> -	if (fwts_hwinfo_lists_differ(l1, l2) == FWTS_HWINFO_LISTS_DIFFER) {
> +	if (fwts_hwinfo_lists_differ(cmp, l1, l2) == FWTS_HWINFO_LISTS_DIFFER) {
>   		(*differences)++;
> -		fwts_hwinfo_lists_dump(fw, l1, l2, message);
> +		fwts_hwinfo_lists_dump(fw, dump, l1, l2, message);
>   	}
>   }
>
>   /*
> + *  fwts_hwinfo_get()
> + *	gather H/W information
> + */
> +int fwts_hwinfo_get(fwts_framework *fw, fwts_hwinfo *hwinfo)
> +{
> +	FWTS_UNUSED(fw);
> +
> +	/* PCI devices */
> +	fwts_hwinfo_pci_get(fw, FWTS_PCI_CLASS_CODE_NETWORK_CONTROLLER, &hwinfo->network);
> +	fwts_hwinfo_pci_get(fw, FWTS_PCI_CLASS_CODE_DISPLAY_CONTROLLER, &hwinfo->videocard);
> +	/* Network devices */
> +	fwts_hwinfo_net_get(fw, &hwinfo->netdevs);
> +	fwts_hwinfo_input_get(fw, &hwinfo->input);
> +	/* Bluetooth devices */
> +	fwts_hwinfo_bluetooth_get(fw, &hwinfo->bluetooth);
> +
> +	return FWTS_OK;
> +}
> +
> +/*
>    *  fwts_hwinfo_compare()
>    *	compare data in each hwinfo list, produce a diff comparison output
>    */
> @@ -199,14 +672,20 @@ void fwts_hwinfo_compare(fwts_framework *fw, fwts_hwinfo *hwinfo1, fwts_hwinfo *
>   {
>   	*differences = 0;
>
> -	fwts_hwinfo_lists_compare(fw, hwinfo1->network, hwinfo2->network, "Network Controller", differences);
> -	fwts_hwinfo_lists_compare(fw, hwinfo1->ethernet, hwinfo2->ethernet, "Ethernet Controller", differences);
> -	fwts_hwinfo_lists_compare(fw, hwinfo1->ifconfig, hwinfo2->ifconfig, "Network - ifconfig", differences);
> -	fwts_hwinfo_lists_compare(fw, hwinfo1->iwconfig, hwinfo2->iwconfig, "Network - iwconfig", differences);
> -	fwts_hwinfo_lists_compare(fw, hwinfo1->hciconfig, hwinfo2->hciconfig, "Bluetooth Device", differences);
> -	fwts_hwinfo_lists_compare(fw, hwinfo1->videocard, hwinfo2->videocard, "Video", differences);
> -	fwts_hwinfo_lists_compare(fw, hwinfo1->xinput, hwinfo2->xinput, "Input Devices", differences);
> -	fwts_hwinfo_lists_compare(fw, hwinfo1->pactl, hwinfo2->pactl, "Pulse Audio Sink", differences);
> +	/* PCI devices */
> +	fwts_hwinfo_lists_compare(fw, fwts_hwinfo_pci_config_cmp, fwts_hwinfo_pci_dump,
> +		&hwinfo1->network, &hwinfo2->network, "Network Controller", differences);
> +	fwts_hwinfo_lists_compare(fw, fwts_hwinfo_pci_config_cmp, fwts_hwinfo_pci_dump,
> +		&hwinfo1->videocard, &hwinfo2->videocard, "Video", differences);
> +	/* Network devices */
> +	fwts_hwinfo_lists_compare(fw, fwts_hwinfo_net_cmp, fwts_hwinfo_net_dump,
> +		&hwinfo1->netdevs, &hwinfo2->netdevs, "Network", differences);
> +	/* Input devices */
> +	fwts_hwinfo_lists_compare(fw, fwts_hwinfo_input_config_cmp, fwts_hwinfo_input_dump,
> +		&hwinfo1->input, &hwinfo2->input, "Input Devices", differences);
> +	/* Bluetooth devices */
> +	fwts_hwinfo_lists_compare(fw, fwts_hwinfo_bluetooth_config_cmp, fwts_hwinfo_bluetooth_dump,
> +		&hwinfo1->bluetooth, &hwinfo2->bluetooth, "Bluetooth Device", differences);
>   }
>
>   /*
> @@ -218,14 +697,15 @@ int fwts_hwinfo_free(fwts_hwinfo *hwinfo)
>   	if (hwinfo == NULL)
>   		return FWTS_ERROR;
>
> -	fwts_list_free(hwinfo->network, free);
> -	fwts_list_free(hwinfo->ethernet, free);
> -	fwts_list_free(hwinfo->ifconfig, free);
> -	fwts_list_free(hwinfo->iwconfig, free);
> -	fwts_list_free(hwinfo->hciconfig, free);
> -	fwts_list_free(hwinfo->videocard, free);
> -	fwts_list_free(hwinfo->xinput, free);
> -	fwts_list_free(hwinfo->pactl, free);
> +	/* PCI devices */
> +	fwts_list_free_items(&hwinfo->network, free);
> +	fwts_list_free_items(&hwinfo->videocard, free);
> +	/* Network devices */
> +	fwts_list_free_items(&hwinfo->netdevs, fwts_hwinfo_net_free);
> +	/* Input devices */
> +	fwts_list_free_items(&hwinfo->input, fwts_hwinfo_input_free);
> +	/* Bluetooth devices */
> +	fwts_list_free_items(&hwinfo->bluetooth, fwts_hwinfo_bluetooth_free);
>
>   	return FWTS_OK;
>   }
>

Acked-by: Alex Hung <alex.hung at canoincal.com>



More information about the fwts-devel mailing list