svn commit: r327177 - in head/usr.sbin: . devmatch

O. Hartmann ohartmann at walstatt.org
Mon Dec 25 19:11:18 UTC 2017


Am Mon, 25 Dec 2017 18:56:08 +0000 (UTC)
Warner Losh <imp at FreeBSD.org> schrieb:

> Author: imp
> Date: Mon Dec 25 18:56:08 2017
> New Revision: 327177
> URL: https://svnweb.freebsd.org/changeset/base/327177
> 
> Log:
>   Match unattached devices on the system to potential kernel modules.
>   
>   devmatch(8) matchs up devices in the system device tree with drivers
>   that may match them. For each unattached device in the system, it
>   tries to find matching PNP info in the linker hints and prints modules
>   to load to claim the devices.
>   
>   In --unbound mode, devmatch can look for drivers that have attached to
>   devices in the device tree and have plug and play information, but for
>   which no PNP info exists. This helps find drivers that haven't been
>   converted yet that are in use on this system.
>   
>   In addition, the ability to dump out linker.hints is provided.
>   
>   Future commits will add hooks to devd.conf and rc.d to fully automate
>   using this information.
> 
> Added:
>   head/usr.sbin/devmatch/
>   head/usr.sbin/devmatch/Makefile   (contents, props changed)
>   head/usr.sbin/devmatch/devmatch.8   (contents, props changed)
>   head/usr.sbin/devmatch/devmatch.c   (contents, props changed)
> Modified:
>   head/usr.sbin/Makefile
> 
> Modified: head/usr.sbin/Makefile
> ==============================================================================
> --- head/usr.sbin/Makefile	Mon Dec 25 16:40:09 2017	(r327176)
> +++ head/usr.sbin/Makefile	Mon Dec 25 18:56:08 2017	(r327177)
> @@ -21,6 +21,7 @@ SUBDIR=	adduser \
>  	dconschat \
>  	devctl \
>  	devinfo \
> +	devmath \
>  	digictl \
>  	diskinfo \
>  	dumpcis \
> 
> Added: head/usr.sbin/devmatch/Makefile
> ==============================================================================
> --- /dev/null	00:00:00 1970	(empty, because file is newly added)
> +++ head/usr.sbin/devmatch/Makefile	Mon Dec 25 18:56:08 2017	(r327177)
> @@ -0,0 +1,8 @@
> +# $FreeBSD$
> +
> +PROG=	devmatch
> +MAN=	devmatch.8
> +
> +LIBADD= devinfo
> +
> +.include <bsd.prog.mk>
> 
> Added: head/usr.sbin/devmatch/devmatch.8
> ==============================================================================
> --- /dev/null	00:00:00 1970	(empty, because file is newly added)
> +++ head/usr.sbin/devmatch/devmatch.8	Mon Dec 25 18:56:08 2017	(r327177)
> @@ -0,0 +1,85 @@
> +.\"
> +.\" Copyright (c) 2017 Netflix, Inc
> +.\"
> +.\" All rights reserved.
> +.\"
> +.\" Redistribution and use in source and binary forms, with or without
> +.\" modification, are permitted provided that the following conditions
> +.\" are met:
> +.\" 1. Redistributions of source code must retain the above copyright
> +.\"    notice, this list of conditions and the following disclaimer.
> +.\" 2. Redistributions in binary form must reproduce the above copyright
> +.\"    notice, this list of conditions and the following disclaimer in the
> +.\"    documentation and/or other materials provided with the distribution.
> +.\"
> +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
> +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
> +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
> +.\" IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +.\"
> +.\" $FreeBSD$
> +.\"
> +.Dd December 25, 2017
> +.Dt DEVMATCH 8
> +.Os
> +.Sh NAME
> +.Nm devinfo
> +.Nd print information about unattached devices
> +.Sh SYNOPSIS
> +.Nm
> +.Op Fl aduv
> +.Op Fl -all
> +.Op Fl -dump
> +.Op Fl -unbound
> +.Op Fl -verbose
> +.Sh DESCRIPTION
> +The
> +.Nm
> +utility, without any arguments, prints all the kernel modules it has
> +found for all the unattached, enabled devices in the system.
> +.Bl -tag -width 20m
> +.It Fl a Fl -all
> +Include all devices, not just the ones that are unattached.
> +.It Fl d Fl -dump
> +Produce a human readable dump of the
> +.Pa linker.hints
> +file.
> +.It Fl u Fl -unbound
> +Attempt to produce a list of those drivers with PNP info whose driver
> +tables with that PNP info can't be found.
> +.It Fl v Fl -verbose
> +Produce more verbose output.
> +.El
> +.Sh SEE ALSO
> +.Xr devinfo 8
> +.Sh BUGS
> +The kernel has hints in it, but we exclude it from the list of modules
> +to suggest for unmatched devices.
> +We exclude it when suggesting drivers, but include it when looking for
> +unbound devices or producing a full dump of
> +.Pa linker.hints .
> +This can be confusing.
> +.Pp
> +Some modules are hard links in
> +.Pa /boot/kernel
> +and will be reported twice.
> +.Pp
> +The PNP string's attributes are evaluated once per PNP entry on that
> +bus rather than once.
> +.Pp
> +The term PNP is overloaded in FreeBSD.
> +It means, generically, the identifying data the bus provides about a
> +device.
> +While this include old ISA PNP identifiers, it also includes the
> +logical equivalent in USB, PCI, and others.
> +.Pp
> +Many drivers currently lack proper PNP table decorations and need to
> +be updated.
> +.Sh AUTHORS
> +.An Warner Losh Aq Mt imp at FreeBSD.org
> 
> Added: head/usr.sbin/devmatch/devmatch.c
> ==============================================================================
> --- /dev/null	00:00:00 1970	(empty, because file is newly added)
> +++ head/usr.sbin/devmatch/devmatch.c	Mon Dec 25 18:56:08 2017	(r327177)
> @@ -0,0 +1,425 @@
> +/*-
> + * Copyright (c) 2017 Netflix, Inc
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + *    notice, this list of conditions and the following disclaimer.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + *    notice, this list of conditions and the following disclaimer in the
> + *    documentation and/or other materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
> + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
> + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
> + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
> + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#include <sys/cdefs.h>
> +__FBSDID("$FreeBSD$");
> +
> +#include <sys/param.h>
> +#include <ctype.h>
> +#include <devinfo.h>
> +#include <err.h>
> +#include <fcntl.h>
> +#include <getopt.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <sys/linker.h>
> +#include <sys/module.h>
> +#include <sys/stat.h>
> +#include <sys/sysctl.h>
> +
> +/* options descriptor */
> +static struct option longopts[] = {
> +	{ "all",		no_argument,		NULL,	'a' },
> +	{ "dump",		no_argument,		NULL,	'd' },
> +	{ "unbound",		no_argument,		NULL,	'u' },
> +	{ "verbose",		no_argument,		NULL,	'v' },
> +	{ NULL,			0,			NULL,	0 }
> +};
> +
> +static int all_flag;
> +static int dump_flag;
> +static int unbound_flag;
> +static int verbose_flag;
> +
> +static void *hints;
> +static void *hints_end;
> +
> +static void
> +read_linker_hints(void)
> +{
> +	char fn[MAXPATHLEN];
> +	struct stat sb;
> +	char *modpath, *p, *q;
> +	size_t buflen;
> +	int fd;
> +
> +	if (sysctlbyname("kern.module_path", NULL, &buflen, NULL, 0) < 0)
> +		errx(1, "Can't find kernel module path.");
> +	modpath = malloc(buflen);
> +	if (modpath == NULL)
> +		err(1, "Can't get memory for modpath.");
> +	if (sysctlbyname("kern.module_path", modpath, &buflen, NULL, 0) < 0)
> +		errx(1, "Can't find kernel module path.");
> +	p = modpath;
> +	while ((q = strsep(&p, ";")) != NULL) {
> +		snprintf(fn, sizeof(fn), "%s/linker.hints", q);
> +		if (stat(fn, &sb) != 0)
> +			continue;
> +		hints = malloc(sb.st_size);
> +		if (hints == NULL)
> +			err(1, "not enough space to read hints file of %ju bytes",
> (uintmax_t)sb.st_size);
> +		fd = open(fn, O_RDONLY);
> +		if (fd < 0)
> +			err(1, "Can't open %s for reading", fn);
> +		if (read(fd, hints, sb.st_size) != sb.st_size)
> +			err(1, "Can't read in %ju bytes from %s",
> (uintmax_t)sb.st_size, fn);
> +		close(fd);
> +		break;
> +	}
> +	if (q == NULL) {
> +		warnx("Can't read linker hints file.");
> +		free(hints);
> +		hints = NULL;
> +	}
> +	if (*(int *)(intptr_t)hints != LINKER_HINTS_VERSION) {
> +		warnx("Linker hints version %d doesn't match expected %d.",
> +		    *(int *)(intptr_t)hints, LINKER_HINTS_VERSION);
> +		free(hints);
> +		hints = NULL;
> +	}
> +	if (hints != NULL)
> +		hints_end = (void *)((intptr_t)hints + (intptr_t)sb.st_size);
> +}
> +
> +static int
> +getint(void **ptr)
> +{
> +	int *p = *ptr;
> +	int rv;
> +
> +	p = (int *)roundup2((intptr_t)p, sizeof(int));
> +	rv = *p++;
> +	*ptr = p;
> +	return rv;
> +}
> +
> +static void
> +getstr(void **ptr, char *val)
> +{
> +	int *p = *ptr;
> +	char *c = (char *)p;
> +	int len = *(uint8_t *)c;
> +
> +	memcpy(val, c + 1, len);
> +	val[len] = 0;
> +	c += len + 1;
> +	*ptr = (void *)c;
> +}
> +
> +static int
> +pnpval_as_int(const char *val, const char *pnpinfo)
> +{
> +	int rv;
> +	char key[256];
> +	char *cp;
> +
> +	if (pnpinfo == NULL)
> +		return -1;
> +
> +	cp = strchr(val, ';');
> +	key[0] = ' ';
> +	if (cp == NULL)
> +		strcpy(key + 1, val);
> +	else {
> +		memcpy(key + 1, val, cp - val);
> +		key[cp - val + 1] = '\0';
> +	}
> +	strcat(key, "=");
> +	if (strncmp(key + 1, pnpinfo, strlen(key + 1)) == 0)
> +		rv = strtol(pnpinfo + strlen(key + 1), NULL, 0);
> +	else {
> +		cp = strstr(pnpinfo, key);
> +		if (cp == NULL)
> +			rv = -1;
> +		else
> +			rv = strtol(cp + strlen(key), NULL, 0);
> +	}
> +	return rv;
> +}
> +
> +static void
> +quoted_strcpy(char *dst, const char *src)
> +{
> +	char q = ' ';
> +
> +	if (*src == '\'' || *src == '"')
> +		q = *src++;
> +	while (*src && *src != q)
> +		*dst++ = *src++; // XXX backtick quoting
> +	*dst++ = '\0';
> +	// XXX overflow
> +}
> +
> +static char *
> +pnpval_as_str(const char *val, const char *pnpinfo)
> +{
> +	static char retval[256];
> +	char key[256];
> +	char *cp;
> +
> +	if (pnpinfo == NULL) {
> +		*retval = '\0';
> +		return retval;
> +	}
> +
> +	cp = strchr(val, ';');
> +	key[0] = ' ';
> +	if (cp == NULL)
> +		strcpy(key + 1, val);
> +	else {
> +		memcpy(key + 1, val, cp - val);
> +		key[cp - val + 1] = '\0';
> +	}
> +	strcat(key, "=");
> +	if (strncmp(key + 1, pnpinfo, strlen(key + 1)) == 0)
> +		quoted_strcpy(retval, pnpinfo + strlen(key + 1));
> +	else {
> +		cp = strstr(pnpinfo, key);
> +		if (cp == NULL)
> +			strcpy(retval, "MISSING");
> +		else
> +			quoted_strcpy(retval, cp + strlen(key));
> +	}
> +	return retval;
> +}
> +
> +static void
> +search_hints(const char *bus, const char *dev, const char *pnpinfo)
> +{
> +	char val1[256], val2[256];
> +	int ival, len, ents, i, notme, mask, bit, v, found;
> +	void *ptr, *walker;
> +	char *lastmod = NULL, *cp, *s;
> +
> +	walker = hints;
> +	getint(&walker);
> +	found = 0;
> +	while (walker < hints_end) {
> +		len = getint(&walker);
> +		ival = getint(&walker);
> +		ptr = walker;
> +		switch (ival) {
> +		case MDT_VERSION:
> +			getstr(&ptr, val1);
> +			ival = getint(&ptr);
> +			getstr(&ptr, val2);
> +			if (dump_flag)
> +				printf("Version: if %s.%d kmod %s\n", val1, ival,
> val2);
> +			break;
> +		case MDT_MODULE:
> +			getstr(&ptr, val1);
> +			getstr(&ptr, val2);
> +			if (lastmod)
> +				free(lastmod);
> +			lastmod = strdup(val2);
> +			if (dump_flag)
> +				printf("Module %s in %s\n", val1, val2);
> +			break;
> +		case MDT_PNP_INFO:
> +			if (!dump_flag && !unbound_flag && strcmp(lastmod, "kernel")
> == 0)
> +				break;
> +			getstr(&ptr, val1);
> +			getstr(&ptr, val2);
> +			ents = getint(&ptr);
> +			if (bus && strcmp(val1, bus) != 0)
> +				break;
> +			if (dump_flag)
> +				printf("PNP info for bus %s format %s %d entries
> (%s)\n",
> +				    val1, val2, ents, lastmod);
> +			for (i = 0; i < ents; i++) {
> +				if (dump_flag)
> +					printf("   ");
> +				cp = val2;
> +				notme = 0;
> +				mask = -1;
> +				bit = -1;
> +				do {
> +					switch (*cp) {
> +					case 'I':
> +					case 'J':
> +					case 'G':
> +					case 'L':
> +					case 'M':
> +						ival = getint(&ptr);
> +						if (dump_flag) {
> +							printf("%#x:", ival);
> +							break;
> +						}
> +						if (bit >= 0 && ((1 << bit) & mask) ==
> 0)
> +							break;
> +						v = pnpval_as_int(cp + 2, pnpinfo);
> +						switch (*cp) {
> +						case 'J':
> +							if (ival == -1)
> +								break;
> +							/*FALLTHROUGH*/
> +						case 'I':
> +							if (v != ival && ival != 0)
> +								notme++;
> +							break;
> +						case 'G':
> +							if (v < ival)
> +								notme++;
> +							break;
> +						case 'L':
> +							if (v > ival)
> +								notme++;
> +							break;
> +						case 'M':
> +							mask = ival;
> +							break;
> +						}
> +						break;
> +					case 'D':
> +					case 'Z':
> +						getstr(&ptr, val1);
> +						if (dump_flag) {
> +							printf("'%s':", val1);
> +							break;
> +						}
> +						if (*cp == 'D')
> +							break;
> +						s = pnpval_as_str(cp + 2, pnpinfo);
> +						if (strcmp(s, val1) != 0)
> +							notme++;
> +						break;
> +					default:
> +						break;
> +					}
> +					bit++;
> +					cp = strchr(cp, ';');
> +					if (cp)
> +						cp++;
> +				} while (cp && *cp);
> +				if (dump_flag)
> +					printf("\n");
> +				else if (!notme) {
> +					if (!unbound_flag) {
> +						if (all_flag)
> +							printf("%s: ", *dev ? dev :
> "unattahed" );
> +						printf("%s\n", lastmod);
> +					}
> +					found++;
> +				}
> +			}
> +			break;
> +		default:
> +			if (dump_flag)
> +				printf("Unknown Type %d len %d\n", ival, len);
> +			break;
> +		}
> +		walker = (void *)(len - sizeof(int) + (intptr_t)walker);
> +	}
> +	if (unbound_flag && found == 0 && *pnpinfo) {
> +		if (verbose_flag)
> +			printf("------------------------- ");
> +		printf("%s on %s pnpinfo %s", *dev ? dev : "unattahed", bus, pnpinfo);
> +		if (verbose_flag)
> +			printf(" -------------------------");
> +		printf("\n");
> +	}
> +}
> +
> +static int
> +find_unmatched(struct devinfo_dev *dev, void *arg)
> +{
> +	struct devinfo_dev *parent;
> +	char *bus, *p;
> +
> +	do {
> +		if (!all_flag && dev->dd_name[0] != '\0')
> +			break;
> +		if (!(dev->dd_flags & DF_ENABLED))
> +			break;
> +		parent = devinfo_handle_to_device(dev->dd_parent);
> +		bus = strdup(parent->dd_name);
> +		p = bus + strlen(bus) - 1;
> +		while (p >= bus && isdigit(*p))
> +			p--;
> +		*++p = '\0';
> +		if (verbose_flag)
> +			printf("Searching %s %s bus at %s for pnpinfo %s\n",
> +			    dev->dd_name, bus, dev->dd_location, dev->dd_pnpinfo);
> +		search_hints(bus, dev->dd_name, dev->dd_pnpinfo);
> +		free(bus);
> +	} while (0);
> +
> +	return (devinfo_foreach_device_child(dev, find_unmatched, arg));
> +}
> +
> +static void
> +usage(void)
> +{
> +
> +	errx(1, "devmatch [-adv]");
> +}
> +
> +int
> +main(int argc, char **argv)
> +{
> +	struct devinfo_dev *root;
> +	int ch;
> +
> +	while ((ch = getopt_long(argc, argv, "aduv",
> +		    longopts, NULL)) != -1) {
> +		switch (ch) {
> +		case 'a':
> +			all_flag++;
> +			break;
> +		case 'd':
> +			dump_flag++;
> +			break;
> +		case 'u':
> +			unbound_flag++;
> +			break;
> +		case 'v':
> +			verbose_flag++;
> +			break;
> +		default:
> +			usage();
> +		}
> +	}
> +	argc -= optind;
> +	argv += optind;
> +
> +	if (argc >= 1)
> +		usage();
> +
> +	read_linker_hints();
> +	if (dump_flag) {
> +		search_hints(NULL, NULL, NULL);
> +		exit(0);
> +	}
> +
> +	if (devinfo_init())
> +		err(1, "devinfo_init");
> +	if ((root = devinfo_handle_to_device(DEVINFO_ROOT_DEVICE)) == NULL)
> +		errx(1, "can't find root device");
> +	devinfo_foreach_device_child(root, find_unmatched, (void *)0);
> +	devinfo_free();
> +}
> _______________________________________________
> svn-src-head at freebsd.org mailing list
> https://lists.freebsd.org/mailman/listinfo/svn-src-head
> To unsubscribe, send any mail to "svn-src-head-unsubscribe at freebsd.org"

Well, I remeber that someone told me that "math" and "match" are different thingis ;-)

To be serious: there is some strange error ...

[...]
===> usr.sbin/devmath (includes)
cd: /usr/src/usr.sbin/devmath: No such file or directory
*** [includes_subdir_usr.sbin/devmath] Error code 2

make[3]: stopped in /usr/src/usr.sbin
.ERROR_TARGET='includes_subdir_usr.sbin/devmath'

-- 
O. Hartmann

Ich widerspreche der Nutzung oder Übermittlung meiner Daten für
Werbezwecke oder für die Markt- oder Meinungsforschung (§ 28 Abs. 4 BDSG).
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 313 bytes
Desc: OpenPGP digital signature
URL: <http://lists.freebsd.org/pipermail/svn-src-all/attachments/20171225/99ca84bf/attachment.sig>


More information about the svn-src-all mailing list