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