xref: /illumos-gate/usr/src/cmd/pcidb/pcidb.c (revision 6b1325cf)
18a37ae75SRobert Mustacchi /*
28a37ae75SRobert Mustacchi  * This file and its contents are supplied under the terms of the
38a37ae75SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
48a37ae75SRobert Mustacchi  * You may only use this file in accordance with the terms of version
58a37ae75SRobert Mustacchi  * 1.0 of the CDDL.
68a37ae75SRobert Mustacchi  *
78a37ae75SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
88a37ae75SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
98a37ae75SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
108a37ae75SRobert Mustacchi  */
118a37ae75SRobert Mustacchi 
128a37ae75SRobert Mustacchi /*
138a37ae75SRobert Mustacchi  * Copyright 2021 Oxide Computer Company
148a37ae75SRobert Mustacchi  */
158a37ae75SRobert Mustacchi 
168a37ae75SRobert Mustacchi /*
178a37ae75SRobert Mustacchi  * A tool to interface with the pci.ids database driven by libpcidb.
188a37ae75SRobert Mustacchi  */
198a37ae75SRobert Mustacchi 
208a37ae75SRobert Mustacchi #include <stdio.h>
218a37ae75SRobert Mustacchi #include <stdarg.h>
228a37ae75SRobert Mustacchi #include <pcidb.h>
238a37ae75SRobert Mustacchi #include <err.h>
248a37ae75SRobert Mustacchi #include <libgen.h>
258a37ae75SRobert Mustacchi #include <string.h>
268a37ae75SRobert Mustacchi #include <strings.h>
278a37ae75SRobert Mustacchi #include <stdlib.h>
288a37ae75SRobert Mustacchi #include <ofmt.h>
298a37ae75SRobert Mustacchi #include <errno.h>
308a37ae75SRobert Mustacchi #include <sys/debug.h>
318a37ae75SRobert Mustacchi #include <priv.h>
328a37ae75SRobert Mustacchi 
338a37ae75SRobert Mustacchi #define	EXIT_USAGE	2
348a37ae75SRobert Mustacchi 
358a37ae75SRobert Mustacchi static char *pcidb_progname;
368a37ae75SRobert Mustacchi 
378a37ae75SRobert Mustacchi typedef enum {
388a37ae75SRobert Mustacchi 	PCIDB_MODE_UNKNOWN,
398a37ae75SRobert Mustacchi 	PCIDB_MODE_LIST,
408a37ae75SRobert Mustacchi 	PCIDB_MODE_SEARCH,
418a37ae75SRobert Mustacchi 	PCIDB_MODE_LOOKUP
428a37ae75SRobert Mustacchi } pcidb_mode_t;
438a37ae75SRobert Mustacchi 
448a37ae75SRobert Mustacchi typedef enum {
458a37ae75SRobert Mustacchi 	PCIDB_TABLE_NONE,
468a37ae75SRobert Mustacchi 	PCIDB_TABLE_VENDOR,
478a37ae75SRobert Mustacchi 	PCIDB_TABLE_DEVICE,
488a37ae75SRobert Mustacchi 	PCIDB_TABLE_SUBSYSTEM,
498a37ae75SRobert Mustacchi 	PCIDB_TABLE_CLASS,
508a37ae75SRobert Mustacchi 	PCIDB_TABLE_SUBCLASS,
518a37ae75SRobert Mustacchi 	PCIDB_TABLE_PROGIF
528a37ae75SRobert Mustacchi } pcidb_table_t;
538a37ae75SRobert Mustacchi 
548a37ae75SRobert Mustacchi typedef enum {
558a37ae75SRobert Mustacchi 	PCIDB_OFMT_VID,
568a37ae75SRobert Mustacchi 	PCIDB_OFMT_VENSTR,
578a37ae75SRobert Mustacchi 	PCIDB_OFMT_DID,
588a37ae75SRobert Mustacchi 	PCIDB_OFMT_DEVSTR,
598a37ae75SRobert Mustacchi 	PCIDB_OFMT_SVID,
608a37ae75SRobert Mustacchi 	PCIDB_OFMT_SDID,
618a37ae75SRobert Mustacchi 	PCIDB_OFMT_SUBVENSTR,
628a37ae75SRobert Mustacchi 	PCIDB_OFMT_SUBSYSSTR,
638a37ae75SRobert Mustacchi 	PCIDB_OFMT_BCC,
648a37ae75SRobert Mustacchi 	PCIDB_OFMT_CLASSSTR,
658a37ae75SRobert Mustacchi 	PCIDB_OFMT_SCC,
668a37ae75SRobert Mustacchi 	PCIDB_OFMT_SUBCLASSSTR,
678a37ae75SRobert Mustacchi 	PCIDB_OFMT_PI,
688a37ae75SRobert Mustacchi 	PCIDB_OFMT_PROGIFSTR
698a37ae75SRobert Mustacchi } pcidb_ofmt_t;
708a37ae75SRobert Mustacchi 
718a37ae75SRobert Mustacchi typedef struct pcidb_filter {
728a37ae75SRobert Mustacchi 	uint32_t pft_vend;
738a37ae75SRobert Mustacchi 	uint32_t pft_dev;
748a37ae75SRobert Mustacchi 	uint32_t pft_subven;
758a37ae75SRobert Mustacchi 	uint32_t pft_subdev;
768a37ae75SRobert Mustacchi 	uint32_t pft_class;
778a37ae75SRobert Mustacchi 	uint32_t pft_subclass;
788a37ae75SRobert Mustacchi 	uint32_t pft_progif;
798a37ae75SRobert Mustacchi } pcidb_filter_t;
808a37ae75SRobert Mustacchi 
818a37ae75SRobert Mustacchi #define	PCIDB_NOFILTER	UINT32_MAX
828a37ae75SRobert Mustacchi 
838a37ae75SRobert Mustacchi typedef struct pcidb_walk {
848a37ae75SRobert Mustacchi 	pcidb_hdl_t *pw_hdl;
858a37ae75SRobert Mustacchi 	ofmt_handle_t pw_ofmt;
868a37ae75SRobert Mustacchi 	pcidb_vendor_t *pw_vendor;
878a37ae75SRobert Mustacchi 	pcidb_device_t *pw_device;
888a37ae75SRobert Mustacchi 	pcidb_subvd_t *pw_subvd;
898a37ae75SRobert Mustacchi 	pcidb_class_t *pw_class;
908a37ae75SRobert Mustacchi 	pcidb_subclass_t *pw_subclass;
918a37ae75SRobert Mustacchi 	pcidb_progif_t *pw_progif;
928a37ae75SRobert Mustacchi 	boolean_t pw_strcase;
938a37ae75SRobert Mustacchi 	uint_t pw_nfilters;
948a37ae75SRobert Mustacchi 	pcidb_filter_t *pw_filters;
958a37ae75SRobert Mustacchi } pcidb_walk_t;
968a37ae75SRobert Mustacchi 
978a37ae75SRobert Mustacchi static boolean_t
pcidb_write_vendor(ofmt_arg_t * ofarg,char * buf,uint_t buflen)988a37ae75SRobert Mustacchi pcidb_write_vendor(ofmt_arg_t *ofarg, char *buf, uint_t buflen)
998a37ae75SRobert Mustacchi {
1008a37ae75SRobert Mustacchi 	pcidb_walk_t *walk = ofarg->ofmt_cbarg;
1018a37ae75SRobert Mustacchi 
1028a37ae75SRobert Mustacchi 	VERIFY(walk->pw_vendor != NULL);
1038a37ae75SRobert Mustacchi 	switch (ofarg->ofmt_id) {
1048a37ae75SRobert Mustacchi 	case PCIDB_OFMT_VID:
1058a37ae75SRobert Mustacchi 		(void) snprintf(buf, buflen, "%x",
1068a37ae75SRobert Mustacchi 		    pcidb_vendor_id(walk->pw_vendor));
1078a37ae75SRobert Mustacchi 		break;
1088a37ae75SRobert Mustacchi 	case PCIDB_OFMT_VENSTR:
1098a37ae75SRobert Mustacchi 		(void) strlcpy(buf, pcidb_vendor_name(walk->pw_vendor), buflen);
1108a37ae75SRobert Mustacchi 		break;
1118a37ae75SRobert Mustacchi 	default:
1128a37ae75SRobert Mustacchi 		abort();
1138a37ae75SRobert Mustacchi 	}
1148a37ae75SRobert Mustacchi 	return (B_TRUE);
1158a37ae75SRobert Mustacchi }
1168a37ae75SRobert Mustacchi 
1178a37ae75SRobert Mustacchi static boolean_t
pcidb_write_device(ofmt_arg_t * ofarg,char * buf,uint_t buflen)1188a37ae75SRobert Mustacchi pcidb_write_device(ofmt_arg_t *ofarg, char *buf, uint_t buflen)
1198a37ae75SRobert Mustacchi {
1208a37ae75SRobert Mustacchi 	pcidb_walk_t *walk = ofarg->ofmt_cbarg;
1218a37ae75SRobert Mustacchi 
1228a37ae75SRobert Mustacchi 	VERIFY(walk->pw_device != NULL);
1238a37ae75SRobert Mustacchi 	switch (ofarg->ofmt_id) {
1248a37ae75SRobert Mustacchi 	case PCIDB_OFMT_DID:
1258a37ae75SRobert Mustacchi 		(void) snprintf(buf, buflen, "%x",
1268a37ae75SRobert Mustacchi 		    pcidb_device_id(walk->pw_device));
1278a37ae75SRobert Mustacchi 		break;
1288a37ae75SRobert Mustacchi 	case PCIDB_OFMT_DEVSTR:
1298a37ae75SRobert Mustacchi 		(void) strlcpy(buf, pcidb_device_name(walk->pw_device), buflen);
1308a37ae75SRobert Mustacchi 		break;
1318a37ae75SRobert Mustacchi 	default:
1328a37ae75SRobert Mustacchi 		abort();
1338a37ae75SRobert Mustacchi 	}
1348a37ae75SRobert Mustacchi 	return (B_TRUE);
1358a37ae75SRobert Mustacchi }
1368a37ae75SRobert Mustacchi 
1378a37ae75SRobert Mustacchi static boolean_t
pcidb_write_subsystem(ofmt_arg_t * ofarg,char * buf,uint_t buflen)1388a37ae75SRobert Mustacchi pcidb_write_subsystem(ofmt_arg_t *ofarg, char *buf, uint_t buflen)
1398a37ae75SRobert Mustacchi {
1408a37ae75SRobert Mustacchi 	pcidb_walk_t *walk = ofarg->ofmt_cbarg;
1418a37ae75SRobert Mustacchi 	pcidb_vendor_t *vendor;
1428a37ae75SRobert Mustacchi 
1438a37ae75SRobert Mustacchi 	VERIFY(walk->pw_subvd != NULL);
1448a37ae75SRobert Mustacchi 	switch (ofarg->ofmt_id) {
1458a37ae75SRobert Mustacchi 	case PCIDB_OFMT_SVID:
1468a37ae75SRobert Mustacchi 		(void) snprintf(buf, buflen, "%x",
1478a37ae75SRobert Mustacchi 		    pcidb_subvd_svid(walk->pw_subvd));
1488a37ae75SRobert Mustacchi 		break;
1498a37ae75SRobert Mustacchi 	case PCIDB_OFMT_SDID:
1508a37ae75SRobert Mustacchi 		(void) snprintf(buf, buflen, "%x",
1518a37ae75SRobert Mustacchi 		    pcidb_subvd_sdid(walk->pw_subvd));
1528a37ae75SRobert Mustacchi 		break;
1538a37ae75SRobert Mustacchi 	case PCIDB_OFMT_SUBSYSSTR:
1548a37ae75SRobert Mustacchi 		(void) strlcpy(buf, pcidb_subvd_name(walk->pw_subvd), buflen);
1558a37ae75SRobert Mustacchi 		break;
1568a37ae75SRobert Mustacchi 	case PCIDB_OFMT_SUBVENSTR:
1578a37ae75SRobert Mustacchi 		vendor = pcidb_lookup_vendor(walk->pw_hdl,
1588a37ae75SRobert Mustacchi 		    pcidb_subvd_svid(walk->pw_subvd));
1598a37ae75SRobert Mustacchi 		if (vendor == NULL) {
1608a37ae75SRobert Mustacchi 			return (B_FALSE);
1618a37ae75SRobert Mustacchi 		}
1628a37ae75SRobert Mustacchi 		(void) strlcpy(buf, pcidb_vendor_name(vendor), buflen);
1638a37ae75SRobert Mustacchi 		break;
1648a37ae75SRobert Mustacchi 	default:
1658a37ae75SRobert Mustacchi 		abort();
1668a37ae75SRobert Mustacchi 	}
1678a37ae75SRobert Mustacchi 	return (B_TRUE);
1688a37ae75SRobert Mustacchi }
1698a37ae75SRobert Mustacchi 
1708a37ae75SRobert Mustacchi static boolean_t
pcidb_write_class(ofmt_arg_t * ofarg,char * buf,uint_t buflen)1718a37ae75SRobert Mustacchi pcidb_write_class(ofmt_arg_t *ofarg, char *buf, uint_t buflen)
1728a37ae75SRobert Mustacchi {
1738a37ae75SRobert Mustacchi 	pcidb_walk_t *walk = ofarg->ofmt_cbarg;
1748a37ae75SRobert Mustacchi 
1758a37ae75SRobert Mustacchi 	VERIFY(walk->pw_class != NULL);
1768a37ae75SRobert Mustacchi 	switch (ofarg->ofmt_id) {
1778a37ae75SRobert Mustacchi 	case PCIDB_OFMT_BCC:
1788a37ae75SRobert Mustacchi 		(void) snprintf(buf, buflen, "%x",
1798a37ae75SRobert Mustacchi 		    pcidb_class_code(walk->pw_class));
1808a37ae75SRobert Mustacchi 		break;
1818a37ae75SRobert Mustacchi 	case PCIDB_OFMT_CLASSSTR:
1828a37ae75SRobert Mustacchi 		(void) strlcpy(buf, pcidb_class_name(walk->pw_class), buflen);
1838a37ae75SRobert Mustacchi 		break;
1848a37ae75SRobert Mustacchi 	default:
1858a37ae75SRobert Mustacchi 		abort();
1868a37ae75SRobert Mustacchi 	}
1878a37ae75SRobert Mustacchi 	return (B_TRUE);
1888a37ae75SRobert Mustacchi }
1898a37ae75SRobert Mustacchi 
1908a37ae75SRobert Mustacchi static boolean_t
pcidb_write_subclass(ofmt_arg_t * ofarg,char * buf,uint_t buflen)1918a37ae75SRobert Mustacchi pcidb_write_subclass(ofmt_arg_t *ofarg, char *buf, uint_t buflen)
1928a37ae75SRobert Mustacchi {
1938a37ae75SRobert Mustacchi 	pcidb_walk_t *walk = ofarg->ofmt_cbarg;
1948a37ae75SRobert Mustacchi 
1958a37ae75SRobert Mustacchi 	VERIFY(walk->pw_subclass != NULL);
1968a37ae75SRobert Mustacchi 	switch (ofarg->ofmt_id) {
1978a37ae75SRobert Mustacchi 	case PCIDB_OFMT_SCC:
1988a37ae75SRobert Mustacchi 		(void) snprintf(buf, buflen, "%x",
1998a37ae75SRobert Mustacchi 		    pcidb_subclass_code(walk->pw_subclass));
2008a37ae75SRobert Mustacchi 		break;
2018a37ae75SRobert Mustacchi 	case PCIDB_OFMT_SUBCLASSSTR:
2028a37ae75SRobert Mustacchi 		(void) strlcpy(buf, pcidb_subclass_name(walk->pw_subclass),
2038a37ae75SRobert Mustacchi 		    buflen);
2048a37ae75SRobert Mustacchi 		break;
2058a37ae75SRobert Mustacchi 	default:
2068a37ae75SRobert Mustacchi 		abort();
2078a37ae75SRobert Mustacchi 	}
2088a37ae75SRobert Mustacchi 	return (B_TRUE);
2098a37ae75SRobert Mustacchi }
2108a37ae75SRobert Mustacchi 
2118a37ae75SRobert Mustacchi static boolean_t
pcidb_write_progif(ofmt_arg_t * ofarg,char * buf,uint_t buflen)2128a37ae75SRobert Mustacchi pcidb_write_progif(ofmt_arg_t *ofarg, char *buf, uint_t buflen)
2138a37ae75SRobert Mustacchi {
2148a37ae75SRobert Mustacchi 	pcidb_walk_t *walk = ofarg->ofmt_cbarg;
2158a37ae75SRobert Mustacchi 
2168a37ae75SRobert Mustacchi 	VERIFY(walk->pw_progif != NULL);
2178a37ae75SRobert Mustacchi 	switch (ofarg->ofmt_id) {
2188a37ae75SRobert Mustacchi 	case PCIDB_OFMT_PI:
2198a37ae75SRobert Mustacchi 		(void) snprintf(buf, buflen, "%x",
2208a37ae75SRobert Mustacchi 		    pcidb_progif_code(walk->pw_progif));
2218a37ae75SRobert Mustacchi 		break;
2228a37ae75SRobert Mustacchi 	case PCIDB_OFMT_PROGIFSTR:
2238a37ae75SRobert Mustacchi 		(void) strlcpy(buf, pcidb_progif_name(walk->pw_progif),
2248a37ae75SRobert Mustacchi 		    buflen);
2258a37ae75SRobert Mustacchi 		break;
2268a37ae75SRobert Mustacchi 	default:
2278a37ae75SRobert Mustacchi 		abort();
2288a37ae75SRobert Mustacchi 	}
2298a37ae75SRobert Mustacchi 	return (B_TRUE);
2308a37ae75SRobert Mustacchi }
2318a37ae75SRobert Mustacchi 
2328a37ae75SRobert Mustacchi static const char *pcidb_vendor_fields = "vid,vendor";
2338a37ae75SRobert Mustacchi static const ofmt_field_t pcidb_vendor_ofmt[] = {
2348a37ae75SRobert Mustacchi 	{ "VID",	8,	PCIDB_OFMT_VID,		pcidb_write_vendor },
2358a37ae75SRobert Mustacchi 	{ "VENDOR",	30,	PCIDB_OFMT_VENSTR,	pcidb_write_vendor },
2368a37ae75SRobert Mustacchi 	{ NULL, 0, 0, NULL }
2378a37ae75SRobert Mustacchi };
2388a37ae75SRobert Mustacchi 
2398a37ae75SRobert Mustacchi static const char *pcidb_device_fields = "vid,did,vendor,device";
2408a37ae75SRobert Mustacchi static const ofmt_field_t pcidb_device_ofmt[] = {
2418a37ae75SRobert Mustacchi 	{ "VID",	8,	PCIDB_OFMT_VID,		pcidb_write_vendor },
2428a37ae75SRobert Mustacchi 	{ "VENDOR",	30,	PCIDB_OFMT_VENSTR,	pcidb_write_vendor },
2438a37ae75SRobert Mustacchi 	{ "DID",	8,	PCIDB_OFMT_DID,		pcidb_write_device },
2448a37ae75SRobert Mustacchi 	{ "DEVICE",	30,	PCIDB_OFMT_DEVSTR,	pcidb_write_device },
2458a37ae75SRobert Mustacchi 	{ NULL, 0, 0, NULL }
2468a37ae75SRobert Mustacchi };
2478a37ae75SRobert Mustacchi 
2488a37ae75SRobert Mustacchi static const char *pcidb_subsystem_fields = "vid,did,svid,sdid,subsystem";
2498a37ae75SRobert Mustacchi static const ofmt_field_t pcidb_subsystem_ofmt[] = {
2508a37ae75SRobert Mustacchi 	{ "VID",	8,	PCIDB_OFMT_VID,		pcidb_write_vendor },
2518a37ae75SRobert Mustacchi 	{ "VENDOR",	30,	PCIDB_OFMT_VENSTR,	pcidb_write_vendor },
2528a37ae75SRobert Mustacchi 	{ "DID",	8,	PCIDB_OFMT_DID,		pcidb_write_device },
2538a37ae75SRobert Mustacchi 	{ "DEVICE",	30,	PCIDB_OFMT_DEVSTR,	pcidb_write_device },
2548a37ae75SRobert Mustacchi 	{ "SVID",	8,	PCIDB_OFMT_SVID,	pcidb_write_subsystem },
2558a37ae75SRobert Mustacchi 	{ "SDID",	8,	PCIDB_OFMT_SDID,	pcidb_write_subsystem },
2568a37ae75SRobert Mustacchi 	{ "SUBSYSTEM",	30,	PCIDB_OFMT_SUBSYSSTR,	pcidb_write_subsystem },
2578a37ae75SRobert Mustacchi 	{ "SUBVENDOR",	30,	PCIDB_OFMT_SUBVENSTR,	pcidb_write_subsystem },
2588a37ae75SRobert Mustacchi 	{ NULL, 0, 0, NULL }
2598a37ae75SRobert Mustacchi };
2608a37ae75SRobert Mustacchi 
2618a37ae75SRobert Mustacchi static const char *pcidb_class_fields = "bcc,class";
2628a37ae75SRobert Mustacchi static const ofmt_field_t pcidb_class_ofmt[] = {
2638a37ae75SRobert Mustacchi 	{ "BCC",	6,	PCIDB_OFMT_BCC,		pcidb_write_class },
2648a37ae75SRobert Mustacchi 	{ "CLASS",	30,	PCIDB_OFMT_CLASSSTR,	pcidb_write_class },
2658a37ae75SRobert Mustacchi 	{ NULL, 0, 0, NULL }
2668a37ae75SRobert Mustacchi };
2678a37ae75SRobert Mustacchi 
2688a37ae75SRobert Mustacchi static const char *pcidb_subclass_fields = "bcc,scc,class,subclass";
2698a37ae75SRobert Mustacchi static const ofmt_field_t pcidb_subclass_ofmt[] = {
2708a37ae75SRobert Mustacchi 	{ "BCC",	6,	PCIDB_OFMT_BCC,		pcidb_write_class },
2718a37ae75SRobert Mustacchi 	{ "CLASS",	30,	PCIDB_OFMT_CLASSSTR,	pcidb_write_class },
2728a37ae75SRobert Mustacchi 	{ "SCC",	6,	PCIDB_OFMT_SCC,		pcidb_write_subclass },
2738a37ae75SRobert Mustacchi 	{ "SUBCLASS",	30,	PCIDB_OFMT_SUBCLASSSTR,	pcidb_write_subclass },
2748a37ae75SRobert Mustacchi 	{ NULL, 0, 0, NULL }
2758a37ae75SRobert Mustacchi };
2768a37ae75SRobert Mustacchi 
2778a37ae75SRobert Mustacchi static const char *pcidb_progif_fields = "bcc,scc,pi,subclass,interface";
2788a37ae75SRobert Mustacchi static const ofmt_field_t pcidb_progif_ofmt[] = {
2798a37ae75SRobert Mustacchi 	{ "BCC",	6,	PCIDB_OFMT_BCC,		pcidb_write_class },
2808a37ae75SRobert Mustacchi 	{ "CLASS",	30,	PCIDB_OFMT_CLASSSTR,	pcidb_write_class },
2818a37ae75SRobert Mustacchi 	{ "SCC",	6,	PCIDB_OFMT_SCC,		pcidb_write_subclass },
2828a37ae75SRobert Mustacchi 	{ "SUBCLASS",	30,	PCIDB_OFMT_SUBCLASSSTR,	pcidb_write_subclass },
2838a37ae75SRobert Mustacchi 	{ "PI",		6,	PCIDB_OFMT_PI,		pcidb_write_progif },
2848a37ae75SRobert Mustacchi 	{ "INTERFACE",	30,	PCIDB_OFMT_PROGIFSTR,	pcidb_write_progif },
2858a37ae75SRobert Mustacchi 	{ NULL, 0, 0, NULL }
2868a37ae75SRobert Mustacchi };
2878a37ae75SRobert Mustacchi 
2888a37ae75SRobert Mustacchi static void
pcidb_ofmt_errx(const char * fmt,...)2898a37ae75SRobert Mustacchi pcidb_ofmt_errx(const char *fmt, ...)
2908a37ae75SRobert Mustacchi {
2918a37ae75SRobert Mustacchi 	va_list ap;
2928a37ae75SRobert Mustacchi 
2938a37ae75SRobert Mustacchi 	va_start(ap, fmt);
2948a37ae75SRobert Mustacchi 	verrx(EXIT_FAILURE, fmt, ap);
2958a37ae75SRobert Mustacchi }
2968a37ae75SRobert Mustacchi 
2978a37ae75SRobert Mustacchi static boolean_t
pcidb_filter_match(pcidb_walk_t * walk)2988a37ae75SRobert Mustacchi pcidb_filter_match(pcidb_walk_t *walk)
2998a37ae75SRobert Mustacchi {
3008a37ae75SRobert Mustacchi 	if (walk->pw_nfilters == 0) {
3018a37ae75SRobert Mustacchi 		return (B_TRUE);
3028a37ae75SRobert Mustacchi 	}
3038a37ae75SRobert Mustacchi 
3048a37ae75SRobert Mustacchi 	for (uint_t i = 0; i < walk->pw_nfilters; i++) {
3058a37ae75SRobert Mustacchi 		const pcidb_filter_t *filt = &walk->pw_filters[i];
3068a37ae75SRobert Mustacchi 		if (filt->pft_vend != PCIDB_NOFILTER &&
3078a37ae75SRobert Mustacchi 		    (walk->pw_vendor == NULL ||
3088a37ae75SRobert Mustacchi 		    filt->pft_vend != pcidb_vendor_id(walk->pw_vendor))) {
3098a37ae75SRobert Mustacchi 			continue;
3108a37ae75SRobert Mustacchi 		}
3118a37ae75SRobert Mustacchi 
3128a37ae75SRobert Mustacchi 		if (filt->pft_dev != PCIDB_NOFILTER &&
3138a37ae75SRobert Mustacchi 		    (walk->pw_device == NULL ||
3148a37ae75SRobert Mustacchi 		    filt->pft_dev != pcidb_device_id(walk->pw_device))) {
3158a37ae75SRobert Mustacchi 			continue;
3168a37ae75SRobert Mustacchi 		}
3178a37ae75SRobert Mustacchi 
3188a37ae75SRobert Mustacchi 		if (filt->pft_subven != PCIDB_NOFILTER &&
3198a37ae75SRobert Mustacchi 		    (walk->pw_subvd == NULL ||
3208a37ae75SRobert Mustacchi 		    filt->pft_subven != pcidb_subvd_svid(walk->pw_subvd))) {
3218a37ae75SRobert Mustacchi 			continue;
3228a37ae75SRobert Mustacchi 		}
3238a37ae75SRobert Mustacchi 
3248a37ae75SRobert Mustacchi 		if (filt->pft_subdev != PCIDB_NOFILTER &&
3258a37ae75SRobert Mustacchi 		    (walk->pw_subvd == NULL ||
3268a37ae75SRobert Mustacchi 		    filt->pft_subdev != pcidb_subvd_sdid(walk->pw_subvd))) {
3278a37ae75SRobert Mustacchi 			continue;
3288a37ae75SRobert Mustacchi 		}
3298a37ae75SRobert Mustacchi 
3308a37ae75SRobert Mustacchi 		if (filt->pft_class != PCIDB_NOFILTER &&
3318a37ae75SRobert Mustacchi 		    (walk->pw_class == NULL ||
3328a37ae75SRobert Mustacchi 		    filt->pft_class != pcidb_class_code(walk->pw_class))) {
3338a37ae75SRobert Mustacchi 			continue;
3348a37ae75SRobert Mustacchi 		}
3358a37ae75SRobert Mustacchi 
3368a37ae75SRobert Mustacchi 		if (filt->pft_subclass != PCIDB_NOFILTER &&
3378a37ae75SRobert Mustacchi 		    (walk->pw_subclass == NULL ||
3388a37ae75SRobert Mustacchi 		    filt->pft_subclass !=
3398a37ae75SRobert Mustacchi 		    pcidb_subclass_code(walk->pw_subclass))) {
3408a37ae75SRobert Mustacchi 			continue;
3418a37ae75SRobert Mustacchi 		}
3428a37ae75SRobert Mustacchi 
3438a37ae75SRobert Mustacchi 		if (filt->pft_progif != PCIDB_NOFILTER &&
3448a37ae75SRobert Mustacchi 		    (walk->pw_progif == NULL ||
3458a37ae75SRobert Mustacchi 		    filt->pft_progif != pcidb_progif_code(walk->pw_progif))) {
3468a37ae75SRobert Mustacchi 			continue;
3478a37ae75SRobert Mustacchi 		}
3488a37ae75SRobert Mustacchi 
3498a37ae75SRobert Mustacchi 		return (B_TRUE);
3508a37ae75SRobert Mustacchi 	}
3518a37ae75SRobert Mustacchi 
3528a37ae75SRobert Mustacchi 	return (B_FALSE);
3538a37ae75SRobert Mustacchi }
3548a37ae75SRobert Mustacchi 
3558a37ae75SRobert Mustacchi static void
pcidb_walk_vendors(pcidb_walk_t * walk)3568a37ae75SRobert Mustacchi pcidb_walk_vendors(pcidb_walk_t *walk)
3578a37ae75SRobert Mustacchi {
3588a37ae75SRobert Mustacchi 	pcidb_hdl_t *hdl = walk->pw_hdl;
3598a37ae75SRobert Mustacchi 
3608a37ae75SRobert Mustacchi 	for (pcidb_vendor_t *vend = pcidb_vendor_iter(hdl); vend != NULL;
3618a37ae75SRobert Mustacchi 	    vend = pcidb_vendor_iter_next(vend)) {
3628a37ae75SRobert Mustacchi 		walk->pw_vendor = vend;
3638a37ae75SRobert Mustacchi 		if (!pcidb_filter_match(walk))
3648a37ae75SRobert Mustacchi 			continue;
3658a37ae75SRobert Mustacchi 		ofmt_print(walk->pw_ofmt, walk);
3668a37ae75SRobert Mustacchi 	}
3678a37ae75SRobert Mustacchi }
3688a37ae75SRobert Mustacchi 
3698a37ae75SRobert Mustacchi static void
pcidb_walk_devices(pcidb_walk_t * walk)3708a37ae75SRobert Mustacchi pcidb_walk_devices(pcidb_walk_t *walk)
3718a37ae75SRobert Mustacchi {
3728a37ae75SRobert Mustacchi 	pcidb_hdl_t *hdl = walk->pw_hdl;
3738a37ae75SRobert Mustacchi 
3748a37ae75SRobert Mustacchi 	for (pcidb_vendor_t *vend = pcidb_vendor_iter(hdl); vend != NULL;
3758a37ae75SRobert Mustacchi 	    vend = pcidb_vendor_iter_next(vend)) {
3768a37ae75SRobert Mustacchi 		walk->pw_vendor = vend;
3778a37ae75SRobert Mustacchi 		for (pcidb_device_t *dev = pcidb_device_iter(vend); dev != NULL;
3788a37ae75SRobert Mustacchi 		    dev = pcidb_device_iter_next(dev)) {
3798a37ae75SRobert Mustacchi 			walk->pw_device = dev;
3808a37ae75SRobert Mustacchi 			if (!pcidb_filter_match(walk))
3818a37ae75SRobert Mustacchi 				continue;
3828a37ae75SRobert Mustacchi 			ofmt_print(walk->pw_ofmt, walk);
3838a37ae75SRobert Mustacchi 		}
3848a37ae75SRobert Mustacchi 	}
3858a37ae75SRobert Mustacchi }
3868a37ae75SRobert Mustacchi 
3878a37ae75SRobert Mustacchi static void
pcidb_walk_subsystems(pcidb_walk_t * walk)3888a37ae75SRobert Mustacchi pcidb_walk_subsystems(pcidb_walk_t *walk)
3898a37ae75SRobert Mustacchi {
3908a37ae75SRobert Mustacchi 	pcidb_hdl_t *hdl = walk->pw_hdl;
3918a37ae75SRobert Mustacchi 
3928a37ae75SRobert Mustacchi 	for (pcidb_vendor_t *vend = pcidb_vendor_iter(hdl); vend != NULL;
3938a37ae75SRobert Mustacchi 	    vend = pcidb_vendor_iter_next(vend)) {
3948a37ae75SRobert Mustacchi 		walk->pw_vendor = vend;
3958a37ae75SRobert Mustacchi 		for (pcidb_device_t *dev = pcidb_device_iter(vend); dev != NULL;
3968a37ae75SRobert Mustacchi 		    dev = pcidb_device_iter_next(dev)) {
3978a37ae75SRobert Mustacchi 			walk->pw_device = dev;
3988a37ae75SRobert Mustacchi 			for (pcidb_subvd_t *sub = pcidb_subvd_iter(dev);
3998a37ae75SRobert Mustacchi 			    sub != NULL; sub = pcidb_subvd_iter_next(sub)) {
4008a37ae75SRobert Mustacchi 				walk->pw_subvd = sub;
4018a37ae75SRobert Mustacchi 				if (!pcidb_filter_match(walk))
4028a37ae75SRobert Mustacchi 					continue;
4038a37ae75SRobert Mustacchi 				ofmt_print(walk->pw_ofmt, walk);
4048a37ae75SRobert Mustacchi 			}
4058a37ae75SRobert Mustacchi 		}
4068a37ae75SRobert Mustacchi 
4078a37ae75SRobert Mustacchi 	}
4088a37ae75SRobert Mustacchi }
4098a37ae75SRobert Mustacchi 
4108a37ae75SRobert Mustacchi static void
pcidb_walk_classes(pcidb_walk_t * walk)4118a37ae75SRobert Mustacchi pcidb_walk_classes(pcidb_walk_t *walk)
4128a37ae75SRobert Mustacchi {
4138a37ae75SRobert Mustacchi 	for (pcidb_class_t *class = pcidb_class_iter(walk->pw_hdl);
4148a37ae75SRobert Mustacchi 	    class != NULL; class = pcidb_class_iter_next(class)) {
4158a37ae75SRobert Mustacchi 		walk->pw_class = class;
4168a37ae75SRobert Mustacchi 		if (!pcidb_filter_match(walk))
4178a37ae75SRobert Mustacchi 			continue;
4188a37ae75SRobert Mustacchi 		ofmt_print(walk->pw_ofmt, walk);
4198a37ae75SRobert Mustacchi 	}
4208a37ae75SRobert Mustacchi }
4218a37ae75SRobert Mustacchi 
4228a37ae75SRobert Mustacchi static void
pcidb_walk_subclasses(pcidb_walk_t * walk)4238a37ae75SRobert Mustacchi pcidb_walk_subclasses(pcidb_walk_t *walk)
4248a37ae75SRobert Mustacchi {
4258a37ae75SRobert Mustacchi 	for (pcidb_class_t *class = pcidb_class_iter(walk->pw_hdl);
4268a37ae75SRobert Mustacchi 	    class != NULL; class = pcidb_class_iter_next(class)) {
4278a37ae75SRobert Mustacchi 		walk->pw_class = class;
4288a37ae75SRobert Mustacchi 		for (pcidb_subclass_t *sub = pcidb_subclass_iter(class);
4298a37ae75SRobert Mustacchi 		    sub != NULL; sub = pcidb_subclass_iter_next(sub)) {
4308a37ae75SRobert Mustacchi 			walk->pw_subclass = sub;
4318a37ae75SRobert Mustacchi 			if (!pcidb_filter_match(walk))
4328a37ae75SRobert Mustacchi 				continue;
4338a37ae75SRobert Mustacchi 			ofmt_print(walk->pw_ofmt, walk);
4348a37ae75SRobert Mustacchi 		}
4358a37ae75SRobert Mustacchi 	}
4368a37ae75SRobert Mustacchi }
4378a37ae75SRobert Mustacchi 
4388a37ae75SRobert Mustacchi static void
pcidb_walk_progifs(pcidb_walk_t * walk)4398a37ae75SRobert Mustacchi pcidb_walk_progifs(pcidb_walk_t *walk)
4408a37ae75SRobert Mustacchi {
4418a37ae75SRobert Mustacchi 	for (pcidb_class_t *class = pcidb_class_iter(walk->pw_hdl);
4428a37ae75SRobert Mustacchi 	    class != NULL; class = pcidb_class_iter_next(class)) {
4438a37ae75SRobert Mustacchi 		walk->pw_class = class;
4448a37ae75SRobert Mustacchi 		for (pcidb_subclass_t *sub = pcidb_subclass_iter(class);
4458a37ae75SRobert Mustacchi 		    sub != NULL; sub = pcidb_subclass_iter_next(sub)) {
4468a37ae75SRobert Mustacchi 			walk->pw_subclass = sub;
4478a37ae75SRobert Mustacchi 			for (pcidb_progif_t *progif = pcidb_progif_iter(sub);
4488a37ae75SRobert Mustacchi 			    progif != NULL;
4498a37ae75SRobert Mustacchi 			    progif = pcidb_progif_iter_next(progif)) {
4508a37ae75SRobert Mustacchi 				walk->pw_progif = progif;
4518a37ae75SRobert Mustacchi 				if (!pcidb_filter_match(walk))
4528a37ae75SRobert Mustacchi 					continue;
4538a37ae75SRobert Mustacchi 				ofmt_print(walk->pw_ofmt, walk);
4548a37ae75SRobert Mustacchi 			}
4558a37ae75SRobert Mustacchi 		}
4568a37ae75SRobert Mustacchi 	}
4578a37ae75SRobert Mustacchi }
4588a37ae75SRobert Mustacchi 
4598a37ae75SRobert Mustacchi static void
pcidb_parse_class_filter(pcidb_filter_t * filter,char * arg,const char * orig)4608a37ae75SRobert Mustacchi pcidb_parse_class_filter(pcidb_filter_t *filter, char *arg, const char *orig)
4618a37ae75SRobert Mustacchi {
4628a37ae75SRobert Mustacchi 	size_t len;
4638a37ae75SRobert Mustacchi 	unsigned long val;
4648a37ae75SRobert Mustacchi 	char *eptr;
4658a37ae75SRobert Mustacchi 
4668a37ae75SRobert Mustacchi 	filter->pft_vend = filter->pft_dev = PCIDB_NOFILTER;
4678a37ae75SRobert Mustacchi 	filter->pft_subven = filter->pft_subdev = PCIDB_NOFILTER;
4688a37ae75SRobert Mustacchi 
4698a37ae75SRobert Mustacchi 	len = strlen(arg);
4708a37ae75SRobert Mustacchi 	if (len != 2 && len != 4 && len != 6) {
4718a37ae75SRobert Mustacchi 		errx(EXIT_FAILURE, "invalid class filter: '%s': bad length",
4728a37ae75SRobert Mustacchi 		    orig);
4738a37ae75SRobert Mustacchi 	}
4748a37ae75SRobert Mustacchi 
4758a37ae75SRobert Mustacchi 	errno = 0;
4768a37ae75SRobert Mustacchi 	val = strtoul(arg, &eptr, 16);
4778a37ae75SRobert Mustacchi 	if (errno != 0 || *eptr != '\0') {
4788a37ae75SRobert Mustacchi 		errx(EXIT_FAILURE, "invalid class filter: '%s': failed to "
4798a37ae75SRobert Mustacchi 		    "parse hex string", orig);
4808a37ae75SRobert Mustacchi 	}
4818a37ae75SRobert Mustacchi 
4828a37ae75SRobert Mustacchi 	if (len == 6) {
4838a37ae75SRobert Mustacchi 		filter->pft_progif = val & 0xff;
4848a37ae75SRobert Mustacchi 		val = val >> 8;
4858a37ae75SRobert Mustacchi 	} else {
4868a37ae75SRobert Mustacchi 		filter->pft_progif = PCIDB_NOFILTER;
4878a37ae75SRobert Mustacchi 	}
4888a37ae75SRobert Mustacchi 
4898a37ae75SRobert Mustacchi 	if (len >= 4) {
4908a37ae75SRobert Mustacchi 		filter->pft_subclass = val & 0xff;
4918a37ae75SRobert Mustacchi 		val = val >> 8;
4928a37ae75SRobert Mustacchi 	} else {
4938a37ae75SRobert Mustacchi 		filter->pft_subclass = PCIDB_NOFILTER;
4948a37ae75SRobert Mustacchi 	}
4958a37ae75SRobert Mustacchi 
4968a37ae75SRobert Mustacchi 	filter->pft_class = val & 0xff;
4978a37ae75SRobert Mustacchi }
4988a37ae75SRobert Mustacchi 
4998a37ae75SRobert Mustacchi static void
pcidb_parse_device_filter(pcidb_filter_t * filter,char * arg,const char * orig)5008a37ae75SRobert Mustacchi pcidb_parse_device_filter(pcidb_filter_t *filter, char *arg, const char *orig)
5018a37ae75SRobert Mustacchi {
5028a37ae75SRobert Mustacchi 	unsigned long val;
5038a37ae75SRobert Mustacchi 	uint32_t primary, secondary;
5048a37ae75SRobert Mustacchi 	char *eptr;
5058a37ae75SRobert Mustacchi 
5068a37ae75SRobert Mustacchi 	filter->pft_vend = filter->pft_dev = PCIDB_NOFILTER;
5078a37ae75SRobert Mustacchi 	filter->pft_subven = filter->pft_subdev = PCIDB_NOFILTER;
5088a37ae75SRobert Mustacchi 	filter->pft_class = filter->pft_subclass = PCIDB_NOFILTER;
5098a37ae75SRobert Mustacchi 	filter->pft_progif = PCIDB_NOFILTER;
5108a37ae75SRobert Mustacchi 
5118a37ae75SRobert Mustacchi 	errno = 0;
5128a37ae75SRobert Mustacchi 	val = strtoul(arg, &eptr, 16);
5138a37ae75SRobert Mustacchi 	if (errno != 0 || (*eptr != '\0' && *eptr != ',')) {
5148a37ae75SRobert Mustacchi 		errx(EXIT_FAILURE, "invalid device filter: '%s': failed to "
5158a37ae75SRobert Mustacchi 		    "parse hex string", orig);
5168a37ae75SRobert Mustacchi 	}
5178a37ae75SRobert Mustacchi 
5188a37ae75SRobert Mustacchi 	if (val > UINT16_MAX) {
519*6b1325cfSRobert Mustacchi 		errx(EXIT_FAILURE, "invalid id: %lx is larger than 0xffff",
520*6b1325cfSRobert Mustacchi 		    val);
5218a37ae75SRobert Mustacchi 	}
5228a37ae75SRobert Mustacchi 
5238a37ae75SRobert Mustacchi 	primary = (uint32_t)val;
5248a37ae75SRobert Mustacchi 	if (*eptr == '\0') {
5258a37ae75SRobert Mustacchi 		filter->pft_vend = primary;
5268a37ae75SRobert Mustacchi 		return;
5278a37ae75SRobert Mustacchi 	} else if (strcmp(eptr, ",s") == 0) {
5288a37ae75SRobert Mustacchi 		filter->pft_subven = primary;
5298a37ae75SRobert Mustacchi 		return;
5308a37ae75SRobert Mustacchi 	} else if (eptr[1] == '\0') {
5318a37ae75SRobert Mustacchi 		errx(EXIT_FAILURE, "invalid device filter: '%s': filter "
5328a37ae75SRobert Mustacchi 		    "terminated early", arg);
5338a37ae75SRobert Mustacchi 	}
5348a37ae75SRobert Mustacchi 
5358a37ae75SRobert Mustacchi 	arg = eptr + 1;
5368a37ae75SRobert Mustacchi 	val = strtoul(arg, &eptr, 16);
5378a37ae75SRobert Mustacchi 	if (errno != 0 || (*eptr != '\0' && *eptr != ',' && *eptr != '.')) {
5388a37ae75SRobert Mustacchi 		errx(EXIT_FAILURE, "invalid device filter: '%s': failed to "
5398a37ae75SRobert Mustacchi 		    "parse hex string at %s", orig, arg);
5408a37ae75SRobert Mustacchi 	}
5418a37ae75SRobert Mustacchi 
5428a37ae75SRobert Mustacchi 	if (val > UINT16_MAX) {
543*6b1325cfSRobert Mustacchi 		errx(EXIT_FAILURE, "invalid id: %lx is larger than 0xffff",
544*6b1325cfSRobert Mustacchi 		    val);
5458a37ae75SRobert Mustacchi 	}
5468a37ae75SRobert Mustacchi 
5478a37ae75SRobert Mustacchi 	secondary = (uint32_t)val;
5488a37ae75SRobert Mustacchi 	if (*eptr == '\0') {
5498a37ae75SRobert Mustacchi 		filter->pft_vend = primary;
5508a37ae75SRobert Mustacchi 		filter->pft_dev = secondary;
5518a37ae75SRobert Mustacchi 		return;
5528a37ae75SRobert Mustacchi 	} else if (eptr[1] == '\0') {
5538a37ae75SRobert Mustacchi 		errx(EXIT_FAILURE, "invalid device filter: '%s': filter "
5548a37ae75SRobert Mustacchi 		    "terminated early", arg);
5558a37ae75SRobert Mustacchi 	}
5568a37ae75SRobert Mustacchi 
5578a37ae75SRobert Mustacchi 	if (*eptr == ',') {
5588a37ae75SRobert Mustacchi 		if (eptr[1] == 'p' && eptr[2] == '\0') {
5598a37ae75SRobert Mustacchi 			filter->pft_vend = primary;
5608a37ae75SRobert Mustacchi 			filter->pft_dev = secondary;
5618a37ae75SRobert Mustacchi 			return;
5628a37ae75SRobert Mustacchi 		}
5638a37ae75SRobert Mustacchi 		if (eptr[1] == 's' && eptr[2] == '\0') {
5648a37ae75SRobert Mustacchi 			filter->pft_subven = primary;
5658a37ae75SRobert Mustacchi 			filter->pft_subdev = secondary;
5668a37ae75SRobert Mustacchi 			return;
5678a37ae75SRobert Mustacchi 		}
5688a37ae75SRobert Mustacchi 		errx(EXIT_FAILURE, "invalid device filter: '%s': invalid "
5698a37ae75SRobert Mustacchi 		    "trailing comma at %s, expected either ,p or ,s",
5708a37ae75SRobert Mustacchi 		    orig, eptr);
5718a37ae75SRobert Mustacchi 	}
5728a37ae75SRobert Mustacchi 
5738a37ae75SRobert Mustacchi 	filter->pft_vend = primary;
5748a37ae75SRobert Mustacchi 	filter->pft_dev = secondary;
5758a37ae75SRobert Mustacchi 
5768a37ae75SRobert Mustacchi 	arg = eptr + 1;
5778a37ae75SRobert Mustacchi 	errno = 0;
5788a37ae75SRobert Mustacchi 	val = strtoul(arg, &eptr, 16);
5798a37ae75SRobert Mustacchi 	if (errno != 0 || (*eptr != '\0' && *eptr != ',')) {
5808a37ae75SRobert Mustacchi 		errx(EXIT_FAILURE, "invalid device filter: '%s': failed to "
5818a37ae75SRobert Mustacchi 		    "parse hex string at %s", orig, arg);
5828a37ae75SRobert Mustacchi 	}
5838a37ae75SRobert Mustacchi 
5848a37ae75SRobert Mustacchi 	if (val > UINT16_MAX) {
585*6b1325cfSRobert Mustacchi 		errx(EXIT_FAILURE, "invalid id: %lx is larger than 0xffff",
586*6b1325cfSRobert Mustacchi 		    val);
5878a37ae75SRobert Mustacchi 	}
5888a37ae75SRobert Mustacchi 
5898a37ae75SRobert Mustacchi 	filter->pft_subven = (uint32_t)val;
5908a37ae75SRobert Mustacchi 	if (*eptr == '\0') {
5918a37ae75SRobert Mustacchi 		return;
5928a37ae75SRobert Mustacchi 	} else if (eptr[1] == '\0') {
5938a37ae75SRobert Mustacchi 		errx(EXIT_FAILURE, "invalid device filter: '%s': filter "
5948a37ae75SRobert Mustacchi 		    "terminated early", arg);
5958a37ae75SRobert Mustacchi 	}
5968a37ae75SRobert Mustacchi 
5978a37ae75SRobert Mustacchi 	arg = eptr + 1;
5988a37ae75SRobert Mustacchi 	errno = 0;
5998a37ae75SRobert Mustacchi 	val = strtoul(arg, &eptr, 16);
6008a37ae75SRobert Mustacchi 	if (errno != 0 || *eptr != '\0') {
6018a37ae75SRobert Mustacchi 		errx(EXIT_FAILURE, "invalid device filter: '%s': failed to "
6028a37ae75SRobert Mustacchi 		    "parse hex string at %s", orig, arg);
6038a37ae75SRobert Mustacchi 	}
6048a37ae75SRobert Mustacchi 
6058a37ae75SRobert Mustacchi 	if (val > UINT16_MAX) {
606*6b1325cfSRobert Mustacchi 		errx(EXIT_FAILURE, "invalid id: %lx is larger than 0xffff",
607*6b1325cfSRobert Mustacchi 		    val);
6088a37ae75SRobert Mustacchi 	}
6098a37ae75SRobert Mustacchi 
6108a37ae75SRobert Mustacchi 	filter->pft_subdev = (uint32_t)val;
6118a37ae75SRobert Mustacchi }
6128a37ae75SRobert Mustacchi 
6138a37ae75SRobert Mustacchi 
6148a37ae75SRobert Mustacchi /*
6158a37ae75SRobert Mustacchi  * Process a series of alias style ways of indicating numeric filters. Use the
6168a37ae75SRobert Mustacchi  * basic alias format for now.
6178a37ae75SRobert Mustacchi  */
6188a37ae75SRobert Mustacchi static void
pcidb_process_filters(int argc,char * argv[],pcidb_walk_t * walkp)6198a37ae75SRobert Mustacchi pcidb_process_filters(int argc, char *argv[], pcidb_walk_t *walkp)
6208a37ae75SRobert Mustacchi {
6218a37ae75SRobert Mustacchi 	if (argc <= 0) {
6228a37ae75SRobert Mustacchi 		walkp->pw_nfilters = 0;
6238a37ae75SRobert Mustacchi 		return;
6248a37ae75SRobert Mustacchi 	}
6258a37ae75SRobert Mustacchi 
6268a37ae75SRobert Mustacchi 	walkp->pw_nfilters = argc;
6278a37ae75SRobert Mustacchi 	walkp->pw_filters = calloc(walkp->pw_nfilters, sizeof (pcidb_filter_t));
6288a37ae75SRobert Mustacchi 	if (walkp->pw_filters == NULL) {
6298a37ae75SRobert Mustacchi 		err(EXIT_FAILURE, "failed to allocate memory for filters");
6308a37ae75SRobert Mustacchi 	}
6318a37ae75SRobert Mustacchi 
6328a37ae75SRobert Mustacchi 	for (int i = 0; i < argc; i++) {
6338a37ae75SRobert Mustacchi 		char *str = strdup(argv[i]);
6348a37ae75SRobert Mustacchi 
6358a37ae75SRobert Mustacchi 		if (str == NULL) {
6368a37ae75SRobert Mustacchi 			errx(EXIT_FAILURE, "failed to duplicate string %s",
6378a37ae75SRobert Mustacchi 			    argv[i]);
6388a37ae75SRobert Mustacchi 		}
6398a37ae75SRobert Mustacchi 
6408a37ae75SRobert Mustacchi 		if (strncmp(str, "pciexclass,", 11) == 0) {
6418a37ae75SRobert Mustacchi 			pcidb_parse_class_filter(&walkp->pw_filters[i],
6428a37ae75SRobert Mustacchi 			    str + 11, argv[i]);
6438a37ae75SRobert Mustacchi 		} else if (strncmp(str, "pciclass,", 9) == 0) {
6448a37ae75SRobert Mustacchi 			pcidb_parse_class_filter(&walkp->pw_filters[i], str + 9,
6458a37ae75SRobert Mustacchi 			    argv[i]);
6468a37ae75SRobert Mustacchi 		} else if (strncmp(str, "pciex", 5) == 0) {
6478a37ae75SRobert Mustacchi 			pcidb_parse_device_filter(&walkp->pw_filters[i],
6488a37ae75SRobert Mustacchi 			    str + 5, argv[i]);
6498a37ae75SRobert Mustacchi 		} else if (strncmp(str, "pci", 3) == 0) {
6508a37ae75SRobert Mustacchi 			pcidb_parse_device_filter(&walkp->pw_filters[i],
6518a37ae75SRobert Mustacchi 			    str + 3, argv[i]);
6528a37ae75SRobert Mustacchi 		} else {
6538a37ae75SRobert Mustacchi 			errx(EXIT_FAILURE, "invalid filter string: %s", str);
6548a37ae75SRobert Mustacchi 		}
6558a37ae75SRobert Mustacchi 
6568a37ae75SRobert Mustacchi 		free(str);
6578a37ae75SRobert Mustacchi 	}
6588a37ae75SRobert Mustacchi }
6598a37ae75SRobert Mustacchi 
6608a37ae75SRobert Mustacchi static void
pcidb_drop_privs(void)6618a37ae75SRobert Mustacchi pcidb_drop_privs(void)
6628a37ae75SRobert Mustacchi {
6638a37ae75SRobert Mustacchi 	priv_set_t *curprivs, *targprivs;
6648a37ae75SRobert Mustacchi 
6658a37ae75SRobert Mustacchi 	if ((curprivs = priv_allocset()) == NULL) {
6668a37ae75SRobert Mustacchi 		err(EXIT_FAILURE, "failed to allocate privilege set to drop "
6678a37ae75SRobert Mustacchi 		    "privs");
6688a37ae75SRobert Mustacchi 	}
6698a37ae75SRobert Mustacchi 
6708a37ae75SRobert Mustacchi 	if (getppriv(PRIV_EFFECTIVE, curprivs) != 0) {
6718a37ae75SRobert Mustacchi 		err(EXIT_FAILURE, "failed to get current privileges");
6728a37ae75SRobert Mustacchi 	}
6738a37ae75SRobert Mustacchi 
6748a37ae75SRobert Mustacchi 	if ((targprivs = priv_allocset()) == NULL) {
6758a37ae75SRobert Mustacchi 		err(EXIT_FAILURE, "failed to allocate privilege set to drop "
6768a37ae75SRobert Mustacchi 		    "privs");
6778a37ae75SRobert Mustacchi 	}
6788a37ae75SRobert Mustacchi 
6798a37ae75SRobert Mustacchi 	/*
6808a37ae75SRobert Mustacchi 	 * Set our privileges to the minimum required. Because stdout will have
6818a37ae75SRobert Mustacchi 	 * already been opened, all we need is the ability to read files from
6828a37ae75SRobert Mustacchi 	 * basic privileges. We opt to keep FILE_DAC_READ if the caller has it
6838a37ae75SRobert Mustacchi 	 * just in case there is something weird about the location of the
6848a37ae75SRobert Mustacchi 	 * pci.ids files.
6858a37ae75SRobert Mustacchi 	 */
6868a37ae75SRobert Mustacchi 	priv_basicset(targprivs);
6878a37ae75SRobert Mustacchi 	VERIFY0(priv_delset(targprivs, PRIV_FILE_LINK_ANY));
6888a37ae75SRobert Mustacchi 	VERIFY0(priv_delset(targprivs, PRIV_PROC_INFO));
6898a37ae75SRobert Mustacchi 	VERIFY0(priv_delset(targprivs, PRIV_PROC_SESSION));
6908a37ae75SRobert Mustacchi 	VERIFY0(priv_delset(targprivs, PRIV_PROC_FORK));
6918a37ae75SRobert Mustacchi 	VERIFY0(priv_delset(targprivs, PRIV_NET_ACCESS));
6928a37ae75SRobert Mustacchi 	VERIFY0(priv_delset(targprivs, PRIV_FILE_WRITE));
6938a37ae75SRobert Mustacchi 	VERIFY0(priv_delset(targprivs, PRIV_PROC_EXEC));
6948a37ae75SRobert Mustacchi 	VERIFY0(priv_addset(targprivs, PRIV_FILE_DAC_READ));
6958a37ae75SRobert Mustacchi 
6968a37ae75SRobert Mustacchi 	priv_intersect(curprivs, targprivs);
6978a37ae75SRobert Mustacchi 
6988a37ae75SRobert Mustacchi 	if (setppriv(PRIV_SET, PRIV_EFFECTIVE, targprivs) != 0) {
6998a37ae75SRobert Mustacchi 		err(EXIT_FAILURE, "failed to reduce privileges");
7008a37ae75SRobert Mustacchi 	}
7018a37ae75SRobert Mustacchi 
7028a37ae75SRobert Mustacchi 	priv_freeset(curprivs);
7038a37ae75SRobert Mustacchi 	priv_freeset(targprivs);
7048a37ae75SRobert Mustacchi }
7058a37ae75SRobert Mustacchi 
7068a37ae75SRobert Mustacchi static int
pcidb_usage(const char * fmt,...)7078a37ae75SRobert Mustacchi pcidb_usage(const char *fmt, ...)
7088a37ae75SRobert Mustacchi {
7098a37ae75SRobert Mustacchi 	if (fmt != NULL) {
7108a37ae75SRobert Mustacchi 		va_list ap;
7118a37ae75SRobert Mustacchi 
7128a37ae75SRobert Mustacchi 		(void) fprintf(stderr, "%s: ", pcidb_progname);
7138a37ae75SRobert Mustacchi 		va_start(ap, fmt);
7148a37ae75SRobert Mustacchi 		(void) vfprintf(stderr, fmt, ap);
7158a37ae75SRobert Mustacchi 		va_end(ap);
7168a37ae75SRobert Mustacchi 		(void) fprintf(stderr, "\n");
7178a37ae75SRobert Mustacchi 	}
7188a37ae75SRobert Mustacchi 
7198a37ae75SRobert Mustacchi 	(void) fprintf(stderr, "usage:  %s [-v|-d|-s|-c|-S|-i] [-H]"
7208a37ae75SRobert Mustacchi 	    "[[-p] [-o <field>[,...]] [<filter>]\n\n"
7218a37ae75SRobert Mustacchi 	    "\t-v\t\tshow vendor table\n"
7228a37ae75SRobert Mustacchi 	    "\t-d\t\tshow device table\n"
7238a37ae75SRobert Mustacchi 	    "\t-s\t\tshow subsystem table\n"
7248a37ae75SRobert Mustacchi 	    "\t-c\t\tshow class table\n"
7258a37ae75SRobert Mustacchi 	    "\t-S\t\tshow subclass table\n"
7268a37ae75SRobert Mustacchi 	    "\t-i\t\tshow programming interface table\n"
7278a37ae75SRobert Mustacchi 	    "\t-H\t\tdo not output column headers\n"
7288a37ae75SRobert Mustacchi 	    "\t-p\t\toutput in parsable form\n"
7298a37ae75SRobert Mustacchi 	    "\t-o field\toutput only specified fields\n\n"
7308a37ae75SRobert Mustacchi 	    "filters take the form of PCI aliases, e.g. pci8086,1522, "
7318a37ae75SRobert Mustacchi 	    "pci1028,1f44,s, or\n"
7328a37ae75SRobert Mustacchi 	    "pciex1022,1480.1462,7c37. Classes can be specified in a similar "
7338a37ae75SRobert Mustacchi 	    "way, e.g.\npciclass,010802 or pciclass,0403.\n", pcidb_progname);
7348a37ae75SRobert Mustacchi 
7358a37ae75SRobert Mustacchi 	return (EXIT_USAGE);
7368a37ae75SRobert Mustacchi }
7378a37ae75SRobert Mustacchi 
7388a37ae75SRobert Mustacchi int
main(int argc,char * argv[])7398a37ae75SRobert Mustacchi main(int argc, char *argv[])
7408a37ae75SRobert Mustacchi {
7418a37ae75SRobert Mustacchi 	pcidb_hdl_t *hdl;
7428a37ae75SRobert Mustacchi 	int c;
7438a37ae75SRobert Mustacchi 	uint_t tablecnt = 0;
7448a37ae75SRobert Mustacchi 	pcidb_table_t table = PCIDB_TABLE_NONE;
7458a37ae75SRobert Mustacchi 	boolean_t parse = B_FALSE, strcase = B_FALSE;
7468a37ae75SRobert Mustacchi 	const char *fields = NULL;
7478a37ae75SRobert Mustacchi 	const char *ofmt_fields_str = NULL;
7488a37ae75SRobert Mustacchi 	const ofmt_field_t *ofmt_fields = NULL;
7498a37ae75SRobert Mustacchi 	ofmt_handle_t ofmt;
7508a37ae75SRobert Mustacchi 	ofmt_status_t oferr;
7518a37ae75SRobert Mustacchi 	uint_t flags = 0;
7528a37ae75SRobert Mustacchi 	pcidb_walk_t walk;
7538a37ae75SRobert Mustacchi 
7548a37ae75SRobert Mustacchi 	bzero(&walk, sizeof (walk));
7558a37ae75SRobert Mustacchi 	pcidb_progname = basename(argv[0]);
7568a37ae75SRobert Mustacchi 
7578a37ae75SRobert Mustacchi 	pcidb_drop_privs();
7588a37ae75SRobert Mustacchi 
7598a37ae75SRobert Mustacchi 	while ((c = getopt(argc, argv, ":vdscSipo:hH")) != -1) {
7608a37ae75SRobert Mustacchi 		switch (c) {
7618a37ae75SRobert Mustacchi 		case 'v':
7628a37ae75SRobert Mustacchi 			tablecnt++;
7638a37ae75SRobert Mustacchi 			table = PCIDB_TABLE_VENDOR;
7648a37ae75SRobert Mustacchi 			break;
7658a37ae75SRobert Mustacchi 		case 'd':
7668a37ae75SRobert Mustacchi 			tablecnt++;
7678a37ae75SRobert Mustacchi 			table = PCIDB_TABLE_DEVICE;
7688a37ae75SRobert Mustacchi 			break;
7698a37ae75SRobert Mustacchi 		case 's':
7708a37ae75SRobert Mustacchi 			tablecnt++;
7718a37ae75SRobert Mustacchi 			table = PCIDB_TABLE_SUBSYSTEM;
7728a37ae75SRobert Mustacchi 			break;
7738a37ae75SRobert Mustacchi 		case 'c':
7748a37ae75SRobert Mustacchi 			tablecnt++;
7758a37ae75SRobert Mustacchi 			table = PCIDB_TABLE_CLASS;
7768a37ae75SRobert Mustacchi 			break;
7778a37ae75SRobert Mustacchi 		case 'S':
7788a37ae75SRobert Mustacchi 			tablecnt++;
7798a37ae75SRobert Mustacchi 			table = PCIDB_TABLE_SUBCLASS;
7808a37ae75SRobert Mustacchi 			break;
7818a37ae75SRobert Mustacchi 		case 'i':
7828a37ae75SRobert Mustacchi 			tablecnt++;
7838a37ae75SRobert Mustacchi 			table = PCIDB_TABLE_PROGIF;
7848a37ae75SRobert Mustacchi 			break;
7858a37ae75SRobert Mustacchi 		case 'p':
7868a37ae75SRobert Mustacchi 			parse = B_TRUE;
7878a37ae75SRobert Mustacchi 			flags |= OFMT_PARSABLE;
7888a37ae75SRobert Mustacchi 			break;
7898a37ae75SRobert Mustacchi 		case 'o':
7908a37ae75SRobert Mustacchi 			fields = optarg;
7918a37ae75SRobert Mustacchi 			break;
7928a37ae75SRobert Mustacchi 		case 'h':
7938a37ae75SRobert Mustacchi 			return (pcidb_usage(NULL));
7948a37ae75SRobert Mustacchi 		case 'H':
7958a37ae75SRobert Mustacchi 			flags |= OFMT_NOHEADER;
7968a37ae75SRobert Mustacchi 			break;
7978a37ae75SRobert Mustacchi 		case ':':
7988a37ae75SRobert Mustacchi 			return (pcidb_usage("Option -%c requires an argument",
7998a37ae75SRobert Mustacchi 			    optopt));
8008a37ae75SRobert Mustacchi 		case '?':
8018a37ae75SRobert Mustacchi 			return (pcidb_usage("unknown option: -%c", optopt));
8028a37ae75SRobert Mustacchi 		}
8038a37ae75SRobert Mustacchi 	}
8048a37ae75SRobert Mustacchi 
8058a37ae75SRobert Mustacchi 	if (tablecnt > 1) {
8068a37ae75SRobert Mustacchi 		errx(EXIT_USAGE, "more than one table specified, only one of "
8078a37ae75SRobert Mustacchi 		    "-v, -d, -s, -c, -S, and -i may be specified");
8088a37ae75SRobert Mustacchi 	}
8098a37ae75SRobert Mustacchi 
8108a37ae75SRobert Mustacchi 	if (parse && fields == NULL) {
8118a37ae75SRobert Mustacchi 		errx(EXIT_USAGE, "-p requires fields specified with -o");
8128a37ae75SRobert Mustacchi 	}
8138a37ae75SRobert Mustacchi 
8148a37ae75SRobert Mustacchi 	argc -= optind;
8158a37ae75SRobert Mustacchi 	argv += optind;
8168a37ae75SRobert Mustacchi 
8178a37ae75SRobert Mustacchi 	pcidb_process_filters(argc, argv, &walk);
8188a37ae75SRobert Mustacchi 
8198a37ae75SRobert Mustacchi 	switch (table) {
8208a37ae75SRobert Mustacchi 	case PCIDB_TABLE_VENDOR:
8218a37ae75SRobert Mustacchi 		ofmt_fields = pcidb_vendor_ofmt;
8228a37ae75SRobert Mustacchi 		ofmt_fields_str = pcidb_vendor_fields;
8238a37ae75SRobert Mustacchi 		break;
8248a37ae75SRobert Mustacchi 	case PCIDB_TABLE_NONE:
8258a37ae75SRobert Mustacchi 	case PCIDB_TABLE_DEVICE:
8268a37ae75SRobert Mustacchi 		ofmt_fields = pcidb_device_ofmt;
8278a37ae75SRobert Mustacchi 		ofmt_fields_str = pcidb_device_fields;
8288a37ae75SRobert Mustacchi 		break;
8298a37ae75SRobert Mustacchi 	case PCIDB_TABLE_SUBSYSTEM:
8308a37ae75SRobert Mustacchi 		ofmt_fields = pcidb_subsystem_ofmt;
8318a37ae75SRobert Mustacchi 		ofmt_fields_str = pcidb_subsystem_fields;
8328a37ae75SRobert Mustacchi 		break;
8338a37ae75SRobert Mustacchi 	case PCIDB_TABLE_CLASS:
8348a37ae75SRobert Mustacchi 		ofmt_fields = pcidb_class_ofmt;
8358a37ae75SRobert Mustacchi 		ofmt_fields_str = pcidb_class_fields;
8368a37ae75SRobert Mustacchi 		break;
8378a37ae75SRobert Mustacchi 	case PCIDB_TABLE_SUBCLASS:
8388a37ae75SRobert Mustacchi 		ofmt_fields = pcidb_subclass_ofmt;
8398a37ae75SRobert Mustacchi 		ofmt_fields_str = pcidb_subclass_fields;
8408a37ae75SRobert Mustacchi 		break;
8418a37ae75SRobert Mustacchi 	case PCIDB_TABLE_PROGIF:
8428a37ae75SRobert Mustacchi 		ofmt_fields = pcidb_progif_ofmt;
8438a37ae75SRobert Mustacchi 		ofmt_fields_str = pcidb_progif_fields;
8448a37ae75SRobert Mustacchi 		break;
8458a37ae75SRobert Mustacchi 	}
8468a37ae75SRobert Mustacchi 
8478a37ae75SRobert Mustacchi 	if (fields == NULL) {
8488a37ae75SRobert Mustacchi 		fields = ofmt_fields_str;
8498a37ae75SRobert Mustacchi 	}
8508a37ae75SRobert Mustacchi 
8518a37ae75SRobert Mustacchi 	oferr = ofmt_open(fields, ofmt_fields, flags, 0, &ofmt);
8528a37ae75SRobert Mustacchi 	ofmt_check(oferr, parse, ofmt, pcidb_ofmt_errx, warnx);
8538a37ae75SRobert Mustacchi 
8548a37ae75SRobert Mustacchi 	hdl = pcidb_open(PCIDB_VERSION);
8558a37ae75SRobert Mustacchi 	if (hdl == NULL) {
8568a37ae75SRobert Mustacchi 		err(EXIT_FAILURE, "failed to initialize PCI IDs database");
8578a37ae75SRobert Mustacchi 	}
8588a37ae75SRobert Mustacchi 
8598a37ae75SRobert Mustacchi 	walk.pw_hdl = hdl;
8608a37ae75SRobert Mustacchi 	walk.pw_ofmt = ofmt;
8618a37ae75SRobert Mustacchi 	walk.pw_strcase = strcase;
8628a37ae75SRobert Mustacchi 
8638a37ae75SRobert Mustacchi 	switch (table) {
8648a37ae75SRobert Mustacchi 	case PCIDB_TABLE_VENDOR:
8658a37ae75SRobert Mustacchi 		pcidb_walk_vendors(&walk);
8668a37ae75SRobert Mustacchi 		break;
8678a37ae75SRobert Mustacchi 	case PCIDB_TABLE_NONE:
8688a37ae75SRobert Mustacchi 	case PCIDB_TABLE_DEVICE:
8698a37ae75SRobert Mustacchi 		pcidb_walk_devices(&walk);
8708a37ae75SRobert Mustacchi 		break;
8718a37ae75SRobert Mustacchi 	case PCIDB_TABLE_SUBSYSTEM:
8728a37ae75SRobert Mustacchi 		pcidb_walk_subsystems(&walk);
8738a37ae75SRobert Mustacchi 		break;
8748a37ae75SRobert Mustacchi 	case PCIDB_TABLE_CLASS:
8758a37ae75SRobert Mustacchi 		pcidb_walk_classes(&walk);
8768a37ae75SRobert Mustacchi 		break;
8778a37ae75SRobert Mustacchi 	case PCIDB_TABLE_SUBCLASS:
8788a37ae75SRobert Mustacchi 		pcidb_walk_subclasses(&walk);
8798a37ae75SRobert Mustacchi 		break;
8808a37ae75SRobert Mustacchi 	case PCIDB_TABLE_PROGIF:
8818a37ae75SRobert Mustacchi 		pcidb_walk_progifs(&walk);
8828a37ae75SRobert Mustacchi 		break;
8838a37ae75SRobert Mustacchi 	}
8848a37ae75SRobert Mustacchi 
8858a37ae75SRobert Mustacchi 	ofmt_close(ofmt);
8868a37ae75SRobert Mustacchi 	pcidb_close(hdl);
8878a37ae75SRobert Mustacchi 	return (EXIT_SUCCESS);
8888a37ae75SRobert Mustacchi }
889