2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
13 * Copyright 2021 Oxide Computer Company
17 * A tool to interface with the pci.ids database driven by libpcidb.
30 #include <sys/debug.h>
35 static char *pcidb_progname
;
48 PCIDB_TABLE_SUBSYSTEM
,
66 PCIDB_OFMT_SUBCLASSSTR
,
71 typedef struct pcidb_filter
{
77 uint32_t pft_subclass
;
81 #define PCIDB_NOFILTER UINT32_MAX
83 typedef struct pcidb_walk
{
85 ofmt_handle_t pw_ofmt
;
86 pcidb_vendor_t
*pw_vendor
;
87 pcidb_device_t
*pw_device
;
88 pcidb_subvd_t
*pw_subvd
;
89 pcidb_class_t
*pw_class
;
90 pcidb_subclass_t
*pw_subclass
;
91 pcidb_progif_t
*pw_progif
;
94 pcidb_filter_t
*pw_filters
;
98 pcidb_write_vendor(ofmt_arg_t
*ofarg
, char *buf
, uint_t buflen
)
100 pcidb_walk_t
*walk
= ofarg
->ofmt_cbarg
;
102 VERIFY(walk
->pw_vendor
!= NULL
);
103 switch (ofarg
->ofmt_id
) {
105 (void) snprintf(buf
, buflen
, "%x",
106 pcidb_vendor_id(walk
->pw_vendor
));
108 case PCIDB_OFMT_VENSTR
:
109 (void) strlcpy(buf
, pcidb_vendor_name(walk
->pw_vendor
), buflen
);
118 pcidb_write_device(ofmt_arg_t
*ofarg
, char *buf
, uint_t buflen
)
120 pcidb_walk_t
*walk
= ofarg
->ofmt_cbarg
;
122 VERIFY(walk
->pw_device
!= NULL
);
123 switch (ofarg
->ofmt_id
) {
125 (void) snprintf(buf
, buflen
, "%x",
126 pcidb_device_id(walk
->pw_device
));
128 case PCIDB_OFMT_DEVSTR
:
129 (void) strlcpy(buf
, pcidb_device_name(walk
->pw_device
), buflen
);
138 pcidb_write_subsystem(ofmt_arg_t
*ofarg
, char *buf
, uint_t buflen
)
140 pcidb_walk_t
*walk
= ofarg
->ofmt_cbarg
;
141 pcidb_vendor_t
*vendor
;
143 VERIFY(walk
->pw_subvd
!= NULL
);
144 switch (ofarg
->ofmt_id
) {
145 case PCIDB_OFMT_SVID
:
146 (void) snprintf(buf
, buflen
, "%x",
147 pcidb_subvd_svid(walk
->pw_subvd
));
149 case PCIDB_OFMT_SDID
:
150 (void) snprintf(buf
, buflen
, "%x",
151 pcidb_subvd_sdid(walk
->pw_subvd
));
153 case PCIDB_OFMT_SUBSYSSTR
:
154 (void) strlcpy(buf
, pcidb_subvd_name(walk
->pw_subvd
), buflen
);
156 case PCIDB_OFMT_SUBVENSTR
:
157 vendor
= pcidb_lookup_vendor(walk
->pw_hdl
,
158 pcidb_subvd_svid(walk
->pw_subvd
));
159 if (vendor
== NULL
) {
162 (void) strlcpy(buf
, pcidb_vendor_name(vendor
), buflen
);
171 pcidb_write_class(ofmt_arg_t
*ofarg
, char *buf
, uint_t buflen
)
173 pcidb_walk_t
*walk
= ofarg
->ofmt_cbarg
;
175 VERIFY(walk
->pw_class
!= NULL
);
176 switch (ofarg
->ofmt_id
) {
178 (void) snprintf(buf
, buflen
, "%x",
179 pcidb_class_code(walk
->pw_class
));
181 case PCIDB_OFMT_CLASSSTR
:
182 (void) strlcpy(buf
, pcidb_class_name(walk
->pw_class
), buflen
);
191 pcidb_write_subclass(ofmt_arg_t
*ofarg
, char *buf
, uint_t buflen
)
193 pcidb_walk_t
*walk
= ofarg
->ofmt_cbarg
;
195 VERIFY(walk
->pw_subclass
!= NULL
);
196 switch (ofarg
->ofmt_id
) {
198 (void) snprintf(buf
, buflen
, "%x",
199 pcidb_subclass_code(walk
->pw_subclass
));
201 case PCIDB_OFMT_SUBCLASSSTR
:
202 (void) strlcpy(buf
, pcidb_subclass_name(walk
->pw_subclass
),
212 pcidb_write_progif(ofmt_arg_t
*ofarg
, char *buf
, uint_t buflen
)
214 pcidb_walk_t
*walk
= ofarg
->ofmt_cbarg
;
216 VERIFY(walk
->pw_progif
!= NULL
);
217 switch (ofarg
->ofmt_id
) {
219 (void) snprintf(buf
, buflen
, "%x",
220 pcidb_progif_code(walk
->pw_progif
));
222 case PCIDB_OFMT_PROGIFSTR
:
223 (void) strlcpy(buf
, pcidb_progif_name(walk
->pw_progif
),
232 static const char *pcidb_vendor_fields
= "vid,vendor";
233 static const ofmt_field_t pcidb_vendor_ofmt
[] = {
234 { "VID", 8, PCIDB_OFMT_VID
, pcidb_write_vendor
},
235 { "VENDOR", 30, PCIDB_OFMT_VENSTR
, pcidb_write_vendor
},
239 static const char *pcidb_device_fields
= "vid,did,vendor,device";
240 static const ofmt_field_t pcidb_device_ofmt
[] = {
241 { "VID", 8, PCIDB_OFMT_VID
, pcidb_write_vendor
},
242 { "VENDOR", 30, PCIDB_OFMT_VENSTR
, pcidb_write_vendor
},
243 { "DID", 8, PCIDB_OFMT_DID
, pcidb_write_device
},
244 { "DEVICE", 30, PCIDB_OFMT_DEVSTR
, pcidb_write_device
},
248 static const char *pcidb_subsystem_fields
= "vid,did,svid,sdid,subsystem";
249 static const ofmt_field_t pcidb_subsystem_ofmt
[] = {
250 { "VID", 8, PCIDB_OFMT_VID
, pcidb_write_vendor
},
251 { "VENDOR", 30, PCIDB_OFMT_VENSTR
, pcidb_write_vendor
},
252 { "DID", 8, PCIDB_OFMT_DID
, pcidb_write_device
},
253 { "DEVICE", 30, PCIDB_OFMT_DEVSTR
, pcidb_write_device
},
254 { "SVID", 8, PCIDB_OFMT_SVID
, pcidb_write_subsystem
},
255 { "SDID", 8, PCIDB_OFMT_SDID
, pcidb_write_subsystem
},
256 { "SUBSYSTEM", 30, PCIDB_OFMT_SUBSYSSTR
, pcidb_write_subsystem
},
257 { "SUBVENDOR", 30, PCIDB_OFMT_SUBVENSTR
, pcidb_write_subsystem
},
261 static const char *pcidb_class_fields
= "bcc,class";
262 static const ofmt_field_t pcidb_class_ofmt
[] = {
263 { "BCC", 6, PCIDB_OFMT_BCC
, pcidb_write_class
},
264 { "CLASS", 30, PCIDB_OFMT_CLASSSTR
, pcidb_write_class
},
268 static const char *pcidb_subclass_fields
= "bcc,scc,class,subclass";
269 static const ofmt_field_t pcidb_subclass_ofmt
[] = {
270 { "BCC", 6, PCIDB_OFMT_BCC
, pcidb_write_class
},
271 { "CLASS", 30, PCIDB_OFMT_CLASSSTR
, pcidb_write_class
},
272 { "SCC", 6, PCIDB_OFMT_SCC
, pcidb_write_subclass
},
273 { "SUBCLASS", 30, PCIDB_OFMT_SUBCLASSSTR
, pcidb_write_subclass
},
277 static const char *pcidb_progif_fields
= "bcc,scc,pi,subclass,interface";
278 static const ofmt_field_t pcidb_progif_ofmt
[] = {
279 { "BCC", 6, PCIDB_OFMT_BCC
, pcidb_write_class
},
280 { "CLASS", 30, PCIDB_OFMT_CLASSSTR
, pcidb_write_class
},
281 { "SCC", 6, PCIDB_OFMT_SCC
, pcidb_write_subclass
},
282 { "SUBCLASS", 30, PCIDB_OFMT_SUBCLASSSTR
, pcidb_write_subclass
},
283 { "PI", 6, PCIDB_OFMT_PI
, pcidb_write_progif
},
284 { "INTERFACE", 30, PCIDB_OFMT_PROGIFSTR
, pcidb_write_progif
},
289 pcidb_ofmt_errx(const char *fmt
, ...)
294 verrx(EXIT_FAILURE
, fmt
, ap
);
298 pcidb_filter_match(pcidb_walk_t
*walk
)
300 if (walk
->pw_nfilters
== 0) {
304 for (uint_t i
= 0; i
< walk
->pw_nfilters
; i
++) {
305 const pcidb_filter_t
*filt
= &walk
->pw_filters
[i
];
306 if (filt
->pft_vend
!= PCIDB_NOFILTER
&&
307 (walk
->pw_vendor
== NULL
||
308 filt
->pft_vend
!= pcidb_vendor_id(walk
->pw_vendor
))) {
312 if (filt
->pft_dev
!= PCIDB_NOFILTER
&&
313 (walk
->pw_device
== NULL
||
314 filt
->pft_dev
!= pcidb_device_id(walk
->pw_device
))) {
318 if (filt
->pft_subven
!= PCIDB_NOFILTER
&&
319 (walk
->pw_subvd
== NULL
||
320 filt
->pft_subven
!= pcidb_subvd_svid(walk
->pw_subvd
))) {
324 if (filt
->pft_subdev
!= PCIDB_NOFILTER
&&
325 (walk
->pw_subvd
== NULL
||
326 filt
->pft_subdev
!= pcidb_subvd_sdid(walk
->pw_subvd
))) {
330 if (filt
->pft_class
!= PCIDB_NOFILTER
&&
331 (walk
->pw_class
== NULL
||
332 filt
->pft_class
!= pcidb_class_code(walk
->pw_class
))) {
336 if (filt
->pft_subclass
!= PCIDB_NOFILTER
&&
337 (walk
->pw_subclass
== NULL
||
338 filt
->pft_subclass
!=
339 pcidb_subclass_code(walk
->pw_subclass
))) {
343 if (filt
->pft_progif
!= PCIDB_NOFILTER
&&
344 (walk
->pw_progif
== NULL
||
345 filt
->pft_progif
!= pcidb_progif_code(walk
->pw_progif
))) {
356 pcidb_walk_vendors(pcidb_walk_t
*walk
)
358 pcidb_hdl_t
*hdl
= walk
->pw_hdl
;
360 for (pcidb_vendor_t
*vend
= pcidb_vendor_iter(hdl
); vend
!= NULL
;
361 vend
= pcidb_vendor_iter_next(vend
)) {
362 walk
->pw_vendor
= vend
;
363 if (!pcidb_filter_match(walk
))
365 ofmt_print(walk
->pw_ofmt
, walk
);
370 pcidb_walk_devices(pcidb_walk_t
*walk
)
372 pcidb_hdl_t
*hdl
= walk
->pw_hdl
;
374 for (pcidb_vendor_t
*vend
= pcidb_vendor_iter(hdl
); vend
!= NULL
;
375 vend
= pcidb_vendor_iter_next(vend
)) {
376 walk
->pw_vendor
= vend
;
377 for (pcidb_device_t
*dev
= pcidb_device_iter(vend
); dev
!= NULL
;
378 dev
= pcidb_device_iter_next(dev
)) {
379 walk
->pw_device
= dev
;
380 if (!pcidb_filter_match(walk
))
382 ofmt_print(walk
->pw_ofmt
, walk
);
388 pcidb_walk_subsystems(pcidb_walk_t
*walk
)
390 pcidb_hdl_t
*hdl
= walk
->pw_hdl
;
392 for (pcidb_vendor_t
*vend
= pcidb_vendor_iter(hdl
); vend
!= NULL
;
393 vend
= pcidb_vendor_iter_next(vend
)) {
394 walk
->pw_vendor
= vend
;
395 for (pcidb_device_t
*dev
= pcidb_device_iter(vend
); dev
!= NULL
;
396 dev
= pcidb_device_iter_next(dev
)) {
397 walk
->pw_device
= dev
;
398 for (pcidb_subvd_t
*sub
= pcidb_subvd_iter(dev
);
399 sub
!= NULL
; sub
= pcidb_subvd_iter_next(sub
)) {
400 walk
->pw_subvd
= sub
;
401 if (!pcidb_filter_match(walk
))
403 ofmt_print(walk
->pw_ofmt
, walk
);
411 pcidb_walk_classes(pcidb_walk_t
*walk
)
413 for (pcidb_class_t
*class = pcidb_class_iter(walk
->pw_hdl
);
414 class != NULL
; class = pcidb_class_iter_next(class)) {
415 walk
->pw_class
= class;
416 if (!pcidb_filter_match(walk
))
418 ofmt_print(walk
->pw_ofmt
, walk
);
423 pcidb_walk_subclasses(pcidb_walk_t
*walk
)
425 for (pcidb_class_t
*class = pcidb_class_iter(walk
->pw_hdl
);
426 class != NULL
; class = pcidb_class_iter_next(class)) {
427 walk
->pw_class
= class;
428 for (pcidb_subclass_t
*sub
= pcidb_subclass_iter(class);
429 sub
!= NULL
; sub
= pcidb_subclass_iter_next(sub
)) {
430 walk
->pw_subclass
= sub
;
431 if (!pcidb_filter_match(walk
))
433 ofmt_print(walk
->pw_ofmt
, walk
);
439 pcidb_walk_progifs(pcidb_walk_t
*walk
)
441 for (pcidb_class_t
*class = pcidb_class_iter(walk
->pw_hdl
);
442 class != NULL
; class = pcidb_class_iter_next(class)) {
443 walk
->pw_class
= class;
444 for (pcidb_subclass_t
*sub
= pcidb_subclass_iter(class);
445 sub
!= NULL
; sub
= pcidb_subclass_iter_next(sub
)) {
446 walk
->pw_subclass
= sub
;
447 for (pcidb_progif_t
*progif
= pcidb_progif_iter(sub
);
449 progif
= pcidb_progif_iter_next(progif
)) {
450 walk
->pw_progif
= progif
;
451 if (!pcidb_filter_match(walk
))
453 ofmt_print(walk
->pw_ofmt
, walk
);
460 pcidb_parse_class_filter(pcidb_filter_t
*filter
, char *arg
, const char *orig
)
466 filter
->pft_vend
= filter
->pft_dev
= PCIDB_NOFILTER
;
467 filter
->pft_subven
= filter
->pft_subdev
= PCIDB_NOFILTER
;
470 if (len
!= 2 && len
!= 4 && len
!= 6) {
471 errx(EXIT_FAILURE
, "invalid class filter: '%s': bad length",
476 val
= strtoul(arg
, &eptr
, 16);
477 if (errno
!= 0 || *eptr
!= '\0') {
478 errx(EXIT_FAILURE
, "invalid class filter: '%s': failed to "
479 "parse hex string", orig
);
483 filter
->pft_progif
= val
& 0xff;
486 filter
->pft_progif
= PCIDB_NOFILTER
;
490 filter
->pft_subclass
= val
& 0xff;
493 filter
->pft_subclass
= PCIDB_NOFILTER
;
496 filter
->pft_class
= val
& 0xff;
500 pcidb_parse_device_filter(pcidb_filter_t
*filter
, char *arg
, const char *orig
)
503 uint32_t primary
, secondary
;
506 filter
->pft_vend
= filter
->pft_dev
= PCIDB_NOFILTER
;
507 filter
->pft_subven
= filter
->pft_subdev
= PCIDB_NOFILTER
;
508 filter
->pft_class
= filter
->pft_subclass
= PCIDB_NOFILTER
;
509 filter
->pft_progif
= PCIDB_NOFILTER
;
512 val
= strtoul(arg
, &eptr
, 16);
513 if (errno
!= 0 || (*eptr
!= '\0' && *eptr
!= ',')) {
514 errx(EXIT_FAILURE
, "invalid device filter: '%s': failed to "
515 "parse hex string", orig
);
518 if (val
> UINT16_MAX
) {
519 errx(EXIT_FAILURE
, "invalid id: %lx is larger than 0xffff",
523 primary
= (uint32_t)val
;
525 filter
->pft_vend
= primary
;
527 } else if (strcmp(eptr
, ",s") == 0) {
528 filter
->pft_subven
= primary
;
530 } else if (eptr
[1] == '\0') {
531 errx(EXIT_FAILURE
, "invalid device filter: '%s': filter "
532 "terminated early", arg
);
536 val
= strtoul(arg
, &eptr
, 16);
537 if (errno
!= 0 || (*eptr
!= '\0' && *eptr
!= ',' && *eptr
!= '.')) {
538 errx(EXIT_FAILURE
, "invalid device filter: '%s': failed to "
539 "parse hex string at %s", orig
, arg
);
542 if (val
> UINT16_MAX
) {
543 errx(EXIT_FAILURE
, "invalid id: %lx is larger than 0xffff",
547 secondary
= (uint32_t)val
;
549 filter
->pft_vend
= primary
;
550 filter
->pft_dev
= secondary
;
552 } else if (eptr
[1] == '\0') {
553 errx(EXIT_FAILURE
, "invalid device filter: '%s': filter "
554 "terminated early", arg
);
558 if (eptr
[1] == 'p' && eptr
[2] == '\0') {
559 filter
->pft_vend
= primary
;
560 filter
->pft_dev
= secondary
;
563 if (eptr
[1] == 's' && eptr
[2] == '\0') {
564 filter
->pft_subven
= primary
;
565 filter
->pft_subdev
= secondary
;
568 errx(EXIT_FAILURE
, "invalid device filter: '%s': invalid "
569 "trailing comma at %s, expected either ,p or ,s",
573 filter
->pft_vend
= primary
;
574 filter
->pft_dev
= secondary
;
578 val
= strtoul(arg
, &eptr
, 16);
579 if (errno
!= 0 || (*eptr
!= '\0' && *eptr
!= ',')) {
580 errx(EXIT_FAILURE
, "invalid device filter: '%s': failed to "
581 "parse hex string at %s", orig
, arg
);
584 if (val
> UINT16_MAX
) {
585 errx(EXIT_FAILURE
, "invalid id: %lx is larger than 0xffff",
589 filter
->pft_subven
= (uint32_t)val
;
592 } else if (eptr
[1] == '\0') {
593 errx(EXIT_FAILURE
, "invalid device filter: '%s': filter "
594 "terminated early", arg
);
599 val
= strtoul(arg
, &eptr
, 16);
600 if (errno
!= 0 || *eptr
!= '\0') {
601 errx(EXIT_FAILURE
, "invalid device filter: '%s': failed to "
602 "parse hex string at %s", orig
, arg
);
605 if (val
> UINT16_MAX
) {
606 errx(EXIT_FAILURE
, "invalid id: %lx is larger than 0xffff",
610 filter
->pft_subdev
= (uint32_t)val
;
615 * Process a series of alias style ways of indicating numeric filters. Use the
616 * basic alias format for now.
619 pcidb_process_filters(int argc
, char *argv
[], pcidb_walk_t
*walkp
)
622 walkp
->pw_nfilters
= 0;
626 walkp
->pw_nfilters
= argc
;
627 walkp
->pw_filters
= calloc(walkp
->pw_nfilters
, sizeof (pcidb_filter_t
));
628 if (walkp
->pw_filters
== NULL
) {
629 err(EXIT_FAILURE
, "failed to allocate memory for filters");
632 for (int i
= 0; i
< argc
; i
++) {
633 char *str
= strdup(argv
[i
]);
636 errx(EXIT_FAILURE
, "failed to duplicate string %s",
640 if (strncmp(str
, "pciexclass,", 11) == 0) {
641 pcidb_parse_class_filter(&walkp
->pw_filters
[i
],
643 } else if (strncmp(str
, "pciclass,", 9) == 0) {
644 pcidb_parse_class_filter(&walkp
->pw_filters
[i
], str
+ 9,
646 } else if (strncmp(str
, "pciex", 5) == 0) {
647 pcidb_parse_device_filter(&walkp
->pw_filters
[i
],
649 } else if (strncmp(str
, "pci", 3) == 0) {
650 pcidb_parse_device_filter(&walkp
->pw_filters
[i
],
653 errx(EXIT_FAILURE
, "invalid filter string: %s", str
);
661 pcidb_drop_privs(void)
663 priv_set_t
*curprivs
, *targprivs
;
665 if ((curprivs
= priv_allocset()) == NULL
) {
666 err(EXIT_FAILURE
, "failed to allocate privilege set to drop "
670 if (getppriv(PRIV_EFFECTIVE
, curprivs
) != 0) {
671 err(EXIT_FAILURE
, "failed to get current privileges");
674 if ((targprivs
= priv_allocset()) == NULL
) {
675 err(EXIT_FAILURE
, "failed to allocate privilege set to drop "
680 * Set our privileges to the minimum required. Because stdout will have
681 * already been opened, all we need is the ability to read files from
682 * basic privileges. We opt to keep FILE_DAC_READ if the caller has it
683 * just in case there is something weird about the location of the
686 priv_basicset(targprivs
);
687 VERIFY0(priv_delset(targprivs
, PRIV_FILE_LINK_ANY
));
688 VERIFY0(priv_delset(targprivs
, PRIV_PROC_INFO
));
689 VERIFY0(priv_delset(targprivs
, PRIV_PROC_SESSION
));
690 VERIFY0(priv_delset(targprivs
, PRIV_PROC_FORK
));
691 VERIFY0(priv_delset(targprivs
, PRIV_NET_ACCESS
));
692 VERIFY0(priv_delset(targprivs
, PRIV_FILE_WRITE
));
693 VERIFY0(priv_delset(targprivs
, PRIV_PROC_EXEC
));
694 VERIFY0(priv_addset(targprivs
, PRIV_FILE_DAC_READ
));
696 priv_intersect(curprivs
, targprivs
);
698 if (setppriv(PRIV_SET
, PRIV_EFFECTIVE
, targprivs
) != 0) {
699 err(EXIT_FAILURE
, "failed to reduce privileges");
702 priv_freeset(curprivs
);
703 priv_freeset(targprivs
);
707 pcidb_usage(const char *fmt
, ...)
712 (void) fprintf(stderr
, "%s: ", pcidb_progname
);
714 (void) vfprintf(stderr
, fmt
, ap
);
716 (void) fprintf(stderr
, "\n");
719 (void) fprintf(stderr
, "usage: %s [-v|-d|-s|-c|-S|-i] [-H]"
720 "[[-p] [-o <field>[,...]] [<filter>]\n\n"
721 "\t-v\t\tshow vendor table\n"
722 "\t-d\t\tshow device table\n"
723 "\t-s\t\tshow subsystem table\n"
724 "\t-c\t\tshow class table\n"
725 "\t-S\t\tshow subclass table\n"
726 "\t-i\t\tshow programming interface table\n"
727 "\t-H\t\tdo not output column headers\n"
728 "\t-p\t\toutput in parsable form\n"
729 "\t-o field\toutput only specified fields\n\n"
730 "filters take the form of PCI aliases, e.g. pci8086,1522, "
731 "pci1028,1f44,s, or\n"
732 "pciex1022,1480.1462,7c37. Classes can be specified in a similar "
733 "way, e.g.\npciclass,010802 or pciclass,0403.\n", pcidb_progname
);
739 main(int argc
, char *argv
[])
744 pcidb_table_t table
= PCIDB_TABLE_NONE
;
745 boolean_t parse
= B_FALSE
, strcase
= B_FALSE
;
746 const char *fields
= NULL
;
747 const char *ofmt_fields_str
= NULL
;
748 const ofmt_field_t
*ofmt_fields
= NULL
;
754 bzero(&walk
, sizeof (walk
));
755 pcidb_progname
= basename(argv
[0]);
759 while ((c
= getopt(argc
, argv
, ":vdscSipo:hH")) != -1) {
763 table
= PCIDB_TABLE_VENDOR
;
767 table
= PCIDB_TABLE_DEVICE
;
771 table
= PCIDB_TABLE_SUBSYSTEM
;
775 table
= PCIDB_TABLE_CLASS
;
779 table
= PCIDB_TABLE_SUBCLASS
;
783 table
= PCIDB_TABLE_PROGIF
;
787 flags
|= OFMT_PARSABLE
;
793 return (pcidb_usage(NULL
));
795 flags
|= OFMT_NOHEADER
;
798 return (pcidb_usage("Option -%c requires an argument",
801 return (pcidb_usage("unknown option: -%c", optopt
));
806 errx(EXIT_USAGE
, "more than one table specified, only one of "
807 "-v, -d, -s, -c, -S, and -i may be specified");
810 if (parse
&& fields
== NULL
) {
811 errx(EXIT_USAGE
, "-p requires fields specified with -o");
817 pcidb_process_filters(argc
, argv
, &walk
);
820 case PCIDB_TABLE_VENDOR
:
821 ofmt_fields
= pcidb_vendor_ofmt
;
822 ofmt_fields_str
= pcidb_vendor_fields
;
824 case PCIDB_TABLE_NONE
:
825 case PCIDB_TABLE_DEVICE
:
826 ofmt_fields
= pcidb_device_ofmt
;
827 ofmt_fields_str
= pcidb_device_fields
;
829 case PCIDB_TABLE_SUBSYSTEM
:
830 ofmt_fields
= pcidb_subsystem_ofmt
;
831 ofmt_fields_str
= pcidb_subsystem_fields
;
833 case PCIDB_TABLE_CLASS
:
834 ofmt_fields
= pcidb_class_ofmt
;
835 ofmt_fields_str
= pcidb_class_fields
;
837 case PCIDB_TABLE_SUBCLASS
:
838 ofmt_fields
= pcidb_subclass_ofmt
;
839 ofmt_fields_str
= pcidb_subclass_fields
;
841 case PCIDB_TABLE_PROGIF
:
842 ofmt_fields
= pcidb_progif_ofmt
;
843 ofmt_fields_str
= pcidb_progif_fields
;
847 if (fields
== NULL
) {
848 fields
= ofmt_fields_str
;
851 oferr
= ofmt_open(fields
, ofmt_fields
, flags
, 0, &ofmt
);
852 ofmt_check(oferr
, parse
, ofmt
, pcidb_ofmt_errx
, warnx
);
854 hdl
= pcidb_open(PCIDB_VERSION
);
856 err(EXIT_FAILURE
, "failed to initialize PCI IDs database");
861 walk
.pw_strcase
= strcase
;
864 case PCIDB_TABLE_VENDOR
:
865 pcidb_walk_vendors(&walk
);
867 case PCIDB_TABLE_NONE
:
868 case PCIDB_TABLE_DEVICE
:
869 pcidb_walk_devices(&walk
);
871 case PCIDB_TABLE_SUBSYSTEM
:
872 pcidb_walk_subsystems(&walk
);
874 case PCIDB_TABLE_CLASS
:
875 pcidb_walk_classes(&walk
);
877 case PCIDB_TABLE_SUBCLASS
:
878 pcidb_walk_subclasses(&walk
);
880 case PCIDB_TABLE_PROGIF
:
881 pcidb_walk_progifs(&walk
);
887 return (EXIT_SUCCESS
);