16101 fix usr/src/cmd err(3C) formatting mismatches
[illumos-gate.git] / usr / src / cmd / pcidb / pcidb.c
blob92aa0ba2daee87adff349812a335da7883e970d3
1 /*
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
5 * 1.0 of the CDDL.
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.
20 #include <stdio.h>
21 #include <stdarg.h>
22 #include <pcidb.h>
23 #include <err.h>
24 #include <libgen.h>
25 #include <string.h>
26 #include <strings.h>
27 #include <stdlib.h>
28 #include <ofmt.h>
29 #include <errno.h>
30 #include <sys/debug.h>
31 #include <priv.h>
33 #define EXIT_USAGE 2
35 static char *pcidb_progname;
37 typedef enum {
38 PCIDB_MODE_UNKNOWN,
39 PCIDB_MODE_LIST,
40 PCIDB_MODE_SEARCH,
41 PCIDB_MODE_LOOKUP
42 } pcidb_mode_t;
44 typedef enum {
45 PCIDB_TABLE_NONE,
46 PCIDB_TABLE_VENDOR,
47 PCIDB_TABLE_DEVICE,
48 PCIDB_TABLE_SUBSYSTEM,
49 PCIDB_TABLE_CLASS,
50 PCIDB_TABLE_SUBCLASS,
51 PCIDB_TABLE_PROGIF
52 } pcidb_table_t;
54 typedef enum {
55 PCIDB_OFMT_VID,
56 PCIDB_OFMT_VENSTR,
57 PCIDB_OFMT_DID,
58 PCIDB_OFMT_DEVSTR,
59 PCIDB_OFMT_SVID,
60 PCIDB_OFMT_SDID,
61 PCIDB_OFMT_SUBVENSTR,
62 PCIDB_OFMT_SUBSYSSTR,
63 PCIDB_OFMT_BCC,
64 PCIDB_OFMT_CLASSSTR,
65 PCIDB_OFMT_SCC,
66 PCIDB_OFMT_SUBCLASSSTR,
67 PCIDB_OFMT_PI,
68 PCIDB_OFMT_PROGIFSTR
69 } pcidb_ofmt_t;
71 typedef struct pcidb_filter {
72 uint32_t pft_vend;
73 uint32_t pft_dev;
74 uint32_t pft_subven;
75 uint32_t pft_subdev;
76 uint32_t pft_class;
77 uint32_t pft_subclass;
78 uint32_t pft_progif;
79 } pcidb_filter_t;
81 #define PCIDB_NOFILTER UINT32_MAX
83 typedef struct pcidb_walk {
84 pcidb_hdl_t *pw_hdl;
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;
92 boolean_t pw_strcase;
93 uint_t pw_nfilters;
94 pcidb_filter_t *pw_filters;
95 } pcidb_walk_t;
97 static boolean_t
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) {
104 case PCIDB_OFMT_VID:
105 (void) snprintf(buf, buflen, "%x",
106 pcidb_vendor_id(walk->pw_vendor));
107 break;
108 case PCIDB_OFMT_VENSTR:
109 (void) strlcpy(buf, pcidb_vendor_name(walk->pw_vendor), buflen);
110 break;
111 default:
112 abort();
114 return (B_TRUE);
117 static boolean_t
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) {
124 case PCIDB_OFMT_DID:
125 (void) snprintf(buf, buflen, "%x",
126 pcidb_device_id(walk->pw_device));
127 break;
128 case PCIDB_OFMT_DEVSTR:
129 (void) strlcpy(buf, pcidb_device_name(walk->pw_device), buflen);
130 break;
131 default:
132 abort();
134 return (B_TRUE);
137 static boolean_t
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));
148 break;
149 case PCIDB_OFMT_SDID:
150 (void) snprintf(buf, buflen, "%x",
151 pcidb_subvd_sdid(walk->pw_subvd));
152 break;
153 case PCIDB_OFMT_SUBSYSSTR:
154 (void) strlcpy(buf, pcidb_subvd_name(walk->pw_subvd), buflen);
155 break;
156 case PCIDB_OFMT_SUBVENSTR:
157 vendor = pcidb_lookup_vendor(walk->pw_hdl,
158 pcidb_subvd_svid(walk->pw_subvd));
159 if (vendor == NULL) {
160 return (B_FALSE);
162 (void) strlcpy(buf, pcidb_vendor_name(vendor), buflen);
163 break;
164 default:
165 abort();
167 return (B_TRUE);
170 static boolean_t
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) {
177 case PCIDB_OFMT_BCC:
178 (void) snprintf(buf, buflen, "%x",
179 pcidb_class_code(walk->pw_class));
180 break;
181 case PCIDB_OFMT_CLASSSTR:
182 (void) strlcpy(buf, pcidb_class_name(walk->pw_class), buflen);
183 break;
184 default:
185 abort();
187 return (B_TRUE);
190 static boolean_t
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) {
197 case PCIDB_OFMT_SCC:
198 (void) snprintf(buf, buflen, "%x",
199 pcidb_subclass_code(walk->pw_subclass));
200 break;
201 case PCIDB_OFMT_SUBCLASSSTR:
202 (void) strlcpy(buf, pcidb_subclass_name(walk->pw_subclass),
203 buflen);
204 break;
205 default:
206 abort();
208 return (B_TRUE);
211 static boolean_t
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) {
218 case PCIDB_OFMT_PI:
219 (void) snprintf(buf, buflen, "%x",
220 pcidb_progif_code(walk->pw_progif));
221 break;
222 case PCIDB_OFMT_PROGIFSTR:
223 (void) strlcpy(buf, pcidb_progif_name(walk->pw_progif),
224 buflen);
225 break;
226 default:
227 abort();
229 return (B_TRUE);
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 },
236 { NULL, 0, 0, NULL }
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 },
245 { NULL, 0, 0, NULL }
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 },
258 { NULL, 0, 0, NULL }
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 },
265 { NULL, 0, 0, NULL }
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 },
274 { NULL, 0, 0, NULL }
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 },
285 { NULL, 0, 0, NULL }
288 static void
289 pcidb_ofmt_errx(const char *fmt, ...)
291 va_list ap;
293 va_start(ap, fmt);
294 verrx(EXIT_FAILURE, fmt, ap);
297 static boolean_t
298 pcidb_filter_match(pcidb_walk_t *walk)
300 if (walk->pw_nfilters == 0) {
301 return (B_TRUE);
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))) {
309 continue;
312 if (filt->pft_dev != PCIDB_NOFILTER &&
313 (walk->pw_device == NULL ||
314 filt->pft_dev != pcidb_device_id(walk->pw_device))) {
315 continue;
318 if (filt->pft_subven != PCIDB_NOFILTER &&
319 (walk->pw_subvd == NULL ||
320 filt->pft_subven != pcidb_subvd_svid(walk->pw_subvd))) {
321 continue;
324 if (filt->pft_subdev != PCIDB_NOFILTER &&
325 (walk->pw_subvd == NULL ||
326 filt->pft_subdev != pcidb_subvd_sdid(walk->pw_subvd))) {
327 continue;
330 if (filt->pft_class != PCIDB_NOFILTER &&
331 (walk->pw_class == NULL ||
332 filt->pft_class != pcidb_class_code(walk->pw_class))) {
333 continue;
336 if (filt->pft_subclass != PCIDB_NOFILTER &&
337 (walk->pw_subclass == NULL ||
338 filt->pft_subclass !=
339 pcidb_subclass_code(walk->pw_subclass))) {
340 continue;
343 if (filt->pft_progif != PCIDB_NOFILTER &&
344 (walk->pw_progif == NULL ||
345 filt->pft_progif != pcidb_progif_code(walk->pw_progif))) {
346 continue;
349 return (B_TRUE);
352 return (B_FALSE);
355 static void
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))
364 continue;
365 ofmt_print(walk->pw_ofmt, walk);
369 static void
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))
381 continue;
382 ofmt_print(walk->pw_ofmt, walk);
387 static void
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))
402 continue;
403 ofmt_print(walk->pw_ofmt, walk);
410 static void
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))
417 continue;
418 ofmt_print(walk->pw_ofmt, walk);
422 static void
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))
432 continue;
433 ofmt_print(walk->pw_ofmt, walk);
438 static void
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);
448 progif != NULL;
449 progif = pcidb_progif_iter_next(progif)) {
450 walk->pw_progif = progif;
451 if (!pcidb_filter_match(walk))
452 continue;
453 ofmt_print(walk->pw_ofmt, walk);
459 static void
460 pcidb_parse_class_filter(pcidb_filter_t *filter, char *arg, const char *orig)
462 size_t len;
463 unsigned long val;
464 char *eptr;
466 filter->pft_vend = filter->pft_dev = PCIDB_NOFILTER;
467 filter->pft_subven = filter->pft_subdev = PCIDB_NOFILTER;
469 len = strlen(arg);
470 if (len != 2 && len != 4 && len != 6) {
471 errx(EXIT_FAILURE, "invalid class filter: '%s': bad length",
472 orig);
475 errno = 0;
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);
482 if (len == 6) {
483 filter->pft_progif = val & 0xff;
484 val = val >> 8;
485 } else {
486 filter->pft_progif = PCIDB_NOFILTER;
489 if (len >= 4) {
490 filter->pft_subclass = val & 0xff;
491 val = val >> 8;
492 } else {
493 filter->pft_subclass = PCIDB_NOFILTER;
496 filter->pft_class = val & 0xff;
499 static void
500 pcidb_parse_device_filter(pcidb_filter_t *filter, char *arg, const char *orig)
502 unsigned long val;
503 uint32_t primary, secondary;
504 char *eptr;
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;
511 errno = 0;
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",
520 val);
523 primary = (uint32_t)val;
524 if (*eptr == '\0') {
525 filter->pft_vend = primary;
526 return;
527 } else if (strcmp(eptr, ",s") == 0) {
528 filter->pft_subven = primary;
529 return;
530 } else if (eptr[1] == '\0') {
531 errx(EXIT_FAILURE, "invalid device filter: '%s': filter "
532 "terminated early", arg);
535 arg = eptr + 1;
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",
544 val);
547 secondary = (uint32_t)val;
548 if (*eptr == '\0') {
549 filter->pft_vend = primary;
550 filter->pft_dev = secondary;
551 return;
552 } else if (eptr[1] == '\0') {
553 errx(EXIT_FAILURE, "invalid device filter: '%s': filter "
554 "terminated early", arg);
557 if (*eptr == ',') {
558 if (eptr[1] == 'p' && eptr[2] == '\0') {
559 filter->pft_vend = primary;
560 filter->pft_dev = secondary;
561 return;
563 if (eptr[1] == 's' && eptr[2] == '\0') {
564 filter->pft_subven = primary;
565 filter->pft_subdev = secondary;
566 return;
568 errx(EXIT_FAILURE, "invalid device filter: '%s': invalid "
569 "trailing comma at %s, expected either ,p or ,s",
570 orig, eptr);
573 filter->pft_vend = primary;
574 filter->pft_dev = secondary;
576 arg = eptr + 1;
577 errno = 0;
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",
586 val);
589 filter->pft_subven = (uint32_t)val;
590 if (*eptr == '\0') {
591 return;
592 } else if (eptr[1] == '\0') {
593 errx(EXIT_FAILURE, "invalid device filter: '%s': filter "
594 "terminated early", arg);
597 arg = eptr + 1;
598 errno = 0;
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",
607 val);
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.
618 static void
619 pcidb_process_filters(int argc, char *argv[], pcidb_walk_t *walkp)
621 if (argc <= 0) {
622 walkp->pw_nfilters = 0;
623 return;
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]);
635 if (str == NULL) {
636 errx(EXIT_FAILURE, "failed to duplicate string %s",
637 argv[i]);
640 if (strncmp(str, "pciexclass,", 11) == 0) {
641 pcidb_parse_class_filter(&walkp->pw_filters[i],
642 str + 11, argv[i]);
643 } else if (strncmp(str, "pciclass,", 9) == 0) {
644 pcidb_parse_class_filter(&walkp->pw_filters[i], str + 9,
645 argv[i]);
646 } else if (strncmp(str, "pciex", 5) == 0) {
647 pcidb_parse_device_filter(&walkp->pw_filters[i],
648 str + 5, argv[i]);
649 } else if (strncmp(str, "pci", 3) == 0) {
650 pcidb_parse_device_filter(&walkp->pw_filters[i],
651 str + 3, argv[i]);
652 } else {
653 errx(EXIT_FAILURE, "invalid filter string: %s", str);
656 free(str);
660 static void
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 "
667 "privs");
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 "
676 "privs");
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
684 * pci.ids files.
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);
706 static int
707 pcidb_usage(const char *fmt, ...)
709 if (fmt != NULL) {
710 va_list ap;
712 (void) fprintf(stderr, "%s: ", pcidb_progname);
713 va_start(ap, fmt);
714 (void) vfprintf(stderr, fmt, ap);
715 va_end(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);
735 return (EXIT_USAGE);
739 main(int argc, char *argv[])
741 pcidb_hdl_t *hdl;
742 int c;
743 uint_t tablecnt = 0;
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;
749 ofmt_handle_t ofmt;
750 ofmt_status_t oferr;
751 uint_t flags = 0;
752 pcidb_walk_t walk;
754 bzero(&walk, sizeof (walk));
755 pcidb_progname = basename(argv[0]);
757 pcidb_drop_privs();
759 while ((c = getopt(argc, argv, ":vdscSipo:hH")) != -1) {
760 switch (c) {
761 case 'v':
762 tablecnt++;
763 table = PCIDB_TABLE_VENDOR;
764 break;
765 case 'd':
766 tablecnt++;
767 table = PCIDB_TABLE_DEVICE;
768 break;
769 case 's':
770 tablecnt++;
771 table = PCIDB_TABLE_SUBSYSTEM;
772 break;
773 case 'c':
774 tablecnt++;
775 table = PCIDB_TABLE_CLASS;
776 break;
777 case 'S':
778 tablecnt++;
779 table = PCIDB_TABLE_SUBCLASS;
780 break;
781 case 'i':
782 tablecnt++;
783 table = PCIDB_TABLE_PROGIF;
784 break;
785 case 'p':
786 parse = B_TRUE;
787 flags |= OFMT_PARSABLE;
788 break;
789 case 'o':
790 fields = optarg;
791 break;
792 case 'h':
793 return (pcidb_usage(NULL));
794 case 'H':
795 flags |= OFMT_NOHEADER;
796 break;
797 case ':':
798 return (pcidb_usage("Option -%c requires an argument",
799 optopt));
800 case '?':
801 return (pcidb_usage("unknown option: -%c", optopt));
805 if (tablecnt > 1) {
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");
814 argc -= optind;
815 argv += optind;
817 pcidb_process_filters(argc, argv, &walk);
819 switch (table) {
820 case PCIDB_TABLE_VENDOR:
821 ofmt_fields = pcidb_vendor_ofmt;
822 ofmt_fields_str = pcidb_vendor_fields;
823 break;
824 case PCIDB_TABLE_NONE:
825 case PCIDB_TABLE_DEVICE:
826 ofmt_fields = pcidb_device_ofmt;
827 ofmt_fields_str = pcidb_device_fields;
828 break;
829 case PCIDB_TABLE_SUBSYSTEM:
830 ofmt_fields = pcidb_subsystem_ofmt;
831 ofmt_fields_str = pcidb_subsystem_fields;
832 break;
833 case PCIDB_TABLE_CLASS:
834 ofmt_fields = pcidb_class_ofmt;
835 ofmt_fields_str = pcidb_class_fields;
836 break;
837 case PCIDB_TABLE_SUBCLASS:
838 ofmt_fields = pcidb_subclass_ofmt;
839 ofmt_fields_str = pcidb_subclass_fields;
840 break;
841 case PCIDB_TABLE_PROGIF:
842 ofmt_fields = pcidb_progif_ofmt;
843 ofmt_fields_str = pcidb_progif_fields;
844 break;
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);
855 if (hdl == NULL) {
856 err(EXIT_FAILURE, "failed to initialize PCI IDs database");
859 walk.pw_hdl = hdl;
860 walk.pw_ofmt = ofmt;
861 walk.pw_strcase = strcase;
863 switch (table) {
864 case PCIDB_TABLE_VENDOR:
865 pcidb_walk_vendors(&walk);
866 break;
867 case PCIDB_TABLE_NONE:
868 case PCIDB_TABLE_DEVICE:
869 pcidb_walk_devices(&walk);
870 break;
871 case PCIDB_TABLE_SUBSYSTEM:
872 pcidb_walk_subsystems(&walk);
873 break;
874 case PCIDB_TABLE_CLASS:
875 pcidb_walk_classes(&walk);
876 break;
877 case PCIDB_TABLE_SUBCLASS:
878 pcidb_walk_subclasses(&walk);
879 break;
880 case PCIDB_TABLE_PROGIF:
881 pcidb_walk_progifs(&walk);
882 break;
885 ofmt_close(ofmt);
886 pcidb_close(hdl);
887 return (EXIT_SUCCESS);