xref: /illumos-gate/usr/src/cmd/pcieadm/pcieadm.c (revision 6b1325cf)
17687d0d8SRobert Mustacchi /*
27687d0d8SRobert Mustacchi  * This file and its contents are supplied under the terms of the
37687d0d8SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
47687d0d8SRobert Mustacchi  * You may only use this file in accordance with the terms of version
57687d0d8SRobert Mustacchi  * 1.0 of the CDDL.
67687d0d8SRobert Mustacchi  *
77687d0d8SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
87687d0d8SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
97687d0d8SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
107687d0d8SRobert Mustacchi  */
117687d0d8SRobert Mustacchi 
127687d0d8SRobert Mustacchi /*
137687d0d8SRobert Mustacchi  * Copyright 2021 Oxide Computer Company
147687d0d8SRobert Mustacchi  */
157687d0d8SRobert Mustacchi 
167687d0d8SRobert Mustacchi /*
177687d0d8SRobert Mustacchi  * PCIe shenanigans
187687d0d8SRobert Mustacchi  *
197687d0d8SRobert Mustacchi  * Currently this implements several different views at seeing into PCIe devices
207687d0d8SRobert Mustacchi  * and is designed to (hopefully) replace pcitool and be a vector for new system
217687d0d8SRobert Mustacchi  * functionality such as dealing with multicast filtering, ACS, etc.
227687d0d8SRobert Mustacchi  *
237687d0d8SRobert Mustacchi  * While most subcommands have their own implementations, there are a couple of
247687d0d8SRobert Mustacchi  * things that are worth bearing in mind:
257687d0d8SRobert Mustacchi  *
267687d0d8SRobert Mustacchi  *  1) Where possible, prefer the use of libofmt. In particular, having good,
277687d0d8SRobert Mustacchi  *  parsable output is important. New subcommands should strive to meet that.
287687d0d8SRobert Mustacchi  *
297687d0d8SRobert Mustacchi  *  2) Because we're often processing binary data (and it's good hygiene),
307687d0d8SRobert Mustacchi  *  subcommands should make sure to drop privileges as early as they can by
317687d0d8SRobert Mustacchi  *  calling pcieadm_init_privs(). More on privileges below.
327687d0d8SRobert Mustacchi  *
337687d0d8SRobert Mustacchi  * Privilege Management
347687d0d8SRobert Mustacchi  * --------------------
357687d0d8SRobert Mustacchi  *
367687d0d8SRobert Mustacchi  * In an attempt to minimize privilege exposure, but to allow subcommands
377687d0d8SRobert Mustacchi  * flexibility when required (e.g. show-cfgspace needs full privs to read from
387687d0d8SRobert Mustacchi  * the kernel), we have two privilege sets that we maintain. One which is the
397687d0d8SRobert Mustacchi  * minimial privs, which basically is a set that has stripped everything. This
407687d0d8SRobert Mustacchi  * is 'pia_priv_min'. The second is one that allows a subcommand to add in
417687d0d8SRobert Mustacchi  * privileges that it requires which will be left in the permitted set. These
427687d0d8SRobert Mustacchi  * are in 'pia_priv_eff'. It's important to know that this set is always
437687d0d8SRobert Mustacchi  * intersected with what the user actually has, so this is not meant to be a way
447687d0d8SRobert Mustacchi  * for a caller to get more privileges than they already have.
457687d0d8SRobert Mustacchi  *
467687d0d8SRobert Mustacchi  * A subcommand is expected to call pcieadm_init_privs() once they have
477687d0d8SRobert Mustacchi  * processed enough arguments that they can set an upper bound on privileges.
487687d0d8SRobert Mustacchi  * It's worth noting that a subcommand will be executed in an already minimial
497687d0d8SRobert Mustacchi  * environment; however, we will have already set up a libdevinfo handle for
507687d0d8SRobert Mustacchi  * them, which should make the need to do much more not so bad.
517687d0d8SRobert Mustacchi  */
527687d0d8SRobert Mustacchi 
537687d0d8SRobert Mustacchi #include <stdio.h>
547687d0d8SRobert Mustacchi #include <stdlib.h>
557687d0d8SRobert Mustacchi #include <stdarg.h>
567687d0d8SRobert Mustacchi #include <unistd.h>
577687d0d8SRobert Mustacchi #include <err.h>
587687d0d8SRobert Mustacchi #include <libdevinfo.h>
597687d0d8SRobert Mustacchi #include <strings.h>
607687d0d8SRobert Mustacchi #include <sys/stat.h>
617687d0d8SRobert Mustacchi #include <sys/pci_tools.h>
627687d0d8SRobert Mustacchi #include <sys/pci.h>
637687d0d8SRobert Mustacchi #include <sys/types.h>
647687d0d8SRobert Mustacchi #include <fcntl.h>
657687d0d8SRobert Mustacchi #include <sys/debug.h>
667687d0d8SRobert Mustacchi #include <upanic.h>
677687d0d8SRobert Mustacchi #include <libgen.h>
687687d0d8SRobert Mustacchi 
697687d0d8SRobert Mustacchi #include "pcieadm.h"
707687d0d8SRobert Mustacchi 
717687d0d8SRobert Mustacchi pcieadm_t pcieadm;
727687d0d8SRobert Mustacchi const char *pcieadm_progname;
737687d0d8SRobert Mustacchi 
747687d0d8SRobert Mustacchi void
pcieadm_init_privs(pcieadm_t * pcip)757687d0d8SRobert Mustacchi pcieadm_init_privs(pcieadm_t *pcip)
767687d0d8SRobert Mustacchi {
777687d0d8SRobert Mustacchi 	static const char *msg = "attempted to re-initialize privileges";
787687d0d8SRobert Mustacchi 	if (pcip->pia_priv_init == NULL) {
797687d0d8SRobert Mustacchi 		upanic(msg, strlen(msg));
807687d0d8SRobert Mustacchi 	}
817687d0d8SRobert Mustacchi 
827687d0d8SRobert Mustacchi 	priv_intersect(pcip->pia_priv_init, pcip->pia_priv_eff);
837687d0d8SRobert Mustacchi 
847687d0d8SRobert Mustacchi 	if (setppriv(PRIV_SET, PRIV_PERMITTED, pcieadm.pia_priv_eff) != 0) {
857687d0d8SRobert Mustacchi 		err(EXIT_FAILURE, "failed to reduce privileges");
867687d0d8SRobert Mustacchi 	}
877687d0d8SRobert Mustacchi 
887687d0d8SRobert Mustacchi 	if (setppriv(PRIV_SET, PRIV_LIMIT, pcieadm.pia_priv_eff) != 0) {
897687d0d8SRobert Mustacchi 		err(EXIT_FAILURE, "failed to reduce privileges");
907687d0d8SRobert Mustacchi 	}
917687d0d8SRobert Mustacchi 
927687d0d8SRobert Mustacchi 	priv_freeset(pcip->pia_priv_init);
937687d0d8SRobert Mustacchi 	pcip->pia_priv_init = NULL;
947687d0d8SRobert Mustacchi }
957687d0d8SRobert Mustacchi 
967687d0d8SRobert Mustacchi void
pcieadm_indent(void)977687d0d8SRobert Mustacchi pcieadm_indent(void)
987687d0d8SRobert Mustacchi {
997687d0d8SRobert Mustacchi 	pcieadm.pia_indent += 2;
1007687d0d8SRobert Mustacchi }
1017687d0d8SRobert Mustacchi 
1027687d0d8SRobert Mustacchi void
pcieadm_deindent(void)1037687d0d8SRobert Mustacchi pcieadm_deindent(void)
1047687d0d8SRobert Mustacchi {
1057687d0d8SRobert Mustacchi 	VERIFY3U(pcieadm.pia_indent, >, 0);
1067687d0d8SRobert Mustacchi 	pcieadm.pia_indent -= 2;
1077687d0d8SRobert Mustacchi }
1087687d0d8SRobert Mustacchi 
1097687d0d8SRobert Mustacchi void
pcieadm_print(const char * fmt,...)1107687d0d8SRobert Mustacchi pcieadm_print(const char *fmt, ...)
1117687d0d8SRobert Mustacchi {
1127687d0d8SRobert Mustacchi 	va_list ap;
1137687d0d8SRobert Mustacchi 
1147687d0d8SRobert Mustacchi 	if (pcieadm.pia_indent > 0) {
1157687d0d8SRobert Mustacchi 		(void) printf("%*s", pcieadm.pia_indent, "");
1167687d0d8SRobert Mustacchi 	}
1177687d0d8SRobert Mustacchi 
1187687d0d8SRobert Mustacchi 	va_start(ap, fmt);
1197687d0d8SRobert Mustacchi 	(void) vprintf(fmt, ap);
1207687d0d8SRobert Mustacchi 	va_end(ap);
1217687d0d8SRobert Mustacchi }
1227687d0d8SRobert Mustacchi 
1237687d0d8SRobert Mustacchi void
pcieadm_ofmt_errx(const char * fmt,...)1247687d0d8SRobert Mustacchi pcieadm_ofmt_errx(const char *fmt, ...)
1257687d0d8SRobert Mustacchi {
1267687d0d8SRobert Mustacchi 	va_list ap;
1277687d0d8SRobert Mustacchi 
1287687d0d8SRobert Mustacchi 	va_start(ap, fmt);
1297687d0d8SRobert Mustacchi 	verrx(EXIT_FAILURE, fmt, ap);
1307687d0d8SRobert Mustacchi }
1317687d0d8SRobert Mustacchi 
132414dafc0SRobert Mustacchi /*
133414dafc0SRobert Mustacchi  * We determine if a node is PCI in a two step process. The first is to see if
134414dafc0SRobert Mustacchi  * the node's name starts with pci, and has an additional character that
135414dafc0SRobert Mustacchi  * indicates it's not the synthetic root of the tree. However, the node name
136414dafc0SRobert Mustacchi  * changes for some classes of devices such as GPUs. As such, for those we try
137414dafc0SRobert Mustacchi  * to look at the compatible property and see if we have a pciexclass or
138414dafc0SRobert Mustacchi  * pciclass entry. We look specifically for the class to make sure that we don't
139414dafc0SRobert Mustacchi  * fall for the synthetic nodes that have a compatible property of
140414dafc0SRobert Mustacchi  * 'pciex_root_complex'.
141414dafc0SRobert Mustacchi  *
142414dafc0SRobert Mustacchi  * The compatible property is a single string that is actually a compressed
143414dafc0SRobert Mustacchi  * string. That is, there are multiple strings concatenated together in a single
144414dafc0SRobert Mustacchi  * pointer.
145414dafc0SRobert Mustacchi  */
146414dafc0SRobert Mustacchi static boolean_t
pcieadm_di_node_is_pci(di_node_t node)1477687d0d8SRobert Mustacchi pcieadm_di_node_is_pci(di_node_t node)
1487687d0d8SRobert Mustacchi {
1497687d0d8SRobert Mustacchi 	const char *name;
150414dafc0SRobert Mustacchi 	char *compat;
151414dafc0SRobert Mustacchi 	int nents;
1527687d0d8SRobert Mustacchi 
1537687d0d8SRobert Mustacchi 	name = di_node_name(node);
154414dafc0SRobert Mustacchi 	if (strncmp("pci", name, 3) == 0) {
155414dafc0SRobert Mustacchi 		return (name[3] != '\0');
156414dafc0SRobert Mustacchi 	}
157414dafc0SRobert Mustacchi 
158414dafc0SRobert Mustacchi 	nents = di_prop_lookup_strings(DDI_DEV_T_ANY, node, "compatible",
159414dafc0SRobert Mustacchi 	    &compat);
160414dafc0SRobert Mustacchi 	if (nents <= 0) {
161414dafc0SRobert Mustacchi 		return (B_FALSE);
162414dafc0SRobert Mustacchi 	}
163414dafc0SRobert Mustacchi 
164414dafc0SRobert Mustacchi 	for (int i = 0; i < nents; i++) {
165414dafc0SRobert Mustacchi 		if (strncmp("pciclass,", compat, strlen("pciclass,")) == 0 ||
166414dafc0SRobert Mustacchi 		    strncmp("pciexclass,", compat, strlen("pciexclass,")) ==
167414dafc0SRobert Mustacchi 		    0) {
168414dafc0SRobert Mustacchi 			return (B_TRUE);
169414dafc0SRobert Mustacchi 		}
170414dafc0SRobert Mustacchi 
171414dafc0SRobert Mustacchi 		compat += strlen(compat) + 1;
172414dafc0SRobert Mustacchi 	}
173414dafc0SRobert Mustacchi 
174414dafc0SRobert Mustacchi 	return (B_FALSE);
1757687d0d8SRobert Mustacchi }
1767687d0d8SRobert Mustacchi 
1777687d0d8SRobert Mustacchi static int
pcieadm_di_walk_cb(di_node_t node,void * arg)1787687d0d8SRobert Mustacchi pcieadm_di_walk_cb(di_node_t node, void *arg)
1797687d0d8SRobert Mustacchi {
1807687d0d8SRobert Mustacchi 	pcieadm_di_walk_t *walk = arg;
1817687d0d8SRobert Mustacchi 
1827687d0d8SRobert Mustacchi 	if (!pcieadm_di_node_is_pci(node)) {
1837687d0d8SRobert Mustacchi 		return (DI_WALK_CONTINUE);
1847687d0d8SRobert Mustacchi 	}
1857687d0d8SRobert Mustacchi 
1867687d0d8SRobert Mustacchi 	return (walk->pdw_func(node, walk->pdw_arg));
1877687d0d8SRobert Mustacchi }
1887687d0d8SRobert Mustacchi 
1897687d0d8SRobert Mustacchi void
pcieadm_di_walk(pcieadm_t * pcip,pcieadm_di_walk_t * arg)1907687d0d8SRobert Mustacchi pcieadm_di_walk(pcieadm_t *pcip, pcieadm_di_walk_t *arg)
1917687d0d8SRobert Mustacchi {
1927687d0d8SRobert Mustacchi 	(void) di_walk_node(pcip->pia_root, DI_WALK_CLDFIRST, arg,
1937687d0d8SRobert Mustacchi 	    pcieadm_di_walk_cb);
1947687d0d8SRobert Mustacchi }
1957687d0d8SRobert Mustacchi 
1967687d0d8SRobert Mustacchi /*
1977687d0d8SRobert Mustacchi  * Attempt to find the nexus that corresponds to this device. To do this, we
1987687d0d8SRobert Mustacchi  * walk up and walk the minors until we find a "reg" minor.
1997687d0d8SRobert Mustacchi  */
2007687d0d8SRobert Mustacchi void
pcieadm_find_nexus(pcieadm_t * pia)2017687d0d8SRobert Mustacchi pcieadm_find_nexus(pcieadm_t *pia)
2027687d0d8SRobert Mustacchi {
2037687d0d8SRobert Mustacchi 	di_node_t cur;
2047687d0d8SRobert Mustacchi 
2057687d0d8SRobert Mustacchi 	for (cur = di_parent_node(pia->pia_devi); cur != DI_NODE_NIL;
2067687d0d8SRobert Mustacchi 	    cur = di_parent_node(cur)) {
2077687d0d8SRobert Mustacchi 		di_minor_t minor = DI_MINOR_NIL;
2087687d0d8SRobert Mustacchi 
2097687d0d8SRobert Mustacchi 		while ((minor = di_minor_next(cur, minor)) != DI_MINOR_NIL) {
2107687d0d8SRobert Mustacchi 			if (di_minor_spectype(minor) == S_IFCHR &&
2117687d0d8SRobert Mustacchi 			    strcmp(di_minor_name(minor), "reg") == 0) {
2127687d0d8SRobert Mustacchi 				pia->pia_nexus = cur;
2137687d0d8SRobert Mustacchi 				return;
2147687d0d8SRobert Mustacchi 			}
2157687d0d8SRobert Mustacchi 		}
2167687d0d8SRobert Mustacchi 	}
2177687d0d8SRobert Mustacchi }
2187687d0d8SRobert Mustacchi 
2197687d0d8SRobert Mustacchi static int
pcieadm_find_dip_cb(di_node_t node,void * arg)2207687d0d8SRobert Mustacchi pcieadm_find_dip_cb(di_node_t node, void *arg)
2217687d0d8SRobert Mustacchi {
2227687d0d8SRobert Mustacchi 	char *path = NULL, *driver;
2237687d0d8SRobert Mustacchi 	char dinst[128], bdf[128], altbdf[128];
2247687d0d8SRobert Mustacchi 	int inst, nprop, *regs;
2257687d0d8SRobert Mustacchi 	pcieadm_t *pia = arg;
2267687d0d8SRobert Mustacchi 
2277687d0d8SRobert Mustacchi 	path = di_devfs_path(node);
2287687d0d8SRobert Mustacchi 	if (path == NULL) {
2297687d0d8SRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct devfs path for node: "
230*6b1325cfSRobert Mustacchi 		    "%s", di_node_name(node));
2317687d0d8SRobert Mustacchi 	}
2327687d0d8SRobert Mustacchi 
2337687d0d8SRobert Mustacchi 	driver = di_driver_name(node);
2347687d0d8SRobert Mustacchi 	inst = di_instance(node);
2357687d0d8SRobert Mustacchi 	if (driver != NULL && inst != -1) {
2367687d0d8SRobert Mustacchi 		(void) snprintf(dinst, sizeof (dinst), "%s%d", driver, inst);
2377687d0d8SRobert Mustacchi 	}
2387687d0d8SRobert Mustacchi 
2397687d0d8SRobert Mustacchi 	nprop = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &regs);
2407687d0d8SRobert Mustacchi 	if (nprop <= 0) {
2417687d0d8SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to lookup regs array for %s",
2427687d0d8SRobert Mustacchi 		    path);
2437687d0d8SRobert Mustacchi 	}
2447687d0d8SRobert Mustacchi 	(void) snprintf(bdf, sizeof (bdf), "%x/%x/%x", PCI_REG_BUS_G(regs[0]),
2457687d0d8SRobert Mustacchi 	    PCI_REG_DEV_G(regs[0]), PCI_REG_FUNC_G(regs[0]));
246414dafc0SRobert Mustacchi 	(void) snprintf(altbdf, sizeof (altbdf), "%02x/%02x/%02x",
2477687d0d8SRobert Mustacchi 	    PCI_REG_BUS_G(regs[0]), PCI_REG_DEV_G(regs[0]),
2487687d0d8SRobert Mustacchi 	    PCI_REG_FUNC_G(regs[0]));
2497687d0d8SRobert Mustacchi 
2507687d0d8SRobert Mustacchi 	if (strcmp(pia->pia_devstr, path) == 0 ||
2517687d0d8SRobert Mustacchi 	    strcmp(pia->pia_devstr, bdf) == 0 ||
2527687d0d8SRobert Mustacchi 	    strcmp(pia->pia_devstr, altbdf) == 0 ||
2537687d0d8SRobert Mustacchi 	    (driver != NULL && inst != -1 &&
2547687d0d8SRobert Mustacchi 	    strcmp(pia->pia_devstr, dinst) == 0)) {
2557687d0d8SRobert Mustacchi 		if (pia->pia_devi != DI_NODE_NIL) {
2567687d0d8SRobert Mustacchi 			errx(EXIT_FAILURE, "device name matched two device "
2577687d0d8SRobert Mustacchi 			    "nodes: %s and %s", di_node_name(pia->pia_devi),
2587687d0d8SRobert Mustacchi 			    di_node_name(node));
2597687d0d8SRobert Mustacchi 		}
2607687d0d8SRobert Mustacchi 
2617687d0d8SRobert Mustacchi 		pia->pia_devi = node;
2627687d0d8SRobert Mustacchi 	}
2637687d0d8SRobert Mustacchi 
2647687d0d8SRobert Mustacchi 	if (path != NULL) {
2657687d0d8SRobert Mustacchi 		di_devfs_path_free(path);
2667687d0d8SRobert Mustacchi 	}
2677687d0d8SRobert Mustacchi 
2687687d0d8SRobert Mustacchi 	return (DI_WALK_CONTINUE);
2697687d0d8SRobert Mustacchi }
2707687d0d8SRobert Mustacchi 
2717687d0d8SRobert Mustacchi void
pcieadm_find_dip(pcieadm_t * pcip,const char * device)2727687d0d8SRobert Mustacchi pcieadm_find_dip(pcieadm_t *pcip, const char *device)
2737687d0d8SRobert Mustacchi {
2747687d0d8SRobert Mustacchi 	pcieadm_di_walk_t walk;
2757687d0d8SRobert Mustacchi 
2767687d0d8SRobert Mustacchi 	/*
2777687d0d8SRobert Mustacchi 	 * If someone specifies /devices, just skip over it.
2787687d0d8SRobert Mustacchi 	 */
2797687d0d8SRobert Mustacchi 	pcip->pia_devstr = device;
2807687d0d8SRobert Mustacchi 	if (strncmp("/devices", device, strlen("/devices")) == 0) {
2817687d0d8SRobert Mustacchi 		pcip->pia_devstr += strlen("/devices");
2827687d0d8SRobert Mustacchi 	}
2837687d0d8SRobert Mustacchi 
2847687d0d8SRobert Mustacchi 	pcip->pia_devi = DI_NODE_NIL;
2857687d0d8SRobert Mustacchi 	walk.pdw_arg = pcip;
2867687d0d8SRobert Mustacchi 	walk.pdw_func = pcieadm_find_dip_cb;
2877687d0d8SRobert Mustacchi 	pcieadm_di_walk(pcip, &walk);
2887687d0d8SRobert Mustacchi 
2897687d0d8SRobert Mustacchi 	if (pcip->pia_devi == DI_NODE_NIL) {
2907687d0d8SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to find device node %s", device);
2917687d0d8SRobert Mustacchi 	}
2927687d0d8SRobert Mustacchi 
2937687d0d8SRobert Mustacchi 	pcip->pia_nexus = DI_NODE_NIL;
2947687d0d8SRobert Mustacchi 	pcieadm_find_nexus(pcip);
2957687d0d8SRobert Mustacchi 	if (pcip->pia_nexus == DI_NODE_NIL) {
2967687d0d8SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to find nexus for %s", device);
2977687d0d8SRobert Mustacchi 	}
2987687d0d8SRobert Mustacchi }
2997687d0d8SRobert Mustacchi 
3007687d0d8SRobert Mustacchi typedef struct pcieadm_cfgspace_file {
3017687d0d8SRobert Mustacchi 	int pcfi_fd;
3027687d0d8SRobert Mustacchi } pcieadm_cfgspace_file_t;
3037687d0d8SRobert Mustacchi 
3047687d0d8SRobert Mustacchi static boolean_t
pcieadm_read_cfgspace_file(uint32_t off,uint8_t len,void * buf,void * arg)3057687d0d8SRobert Mustacchi pcieadm_read_cfgspace_file(uint32_t off, uint8_t len, void *buf, void *arg)
3067687d0d8SRobert Mustacchi {
3077687d0d8SRobert Mustacchi 	uint32_t bufoff = 0;
3087687d0d8SRobert Mustacchi 	pcieadm_cfgspace_file_t *pcfi = arg;
3097687d0d8SRobert Mustacchi 
3107687d0d8SRobert Mustacchi 	while (len > 0) {
3117687d0d8SRobert Mustacchi 		ssize_t ret = pread(pcfi->pcfi_fd, buf + bufoff, len, off);
3127687d0d8SRobert Mustacchi 		if (ret < 0) {
3137687d0d8SRobert Mustacchi 			err(EXIT_FAILURE, "failed to read %u bytes at %"
3147687d0d8SRobert Mustacchi 			    PRIu32, len, off);
3157687d0d8SRobert Mustacchi 		} else if (ret == 0) {
3167687d0d8SRobert Mustacchi 			warnx("hit unexpected EOF reading cfgspace from file "
3177687d0d8SRobert Mustacchi 			    "at offest %" PRIu32 ", still wanted to read %u "
3187687d0d8SRobert Mustacchi 			    "bytes", off, len);
3197687d0d8SRobert Mustacchi 			return (B_FALSE);
3207687d0d8SRobert Mustacchi 		} else {
3217687d0d8SRobert Mustacchi 			len -= ret;
3227687d0d8SRobert Mustacchi 			off += ret;
3237687d0d8SRobert Mustacchi 			bufoff += ret;
3247687d0d8SRobert Mustacchi 		}
3257687d0d8SRobert Mustacchi 
3267687d0d8SRobert Mustacchi 	}
3277687d0d8SRobert Mustacchi 
3287687d0d8SRobert Mustacchi 	return (B_TRUE);
3297687d0d8SRobert Mustacchi }
3307687d0d8SRobert Mustacchi 
3317687d0d8SRobert Mustacchi void
pcieadm_init_cfgspace_file(pcieadm_t * pcip,const char * path,pcieadm_cfgspace_f * funcp,void ** arg)3327687d0d8SRobert Mustacchi pcieadm_init_cfgspace_file(pcieadm_t *pcip, const char *path,
3337687d0d8SRobert Mustacchi     pcieadm_cfgspace_f *funcp, void **arg)
3347687d0d8SRobert Mustacchi {
3357687d0d8SRobert Mustacchi 	int fd;
3367687d0d8SRobert Mustacchi 	struct stat st;
3377687d0d8SRobert Mustacchi 	pcieadm_cfgspace_file_t *pcfi;
3387687d0d8SRobert Mustacchi 
3397687d0d8SRobert Mustacchi 	if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcip->pia_priv_eff) != 0) {
3407687d0d8SRobert Mustacchi 		err(EXIT_FAILURE, "failed to raise privileges");
3417687d0d8SRobert Mustacchi 	}
3427687d0d8SRobert Mustacchi 
3437687d0d8SRobert Mustacchi 	if ((fd = open(path, O_RDONLY)) < 0) {
3447687d0d8SRobert Mustacchi 		err(EXIT_FAILURE, "failed to open input file %s", path);
3457687d0d8SRobert Mustacchi 	}
3467687d0d8SRobert Mustacchi 
3477687d0d8SRobert Mustacchi 	if (fstat(fd, &st) != 0) {
3487687d0d8SRobert Mustacchi 		err(EXIT_FAILURE, "failed to get stat information for %s",
3497687d0d8SRobert Mustacchi 		    path);
3507687d0d8SRobert Mustacchi 	}
3517687d0d8SRobert Mustacchi 
3527687d0d8SRobert Mustacchi 	if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcip->pia_priv_min) != 0) {
3537687d0d8SRobert Mustacchi 		err(EXIT_FAILURE, "failed to reduce privileges");
3547687d0d8SRobert Mustacchi 	}
3557687d0d8SRobert Mustacchi 
3567687d0d8SRobert Mustacchi 	if (S_ISDIR(st.st_mode)) {
3577687d0d8SRobert Mustacchi 		errx(EXIT_FAILURE, "input file %s is a directory, unable "
3587687d0d8SRobert Mustacchi 		    "to read data", path);
3597687d0d8SRobert Mustacchi 	}
3607687d0d8SRobert Mustacchi 
3617687d0d8SRobert Mustacchi 	if (S_ISLNK(st.st_mode)) {
3627687d0d8SRobert Mustacchi 		errx(EXIT_FAILURE, "input file %s is a symbolic link, unable "
3637687d0d8SRobert Mustacchi 		    "to read data", path);
3647687d0d8SRobert Mustacchi 	}
3657687d0d8SRobert Mustacchi 
3667687d0d8SRobert Mustacchi 	if (S_ISDOOR(st.st_mode)) {
3677687d0d8SRobert Mustacchi 		errx(EXIT_FAILURE, "input file %s is a door, unable "
3687687d0d8SRobert Mustacchi 		    "to read data", path);
3697687d0d8SRobert Mustacchi 	}
3707687d0d8SRobert Mustacchi 
3717687d0d8SRobert Mustacchi 	if (S_ISPORT(st.st_mode)) {
3727687d0d8SRobert Mustacchi 		errx(EXIT_FAILURE, "input file %s is an event port, unable "
3737687d0d8SRobert Mustacchi 		    "to read data", path);
3747687d0d8SRobert Mustacchi 	}
3757687d0d8SRobert Mustacchi 
3767687d0d8SRobert Mustacchi 	/*
3777687d0d8SRobert Mustacchi 	 * Assume if we were given a FIFO, character/block device, socket, or
3787687d0d8SRobert Mustacchi 	 * something else that it's probably fine.
3797687d0d8SRobert Mustacchi 	 */
3807687d0d8SRobert Mustacchi 	pcfi = calloc(1, sizeof (*pcfi));
3817687d0d8SRobert Mustacchi 	if (pcfi == NULL) {
3827687d0d8SRobert Mustacchi 		err(EXIT_FAILURE, "failed to allocate memory for reading "
3837687d0d8SRobert Mustacchi 		    "cfgspace data from a file");
3847687d0d8SRobert Mustacchi 	}
3857687d0d8SRobert Mustacchi 
3867687d0d8SRobert Mustacchi 	pcfi->pcfi_fd = fd;
3877687d0d8SRobert Mustacchi 	*arg = pcfi;
3887687d0d8SRobert Mustacchi 	*funcp = pcieadm_read_cfgspace_file;
3897687d0d8SRobert Mustacchi }
3907687d0d8SRobert Mustacchi 
3917687d0d8SRobert Mustacchi void
pcieadm_fini_cfgspace_file(void * arg)3927687d0d8SRobert Mustacchi pcieadm_fini_cfgspace_file(void *arg)
3937687d0d8SRobert Mustacchi {
3947687d0d8SRobert Mustacchi 	pcieadm_cfgspace_file_t *pcfi = arg;
3957687d0d8SRobert Mustacchi 	VERIFY0(close(pcfi->pcfi_fd));
3967687d0d8SRobert Mustacchi 	free(pcfi);
3977687d0d8SRobert Mustacchi }
3987687d0d8SRobert Mustacchi 
3997687d0d8SRobert Mustacchi typedef struct pcieadm_cfgspace_kernel {
4007687d0d8SRobert Mustacchi 	pcieadm_t *pck_pci;
4017687d0d8SRobert Mustacchi 	int pck_fd;
4027687d0d8SRobert Mustacchi 	uint8_t pck_bus;
4037687d0d8SRobert Mustacchi 	uint8_t pck_dev;
4047687d0d8SRobert Mustacchi 	uint8_t pck_func;
4057687d0d8SRobert Mustacchi } pcieadm_cfgspace_kernel_t;
4067687d0d8SRobert Mustacchi 
4077687d0d8SRobert Mustacchi static boolean_t
pcieadm_read_cfgspace_kernel(uint32_t off,uint8_t len,void * buf,void * arg)4087687d0d8SRobert Mustacchi pcieadm_read_cfgspace_kernel(uint32_t off, uint8_t len, void *buf, void *arg)
4097687d0d8SRobert Mustacchi {
4107687d0d8SRobert Mustacchi 	pcieadm_cfgspace_kernel_t *pck = arg;
4117687d0d8SRobert Mustacchi 	pcieadm_t *pcip = pck->pck_pci;
4127687d0d8SRobert Mustacchi 	pcitool_reg_t pci_reg;
4137687d0d8SRobert Mustacchi 
4147687d0d8SRobert Mustacchi 	bzero(&pci_reg, sizeof (pci_reg));
4157687d0d8SRobert Mustacchi 	pci_reg.user_version = PCITOOL_VERSION;
4167687d0d8SRobert Mustacchi 	pci_reg.bus_no = pck->pck_bus;
4177687d0d8SRobert Mustacchi 	pci_reg.dev_no = pck->pck_dev;
4187687d0d8SRobert Mustacchi 	pci_reg.func_no = pck->pck_func;
4197687d0d8SRobert Mustacchi 	pci_reg.barnum = 0;
4207687d0d8SRobert Mustacchi 	pci_reg.offset = off;
4217687d0d8SRobert Mustacchi 	pci_reg.acc_attr = PCITOOL_ACC_ATTR_ENDN_LTL;
4227687d0d8SRobert Mustacchi 
4237687d0d8SRobert Mustacchi 	switch (len) {
4247687d0d8SRobert Mustacchi 	case 1:
4257687d0d8SRobert Mustacchi 		pci_reg.acc_attr += PCITOOL_ACC_ATTR_SIZE_1;
4267687d0d8SRobert Mustacchi 		break;
4277687d0d8SRobert Mustacchi 	case 2:
4287687d0d8SRobert Mustacchi 		pci_reg.acc_attr += PCITOOL_ACC_ATTR_SIZE_2;
4297687d0d8SRobert Mustacchi 		break;
4307687d0d8SRobert Mustacchi 	case 4:
4317687d0d8SRobert Mustacchi 		pci_reg.acc_attr += PCITOOL_ACC_ATTR_SIZE_4;
4327687d0d8SRobert Mustacchi 		break;
4337687d0d8SRobert Mustacchi 	case 8:
4347687d0d8SRobert Mustacchi 		pci_reg.acc_attr += PCITOOL_ACC_ATTR_SIZE_8;
4357687d0d8SRobert Mustacchi 		break;
4367687d0d8SRobert Mustacchi 	default:
4377687d0d8SRobert Mustacchi 		errx(EXIT_FAILURE, "asked to read invalid size from kernel: %u",
4387687d0d8SRobert Mustacchi 		    len);
4397687d0d8SRobert Mustacchi 	}
4407687d0d8SRobert Mustacchi 
4417687d0d8SRobert Mustacchi 	if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcip->pia_priv_eff) != 0) {
4427687d0d8SRobert Mustacchi 		err(EXIT_FAILURE, "failed to raise privileges");
4437687d0d8SRobert Mustacchi 	}
4447687d0d8SRobert Mustacchi 
4457687d0d8SRobert Mustacchi 	if (ioctl(pck->pck_fd, PCITOOL_DEVICE_GET_REG, &pci_reg) != 0) {
4467687d0d8SRobert Mustacchi 		err(EXIT_FAILURE, "failed to read device offset 0x%x", off);
4477687d0d8SRobert Mustacchi 	}
4487687d0d8SRobert Mustacchi 
4497687d0d8SRobert Mustacchi 	if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcip->pia_priv_min) != 0) {
4507687d0d8SRobert Mustacchi 		err(EXIT_FAILURE, "failed to reduce privileges");
4517687d0d8SRobert Mustacchi 	}
4527687d0d8SRobert Mustacchi 
4537687d0d8SRobert Mustacchi 	switch (len) {
4547687d0d8SRobert Mustacchi 	case 1:
4557687d0d8SRobert Mustacchi 		*(uint8_t *)buf = (uint8_t)pci_reg.data;
4567687d0d8SRobert Mustacchi 		break;
4577687d0d8SRobert Mustacchi 	case 2:
4587687d0d8SRobert Mustacchi 		*(uint16_t *)buf = (uint16_t)pci_reg.data;
4597687d0d8SRobert Mustacchi 		break;
4607687d0d8SRobert Mustacchi 	case 4:
4617687d0d8SRobert Mustacchi 		*(uint32_t *)buf = (uint32_t)pci_reg.data;
4627687d0d8SRobert Mustacchi 		break;
4637687d0d8SRobert Mustacchi 	case 8:
4647687d0d8SRobert Mustacchi 		*(uint64_t *)buf = (uint64_t)pci_reg.data;
4657687d0d8SRobert Mustacchi 		break;
4667687d0d8SRobert Mustacchi 	}
4677687d0d8SRobert Mustacchi 
4687687d0d8SRobert Mustacchi 	return (B_TRUE);
4697687d0d8SRobert Mustacchi }
4707687d0d8SRobert Mustacchi 
4717687d0d8SRobert Mustacchi void
pcieadm_init_cfgspace_kernel(pcieadm_t * pcip,pcieadm_cfgspace_f * funcp,void ** arg)4727687d0d8SRobert Mustacchi pcieadm_init_cfgspace_kernel(pcieadm_t *pcip, pcieadm_cfgspace_f *funcp,
4737687d0d8SRobert Mustacchi     void **arg)
4747687d0d8SRobert Mustacchi {
4757687d0d8SRobert Mustacchi 	char *nexus_base;
4767687d0d8SRobert Mustacchi 	char nexus_reg[PATH_MAX];
4777687d0d8SRobert Mustacchi 	int fd, nregs, *regs;
4787687d0d8SRobert Mustacchi 	pcieadm_cfgspace_kernel_t *pck;
4797687d0d8SRobert Mustacchi 
4807687d0d8SRobert Mustacchi 	if ((nexus_base = di_devfs_path(pcip->pia_nexus)) == NULL) {
4817687d0d8SRobert Mustacchi 		err(EXIT_FAILURE, "failed to get path to nexus node");
4827687d0d8SRobert Mustacchi 	}
4837687d0d8SRobert Mustacchi 
4847687d0d8SRobert Mustacchi 	if (snprintf(nexus_reg, sizeof (nexus_reg), "/devices%s:reg",
4857687d0d8SRobert Mustacchi 	    nexus_base) >= sizeof (nexus_reg)) {
4867687d0d8SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to construct nexus path, path "
4877687d0d8SRobert Mustacchi 		    "overflow");
4887687d0d8SRobert Mustacchi 	}
4897687d0d8SRobert Mustacchi 	free(nexus_base);
4907687d0d8SRobert Mustacchi 
4917687d0d8SRobert Mustacchi 	if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcip->pia_priv_eff) != 0) {
4927687d0d8SRobert Mustacchi 		err(EXIT_FAILURE, "failed to raise privileges");
4937687d0d8SRobert Mustacchi 	}
4947687d0d8SRobert Mustacchi 
4957687d0d8SRobert Mustacchi 	if ((fd = open(nexus_reg, O_RDONLY)) < 0) {
4967687d0d8SRobert Mustacchi 		err(EXIT_FAILURE, "failed to open %s", nexus_reg);
4977687d0d8SRobert Mustacchi 	}
4987687d0d8SRobert Mustacchi 
4997687d0d8SRobert Mustacchi 	if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcip->pia_priv_min) != 0) {
5007687d0d8SRobert Mustacchi 		err(EXIT_FAILURE, "failed to reduce privileges");
5017687d0d8SRobert Mustacchi 	}
5027687d0d8SRobert Mustacchi 
5037687d0d8SRobert Mustacchi 	nregs = di_prop_lookup_ints(DDI_DEV_T_ANY, pcip->pia_devi, "reg",
5047687d0d8SRobert Mustacchi 	    &regs);
5057687d0d8SRobert Mustacchi 	if (nregs <= 0) {
5067687d0d8SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to lookup regs array for %s",
5077687d0d8SRobert Mustacchi 		    pcip->pia_devstr);
5087687d0d8SRobert Mustacchi 	}
5097687d0d8SRobert Mustacchi 
5107687d0d8SRobert Mustacchi 	pck = calloc(1, sizeof (pcieadm_cfgspace_kernel_t));
5117687d0d8SRobert Mustacchi 	if (pck == NULL) {
5127687d0d8SRobert Mustacchi 		err(EXIT_FAILURE, "failed to allocate memory for reading "
5137687d0d8SRobert Mustacchi 		    "kernel cfgspace data");
5147687d0d8SRobert Mustacchi 	}
5157687d0d8SRobert Mustacchi 
5167687d0d8SRobert Mustacchi 	pck->pck_pci = pcip;
5177687d0d8SRobert Mustacchi 	pck->pck_fd = fd;
5187687d0d8SRobert Mustacchi 	pck->pck_bus = PCI_REG_BUS_G(regs[0]);
5197687d0d8SRobert Mustacchi 	pck->pck_dev = PCI_REG_DEV_G(regs[0]);
5207687d0d8SRobert Mustacchi 	pck->pck_func = PCI_REG_FUNC_G(regs[0]);
5217687d0d8SRobert Mustacchi 
5227687d0d8SRobert Mustacchi 	*funcp = pcieadm_read_cfgspace_kernel;
5237687d0d8SRobert Mustacchi 	*arg = pck;
5247687d0d8SRobert Mustacchi }
5257687d0d8SRobert Mustacchi 
5267687d0d8SRobert Mustacchi void
pcieadm_fini_cfgspace_kernel(void * arg)5277687d0d8SRobert Mustacchi pcieadm_fini_cfgspace_kernel(void *arg)
5287687d0d8SRobert Mustacchi {
5297687d0d8SRobert Mustacchi 	pcieadm_cfgspace_kernel_t *pck = arg;
5307687d0d8SRobert Mustacchi 
5317687d0d8SRobert Mustacchi 	VERIFY0(close(pck->pck_fd));
5327687d0d8SRobert Mustacchi 	free(pck);
5337687d0d8SRobert Mustacchi }
5347687d0d8SRobert Mustacchi 
5357687d0d8SRobert Mustacchi static const pcieadm_cmdtab_t pcieadm_cmds[] = {
5367687d0d8SRobert Mustacchi 	{ "save-cfgspace", pcieadm_save_cfgspace, pcieadm_save_cfgspace_usage },
5377687d0d8SRobert Mustacchi 	{ "show-cfgspace", pcieadm_show_cfgspace, pcieadm_show_cfgspace_usage },
5387687d0d8SRobert Mustacchi 	{ "show-devs", pcieadm_show_devs, pcieadm_show_devs_usage },
5397687d0d8SRobert Mustacchi 	{ NULL }
5407687d0d8SRobert Mustacchi };
5417687d0d8SRobert Mustacchi 
5427687d0d8SRobert Mustacchi static void
pcieadm_usage(const char * format,...)5437687d0d8SRobert Mustacchi pcieadm_usage(const char *format, ...)
5447687d0d8SRobert Mustacchi {
5457687d0d8SRobert Mustacchi 	uint_t cmd;
5467687d0d8SRobert Mustacchi 
5477687d0d8SRobert Mustacchi 	if (format != NULL) {
5487687d0d8SRobert Mustacchi 		va_list ap;
5497687d0d8SRobert Mustacchi 
5507687d0d8SRobert Mustacchi 		va_start(ap, format);
5517687d0d8SRobert Mustacchi 		vwarnx(format, ap);
5527687d0d8SRobert Mustacchi 		va_end(ap);
5537687d0d8SRobert Mustacchi 	}
5547687d0d8SRobert Mustacchi 
5557687d0d8SRobert Mustacchi 	(void) fprintf(stderr, "usage:  %s <subcommand> <args> ...\n\n",
5567687d0d8SRobert Mustacchi 	    pcieadm_progname);
5577687d0d8SRobert Mustacchi 
5587687d0d8SRobert Mustacchi 	for (cmd = 0; pcieadm_cmds[cmd].pct_name != NULL; cmd++) {
5597687d0d8SRobert Mustacchi 		if (pcieadm_cmds[cmd].pct_use != NULL) {
5607687d0d8SRobert Mustacchi 			pcieadm_cmds[cmd].pct_use(stderr);
5617687d0d8SRobert Mustacchi 		}
5627687d0d8SRobert Mustacchi 	}
5637687d0d8SRobert Mustacchi }
5647687d0d8SRobert Mustacchi 
5657687d0d8SRobert Mustacchi int
main(int argc,char * argv[])5667687d0d8SRobert Mustacchi main(int argc, char *argv[])
5677687d0d8SRobert Mustacchi {
5687687d0d8SRobert Mustacchi 	uint_t cmd;
5697687d0d8SRobert Mustacchi 
5707687d0d8SRobert Mustacchi 	pcieadm_progname = basename(argv[0]);
5717687d0d8SRobert Mustacchi 
5727687d0d8SRobert Mustacchi 	if (argc < 2) {
5737687d0d8SRobert Mustacchi 		pcieadm_usage("missing required sub-command");
5747687d0d8SRobert Mustacchi 		exit(EXIT_USAGE);
5757687d0d8SRobert Mustacchi 	}
5767687d0d8SRobert Mustacchi 
5777687d0d8SRobert Mustacchi 	for (cmd = 0; pcieadm_cmds[cmd].pct_name != NULL; cmd++) {
5787687d0d8SRobert Mustacchi 		if (strcmp(pcieadm_cmds[cmd].pct_name, argv[1]) == 0) {
5797687d0d8SRobert Mustacchi 			break;
5807687d0d8SRobert Mustacchi 		}
5817687d0d8SRobert Mustacchi 	}
5827687d0d8SRobert Mustacchi 
5837687d0d8SRobert Mustacchi 	if (pcieadm_cmds[cmd].pct_name == NULL) {
5847687d0d8SRobert Mustacchi 		pcieadm_usage("unknown sub-command: %s", argv[1]);
5857687d0d8SRobert Mustacchi 		exit(EXIT_USAGE);
5867687d0d8SRobert Mustacchi 	}
5877687d0d8SRobert Mustacchi 	argc -= 2;
5887687d0d8SRobert Mustacchi 	argv += 2;
5897687d0d8SRobert Mustacchi 	optind = 0;
5907687d0d8SRobert Mustacchi 	pcieadm.pia_cmdtab = &pcieadm_cmds[cmd];
5917687d0d8SRobert Mustacchi 
5927687d0d8SRobert Mustacchi 	/*
5937687d0d8SRobert Mustacchi 	 * Set up common things that all of pcieadm needs before dispatching to
5947687d0d8SRobert Mustacchi 	 * a specific sub-command.
5957687d0d8SRobert Mustacchi 	 */
5967687d0d8SRobert Mustacchi 	pcieadm.pia_pcidb = pcidb_open(PCIDB_VERSION);
5977687d0d8SRobert Mustacchi 	if (pcieadm.pia_pcidb == NULL) {
5987687d0d8SRobert Mustacchi 		err(EXIT_FAILURE, "failed to open PCI ID database");
5997687d0d8SRobert Mustacchi 	}
6007687d0d8SRobert Mustacchi 
6017687d0d8SRobert Mustacchi 	pcieadm.pia_root = di_init("/", DINFOCPYALL);
6027687d0d8SRobert Mustacchi 	if (pcieadm.pia_root == DI_NODE_NIL) {
6037687d0d8SRobert Mustacchi 		err(EXIT_FAILURE, "failed to initialize devinfo tree");
6047687d0d8SRobert Mustacchi 	}
6057687d0d8SRobert Mustacchi 
6067687d0d8SRobert Mustacchi 	/*
6077687d0d8SRobert Mustacchi 	 * Set up privileges now that we have already opened our core libraries.
6087687d0d8SRobert Mustacchi 	 * We first set up the minimum actual privilege set that we use while
6097687d0d8SRobert Mustacchi 	 * running. We next set up a second privilege set that has additional
6107687d0d8SRobert Mustacchi 	 * privileges that are intersected with the users actual privileges and
6117687d0d8SRobert Mustacchi 	 * are appended to by the underlying command backends.
6127687d0d8SRobert Mustacchi 	 */
6137687d0d8SRobert Mustacchi 	if ((pcieadm.pia_priv_init = priv_allocset()) == NULL) {
6147687d0d8SRobert Mustacchi 		err(EXIT_FAILURE, "failed to allocate privilege set");
6157687d0d8SRobert Mustacchi 	}
6167687d0d8SRobert Mustacchi 
6177687d0d8SRobert Mustacchi 	if (getppriv(PRIV_EFFECTIVE, pcieadm.pia_priv_init) != 0) {
6187687d0d8SRobert Mustacchi 		err(EXIT_FAILURE, "failed to get current privileges");
6197687d0d8SRobert Mustacchi 	}
6207687d0d8SRobert Mustacchi 
6217687d0d8SRobert Mustacchi 	if ((pcieadm.pia_priv_min = priv_allocset()) == NULL) {
6227687d0d8SRobert Mustacchi 		err(EXIT_FAILURE, "failed to allocate privilege set");
6237687d0d8SRobert Mustacchi 	}
6247687d0d8SRobert Mustacchi 
6257687d0d8SRobert Mustacchi 	if ((pcieadm.pia_priv_eff = priv_allocset()) == NULL) {
6267687d0d8SRobert Mustacchi 		err(EXIT_FAILURE, "failed to allocate privilege set");
6277687d0d8SRobert Mustacchi 	}
6287687d0d8SRobert Mustacchi 
6297687d0d8SRobert Mustacchi 	/*
6307687d0d8SRobert Mustacchi 	 * Note, PRIV_FILE_READ is not removed from the basic set so that way we
6317687d0d8SRobert Mustacchi 	 * can still open libraries that are required due to lazy loading.
6327687d0d8SRobert Mustacchi 	 */
6337687d0d8SRobert Mustacchi 	priv_basicset(pcieadm.pia_priv_min);
6347687d0d8SRobert Mustacchi 	VERIFY0(priv_delset(pcieadm.pia_priv_min, PRIV_FILE_LINK_ANY));
6357687d0d8SRobert Mustacchi 	VERIFY0(priv_delset(pcieadm.pia_priv_min, PRIV_PROC_INFO));
6367687d0d8SRobert Mustacchi 	VERIFY0(priv_delset(pcieadm.pia_priv_min, PRIV_PROC_SESSION));
6377687d0d8SRobert Mustacchi 	VERIFY0(priv_delset(pcieadm.pia_priv_min, PRIV_PROC_FORK));
6387687d0d8SRobert Mustacchi 	VERIFY0(priv_delset(pcieadm.pia_priv_min, PRIV_NET_ACCESS));
6397687d0d8SRobert Mustacchi 	VERIFY0(priv_delset(pcieadm.pia_priv_min, PRIV_FILE_WRITE));
6407687d0d8SRobert Mustacchi 	VERIFY0(priv_delset(pcieadm.pia_priv_min, PRIV_PROC_EXEC));
6417687d0d8SRobert Mustacchi 	VERIFY0(priv_delset(pcieadm.pia_priv_min, PRIV_PROC_EXEC));
6427687d0d8SRobert Mustacchi 
6437687d0d8SRobert Mustacchi 	priv_copyset(pcieadm.pia_priv_min, pcieadm.pia_priv_eff);
6447687d0d8SRobert Mustacchi 	priv_intersect(pcieadm.pia_priv_init, pcieadm.pia_priv_eff);
6457687d0d8SRobert Mustacchi 
6467687d0d8SRobert Mustacchi 	if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcieadm.pia_priv_min) != 0) {
6477687d0d8SRobert Mustacchi 		err(EXIT_FAILURE, "failed to reduce privileges");
6487687d0d8SRobert Mustacchi 	}
6497687d0d8SRobert Mustacchi 
6507687d0d8SRobert Mustacchi 	return (pcieadm.pia_cmdtab->pct_func(&pcieadm, argc, argv));
6517687d0d8SRobert Mustacchi }
652