diff options
| author | Robert Mustacchi <rm@fingolfin.org> | 2021-03-05 10:25:21 -0800 |
|---|---|---|
| committer | Robert Mustacchi <rm@fingolfin.org> | 2021-03-24 11:22:58 -0700 |
| commit | 8a37ae750765321f9d9de63763676fa7280d93da (patch) | |
| tree | 9813e8103e48b11517a06b3de26717d097c7e9e1 | |
| parent | 5ad6a0f49b59cb4bd38eab045ce9894881e9d862 (diff) | |
| download | illumos-joyent-8a37ae750765321f9d9de63763676fa7280d93da.tar.gz | |
13630 libpcidb could know about class codes
Reviewed by: C Fraire <cfraire@me.com>
Reviewed by: Patrick Mooney <pmooney@pfmooney.com>
Reviewed by: Andy Fiddaman <andy@omnios.org>
Reviewed by: Rich Lowe <richlowe@richlowe.net>
Approved by: Rich Lowe <richlowe@richlowe.net>
| -rw-r--r-- | usr/src/cmd/Makefile | 1 | ||||
| -rw-r--r-- | usr/src/cmd/pcidb/Makefile | 45 | ||||
| -rw-r--r-- | usr/src/cmd/pcidb/pcidb.c | 884 | ||||
| -rw-r--r-- | usr/src/lib/libpcidb/Makefile.com | 7 | ||||
| -rw-r--r-- | usr/src/lib/libpcidb/common/mapfile-vers | 48 | ||||
| -rw-r--r-- | usr/src/lib/libpcidb/common/pcidb.c | 701 | ||||
| -rw-r--r-- | usr/src/lib/libpcidb/common/pcidb.h | 30 | ||||
| -rw-r--r-- | usr/src/pkg/manifests/diagnostic-pci.mf | 26 | ||||
| -rw-r--r-- | usr/src/pkg/manifests/system-test-utiltest.mf | 2 | ||||
| -rw-r--r-- | usr/src/test/util-tests/runfiles/default.run | 2 | ||||
| -rw-r--r-- | usr/src/test/util-tests/tests/Makefile | 2 | ||||
| -rw-r--r-- | usr/src/test/util-tests/tests/pcidb/Makefile | 36 | ||||
| -rw-r--r-- | usr/src/test/util-tests/tests/pcidb/pcidbtest.ksh | 223 |
13 files changed, 1762 insertions, 245 deletions
diff --git a/usr/src/cmd/Makefile b/usr/src/cmd/Makefile index 7bac5c58ce..3bc0bf2af4 100644 --- a/usr/src/cmd/Makefile +++ b/usr/src/cmd/Makefile @@ -304,6 +304,7 @@ COMMON_SUBDIRS= \ passwd \ pathchk \ pbind \ + pcidb \ pcidr \ pcieb \ pcitool \ diff --git a/usr/src/cmd/pcidb/Makefile b/usr/src/cmd/pcidb/Makefile new file mode 100644 index 0000000000..41a5737c7a --- /dev/null +++ b/usr/src/cmd/pcidb/Makefile @@ -0,0 +1,45 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2021 Oxide Computer Company +# + +PROG= pcidb + +include ../Makefile.cmd +include ../Makefile.cmd.64 +include ../Makefile.ctf + +CFLAGS += $(CCVERBOSE) +CSTD = $(CSTD_GNU99) +LDLIBS += -lpcidb -lofmt +OBJS = pcidb.o +ROOTCMDDIR = $(ROOTLIB)/pci + +.KEEP_STATE: + +$(PROG): $(OBJS) + $(LINK.c) -o $@ $(OBJS) $(LDLIBS) + $(POST_PROCESS) + +%.o: %.c + $(COMPILE.c) $< + $(POST_PROCESS_O) + +all: $(PROG) + +install: all $(ROOTCMD) + +clean: + $(RM) $(OBJS) + +include ../Makefile.targ diff --git a/usr/src/cmd/pcidb/pcidb.c b/usr/src/cmd/pcidb/pcidb.c new file mode 100644 index 0000000000..7a0785c7ae --- /dev/null +++ b/usr/src/cmd/pcidb/pcidb.c @@ -0,0 +1,884 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2021 Oxide Computer Company + */ + +/* + * A tool to interface with the pci.ids database driven by libpcidb. + */ + +#include <stdio.h> +#include <stdarg.h> +#include <pcidb.h> +#include <err.h> +#include <libgen.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <ofmt.h> +#include <errno.h> +#include <sys/debug.h> +#include <priv.h> + +#define EXIT_USAGE 2 + +static char *pcidb_progname; + +typedef enum { + PCIDB_MODE_UNKNOWN, + PCIDB_MODE_LIST, + PCIDB_MODE_SEARCH, + PCIDB_MODE_LOOKUP +} pcidb_mode_t; + +typedef enum { + PCIDB_TABLE_NONE, + PCIDB_TABLE_VENDOR, + PCIDB_TABLE_DEVICE, + PCIDB_TABLE_SUBSYSTEM, + PCIDB_TABLE_CLASS, + PCIDB_TABLE_SUBCLASS, + PCIDB_TABLE_PROGIF +} pcidb_table_t; + +typedef enum { + PCIDB_OFMT_VID, + PCIDB_OFMT_VENSTR, + PCIDB_OFMT_DID, + PCIDB_OFMT_DEVSTR, + PCIDB_OFMT_SVID, + PCIDB_OFMT_SDID, + PCIDB_OFMT_SUBVENSTR, + PCIDB_OFMT_SUBSYSSTR, + PCIDB_OFMT_BCC, + PCIDB_OFMT_CLASSSTR, + PCIDB_OFMT_SCC, + PCIDB_OFMT_SUBCLASSSTR, + PCIDB_OFMT_PI, + PCIDB_OFMT_PROGIFSTR +} pcidb_ofmt_t; + +typedef struct pcidb_filter { + uint32_t pft_vend; + uint32_t pft_dev; + uint32_t pft_subven; + uint32_t pft_subdev; + uint32_t pft_class; + uint32_t pft_subclass; + uint32_t pft_progif; +} pcidb_filter_t; + +#define PCIDB_NOFILTER UINT32_MAX + +typedef struct pcidb_walk { + pcidb_hdl_t *pw_hdl; + ofmt_handle_t pw_ofmt; + pcidb_vendor_t *pw_vendor; + pcidb_device_t *pw_device; + pcidb_subvd_t *pw_subvd; + pcidb_class_t *pw_class; + pcidb_subclass_t *pw_subclass; + pcidb_progif_t *pw_progif; + boolean_t pw_strcase; + uint_t pw_nfilters; + pcidb_filter_t *pw_filters; +} pcidb_walk_t; + +static boolean_t +pcidb_write_vendor(ofmt_arg_t *ofarg, char *buf, uint_t buflen) +{ + pcidb_walk_t *walk = ofarg->ofmt_cbarg; + + VERIFY(walk->pw_vendor != NULL); + switch (ofarg->ofmt_id) { + case PCIDB_OFMT_VID: + (void) snprintf(buf, buflen, "%x", + pcidb_vendor_id(walk->pw_vendor)); + break; + case PCIDB_OFMT_VENSTR: + (void) strlcpy(buf, pcidb_vendor_name(walk->pw_vendor), buflen); + break; + default: + abort(); + } + return (B_TRUE); +} + +static boolean_t +pcidb_write_device(ofmt_arg_t *ofarg, char *buf, uint_t buflen) +{ + pcidb_walk_t *walk = ofarg->ofmt_cbarg; + + VERIFY(walk->pw_device != NULL); + switch (ofarg->ofmt_id) { + case PCIDB_OFMT_DID: + (void) snprintf(buf, buflen, "%x", + pcidb_device_id(walk->pw_device)); + break; + case PCIDB_OFMT_DEVSTR: + (void) strlcpy(buf, pcidb_device_name(walk->pw_device), buflen); + break; + default: + abort(); + } + return (B_TRUE); +} + +static boolean_t +pcidb_write_subsystem(ofmt_arg_t *ofarg, char *buf, uint_t buflen) +{ + pcidb_walk_t *walk = ofarg->ofmt_cbarg; + pcidb_vendor_t *vendor; + + VERIFY(walk->pw_subvd != NULL); + switch (ofarg->ofmt_id) { + case PCIDB_OFMT_SVID: + (void) snprintf(buf, buflen, "%x", + pcidb_subvd_svid(walk->pw_subvd)); + break; + case PCIDB_OFMT_SDID: + (void) snprintf(buf, buflen, "%x", + pcidb_subvd_sdid(walk->pw_subvd)); + break; + case PCIDB_OFMT_SUBSYSSTR: + (void) strlcpy(buf, pcidb_subvd_name(walk->pw_subvd), buflen); + break; + case PCIDB_OFMT_SUBVENSTR: + vendor = pcidb_lookup_vendor(walk->pw_hdl, + pcidb_subvd_svid(walk->pw_subvd)); + if (vendor == NULL) { + return (B_FALSE); + } + (void) strlcpy(buf, pcidb_vendor_name(vendor), buflen); + break; + default: + abort(); + } + return (B_TRUE); +} + +static boolean_t +pcidb_write_class(ofmt_arg_t *ofarg, char *buf, uint_t buflen) +{ + pcidb_walk_t *walk = ofarg->ofmt_cbarg; + + VERIFY(walk->pw_class != NULL); + switch (ofarg->ofmt_id) { + case PCIDB_OFMT_BCC: + (void) snprintf(buf, buflen, "%x", + pcidb_class_code(walk->pw_class)); + break; + case PCIDB_OFMT_CLASSSTR: + (void) strlcpy(buf, pcidb_class_name(walk->pw_class), buflen); + break; + default: + abort(); + } + return (B_TRUE); +} + +static boolean_t +pcidb_write_subclass(ofmt_arg_t *ofarg, char *buf, uint_t buflen) +{ + pcidb_walk_t *walk = ofarg->ofmt_cbarg; + + VERIFY(walk->pw_subclass != NULL); + switch (ofarg->ofmt_id) { + case PCIDB_OFMT_SCC: + (void) snprintf(buf, buflen, "%x", + pcidb_subclass_code(walk->pw_subclass)); + break; + case PCIDB_OFMT_SUBCLASSSTR: + (void) strlcpy(buf, pcidb_subclass_name(walk->pw_subclass), + buflen); + break; + default: + abort(); + } + return (B_TRUE); +} + +static boolean_t +pcidb_write_progif(ofmt_arg_t *ofarg, char *buf, uint_t buflen) +{ + pcidb_walk_t *walk = ofarg->ofmt_cbarg; + + VERIFY(walk->pw_progif != NULL); + switch (ofarg->ofmt_id) { + case PCIDB_OFMT_PI: + (void) snprintf(buf, buflen, "%x", + pcidb_progif_code(walk->pw_progif)); + break; + case PCIDB_OFMT_PROGIFSTR: + (void) strlcpy(buf, pcidb_progif_name(walk->pw_progif), + buflen); + break; + default: + abort(); + } + return (B_TRUE); +} + +static const char *pcidb_vendor_fields = "vid,vendor"; +static const ofmt_field_t pcidb_vendor_ofmt[] = { + { "VID", 8, PCIDB_OFMT_VID, pcidb_write_vendor }, + { "VENDOR", 30, PCIDB_OFMT_VENSTR, pcidb_write_vendor }, + { NULL, 0, 0, NULL } +}; + +static const char *pcidb_device_fields = "vid,did,vendor,device"; +static const ofmt_field_t pcidb_device_ofmt[] = { + { "VID", 8, PCIDB_OFMT_VID, pcidb_write_vendor }, + { "VENDOR", 30, PCIDB_OFMT_VENSTR, pcidb_write_vendor }, + { "DID", 8, PCIDB_OFMT_DID, pcidb_write_device }, + { "DEVICE", 30, PCIDB_OFMT_DEVSTR, pcidb_write_device }, + { NULL, 0, 0, NULL } +}; + +static const char *pcidb_subsystem_fields = "vid,did,svid,sdid,subsystem"; +static const ofmt_field_t pcidb_subsystem_ofmt[] = { + { "VID", 8, PCIDB_OFMT_VID, pcidb_write_vendor }, + { "VENDOR", 30, PCIDB_OFMT_VENSTR, pcidb_write_vendor }, + { "DID", 8, PCIDB_OFMT_DID, pcidb_write_device }, + { "DEVICE", 30, PCIDB_OFMT_DEVSTR, pcidb_write_device }, + { "SVID", 8, PCIDB_OFMT_SVID, pcidb_write_subsystem }, + { "SDID", 8, PCIDB_OFMT_SDID, pcidb_write_subsystem }, + { "SUBSYSTEM", 30, PCIDB_OFMT_SUBSYSSTR, pcidb_write_subsystem }, + { "SUBVENDOR", 30, PCIDB_OFMT_SUBVENSTR, pcidb_write_subsystem }, + { NULL, 0, 0, NULL } +}; + +static const char *pcidb_class_fields = "bcc,class"; +static const ofmt_field_t pcidb_class_ofmt[] = { + { "BCC", 6, PCIDB_OFMT_BCC, pcidb_write_class }, + { "CLASS", 30, PCIDB_OFMT_CLASSSTR, pcidb_write_class }, + { NULL, 0, 0, NULL } +}; + +static const char *pcidb_subclass_fields = "bcc,scc,class,subclass"; +static const ofmt_field_t pcidb_subclass_ofmt[] = { + { "BCC", 6, PCIDB_OFMT_BCC, pcidb_write_class }, + { "CLASS", 30, PCIDB_OFMT_CLASSSTR, pcidb_write_class }, + { "SCC", 6, PCIDB_OFMT_SCC, pcidb_write_subclass }, + { "SUBCLASS", 30, PCIDB_OFMT_SUBCLASSSTR, pcidb_write_subclass }, + { NULL, 0, 0, NULL } +}; + +static const char *pcidb_progif_fields = "bcc,scc,pi,subclass,interface"; +static const ofmt_field_t pcidb_progif_ofmt[] = { + { "BCC", 6, PCIDB_OFMT_BCC, pcidb_write_class }, + { "CLASS", 30, PCIDB_OFMT_CLASSSTR, pcidb_write_class }, + { "SCC", 6, PCIDB_OFMT_SCC, pcidb_write_subclass }, + { "SUBCLASS", 30, PCIDB_OFMT_SUBCLASSSTR, pcidb_write_subclass }, + { "PI", 6, PCIDB_OFMT_PI, pcidb_write_progif }, + { "INTERFACE", 30, PCIDB_OFMT_PROGIFSTR, pcidb_write_progif }, + { NULL, 0, 0, NULL } +}; + +static void +pcidb_ofmt_errx(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + verrx(EXIT_FAILURE, fmt, ap); +} + +static boolean_t +pcidb_filter_match(pcidb_walk_t *walk) +{ + if (walk->pw_nfilters == 0) { + return (B_TRUE); + } + + for (uint_t i = 0; i < walk->pw_nfilters; i++) { + const pcidb_filter_t *filt = &walk->pw_filters[i]; + if (filt->pft_vend != PCIDB_NOFILTER && + (walk->pw_vendor == NULL || + filt->pft_vend != pcidb_vendor_id(walk->pw_vendor))) { + continue; + } + + if (filt->pft_dev != PCIDB_NOFILTER && + (walk->pw_device == NULL || + filt->pft_dev != pcidb_device_id(walk->pw_device))) { + continue; + } + + if (filt->pft_subven != PCIDB_NOFILTER && + (walk->pw_subvd == NULL || + filt->pft_subven != pcidb_subvd_svid(walk->pw_subvd))) { + continue; + } + + if (filt->pft_subdev != PCIDB_NOFILTER && + (walk->pw_subvd == NULL || + filt->pft_subdev != pcidb_subvd_sdid(walk->pw_subvd))) { + continue; + } + + if (filt->pft_class != PCIDB_NOFILTER && + (walk->pw_class == NULL || + filt->pft_class != pcidb_class_code(walk->pw_class))) { + continue; + } + + if (filt->pft_subclass != PCIDB_NOFILTER && + (walk->pw_subclass == NULL || + filt->pft_subclass != + pcidb_subclass_code(walk->pw_subclass))) { + continue; + } + + if (filt->pft_progif != PCIDB_NOFILTER && + (walk->pw_progif == NULL || + filt->pft_progif != pcidb_progif_code(walk->pw_progif))) { + continue; + } + + return (B_TRUE); + } + + return (B_FALSE); +} + +static void +pcidb_walk_vendors(pcidb_walk_t *walk) +{ + pcidb_hdl_t *hdl = walk->pw_hdl; + + for (pcidb_vendor_t *vend = pcidb_vendor_iter(hdl); vend != NULL; + vend = pcidb_vendor_iter_next(vend)) { + walk->pw_vendor = vend; + if (!pcidb_filter_match(walk)) + continue; + ofmt_print(walk->pw_ofmt, walk); + } +} + +static void +pcidb_walk_devices(pcidb_walk_t *walk) +{ + pcidb_hdl_t *hdl = walk->pw_hdl; + + for (pcidb_vendor_t *vend = pcidb_vendor_iter(hdl); vend != NULL; + vend = pcidb_vendor_iter_next(vend)) { + walk->pw_vendor = vend; + for (pcidb_device_t *dev = pcidb_device_iter(vend); dev != NULL; + dev = pcidb_device_iter_next(dev)) { + walk->pw_device = dev; + if (!pcidb_filter_match(walk)) + continue; + ofmt_print(walk->pw_ofmt, walk); + } + } +} + +static void +pcidb_walk_subsystems(pcidb_walk_t *walk) +{ + pcidb_hdl_t *hdl = walk->pw_hdl; + + for (pcidb_vendor_t *vend = pcidb_vendor_iter(hdl); vend != NULL; + vend = pcidb_vendor_iter_next(vend)) { + walk->pw_vendor = vend; + for (pcidb_device_t *dev = pcidb_device_iter(vend); dev != NULL; + dev = pcidb_device_iter_next(dev)) { + walk->pw_device = dev; + for (pcidb_subvd_t *sub = pcidb_subvd_iter(dev); + sub != NULL; sub = pcidb_subvd_iter_next(sub)) { + walk->pw_subvd = sub; + if (!pcidb_filter_match(walk)) + continue; + ofmt_print(walk->pw_ofmt, walk); + } + } + + } +} + +static void +pcidb_walk_classes(pcidb_walk_t *walk) +{ + for (pcidb_class_t *class = pcidb_class_iter(walk->pw_hdl); + class != NULL; class = pcidb_class_iter_next(class)) { + walk->pw_class = class; + if (!pcidb_filter_match(walk)) + continue; + ofmt_print(walk->pw_ofmt, walk); + } +} + +static void +pcidb_walk_subclasses(pcidb_walk_t *walk) +{ + for (pcidb_class_t *class = pcidb_class_iter(walk->pw_hdl); + class != NULL; class = pcidb_class_iter_next(class)) { + walk->pw_class = class; + for (pcidb_subclass_t *sub = pcidb_subclass_iter(class); + sub != NULL; sub = pcidb_subclass_iter_next(sub)) { + walk->pw_subclass = sub; + if (!pcidb_filter_match(walk)) + continue; + ofmt_print(walk->pw_ofmt, walk); + } + } +} + +static void +pcidb_walk_progifs(pcidb_walk_t *walk) +{ + for (pcidb_class_t *class = pcidb_class_iter(walk->pw_hdl); + class != NULL; class = pcidb_class_iter_next(class)) { + walk->pw_class = class; + for (pcidb_subclass_t *sub = pcidb_subclass_iter(class); + sub != NULL; sub = pcidb_subclass_iter_next(sub)) { + walk->pw_subclass = sub; + for (pcidb_progif_t *progif = pcidb_progif_iter(sub); + progif != NULL; + progif = pcidb_progif_iter_next(progif)) { + walk->pw_progif = progif; + if (!pcidb_filter_match(walk)) + continue; + ofmt_print(walk->pw_ofmt, walk); + } + } + } +} + +static void +pcidb_parse_class_filter(pcidb_filter_t *filter, char *arg, const char *orig) +{ + size_t len; + unsigned long val; + char *eptr; + + filter->pft_vend = filter->pft_dev = PCIDB_NOFILTER; + filter->pft_subven = filter->pft_subdev = PCIDB_NOFILTER; + + len = strlen(arg); + if (len != 2 && len != 4 && len != 6) { + errx(EXIT_FAILURE, "invalid class filter: '%s': bad length", + orig); + } + + errno = 0; + val = strtoul(arg, &eptr, 16); + if (errno != 0 || *eptr != '\0') { + errx(EXIT_FAILURE, "invalid class filter: '%s': failed to " + "parse hex string", orig); + } + + if (len == 6) { + filter->pft_progif = val & 0xff; + val = val >> 8; + } else { + filter->pft_progif = PCIDB_NOFILTER; + } + + if (len >= 4) { + filter->pft_subclass = val & 0xff; + val = val >> 8; + } else { + filter->pft_subclass = PCIDB_NOFILTER; + } + + filter->pft_class = val & 0xff; +} + +static void +pcidb_parse_device_filter(pcidb_filter_t *filter, char *arg, const char *orig) +{ + unsigned long val; + uint32_t primary, secondary; + char *eptr; + + filter->pft_vend = filter->pft_dev = PCIDB_NOFILTER; + filter->pft_subven = filter->pft_subdev = PCIDB_NOFILTER; + filter->pft_class = filter->pft_subclass = PCIDB_NOFILTER; + filter->pft_progif = PCIDB_NOFILTER; + + errno = 0; + val = strtoul(arg, &eptr, 16); + if (errno != 0 || (*eptr != '\0' && *eptr != ',')) { + errx(EXIT_FAILURE, "invalid device filter: '%s': failed to " + "parse hex string", orig); + } + + if (val > UINT16_MAX) { + errx(EXIT_FAILURE, "invalid id: %x is larger than 0xffff", val); + } + + primary = (uint32_t)val; + if (*eptr == '\0') { + filter->pft_vend = primary; + return; + } else if (strcmp(eptr, ",s") == 0) { + filter->pft_subven = primary; + return; + } else if (eptr[1] == '\0') { + errx(EXIT_FAILURE, "invalid device filter: '%s': filter " + "terminated early", arg); + } + + arg = eptr + 1; + val = strtoul(arg, &eptr, 16); + if (errno != 0 || (*eptr != '\0' && *eptr != ',' && *eptr != '.')) { + errx(EXIT_FAILURE, "invalid device filter: '%s': failed to " + "parse hex string at %s", orig, arg); + } + + if (val > UINT16_MAX) { + errx(EXIT_FAILURE, "invalid id: %x is larger than 0xffff", val); + } + + secondary = (uint32_t)val; + if (*eptr == '\0') { + filter->pft_vend = primary; + filter->pft_dev = secondary; + return; + } else if (eptr[1] == '\0') { + errx(EXIT_FAILURE, "invalid device filter: '%s': filter " + "terminated early", arg); + } + + if (*eptr == ',') { + if (eptr[1] == 'p' && eptr[2] == '\0') { + filter->pft_vend = primary; + filter->pft_dev = secondary; + return; + } + if (eptr[1] == 's' && eptr[2] == '\0') { + filter->pft_subven = primary; + filter->pft_subdev = secondary; + return; + } + errx(EXIT_FAILURE, "invalid device filter: '%s': invalid " + "trailing comma at %s, expected either ,p or ,s", + orig, eptr); + } + + filter->pft_vend = primary; + filter->pft_dev = secondary; + + arg = eptr + 1; + errno = 0; + val = strtoul(arg, &eptr, 16); + if (errno != 0 || (*eptr != '\0' && *eptr != ',')) { + errx(EXIT_FAILURE, "invalid device filter: '%s': failed to " + "parse hex string at %s", orig, arg); + } + + if (val > UINT16_MAX) { + errx(EXIT_FAILURE, "invalid id: %x is larger than 0xffff", val); + } + + filter->pft_subven = (uint32_t)val; + if (*eptr == '\0') { + return; + } else if (eptr[1] == '\0') { + errx(EXIT_FAILURE, "invalid device filter: '%s': filter " + "terminated early", arg); + } + + arg = eptr + 1; + errno = 0; + val = strtoul(arg, &eptr, 16); + if (errno != 0 || *eptr != '\0') { + errx(EXIT_FAILURE, "invalid device filter: '%s': failed to " + "parse hex string at %s", orig, arg); + } + + if (val > UINT16_MAX) { + errx(EXIT_FAILURE, "invalid id: %x is larger than 0xffff", val); + } + + filter->pft_subdev = (uint32_t)val; +} + + +/* + * Process a series of alias style ways of indicating numeric filters. Use the + * basic alias format for now. + */ +static void +pcidb_process_filters(int argc, char *argv[], pcidb_walk_t *walkp) +{ + if (argc <= 0) { + walkp->pw_nfilters = 0; + return; + } + + walkp->pw_nfilters = argc; + walkp->pw_filters = calloc(walkp->pw_nfilters, sizeof (pcidb_filter_t)); + if (walkp->pw_filters == NULL) { + err(EXIT_FAILURE, "failed to allocate memory for filters"); + } + + for (int i = 0; i < argc; i++) { + char *str = strdup(argv[i]); + + if (str == NULL) { + errx(EXIT_FAILURE, "failed to duplicate string %s", + argv[i]); + } + + if (strncmp(str, "pciexclass,", 11) == 0) { + pcidb_parse_class_filter(&walkp->pw_filters[i], + str + 11, argv[i]); + } else if (strncmp(str, "pciclass,", 9) == 0) { + pcidb_parse_class_filter(&walkp->pw_filters[i], str + 9, + argv[i]); + } else if (strncmp(str, "pciex", 5) == 0) { + pcidb_parse_device_filter(&walkp->pw_filters[i], + str + 5, argv[i]); + } else if (strncmp(str, "pci", 3) == 0) { + pcidb_parse_device_filter(&walkp->pw_filters[i], + str + 3, argv[i]); + } else { + errx(EXIT_FAILURE, "invalid filter string: %s", str); + } + + free(str); + } +} + +static void +pcidb_drop_privs(void) +{ + priv_set_t *curprivs, *targprivs; + + if ((curprivs = priv_allocset()) == NULL) { + err(EXIT_FAILURE, "failed to allocate privilege set to drop " + "privs"); + } + + if (getppriv(PRIV_EFFECTIVE, curprivs) != 0) { + err(EXIT_FAILURE, "failed to get current privileges"); + } + + if ((targprivs = priv_allocset()) == NULL) { + err(EXIT_FAILURE, "failed to allocate privilege set to drop " + "privs"); + } + + /* + * Set our privileges to the minimum required. Because stdout will have + * already been opened, all we need is the ability to read files from + * basic privileges. We opt to keep FILE_DAC_READ if the caller has it + * just in case there is something weird about the location of the + * pci.ids files. + */ + priv_basicset(targprivs); + VERIFY0(priv_delset(targprivs, PRIV_FILE_LINK_ANY)); + VERIFY0(priv_delset(targprivs, PRIV_PROC_INFO)); + VERIFY0(priv_delset(targprivs, PRIV_PROC_SESSION)); + VERIFY0(priv_delset(targprivs, PRIV_PROC_FORK)); + VERIFY0(priv_delset(targprivs, PRIV_NET_ACCESS)); + VERIFY0(priv_delset(targprivs, PRIV_FILE_WRITE)); + VERIFY0(priv_delset(targprivs, PRIV_PROC_EXEC)); + VERIFY0(priv_addset(targprivs, PRIV_FILE_DAC_READ)); + + priv_intersect(curprivs, targprivs); + + if (setppriv(PRIV_SET, PRIV_EFFECTIVE, targprivs) != 0) { + err(EXIT_FAILURE, "failed to reduce privileges"); + } + + priv_freeset(curprivs); + priv_freeset(targprivs); +} + +static int +pcidb_usage(const char *fmt, ...) +{ + if (fmt != NULL) { + va_list ap; + + (void) fprintf(stderr, "%s: ", pcidb_progname); + va_start(ap, fmt); + (void) vfprintf(stderr, fmt, ap); + va_end(ap); + (void) fprintf(stderr, "\n"); + } + + (void) fprintf(stderr, "usage: %s [-v|-d|-s|-c|-S|-i] [-H]" + "[[-p] [-o <field>[,...]] [<filter>]\n\n" + "\t-v\t\tshow vendor table\n" + "\t-d\t\tshow device table\n" + "\t-s\t\tshow subsystem table\n" + "\t-c\t\tshow class table\n" + "\t-S\t\tshow subclass table\n" + "\t-i\t\tshow programming interface table\n" + "\t-H\t\tdo not output column headers\n" + "\t-p\t\toutput in parsable form\n" + "\t-o field\toutput only specified fields\n\n" + "filters take the form of PCI aliases, e.g. pci8086,1522, " + "pci1028,1f44,s, or\n" + "pciex1022,1480.1462,7c37. Classes can be specified in a similar " + "way, e.g.\npciclass,010802 or pciclass,0403.\n", pcidb_progname); + + return (EXIT_USAGE); +} + +int +main(int argc, char *argv[]) +{ + pcidb_hdl_t *hdl; + int c; + uint_t tablecnt = 0; + pcidb_table_t table = PCIDB_TABLE_NONE; + boolean_t parse = B_FALSE, strcase = B_FALSE; + const char *fields = NULL; + const char *ofmt_fields_str = NULL; + const ofmt_field_t *ofmt_fields = NULL; + ofmt_handle_t ofmt; + ofmt_status_t oferr; + uint_t flags = 0; + pcidb_walk_t walk; + + bzero(&walk, sizeof (walk)); + pcidb_progname = basename(argv[0]); + + pcidb_drop_privs(); + + while ((c = getopt(argc, argv, ":vdscSipo:hH")) != -1) { + switch (c) { + case 'v': + tablecnt++; + table = PCIDB_TABLE_VENDOR; + break; + case 'd': + tablecnt++; + table = PCIDB_TABLE_DEVICE; + break; + case 's': + tablecnt++; + table = PCIDB_TABLE_SUBSYSTEM; + break; + case 'c': + tablecnt++; + table = PCIDB_TABLE_CLASS; + break; + case 'S': + tablecnt++; + table = PCIDB_TABLE_SUBCLASS; + break; + case 'i': + tablecnt++; + table = PCIDB_TABLE_PROGIF; + break; + case 'p': + parse = B_TRUE; + flags |= OFMT_PARSABLE; + break; + case 'o': + fields = optarg; + break; + case 'h': + return (pcidb_usage(NULL)); + case 'H': + flags |= OFMT_NOHEADER; + break; + case ':': + return (pcidb_usage("Option -%c requires an argument", + optopt)); + case '?': + return (pcidb_usage("unknown option: -%c", optopt)); + } + } + + if (tablecnt > 1) { + errx(EXIT_USAGE, "more than one table specified, only one of " + "-v, -d, -s, -c, -S, and -i may be specified"); + } + + if (parse && fields == NULL) { + errx(EXIT_USAGE, "-p requires fields specified with -o"); + } + + argc -= optind; + argv += optind; + + pcidb_process_filters(argc, argv, &walk); + + switch (table) { + case PCIDB_TABLE_VENDOR: + ofmt_fields = pcidb_vendor_ofmt; + ofmt_fields_str = pcidb_vendor_fields; + break; + case PCIDB_TABLE_NONE: + case PCIDB_TABLE_DEVICE: + ofmt_fields = pcidb_device_ofmt; + ofmt_fields_str = pcidb_device_fields; + break; + case PCIDB_TABLE_SUBSYSTEM: + ofmt_fields = pcidb_subsystem_ofmt; + ofmt_fields_str = pcidb_subsystem_fields; + break; + case PCIDB_TABLE_CLASS: + ofmt_fields = pcidb_class_ofmt; + ofmt_fields_str = pcidb_class_fields; + break; + case PCIDB_TABLE_SUBCLASS: + ofmt_fields = pcidb_subclass_ofmt; + ofmt_fields_str = pcidb_subclass_fields; + break; + case PCIDB_TABLE_PROGIF: + ofmt_fields = pcidb_progif_ofmt; + ofmt_fields_str = pcidb_progif_fields; + break; + } + + if (fields == NULL) { + fields = ofmt_fields_str; + } + + oferr = ofmt_open(fields, ofmt_fields, flags, 0, &ofmt); + ofmt_check(oferr, parse, ofmt, pcidb_ofmt_errx, warnx); + + hdl = pcidb_open(PCIDB_VERSION); + if (hdl == NULL) { + err(EXIT_FAILURE, "failed to initialize PCI IDs database"); + } + + walk.pw_hdl = hdl; + walk.pw_ofmt = ofmt; + walk.pw_strcase = strcase; + + switch (table) { + case PCIDB_TABLE_VENDOR: + pcidb_walk_vendors(&walk); + break; + case PCIDB_TABLE_NONE: + case PCIDB_TABLE_DEVICE: + pcidb_walk_devices(&walk); + break; + case PCIDB_TABLE_SUBSYSTEM: + pcidb_walk_subsystems(&walk); + break; + case PCIDB_TABLE_CLASS: + pcidb_walk_classes(&walk); + break; + case PCIDB_TABLE_SUBCLASS: + pcidb_walk_subclasses(&walk); + break; + case PCIDB_TABLE_PROGIF: + pcidb_walk_progifs(&walk); + break; + } + + ofmt_close(ofmt); + pcidb_close(hdl); + return (EXIT_SUCCESS); +} diff --git a/usr/src/lib/libpcidb/Makefile.com b/usr/src/lib/libpcidb/Makefile.com index 43a327423b..96ff944ad5 100644 --- a/usr/src/lib/libpcidb/Makefile.com +++ b/usr/src/lib/libpcidb/Makefile.com @@ -24,7 +24,7 @@ LIBRARY = libpcidb.a VERS = .1 -OBJECTS = pcidb.o +OBJECTS = pcidb.o list.o include ../../Makefile.lib @@ -33,11 +33,16 @@ LIBS = $(DYNLIB) SRCDIR = ../common LDLIBS += -lc +CSTD = $(CSTD_GNU99) .KEEP_STATE: all: $(LIBS) +pics/%.o: $(SRC)/common/list/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + include ../../Makefile.targ diff --git a/usr/src/lib/libpcidb/common/mapfile-vers b/usr/src/lib/libpcidb/common/mapfile-vers index 509778b0e8..8c17896938 100644 --- a/usr/src/lib/libpcidb/common/mapfile-vers +++ b/usr/src/lib/libpcidb/common/mapfile-vers @@ -20,6 +20,7 @@ # # # Copyright (c) 2012 Joyent, Inc. All rights reserved. +# Copyright 2021 Oxide Computer Company # # @@ -40,30 +41,47 @@ $mapfile_version 2 SYMBOL_VERSION SUNWprivate { global: - pcidb_open; + pcidb_class_code; + pcidb_class_iter_next; + pcidb_class_iter; + pcidb_class_name; pcidb_close; - pcidb_lookup_vendor; - pcidb_vendor_iter; - pcidb_vendor_iter_next; - pcidb_vendor_name; - pcidb_vendor_id; - pcidb_lookup_device; - pcidb_lookup_device_by_vendor; - pcidb_device_iter; + pcidb_device_id; pcidb_device_iter_next; + pcidb_device_iter; pcidb_device_name; - pcidb_device_id; pcidb_device_vendor; + pcidb_lookup_class; + pcidb_lookup_device_by_vendor; + pcidb_lookup_device; + pcidb_lookup_progif_by_subclass; + pcidb_lookup_progif; + pcidb_lookup_subclass_by_class; + pcidb_lookup_subclass; + pcidb_lookup_subvd_by_device; + pcidb_lookup_subvd_by_vendor; pcidb_lookup_subvd; - pcidb_lookup_subvd_by_vendor; - pcidb_lookup_subvd_by_device; - pcidb_subvd_iter; + pcidb_lookup_vendor; + pcidb_open; + pcidb_progif_code; + pcidb_progif_iter_next; + pcidb_progif_iter; + pcidb_progif_name; + pcidb_subclass_code; + pcidb_subclass_iter_next; + pcidb_subclass_iter; + pcidb_subclass_name; + pcidb_subvd_device; pcidb_subvd_iter_next; + pcidb_subvd_iter; pcidb_subvd_name; - pcidb_subvd_svid; pcidb_subvd_sdid; - pcidb_subvd_device; + pcidb_subvd_svid; pcidb_subvd_vendor; + pcidb_vendor_id; + pcidb_vendor_iter_next; + pcidb_vendor_iter; + pcidb_vendor_name; local: *; }; diff --git a/usr/src/lib/libpcidb/common/pcidb.c b/usr/src/lib/libpcidb/common/pcidb.c index 37bfc75f06..bac836f256 100644 --- a/usr/src/lib/libpcidb/common/pcidb.c +++ b/usr/src/lib/libpcidb/common/pcidb.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2012, Joyent, Inc. All rights reserved. + * Copyright 2021 Oxide Computer Company */ /* @@ -57,201 +58,232 @@ #include <string.h> #include <assert.h> #include <unistd.h> +#include <stddef.h> +#include <sys/list.h> #include "pcidb.h" #define PCI_NAME_MAX 256 #define PCI_READLINE 1024 -/* Forward declarations */ -struct pcidb_vendor; -struct pcidb_device; -struct pcidb_subvd; +struct pcidb_progif { + char pp_name[PCI_NAME_MAX]; + list_node_t pp_link; + pcidb_subclass_t *pp_subclass; + uint8_t pp_code; +}; + +struct pcidb_subclass { + char psc_name[PCI_NAME_MAX]; + list_node_t psc_link; + list_t psc_progifs; + pcidb_class_t *psc_class; + uint8_t psc_code; +}; + +struct pcidb_class { + char pc_name[PCI_NAME_MAX]; + list_node_t pc_link; + list_t pc_subclass; + pcidb_hdl_t *pc_hdl; + uint8_t pc_code; +}; struct pcidb_subvd { - uint16_t ps_vid; - uint16_t ps_did; - char ps_name[PCI_NAME_MAX]; - struct pcidb_subvd *ps_prev; - struct pcidb_subvd *ps_next; - struct pcidb_device *ps_dev; - struct pcidb_vendor *ps_vend; + uint16_t ps_vid; + uint16_t ps_did; + char ps_name[PCI_NAME_MAX]; + list_node_t ps_link; + pcidb_device_t *ps_dev; + pcidb_vendor_t *ps_vend; }; struct pcidb_device { - uint16_t pd_id; - char pd_name[PCI_NAME_MAX]; - struct pcidb_subvd *pd_sstart; - struct pcidb_subvd *pd_send; - struct pcidb_device *pd_next; - struct pcidb_device *pd_prev; - struct pcidb_vendor *pd_vend; + uint16_t pd_id; + char pd_name[PCI_NAME_MAX]; + list_t pd_subs; + list_node_t pd_link; + pcidb_vendor_t *pd_vend; }; struct pcidb_vendor { - uint16_t pv_id; - char pv_name[PCI_NAME_MAX]; - struct pcidb_device *pv_dstart; - struct pcidb_device *pv_dend; - struct pcidb_vendor *pv_prev; - struct pcidb_vendor *pv_next; + uint16_t pv_id; + char pv_name[PCI_NAME_MAX]; + list_t pv_devs; + list_node_t pv_link; + pcidb_hdl_t *pv_hdl; }; struct pcidb_hdl { - pcidb_vendor_t *ph_vstart; - pcidb_vendor_t *ph_vend; + list_t ph_vendors; + list_t ph_classes; }; typedef enum pcidb_parse { + PDB_INIT, PDB_VENDOR, PDB_DEVICE, - PDB_SUBDEV + PDB_SUBDEV, + PDB_CLASS, + PDB_SUBCLASS, + PDB_PROGIF } pcidb_parse_t; static const char *pci_db = "/usr/share/hwdata/pci.ids"; -static void -pcihdl_add_vendor(pcidb_hdl_t *hdl, pcidb_vendor_t *v) -{ - if (hdl->ph_vstart == NULL && hdl->ph_vend == NULL) { - hdl->ph_vstart = v; - hdl->ph_vend = v; - v->pv_prev = NULL; - v->pv_next = NULL; - } else { - v->pv_prev = hdl->ph_vend; - v->pv_next = NULL; - hdl->ph_vend->pv_next = v; - hdl->ph_vend = v; - } -} - static pcidb_vendor_t * parse_vendor(char *buf, pcidb_hdl_t *hdl) { - pcidb_vendor_t *v; - size_t len; + pcidb_vendor_t *vend; - v = malloc(sizeof (pcidb_vendor_t)); - if (v == NULL) + vend = malloc(sizeof (pcidb_vendor_t)); + if (vend == NULL) return (NULL); - pcihdl_add_vendor(hdl, v); - v->pv_dstart = NULL; - v->pv_dend = NULL; + list_create(&vend->pv_devs, sizeof (pcidb_device_t), + offsetof(pcidb_device_t, pd_link)); + vend->pv_hdl = hdl; + list_insert_tail(&hdl->ph_vendors, vend); buf[4] = '\0'; - v->pv_id = strtol(buf, NULL, 16); + vend->pv_id = strtol(buf, NULL, 16); buf += 6; - len = strlen(buf); - if (buf[len-1] == '\n') - buf[len-1] = '\0'; - (void) strlcpy(v->pv_name, buf, PCI_NAME_MAX); + (void) strlcpy(vend->pv_name, buf, PCI_NAME_MAX); - return (v); -} - -static void -insert_device(pcidb_vendor_t *v, pcidb_device_t *d) -{ - d->pd_vend = v; - if (v->pv_dstart == NULL && v->pv_dend == NULL) { - v->pv_dstart = d; - v->pv_dend = d; - d->pd_next = NULL; - d->pd_prev = NULL; - } else { - d->pd_prev = v->pv_dend; - d->pd_next = NULL; - v->pv_dend->pd_next = d; - v->pv_dend = d; - } + return (vend); } static pcidb_device_t * -parse_device(char *buf, pcidb_vendor_t *v) +parse_device(char *buf, pcidb_vendor_t *vend) { - pcidb_device_t *d; - size_t len; + pcidb_device_t *dev; - d = malloc(sizeof (pcidb_device_t)); - if (d == NULL) - return (d); + dev = malloc(sizeof (pcidb_device_t)); + if (dev == NULL) + return (dev); - d->pd_sstart = NULL; - d->pd_send = NULL; - insert_device(v, d); + list_create(&dev->pd_subs, sizeof (pcidb_subvd_t), + offsetof(pcidb_subvd_t, ps_link)); + dev->pd_vend = vend; + list_insert_tail(&vend->pv_devs, dev); buf++; buf[4] = '\0'; - d->pd_id = strtol(buf, NULL, 16); + dev->pd_id = strtol(buf, NULL, 16); buf += 6; - len = strlen(buf); - if (buf[len-1] == '\n') - buf[len-1] = '\0'; - - (void) strlcpy(d->pd_name, buf, PCI_NAME_MAX); - return (d); -} - -static void -insert_subdev(pcidb_device_t *d, pcidb_subvd_t *s) -{ - s->ps_dev = d; - s->ps_vend = d->pd_vend; - if (d->pd_sstart == NULL) { - d->pd_sstart = s; - d->pd_send = s; - s->ps_prev = NULL; - s->ps_next = NULL; - } else { - s->ps_prev = d->pd_send; - s->ps_next = NULL; - d->pd_send->ps_next = s; - d->pd_send = s; - } + + (void) strlcpy(dev->pd_name, buf, PCI_NAME_MAX); + return (dev); } static pcidb_subvd_t * -parse_subdev(char *buf, pcidb_device_t *d) +parse_subdev(char *buf, pcidb_device_t *dev) { - pcidb_subvd_t *s; - size_t len; + pcidb_subvd_t *sub; - s = malloc(sizeof (pcidb_subvd_t)); - if (s == NULL) + sub = malloc(sizeof (pcidb_subvd_t)); + if (sub == NULL) return (NULL); - insert_subdev(d, s); + + sub->ps_dev = dev; + sub->ps_vend = dev->pd_vend; + list_insert_tail(&dev->pd_subs, sub); buf += 2; buf[4] = '\0'; - s->ps_vid = strtol(buf, NULL, 16); + sub->ps_vid = strtol(buf, NULL, 16); buf += 5; buf[4] = '\0'; - s->ps_did = strtol(buf, NULL, 16); + sub->ps_did = strtol(buf, NULL, 16); buf += 6; - len = strlen(buf); - if (buf[len-1] == '\n') - buf[len-1] = '\0'; + (void) strlcpy(sub->ps_name, buf, PCI_NAME_MAX); + + return (sub); +} + +static pcidb_class_t * +pcidb_parse_class(char *buf, pcidb_hdl_t *hdl) +{ + pcidb_class_t *class; + + class = malloc(sizeof (pcidb_class_t)); + if (class == NULL) + return (NULL); + + list_create(&class->pc_subclass, sizeof (pcidb_subclass_t), + offsetof(pcidb_subclass_t, psc_link)); + class->pc_hdl = hdl; + list_insert_tail(&hdl->ph_classes, class); + + buf += 2; + buf[3] = '\0'; + class->pc_code = strtol(buf, NULL, 16); + buf += 4; + (void) strlcpy(class->pc_name, buf, PCI_NAME_MAX); + + return (class); +} + +static pcidb_subclass_t * +pcidb_parse_subclass(char *buf, pcidb_class_t *class) +{ + pcidb_subclass_t *sub; + + sub = malloc(sizeof (pcidb_subclass_t)); + if (sub == NULL) + return (NULL); + + list_create(&sub->psc_progifs, sizeof (pcidb_progif_t), + offsetof(pcidb_progif_t, pp_link)); + sub->psc_class = class; + list_insert_tail(&class->pc_subclass, sub); + + buf++; + buf[3] = '\0'; + sub->psc_code = strtol(buf, NULL, 16); + buf += 4; + (void) strlcpy(sub->psc_name, buf, PCI_NAME_MAX); + + return (sub); +} + +static pcidb_progif_t * +pcidb_parse_progif(char *buf, pcidb_subclass_t *sub) +{ + pcidb_progif_t *prog; + + prog = malloc(sizeof (pcidb_progif_t)); + if (prog == NULL) { + return (NULL); + } + + prog->pp_subclass = sub; + list_insert_tail(&sub->psc_progifs, prog); - (void) strlcpy(s->ps_name, buf, PCI_NAME_MAX); + buf += 2; + buf[3] = '\0'; + prog->pp_code = strtol(buf, NULL, 16); + buf += 4; + (void) strlcpy(prog->pp_name, buf, PCI_NAME_MAX); - return (s); + return (prog); } static int readline(FILE *f, char *buf, size_t len) { for (;;) { + char *c; + if (fgets(buf, len, f) == NULL) return (-1); - if (buf[0] == 'C') - return (-1); + if ((c = strchr(buf, '\n')) != NULL) + *c = '\0'; - if (buf[0] != '#' && buf[0] != '\n') + if (buf[0] != '#' && buf[0] != '\0') return (0); } } @@ -259,12 +291,15 @@ readline(FILE *f, char *buf, size_t len) static int parse_db(FILE *f, pcidb_hdl_t *hdl) { - char buf[1024]; - pcidb_vendor_t *v = NULL; - pcidb_device_t *d = NULL; - pcidb_parse_t state = PDB_VENDOR; + pcidb_vendor_t *vend = NULL; + pcidb_device_t *dev = NULL; + pcidb_class_t *class = NULL; + pcidb_subclass_t *sub = NULL; + pcidb_parse_t state = PDB_INIT; for (;;) { + char buf[1024]; + errno = 0; if (readline(f, buf, sizeof (buf)) != 0) { if (errno != 0) @@ -275,15 +310,26 @@ parse_db(FILE *f, pcidb_hdl_t *hdl) newstate: switch (state) { + case PDB_INIT: + vend = NULL; + dev = NULL; + class = NULL; + sub = NULL; + if (buf[0] == 'C') { + state = PDB_CLASS; + } else { + state = PDB_VENDOR; + } + goto newstate; case PDB_VENDOR: - v = parse_vendor(buf, hdl); - if (v == NULL) - return (0); + vend = parse_vendor(buf, hdl); + if (vend == NULL) + return (-1); state = PDB_DEVICE; - continue; + break; case PDB_DEVICE: if (buf[0] != '\t') { - state = PDB_VENDOR; + state = PDB_INIT; goto newstate; } @@ -292,14 +338,14 @@ newstate: goto newstate; } - assert(v != NULL); - d = parse_device(buf, v); - if (d == NULL) + assert(vend != NULL); + dev = parse_device(buf, vend); + if (dev == NULL) return (0); - continue; + break; case PDB_SUBDEV: if (buf[0] != '\t') { - state = PDB_VENDOR; + state = PDB_INIT; goto newstate; } @@ -309,8 +355,48 @@ newstate: } assert(buf[0] == '\t' && buf[1] == '\t'); - assert(d != NULL); - (void) parse_subdev(buf, d); + assert(dev != NULL); + if (parse_subdev(buf, dev) == NULL) { + return (-1); + } + break; + case PDB_CLASS: + class = pcidb_parse_class(buf, hdl); + state = PDB_SUBCLASS; + break; + case PDB_SUBCLASS: + if (buf[0] != '\t') { + state = PDB_INIT; + goto newstate; + } + + if (buf[1] == '\t') { + state = PDB_PROGIF; + goto newstate; + } + + assert(class != NULL); + sub = pcidb_parse_subclass(buf, class); + if (sub == NULL) { + return (-1); + } + break; + case PDB_PROGIF: + if (buf[0] != '\t') { + state = PDB_INIT; + goto newstate; + } + + if (buf[0] == '\t' && buf[1] != '\t') { + state = PDB_SUBCLASS; + goto newstate; + } + + assert(sub != NULL); + if (pcidb_parse_progif(buf, sub) == NULL) { + return (-1); + } + break; } } } @@ -330,8 +416,10 @@ pcidb_open(int version) if (h == NULL) return (NULL); - h->ph_vstart = NULL; - h->ph_vend = NULL; + list_create(&h->ph_vendors, sizeof (pcidb_vendor_t), + offsetof(pcidb_vendor_t, pv_link)); + list_create(&h->ph_classes, sizeof (pcidb_class_t), + offsetof(pcidb_class_t, pc_link)); f = fopen(pci_db, "rF"); if (f == NULL) { @@ -342,7 +430,6 @@ pcidb_open(int version) if (parse_db(f, h) < 0) { (void) fclose(f); pcidb_close(h); - free(h); return (NULL); } @@ -352,36 +439,51 @@ pcidb_open(int version) } void -pcidb_close(pcidb_hdl_t *h) +pcidb_close(pcidb_hdl_t *hdl) { - pcidb_vendor_t *v, *tv; + pcidb_vendor_t *vend; + pcidb_class_t *class; - pcidb_device_t *d, *td; - pcidb_subvd_t *s, *ts; - - if (h == NULL) + if (hdl == NULL) return; - v = h->ph_vstart; - while (v != NULL) { - d = v->pv_dstart; - while (d != NULL) { - s = d->pd_sstart; - while (s != NULL) { - ts = s; - s = s->ps_next; - free(ts); + while ((vend = list_remove_head(&hdl->ph_vendors)) != NULL) { + pcidb_device_t *dev; + + while ((dev = list_remove_head(&vend->pv_devs)) != NULL) { + pcidb_subvd_t *sub; + + while ((sub = list_remove_head(&dev->pd_subs)) != + NULL) { + free(sub); + } + list_destroy(&dev->pd_subs); + free(dev); + } + list_destroy(&vend->pv_devs); + free(vend); + } + list_destroy(&hdl->ph_vendors); + + while ((class = list_remove_head(&hdl->ph_classes)) != NULL) { + pcidb_subclass_t *sub; + + while ((sub = list_remove_head(&class->pc_subclass)) != NULL) { + pcidb_progif_t *prog; + + while ((prog = list_remove_head(&sub->psc_progifs)) != + NULL) { + free(prog); } - td = d; - d = d->pd_next; - free(td); + list_destroy(&sub->psc_progifs); + free(sub); } - tv = v; - v = v->pv_next; - free(tv); + list_destroy(&class->pc_subclass); + free(class); } + list_destroy(&hdl->ph_classes); - free(h); + free(hdl); } pcidb_vendor_t * @@ -389,7 +491,8 @@ pcidb_lookup_vendor(pcidb_hdl_t *hdl, uint16_t id) { pcidb_vendor_t *v; - for (v = hdl->ph_vstart; v != NULL; v = v->pv_next) { + for (v = list_head(&hdl->ph_vendors); v != NULL; + v = list_next(&hdl->ph_vendors, v)) { if (v->pv_id == id) return (v); } @@ -398,165 +501,307 @@ pcidb_lookup_vendor(pcidb_hdl_t *hdl, uint16_t id) } const char * -pcidb_vendor_name(pcidb_vendor_t *v) +pcidb_vendor_name(pcidb_vendor_t *vend) { - return (v->pv_name); + return (vend->pv_name); } uint16_t -pcidb_vendor_id(pcidb_vendor_t *v) +pcidb_vendor_id(pcidb_vendor_t *vend) { - return (v->pv_id); + return (vend->pv_id); } pcidb_vendor_t * -pcidb_vendor_iter(pcidb_hdl_t *h) +pcidb_vendor_iter(pcidb_hdl_t *hdl) { - return (h->ph_vstart); + return (list_head(&hdl->ph_vendors)); } pcidb_vendor_t * -pcidb_vendor_iter_next(pcidb_vendor_t *v) +pcidb_vendor_iter_next(pcidb_vendor_t *vend) { - assert(v != NULL); - return (v->pv_next); + assert(vend != NULL); + return (list_next(&vend->pv_hdl->ph_vendors, vend)); } pcidb_device_t * -pcidb_lookup_device_by_vendor(pcidb_vendor_t *v, uint16_t id) +pcidb_lookup_device_by_vendor(pcidb_vendor_t *vend, uint16_t id) { - pcidb_device_t *d; - assert(v != NULL); + assert(vend != NULL); - for (d = v->pv_dstart; d != NULL; d = d->pd_next) - if (d->pd_id == id) - return (d); + for (pcidb_device_t *dev = list_head(&vend->pv_devs); dev != NULL; + dev = list_next(&vend->pv_devs, dev)) { + if (dev->pd_id == id) + return (dev); + } return (NULL); } pcidb_device_t * -pcidb_lookup_device(pcidb_hdl_t *h, uint16_t vid, uint16_t did) +pcidb_lookup_device(pcidb_hdl_t *hdl, uint16_t vid, uint16_t did) { - pcidb_vendor_t *v; + pcidb_vendor_t *vend; - v = pcidb_lookup_vendor(h, vid); - if (v == NULL) + vend = pcidb_lookup_vendor(hdl, vid); + if (vend == NULL) return (NULL); - return (pcidb_lookup_device_by_vendor(v, did)); + return (pcidb_lookup_device_by_vendor(vend, did)); } pcidb_device_t * -pcidb_device_iter(pcidb_vendor_t *v) +pcidb_device_iter(pcidb_vendor_t *vend) { - return (v->pv_dstart); + return (list_head(&vend->pv_devs)); } pcidb_device_t * -pcidb_device_iter_next(pcidb_device_t *d) +pcidb_device_iter_next(pcidb_device_t *dev) { - return (d->pd_next); + return (list_next(&dev->pd_vend->pv_devs, dev)); } const char * -pcidb_device_name(pcidb_device_t *d) +pcidb_device_name(pcidb_device_t *dev) { - return (d->pd_name); + return (dev->pd_name); } uint16_t -pcidb_device_id(pcidb_device_t *d) +pcidb_device_id(pcidb_device_t *dev) { - return (d->pd_id); + return (dev->pd_id); } pcidb_vendor_t * -pcidb_device_vendor(pcidb_device_t *d) +pcidb_device_vendor(pcidb_device_t *dev) { - return (d->pd_vend); + return (dev->pd_vend); } pcidb_subvd_t * -pcidb_lookup_subvd_by_device(pcidb_device_t *d, uint16_t svid, uint16_t sdid) +pcidb_lookup_subvd_by_device(pcidb_device_t *dev, uint16_t svid, uint16_t sdid) { - pcidb_subvd_t *s; + pcidb_subvd_t *sub; - assert(d != NULL); + assert(dev != NULL); - for (s = d->pd_sstart; s != NULL; s = s->ps_next) - if (s->ps_vid == svid && s->ps_did == sdid) - return (s); + for (sub = list_head(&dev->pd_subs); sub != NULL; + sub = list_next(&dev->pd_subs, sub)) { + if (sub->ps_vid == svid && sub->ps_did == sdid) + return (sub); + } return (NULL); } pcidb_subvd_t * -pcidb_lookup_subvd_by_vendor(pcidb_vendor_t *v, uint16_t devid, uint16_t svid, - uint16_t sdid) +pcidb_lookup_subvd_by_vendor(pcidb_vendor_t *vend, uint16_t devid, + uint16_t svid, uint16_t sdid) { - pcidb_device_t *d; + pcidb_device_t *dev; - assert(v != NULL); - d = pcidb_lookup_device_by_vendor(v, devid); - if (d == NULL) + assert(vend != NULL); + dev = pcidb_lookup_device_by_vendor(vend, devid); + if (dev == NULL) return (NULL); - return (pcidb_lookup_subvd_by_device(d, svid, sdid)); + return (pcidb_lookup_subvd_by_device(dev, svid, sdid)); } pcidb_subvd_t * -pcidb_lookup_subvd(pcidb_hdl_t *h, uint16_t vid, uint16_t did, uint16_t svid, +pcidb_lookup_subvd(pcidb_hdl_t *hdl, uint16_t vid, uint16_t did, uint16_t svid, uint16_t sdid) { - pcidb_device_t *d; + pcidb_device_t *dev; - assert(h != NULL); - d = pcidb_lookup_device(h, vid, did); - if (d == NULL) + assert(hdl != NULL); + dev = pcidb_lookup_device(hdl, vid, did); + if (dev == NULL) return (NULL); - return (pcidb_lookup_subvd_by_device(d, svid, sdid)); + return (pcidb_lookup_subvd_by_device(dev, svid, sdid)); } pcidb_subvd_t * -pcidb_subvd_iter(pcidb_device_t *d) +pcidb_subvd_iter(pcidb_device_t *dev) { - return (d->pd_sstart); + return (list_head(&dev->pd_subs)); } pcidb_subvd_t * -pcidb_subvd_iter_next(pcidb_subvd_t *s) +pcidb_subvd_iter_next(pcidb_subvd_t *sub) { - return (s->ps_next); + return (list_next(&sub->ps_dev->pd_subs, sub)); } const char * -pcidb_subvd_name(pcidb_subvd_t *s) +pcidb_subvd_name(pcidb_subvd_t *sub) { - return (s->ps_name); + return (sub->ps_name); } uint16_t -pcidb_subvd_svid(pcidb_subvd_t *s) +pcidb_subvd_svid(pcidb_subvd_t *sub) { - return (s->ps_vid); + return (sub->ps_vid); } uint16_t -pcidb_subvd_sdid(pcidb_subvd_t *s) +pcidb_subvd_sdid(pcidb_subvd_t *sub) { - return (s->ps_did); + return (sub->ps_did); } pcidb_device_t * -pcidb_subvd_device(pcidb_subvd_t *s) +pcidb_subvd_device(pcidb_subvd_t *sub) { - return (s->ps_dev); + return (sub->ps_dev); } pcidb_vendor_t * -pcidb_subvd_vendor(pcidb_subvd_t *s) +pcidb_subvd_vendor(pcidb_subvd_t *sub) +{ + return (sub->ps_vend); +} + + +pcidb_class_t * +pcidb_lookup_class(pcidb_hdl_t *hdl, uint8_t code) +{ + for (pcidb_class_t *class = list_head(&hdl->ph_classes); class != NULL; + class = list_next(&hdl->ph_classes, class)) { + if (class->pc_code == code) { + return (class); + } + } + + return (NULL); +} + +pcidb_class_t * +pcidb_class_iter(pcidb_hdl_t *hdl) +{ + return (list_head(&hdl->ph_classes)); +} + +pcidb_class_t * +pcidb_class_iter_next(pcidb_class_t *class) +{ + return (list_next(&class->pc_hdl->ph_classes, class)); +} + +const char * +pcidb_class_name(pcidb_class_t *class) +{ + return (class->pc_name); +} + +uint8_t +pcidb_class_code(pcidb_class_t *class) +{ + return (class->pc_code); +} + +pcidb_subclass_t * +pcidb_lookup_subclass(pcidb_hdl_t *hdl, uint8_t ccode, uint8_t subcode) +{ + pcidb_class_t *class; + + class = pcidb_lookup_class(hdl, ccode); + if (class == NULL) { + return (NULL); + } + + return (pcidb_lookup_subclass_by_class(class, subcode)); +} + +pcidb_subclass_t * +pcidb_lookup_subclass_by_class(pcidb_class_t *class, uint8_t code) +{ + for (pcidb_subclass_t *sub = list_head(&class->pc_subclass); + sub != NULL; sub = list_next(&class->pc_subclass, sub)) { + if (sub->psc_code == code) { + return (sub); + } + } + + return (NULL); +} + +pcidb_subclass_t * +pcidb_subclass_iter(pcidb_class_t *class) +{ + return (list_head(&class->pc_subclass)); +} + +pcidb_subclass_t * +pcidb_subclass_iter_next(pcidb_subclass_t *sub) +{ + return (list_next(&sub->psc_class->pc_subclass, sub)); +} + +const char * +pcidb_subclass_name(pcidb_subclass_t *sub) +{ + return (sub->psc_name); +} + +uint8_t +pcidb_subclass_code(pcidb_subclass_t *sub) +{ + return (sub->psc_code); +} + +pcidb_progif_t * +pcidb_lookup_progif(pcidb_hdl_t *hdl, uint8_t ccode, uint8_t scode, + uint8_t pcode) +{ + pcidb_subclass_t *sub; + + sub = pcidb_lookup_subclass(hdl, ccode, scode); + if (sub == NULL) { + return (NULL); + } + + return (pcidb_lookup_progif_by_subclass(sub, pcode)); +} + +pcidb_progif_t * +pcidb_lookup_progif_by_subclass(pcidb_subclass_t *sub, uint8_t code) +{ + for (pcidb_progif_t *prog = list_head(&sub->psc_progifs); prog != NULL; + prog = list_next(&sub->psc_progifs, prog)) { + if (prog->pp_code == code) { + return (prog); + } + } + + return (NULL); +} + +pcidb_progif_t * +pcidb_progif_iter(pcidb_subclass_t *sub) +{ + return (list_head(&sub->psc_progifs)); +} + +pcidb_progif_t * +pcidb_progif_iter_next(pcidb_progif_t *prog) +{ + return (list_next(&prog->pp_subclass->psc_progifs, prog)); +} + +const char * +pcidb_progif_name(pcidb_progif_t *prog) +{ + return (prog->pp_name); +} + +uint8_t +pcidb_progif_code(pcidb_progif_t *prog) { - return (s->ps_vend); + return (prog->pp_code); } diff --git a/usr/src/lib/libpcidb/common/pcidb.h b/usr/src/lib/libpcidb/common/pcidb.h index a11e4d90f1..0cf0047b26 100644 --- a/usr/src/lib/libpcidb/common/pcidb.h +++ b/usr/src/lib/libpcidb/common/pcidb.h @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2012, Joyent, Inc. All rights reserved. + * Copyright 2021 Oxide Computer Company */ /* @@ -41,6 +42,9 @@ typedef struct pcidb_hdl pcidb_hdl_t; typedef struct pcidb_vendor pcidb_vendor_t; typedef struct pcidb_device pcidb_device_t; typedef struct pcidb_subvd pcidb_subvd_t; +typedef struct pcidb_class pcidb_class_t; +typedef struct pcidb_subclass pcidb_subclass_t; +typedef struct pcidb_progif pcidb_progif_t; extern pcidb_hdl_t *pcidb_open(int); extern void pcidb_close(pcidb_hdl_t *); @@ -77,6 +81,32 @@ extern uint16_t pcidb_subvd_sdid(pcidb_subvd_t *); extern pcidb_device_t *pcidb_subvd_device(pcidb_subvd_t *); extern pcidb_vendor_t *pcidb_subvd_vendor(pcidb_subvd_t *); +extern pcidb_class_t *pcidb_lookup_class(pcidb_hdl_t *, uint8_t); +extern pcidb_class_t *pcidb_class_iter(pcidb_hdl_t *); +extern pcidb_class_t *pcidb_class_iter_next(pcidb_class_t *); + +extern const char *pcidb_class_name(pcidb_class_t *); +extern uint8_t pcidb_class_code(pcidb_class_t *); + +extern pcidb_subclass_t *pcidb_lookup_subclass(pcidb_hdl_t *, uint8_t, uint8_t); +extern pcidb_subclass_t *pcidb_lookup_subclass_by_class(pcidb_class_t *, + uint8_t); +extern pcidb_subclass_t *pcidb_subclass_iter(pcidb_class_t *); +extern pcidb_subclass_t *pcidb_subclass_iter_next(pcidb_subclass_t *); + +extern const char *pcidb_subclass_name(pcidb_subclass_t *); +extern uint8_t pcidb_subclass_code(pcidb_subclass_t *); + +extern pcidb_progif_t *pcidb_lookup_progif(pcidb_hdl_t *, uint8_t, uint8_t, + uint8_t); +extern pcidb_progif_t *pcidb_lookup_progif_by_subclass(pcidb_subclass_t *, + uint8_t); +extern pcidb_progif_t *pcidb_progif_iter(pcidb_subclass_t *); +extern pcidb_progif_t *pcidb_progif_iter_next(pcidb_progif_t *); + +extern const char *pcidb_progif_name(pcidb_progif_t *); +extern uint8_t pcidb_progif_code(pcidb_progif_t *); + #ifdef __cplusplus } #endif diff --git a/usr/src/pkg/manifests/diagnostic-pci.mf b/usr/src/pkg/manifests/diagnostic-pci.mf new file mode 100644 index 0000000000..c666862ebd --- /dev/null +++ b/usr/src/pkg/manifests/diagnostic-pci.mf @@ -0,0 +1,26 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2021 Oxide Computer Company +# + +set name=pkg.fmri value=pkg:/diagnostic/pci@$(PKGVERS) +set name=pkg.description value="PCI Utilities" +set name=pkg.summary value="PCI Utilities" +set name=info.classification \ + value="org.opensolaris.category.2008:Applications/System Utilities" +set name=variant.arch value=$(ARCH) +dir path=usr group=sys +dir path=usr/lib +dir path=usr/lib/pci +file path=usr/lib/pci/pcidb mode=0555 +license lic_CDDL license=lic_CDDL diff --git a/usr/src/pkg/manifests/system-test-utiltest.mf b/usr/src/pkg/manifests/system-test-utiltest.mf index 96a71c9d33..0e68abbe97 100644 --- a/usr/src/pkg/manifests/system-test-utiltest.mf +++ b/usr/src/pkg/manifests/system-test-utiltest.mf @@ -1675,6 +1675,7 @@ file path=opt/util-tests/tests/mdb/typedef/tst.union.mdb mode=0444 file path=opt/util-tests/tests/mdb/typedef/tst.union.mdb.out mode=0444 file path=opt/util-tests/tests/mergeq/mqt mode=0555 file path=opt/util-tests/tests/mergeq/wqt mode=0555 +file path=opt/util-tests/tests/pcidbtest mode=0555 file path=opt/util-tests/tests/printf_test mode=0555 file path=opt/util-tests/tests/sed/multi_test mode=0555 file path=opt/util-tests/tests/sed/regress.multitest.out/1.1 mode=0444 @@ -1823,6 +1824,7 @@ license usr/src/test/util-tests/tests/demangle/THIRDPARTYLICENSE.rust \ license=usr/src/test/util-tests/tests/demangle/THIRDPARTYLICENSE.rust license usr/src/test/util-tests/tests/sed/bsd/THIRDPARTYLICENSE \ license=usr/src/test/util-tests/tests/sed/bsd/THIRDPARTYLICENSE +depend fmri=diagnostic/pci type=require depend fmri=locale/de type=require depend fmri=system/library/iconv/utf-8 type=require depend fmri=system/test/testrunner type=require diff --git a/usr/src/test/util-tests/runfiles/default.run b/usr/src/test/util-tests/runfiles/default.run index 83e55604de..578fa8b6c7 100644 --- a/usr/src/test/util-tests/runfiles/default.run +++ b/usr/src/test/util-tests/runfiles/default.run @@ -81,3 +81,5 @@ tests = ['custr_remove', 'custr_trunc'] [/opt/util-tests/tests/sed] tests = ['sed_addr', 'multi_test'] + +[/opt/util-tests/tests/pcidbtest] diff --git a/usr/src/test/util-tests/tests/Makefile b/usr/src/test/util-tests/tests/Makefile index 46c29b416c..41d692ff1b 100644 --- a/usr/src/test/util-tests/tests/Makefile +++ b/usr/src/test/util-tests/tests/Makefile @@ -20,6 +20,6 @@ SUBDIRS = date dis dladm iconv libnvpair_json libsff printf xargs grep_xpg4 SUBDIRS += demangle mergeq workq chown ctf smbios libjedec awk make sleep -SUBDIRS += libcustr find mdb sed head +SUBDIRS += libcustr find mdb sed head pcidb include $(SRC)/test/Makefile.com diff --git a/usr/src/test/util-tests/tests/pcidb/Makefile b/usr/src/test/util-tests/tests/pcidb/Makefile new file mode 100644 index 0000000000..362f26a277 --- /dev/null +++ b/usr/src/test/util-tests/tests/pcidb/Makefile @@ -0,0 +1,36 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2021 Oxide Computer Company +# + +include $(SRC)/cmd/Makefile.cmd +include $(SRC)/test/Makefile.com + +ROOTOPTPKG = $(ROOT)/opt/util-tests/tests +PROG = pcidbtest + +ROOTPROG = $(PROG:%=$(ROOTOPTPKG)/%) + +all: + +install: $(ROOTPROG) + +clobber: clean + +clean: + +$(ROOTOPTPKG): + $(INS.dir) + +$(ROOTOPTPKG)/%: %.ksh $(ROOTOPTPKG) + $(INS.rename) diff --git a/usr/src/test/util-tests/tests/pcidb/pcidbtest.ksh b/usr/src/test/util-tests/tests/pcidb/pcidbtest.ksh new file mode 100644 index 0000000000..6a3cfb2edd --- /dev/null +++ b/usr/src/test/util-tests/tests/pcidb/pcidbtest.ksh @@ -0,0 +1,223 @@ +#!/usr/bin/ksh +# +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2021 Oxide Computer Company +# + +unalias -a +set -o pipefail + +pcidb_arg0="$(basename $0)" +pcidb_prog="/usr/lib/pci/pcidb" +pcidb_exit=0 + +warn() +{ + typeset msg="$*" + [[ -z "$msg" ]] && msg="failed" + echo "TEST FAILED: $pcidb_arg0: $msg" >&2 +} + +# +# The following is intended to catch bad filters. +# +pcidb_bad_filter() +{ + typeset filt="$1" + + if $pcidb_prog $filt 2>/dev/null; then + warn "invalid filter $filt erroneously worked" + pcidb_exit=1 + return + fi + + printf "TEST PASSED: invalid filter %s\n" "$filt" + +} + +pcidb_bad_args() +{ + if $pcidb_prog $@ 2>/dev/null 1>/dev/null; then + warn "should have failed with args "$@", but passed" + pcidb_exit=1 + return + fi + + printf "TEST PASSED: invalid arguments %s\n" "$*" +} + +pcidb_match() +{ + typeset output + typeset match="$1" + shift + + output=$($pcidb_prog $@) + if (( $? != 0)); then + warn "failed to run pcidb with args: $@" + pcidb_exit=1 + return + fi + + if [[ "$output" != "$match" ]]; then + warn "output mismatch with args: $@\n found: $output\n" \ + "expected: $match" + pcidb_exit=1 + return + fi + + printf "TEST PASSED: successfully matched against %s\n" "$*" +} + +if [[ -n $PCIDB ]]; then + pcidb_prog=$PCIDB +fi + +# +# Before we begin execution, set up the environment such that we have a +# standard locale and that umem will help us catch mistakes. +# +export LC_ALL=C.UTF-8 +export LD_PRELOAD=libumem.so +export UMEM_DEBUG=default + +# +# Validate that filters match either exactly one or at least one line of +# output using parsable mode. When we match more than one entry, we +# don't try to assert the count because we expect that it will actually +# change over time. +# +exp="1de +8086" +pcidb_match "$exp" -v -p -o vid pci8086 pci1de +pcidb_match "Advanced Micro Devices, Inc. [AMD]" -v -p -o vendor pci1022 +pcidb_match "1af4:1044:Virtio RNG" -p -o vid,did,device pci1af4,1044 +pcidb_match "Dell:HBA330 Adapter" -s -p -o subvendor,subsystem \ + pci1000,97.1028,1f45 +pcidb_match "c:3:30:XHCI" -i -p -o bcc,scc,pi,interface pciclass,0c0330 +pcidb_match "I2O" -S -p -o subclass pciexclass,0e +pcidb_match "Ethernet 1Gb 2-port 368i Adapter" -s -p -o subsystem pci1590,216,s + +# +# We should get no output when we specify a class or device filter and +# use a different table or we have an over specified filter. +# +pcidb_match "" -d pciclass,03 +pcidb_match "" -S pci1000 +pcidb_match "" -v pci8086,1234 +pcidb_match "" -c pciclass,010802 + +# +# Run through filter parsing +# +pcidb_bad_filter "foo" +pcidb_bad_filter ";ffvi" +pcidb_bad_filter "12345" +pcidb_bad_filter "pc8086" +pcidb_bad_filter "pciqwer" +pcidb_bad_filter "pci12345" +pcidb_bad_filter "pci8086," +pcidb_bad_filter "pci8086,locke" +pcidb_bad_filter "pci8086sigh" +pcidb_bad_filter "pci8086,p" +pcidb_bad_filter "pci8086,12345" +pcidb_bad_filter "pci8086,1234zz" +pcidb_bad_filter "pci8086,1234." +pcidb_bad_filter "pci8086,1234," +pcidb_bad_filter "pci8086,1234,b" +pcidb_bad_filter "pci8086,1234,8" +pcidb_bad_filter "pci8086,1234,wat" +pcidb_bad_filter "pci8086,1234.terra" +pcidb_bad_filter "pci8086,1234.terra,celes" +pcidb_bad_filter "pci8086,1234.fffff" +pcidb_bad_filter "pci8086,1234.abcd," +pcidb_bad_filter "pci8086,1234.abcd." +pcidb_bad_filter "pci8086,1234.abcdqr" +pcidb_bad_filter "pci8086,1234.abcd,2,p" +pcidb_bad_filter "pci8086,1234.abcd,2000000000" +pcidb_bad_filter "pci8086,1234.abcd,kefka" +pcidb_bad_filter "pci8086,1234.abcd,34ultros" +pcidb_bad_filter "pciexqwer" +pcidb_bad_filter "pciex12345" +pcidb_bad_filter "pciex8086," +pcidb_bad_filter "pciex8086,locke" +pcidb_bad_filter "pciex8086sigh" +pcidb_bad_filter "pciex8086,p" +pcidb_bad_filter "pciex8086,12345" +pcidb_bad_filter "pciex8086,1234zz" +pcidb_bad_filter "pciex8086,1234." +pcidb_bad_filter "pciex8086,1234," +pcidb_bad_filter "pciex8086,1234,b" +pcidb_bad_filter "pciex8086,1234,8" +pcidb_bad_filter "pciex8086,1234,wat" +pcidb_bad_filter "pciex8086,1234.terra" +pcidb_bad_filter "pciex8086,1234.terra,celes" +pcidb_bad_filter "pciex8086,1234.fffff" +pcidb_bad_filter "pciex8086,1234.abcd," +pcidb_bad_filter "pciex8086,1234.abcd." +pcidb_bad_filter "pciex8086,1234.abcdqr" +pcidb_bad_filter "pciex8086,1234.abcd,2,p" +pcidb_bad_filter "pciex8086,1234.abcd,2000000000" +pcidb_bad_filter "pciex8086,1234.abcd,kefka" +pcidb_bad_filter "pciex8086,1234.abcd,34ultros" +pcidb_bad_filter "pciclas" +pcidb_bad_filter "pciclassedgar" +pcidb_bad_filter "pciclass,sabin" +pcidb_bad_filter "pciclass,0" +pcidb_bad_filter "pciclass,013" +pcidb_bad_filter "pciclass,01345" +pcidb_bad_filter "pciclass,0134567" +pcidb_bad_filter "pciclass,01," +pcidb_bad_filter "pciclass,010," +pcidb_bad_filter "pciclass,010aa," +pcidb_bad_filter "pciclass,0102as" +pcidb_bad_filter "pciclass,0102.as" +pcidb_bad_filter "pciclass,0102@as" +pcidb_bad_filter "pciclass,010298aa" +pcidb_bad_filter "pciclass,010298," +pcidb_bad_filter "pciclass,010298!" +pcidb_bad_filter "pciclass,010298!shadow" +pcidb_bad_filter "pciexclas" +pcidb_bad_filter "pciexclassedgar" +pcidb_bad_filter "pciexclass,sabin" +pcidb_bad_filter "pciexclass,0" +pcidb_bad_filter "pciexclass,013" +pcidb_bad_filter "pciexclass,01345" +pcidb_bad_filter "pciexclass,0134567" +pcidb_bad_filter "pciexclass,01," +pcidb_bad_filter "pciexclass,010," +pcidb_bad_filter "pciexclass,010aa," +pcidb_bad_filter "pciexclass,0102as" +pcidb_bad_filter "pciexclass,0102.as" +pcidb_bad_filter "pciexclass,0102@as" +pcidb_bad_filter "pciexclass,010298aa" +pcidb_bad_filter "pciexclass,010298," +pcidb_bad_filter "pciexclass,010298!" +pcidb_bad_filter "pciexclass,010298!shadow" + +# +# Verify that if we ask for bad columns we error +# +pcidb_bad_args -p +pcidb_bad_args -o +pcidb_bad_args -o -p +pcidb_bad_args -p -o terra +pcidb_bad_args -p -o subclass -v +pcidb_bad_args -v -d -c + +if (( pcidb_exit == 0 )); then + printf "All tests passed successfully!\n" +fi + +exit $pcidb_exit |
