17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*4c06356bSdh  * Common Development and Distribution License (the "License").
6*4c06356bSdh  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*4c06356bSdh  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include "cfga_scsi.h"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate typedef struct {
297c478bd9Sstevel@tonic-gate 	char *dyncomp;
307c478bd9Sstevel@tonic-gate 	char *devlink;
317c478bd9Sstevel@tonic-gate 	int l_errno;
327c478bd9Sstevel@tonic-gate 	scfga_ret_t ret;
337c478bd9Sstevel@tonic-gate } dyn_t;
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate typedef struct {
367c478bd9Sstevel@tonic-gate 	scfga_recur_t (*devlink_to_dyncomp_p)(dyn_t *dyntp);
377c478bd9Sstevel@tonic-gate 	scfga_recur_t (*dyncomp_to_devlink_p)(dyn_t *dyntp);
387c478bd9Sstevel@tonic-gate } dynrules_t;
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate typedef struct {
417c478bd9Sstevel@tonic-gate 	dyn_t *dynp;
427c478bd9Sstevel@tonic-gate 	dynrules_t *rule_array;
437c478bd9Sstevel@tonic-gate 	int nrules;
447c478bd9Sstevel@tonic-gate } dyncvt_t;
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate typedef struct {
477c478bd9Sstevel@tonic-gate 	const char *hba_phys;
487c478bd9Sstevel@tonic-gate 	const char *dyncomp;
497c478bd9Sstevel@tonic-gate 	char *path;
507c478bd9Sstevel@tonic-gate 	int l_errno;
517c478bd9Sstevel@tonic-gate 	scfga_ret_t ret;
527c478bd9Sstevel@tonic-gate } devpath_t;
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate /* Function prototypes */
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate static int drv_to_hba_logid(di_node_t node, di_minor_t minor, void *arg);
597c478bd9Sstevel@tonic-gate static scfga_ret_t drv_dyn_to_devpath(const char *hba_phys,
607c478bd9Sstevel@tonic-gate     const char *dyncomp, char **pathpp, int *l_errnop);
617c478bd9Sstevel@tonic-gate static int do_drv_dyn_to_devpath(di_node_t node, void *arg);
627c478bd9Sstevel@tonic-gate static scfga_ret_t devlink_dyn_to_devpath(const char *hba_phys,
637c478bd9Sstevel@tonic-gate     const char *dyncomp, char **pathpp, int *l_errnop);
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate static scfga_recur_t disk_dyncomp_to_devlink(dyn_t *dyntp);
667c478bd9Sstevel@tonic-gate static scfga_recur_t tape_dyncomp_to_devlink(dyn_t *dyntp);
677c478bd9Sstevel@tonic-gate static scfga_recur_t def_dyncomp_to_devlink(dyn_t *dyntp);
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate static scfga_ret_t devlink_to_dyncomp(char *devlink,
707c478bd9Sstevel@tonic-gate     char **dyncompp, int *l_errnop);
717c478bd9Sstevel@tonic-gate static scfga_recur_t disk_devlink_to_dyncomp(dyn_t *dyntp);
727c478bd9Sstevel@tonic-gate static scfga_recur_t tape_devlink_to_dyncomp(dyn_t *dyntp);
737c478bd9Sstevel@tonic-gate static scfga_recur_t def_devlink_to_dyncomp(dyn_t *dyntp);
747c478bd9Sstevel@tonic-gate static scfga_ret_t drv_to_dyncomp(di_node_t node, const char *phys,
757c478bd9Sstevel@tonic-gate     char **dyncompp, int *l_errnop);
767c478bd9Sstevel@tonic-gate static scfga_ret_t get_hba_devlink(const char *hba_phys,
777c478bd9Sstevel@tonic-gate     char **hba_logpp, int *l_errnop);
78*4c06356bSdh static scfga_ret_t path_apid_dyn_to_path(const char *hba_phys, const char *dyn,
79*4c06356bSdh     char **pathpp, int *l_errnop);
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate /* Globals */
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate /*
857c478bd9Sstevel@tonic-gate  * Rules for converting between a devlink and logical ap_id and vice-versa
867c478bd9Sstevel@tonic-gate  * The default rules must be the last entry.
877c478bd9Sstevel@tonic-gate  */
887c478bd9Sstevel@tonic-gate static dynrules_t dyncvt_rules[] = {
897c478bd9Sstevel@tonic-gate 	{disk_devlink_to_dyncomp,	disk_dyncomp_to_devlink},
907c478bd9Sstevel@tonic-gate 	{tape_devlink_to_dyncomp,	tape_dyncomp_to_devlink},
917c478bd9Sstevel@tonic-gate 	{def_devlink_to_dyncomp,	def_dyncomp_to_devlink}
927c478bd9Sstevel@tonic-gate };
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate #define	N_DYNRULES	(sizeof (dyncvt_rules)/sizeof (dyncvt_rules[0]))
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate /*
977c478bd9Sstevel@tonic-gate  * Numbering of disk slices is assumed to be 0 through n - 1
987c478bd9Sstevel@tonic-gate  */
997c478bd9Sstevel@tonic-gate typedef struct {
1007c478bd9Sstevel@tonic-gate 	char *prefix;
1017c478bd9Sstevel@tonic-gate 	int nslices;
1027c478bd9Sstevel@tonic-gate } slice_t;
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate static slice_t disk_slices[] = {
1057c478bd9Sstevel@tonic-gate 	{"s", 16},
1067c478bd9Sstevel@tonic-gate 	{"p", 5},
1077c478bd9Sstevel@tonic-gate };
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate #define	N_SLICE_TYPES	(sizeof (disk_slices) / sizeof (disk_slices[0]))
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate static const char *tape_modes[] = {
1127c478bd9Sstevel@tonic-gate 	"",
1137c478bd9Sstevel@tonic-gate 	"b", "bn",
1147c478bd9Sstevel@tonic-gate 	"c", "cb", "cbn", "cn",
1157c478bd9Sstevel@tonic-gate 	"h", "hb", "hbn", "hn",
1167c478bd9Sstevel@tonic-gate 	"l", "lb", "lbn", "ln",
1177c478bd9Sstevel@tonic-gate 	"m", "mb", "mbn", "mn",
1187c478bd9Sstevel@tonic-gate 	"n",
1197c478bd9Sstevel@tonic-gate 	"u", "ub", "ubn", "un"
1207c478bd9Sstevel@tonic-gate };
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate #define	N_TAPE_MODES	(sizeof (tape_modes) / sizeof (tape_modes[0]))
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate /* Various conversions routines */
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate /*
1287c478bd9Sstevel@tonic-gate  * Generates the HBA logical ap_id from physical ap_id.
1297c478bd9Sstevel@tonic-gate  */
1307c478bd9Sstevel@tonic-gate scfga_ret_t
make_hba_logid(const char * hba_phys,char ** hba_logpp,int * l_errnop)1317c478bd9Sstevel@tonic-gate make_hba_logid(const char *hba_phys, char **hba_logpp, int *l_errnop)
1327c478bd9Sstevel@tonic-gate {
1337c478bd9Sstevel@tonic-gate 	walkarg_t u;
1347c478bd9Sstevel@tonic-gate 	pathm_t pmt = {NULL};
1357c478bd9Sstevel@tonic-gate 	scfga_ret_t ret;
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	if (*hba_logpp != NULL) {
1397c478bd9Sstevel@tonic-gate 		return (SCFGA_ERR);
1407c478bd9Sstevel@tonic-gate 	}
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	/* A devlink for the HBA may or may not exist */
1437c478bd9Sstevel@tonic-gate 	if (get_hba_devlink(hba_phys, hba_logpp, l_errnop) == SCFGA_OK) {
1447c478bd9Sstevel@tonic-gate 		assert(*hba_logpp != NULL);
1457c478bd9Sstevel@tonic-gate 		return (SCFGA_OK);
1467c478bd9Sstevel@tonic-gate 	}
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	/*
1497c478bd9Sstevel@tonic-gate 	 * No devlink based logical ap_id.
1507c478bd9Sstevel@tonic-gate 	 * Try driver name and instance number.
1517c478bd9Sstevel@tonic-gate 	 */
1527c478bd9Sstevel@tonic-gate 	u.minor_args.nodetype = DDI_NT_SCSI_ATTACHMENT_POINT;
1537c478bd9Sstevel@tonic-gate 	u.minor_args.fcn = drv_to_hba_logid;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	pmt.phys = (char *)hba_phys;
1567c478bd9Sstevel@tonic-gate 	pmt.ret = SCFGA_APID_NOEXIST;
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	errno = 0;
1597c478bd9Sstevel@tonic-gate 	ret = walk_tree(pmt.phys, &pmt, DINFOMINOR | DINFOPROP, &u,
1607c478bd9Sstevel@tonic-gate 	    SCFGA_WALK_MINOR, &pmt.l_errno);
1617c478bd9Sstevel@tonic-gate 	if (ret == SCFGA_OK && (ret = pmt.ret) == SCFGA_OK) {
1627c478bd9Sstevel@tonic-gate 		assert(pmt.log != NULL);
1637c478bd9Sstevel@tonic-gate 		*hba_logpp = pmt.log;
1647c478bd9Sstevel@tonic-gate 		return (SCFGA_OK);
1657c478bd9Sstevel@tonic-gate 	}
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	/* failed to create logical ap_id */
1687c478bd9Sstevel@tonic-gate 	if (pmt.log != NULL) {
1697c478bd9Sstevel@tonic-gate 		S_FREE(pmt.log);
1707c478bd9Sstevel@tonic-gate 	}
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	*l_errnop = pmt.l_errno;
1747c478bd9Sstevel@tonic-gate 	return (ret);
1757c478bd9Sstevel@tonic-gate }
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate static scfga_ret_t
get_hba_devlink(const char * hba_phys,char ** hba_logpp,int * l_errnop)1787c478bd9Sstevel@tonic-gate get_hba_devlink(const char *hba_phys, char **hba_logpp, int *l_errnop)
1797c478bd9Sstevel@tonic-gate {
1807c478bd9Sstevel@tonic-gate 	size_t len;
1817c478bd9Sstevel@tonic-gate 	scfga_ret_t ret;
1827c478bd9Sstevel@tonic-gate 	int match_minor = 1;
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	ret = physpath_to_devlink((char *)hba_phys, hba_logpp,
1857c478bd9Sstevel@tonic-gate 	    l_errnop, match_minor);
1867c478bd9Sstevel@tonic-gate 	if (ret != SCFGA_OK) {
1877c478bd9Sstevel@tonic-gate 		return (ret);
1887c478bd9Sstevel@tonic-gate 	}
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	assert(*hba_logpp != NULL);
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	/* Remove the "/dev/cfg/"  prefix */
1937c478bd9Sstevel@tonic-gate 	len = strlen(CFGA_DEV_DIR SLASH);
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	(void) memmove(*hba_logpp, *hba_logpp + len,
1967c478bd9Sstevel@tonic-gate 	    strlen(*hba_logpp + len) + 1);
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	return (SCFGA_OK);
1997c478bd9Sstevel@tonic-gate }
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate /* Make logical name for HBA  based on driver and instance */
2027c478bd9Sstevel@tonic-gate static int
drv_to_hba_logid(di_node_t node,di_minor_t minor,void * arg)2037c478bd9Sstevel@tonic-gate drv_to_hba_logid(di_node_t node, di_minor_t minor, void *arg)
2047c478bd9Sstevel@tonic-gate {
2057c478bd9Sstevel@tonic-gate 	int inst;
2067c478bd9Sstevel@tonic-gate 	char *drv, *mn, *log;
2077c478bd9Sstevel@tonic-gate 	pathm_t *ptp;
2087c478bd9Sstevel@tonic-gate 	const size_t loglen = MAXPATHLEN;
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	ptp = (pathm_t *)arg;
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	errno = 0;
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 	mn = di_minor_name(minor);
2157c478bd9Sstevel@tonic-gate 	drv = di_driver_name(node);
2167c478bd9Sstevel@tonic-gate 	inst = di_instance(node);
2177c478bd9Sstevel@tonic-gate 	log = calloc(1, loglen);
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	if (mn != NULL && drv != NULL && inst != -1 && log != NULL) {
2207c478bd9Sstevel@tonic-gate 		/* Count does not include terminating NULL */
2217c478bd9Sstevel@tonic-gate 		if (snprintf(log, loglen, "%s%d:%s", drv, inst, mn) < loglen) {
2227c478bd9Sstevel@tonic-gate 			ptp->ret = SCFGA_OK;
2237c478bd9Sstevel@tonic-gate 			ptp->log = log;
2247c478bd9Sstevel@tonic-gate 			return (DI_WALK_TERMINATE);
2257c478bd9Sstevel@tonic-gate 		}
2267c478bd9Sstevel@tonic-gate 	}
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	S_FREE(log);
2297c478bd9Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
2307c478bd9Sstevel@tonic-gate }
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate /*
2337c478bd9Sstevel@tonic-gate  * Given a bus or device ap_id <hba_phys, dyncomp>, returns the physical
2347c478bd9Sstevel@tonic-gate  * path in pathpp.
2357c478bd9Sstevel@tonic-gate  * Returns: SCFGA_APID_NOEXIST if the path does not exist.
2367c478bd9Sstevel@tonic-gate  */
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate scfga_ret_t
apid_to_path(const char * hba_phys,const char * dyncomp,char ** pathpp,int * l_errnop)2397c478bd9Sstevel@tonic-gate apid_to_path(
2407c478bd9Sstevel@tonic-gate 	const char *hba_phys,
2417c478bd9Sstevel@tonic-gate 	const char *dyncomp,
2427c478bd9Sstevel@tonic-gate 	char **pathpp,
2437c478bd9Sstevel@tonic-gate 	int *l_errnop)
2447c478bd9Sstevel@tonic-gate {
2457c478bd9Sstevel@tonic-gate 	scfga_ret_t ret;
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	if (*pathpp != NULL) {
2487c478bd9Sstevel@tonic-gate 		return (SCFGA_LIB_ERR);
2497c478bd9Sstevel@tonic-gate 	}
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	/* If a bus, the physical ap_id is the physical path */
2527c478bd9Sstevel@tonic-gate 	if (dyncomp == NULL) {
2537c478bd9Sstevel@tonic-gate 		if ((*pathpp = strdup(hba_phys)) == NULL) {
2547c478bd9Sstevel@tonic-gate 			*l_errnop = errno;
2557c478bd9Sstevel@tonic-gate 			return (SCFGA_LIB_ERR);
2567c478bd9Sstevel@tonic-gate 		}
2577c478bd9Sstevel@tonic-gate 		return (SCFGA_OK);
2587c478bd9Sstevel@tonic-gate 	}
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	/* Dynamic component exists, we have a device */
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	/*
2637c478bd9Sstevel@tonic-gate 	 * If the dynamic component has a '/', it was derived from a devlink
2647c478bd9Sstevel@tonic-gate 	 * Else it was derived from driver name and instance number.
265*4c06356bSdh 	 * If it is pathinfo instance number based ap id, it will have a format
266*4c06356bSdh 	 * path#.???.
2677c478bd9Sstevel@tonic-gate 	 */
2687c478bd9Sstevel@tonic-gate 	if (strchr(dyncomp, '/') != NULL) {
2697c478bd9Sstevel@tonic-gate 		ret = devlink_dyn_to_devpath(hba_phys, dyncomp, pathpp,
2707c478bd9Sstevel@tonic-gate 		    l_errnop);
271*4c06356bSdh 	} else if (strstr(dyncomp, PATH_APID_DYN_SEP) != NULL) {
272*4c06356bSdh 		ret = path_apid_dyn_to_path(hba_phys, dyncomp, pathpp,
273*4c06356bSdh 		    l_errnop);
2747c478bd9Sstevel@tonic-gate 	} else {
2757c478bd9Sstevel@tonic-gate 		ret = drv_dyn_to_devpath(hba_phys, dyncomp, pathpp, l_errnop);
2767c478bd9Sstevel@tonic-gate 	}
2777c478bd9Sstevel@tonic-gate 	assert(ret != SCFGA_OK || *pathpp != NULL);
2787c478bd9Sstevel@tonic-gate 
279*4c06356bSdh 
2807c478bd9Sstevel@tonic-gate 	return (ret);
2817c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate 
283*4c06356bSdh /*
284*4c06356bSdh  * Get the devfs path of pathinfo node that is associated with
285*4c06356bSdh  * the given dynamic component.
286*4c06356bSdh  *
287*4c06356bSdh  * input
288*4c06356bSdh  *   hba_phys: physical path of HBA
289*4c06356bSdh  *   dyn : bus address of pathinfo node
290*4c06356bSdh  * output:
291*4c06356bSdh  *   pathpp: devfs path of the pathinfo node.
292*4c06356bSdh  */
293*4c06356bSdh static scfga_ret_t
path_apid_dyn_to_path(const char * hba_phys,const char * dyn,char ** pathpp,int * l_errnop)294*4c06356bSdh path_apid_dyn_to_path(
295*4c06356bSdh 	const char *hba_phys,
296*4c06356bSdh 	const char *dyn,
297*4c06356bSdh 	char **pathpp,
298*4c06356bSdh 	int *l_errnop)
299*4c06356bSdh {
300*4c06356bSdh 
301*4c06356bSdh 	di_node_t   root, walk_root;
302*4c06356bSdh 	di_path_t   pi_node = DI_PATH_NIL;
303*4c06356bSdh 	char	    *root_path, *devpath, *cp;
304*4c06356bSdh 	int	    len;
305*4c06356bSdh 
306*4c06356bSdh 	*l_errnop = 0;
307*4c06356bSdh 
308*4c06356bSdh 	/* *pathpp should be NULL if pathpp is not NULL. */
309*4c06356bSdh 	if ((hba_phys == NULL) || (pathpp != NULL) && (*pathpp != NULL)) {
310*4c06356bSdh 		return (SCFGA_LIB_ERR);
311*4c06356bSdh 	}
312*4c06356bSdh 
313*4c06356bSdh 	if ((root_path = strdup(hba_phys)) == NULL) {
314*4c06356bSdh 		*l_errnop = errno;
315*4c06356bSdh 		return (SCFGA_LIB_ERR);
316*4c06356bSdh 	}
317*4c06356bSdh 
318*4c06356bSdh 	/* Fix up path for di_init() */
319*4c06356bSdh 	len = strlen(DEVICES_DIR);
320*4c06356bSdh 	if (strncmp(root_path, DEVICES_DIR SLASH,
321*4c06356bSdh 	    len + strlen(SLASH)) == 0) {
322*4c06356bSdh 		cp = root_path + len;
323*4c06356bSdh 		(void) memmove(root_path, cp, strlen(cp) + 1);
324*4c06356bSdh 	} else if (*root_path != '/') {
325*4c06356bSdh 		*l_errnop = 0;
326*4c06356bSdh 		S_FREE(root_path);
327*4c06356bSdh 		return (SCFGA_ERR);
328*4c06356bSdh 	}
329*4c06356bSdh 
330*4c06356bSdh 	/* Remove dynamic component if any */
331*4c06356bSdh 	if ((cp = GET_DYN(root_path)) != NULL) {
332*4c06356bSdh 		*cp = '\0';
333*4c06356bSdh 	}
334*4c06356bSdh 
335*4c06356bSdh 	/* Remove minor name if any */
336*4c06356bSdh 	if ((cp = strrchr(root_path, ':')) != NULL) {
337*4c06356bSdh 		*cp = '\0';
338*4c06356bSdh 	}
339*4c06356bSdh 
340*4c06356bSdh 	/*
341*4c06356bSdh 	 * Cached snapshots are always rooted at "/"
342*4c06356bSdh 	 */
343*4c06356bSdh 
344*4c06356bSdh 	/* Get a snapshot */
345*4c06356bSdh 	if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
346*4c06356bSdh 		*l_errnop = errno;
347*4c06356bSdh 		S_FREE(root_path);
348*4c06356bSdh 		return (SCFGA_ERR);
349*4c06356bSdh 	}
350*4c06356bSdh 
351*4c06356bSdh 	/*
352*4c06356bSdh 	 * Lookup the subtree of interest
353*4c06356bSdh 	 */
354*4c06356bSdh 	walk_root = di_lookup_node(root, root_path);
355*4c06356bSdh 
356*4c06356bSdh 	if (walk_root == DI_NODE_NIL) {
357*4c06356bSdh 		*l_errnop = errno;
358*4c06356bSdh 		di_fini(root);
359*4c06356bSdh 		S_FREE(root_path);
360*4c06356bSdh 		return (SCFGA_LIB_ERR);
361*4c06356bSdh 	}
362*4c06356bSdh 
363*4c06356bSdh 	S_FREE(root_path);
364*4c06356bSdh 
365*4c06356bSdh 	if ((pi_node = di_path_next_client(walk_root, pi_node)) ==
366*4c06356bSdh 	    DI_PATH_NIL) {
367*4c06356bSdh 		di_fini(root);
368*4c06356bSdh 		return (SCFGA_APID_NOEXIST);
369*4c06356bSdh 	}
370*4c06356bSdh 
371*4c06356bSdh 	/*
372*4c06356bSdh 	 * now parse the path info node.
373*4c06356bSdh 	 */
374*4c06356bSdh 	do {
375*4c06356bSdh 		/* check the length first. */
376*4c06356bSdh 		if (strlen(di_path_bus_addr(pi_node)) != strlen(dyn)) {
377*4c06356bSdh 			continue;
378*4c06356bSdh 		}
379*4c06356bSdh 
380*4c06356bSdh 		if (strcmp(di_path_bus_addr(pi_node), dyn) == 0) {
381*4c06356bSdh 			/* get the devfspath of pathinfo node. */
382*4c06356bSdh 			devpath = di_path_devfs_path(pi_node);
383*4c06356bSdh 			if (devpath == NULL) {
384*4c06356bSdh 				*l_errnop = errno;
385*4c06356bSdh 				di_fini(root);
386*4c06356bSdh 				return (SCFGA_ERR);
387*4c06356bSdh 			}
388*4c06356bSdh 
389*4c06356bSdh 			len = strlen(DEVICES_DIR) + strlen(devpath) + 1;
390*4c06356bSdh 			*pathpp = calloc(1, len);
391*4c06356bSdh 			if (*pathpp == NULL) {
392*4c06356bSdh 				*l_errnop = errno;
393*4c06356bSdh 				di_devfs_path_free(devpath);
394*4c06356bSdh 				di_fini(root);
395*4c06356bSdh 				return (SCFGA_ERR);
396*4c06356bSdh 			} else {
397*4c06356bSdh 				(void) snprintf(*pathpp, len, "%s%s",
398*4c06356bSdh 				    DEVICES_DIR, devpath);
399*4c06356bSdh 				di_devfs_path_free(devpath);
400*4c06356bSdh 				di_fini(root);
401*4c06356bSdh 				return (SCFGA_OK);
402*4c06356bSdh 			}
403*4c06356bSdh 		}
404*4c06356bSdh 		pi_node = di_path_next_client(walk_root, pi_node);
405*4c06356bSdh 	} while (pi_node != DI_PATH_NIL);
406*4c06356bSdh 
407*4c06356bSdh 	di_fini(root);
408*4c06356bSdh 	return (SCFGA_APID_NOEXIST);
409*4c06356bSdh }
410*4c06356bSdh 
4117c478bd9Sstevel@tonic-gate static scfga_ret_t
drv_dyn_to_devpath(const char * hba_phys,const char * dyncomp,char ** pathpp,int * l_errnop)4127c478bd9Sstevel@tonic-gate drv_dyn_to_devpath(
4137c478bd9Sstevel@tonic-gate 	const char *hba_phys,
4147c478bd9Sstevel@tonic-gate 	const char *dyncomp,
4157c478bd9Sstevel@tonic-gate 	char **pathpp,
4167c478bd9Sstevel@tonic-gate 	int *l_errnop)
4177c478bd9Sstevel@tonic-gate {
4187c478bd9Sstevel@tonic-gate 	walkarg_t u;
4197c478bd9Sstevel@tonic-gate 	devpath_t dpt = {NULL};
4207c478bd9Sstevel@tonic-gate 	scfga_ret_t ret;
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	/* A device MUST have a dynamic component */
4237c478bd9Sstevel@tonic-gate 	if (dyncomp == NULL || *pathpp != NULL) {
4247c478bd9Sstevel@tonic-gate 		return (SCFGA_LIB_ERR);
4257c478bd9Sstevel@tonic-gate 	}
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	u.node_args.flags = DI_WALK_CLDFIRST;
4287c478bd9Sstevel@tonic-gate 	u.node_args.fcn = do_drv_dyn_to_devpath;
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	dpt.hba_phys = hba_phys;
4317c478bd9Sstevel@tonic-gate 	dpt.dyncomp = dyncomp;
4327c478bd9Sstevel@tonic-gate 	dpt.ret = SCFGA_APID_NOEXIST;
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	ret = walk_tree(hba_phys, &dpt, DINFOCPYALL, &u,
4357c478bd9Sstevel@tonic-gate 	    SCFGA_WALK_NODE, &dpt.l_errno);
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	if (ret == SCFGA_OK && (ret = dpt.ret) == SCFGA_OK) {
4387c478bd9Sstevel@tonic-gate 		assert(dpt.path != NULL);
4397c478bd9Sstevel@tonic-gate 		*pathpp = dpt.path;
4407c478bd9Sstevel@tonic-gate 		return (SCFGA_OK);
4417c478bd9Sstevel@tonic-gate 	}
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	if (dpt.path != NULL) {
4447c478bd9Sstevel@tonic-gate 		S_FREE(dpt.path);
4457c478bd9Sstevel@tonic-gate 	}
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	*l_errnop = dpt.l_errno;
4497c478bd9Sstevel@tonic-gate 	return (ret);
4507c478bd9Sstevel@tonic-gate }
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate /* Converts a driver and instance number based logid into a physical path */
4537c478bd9Sstevel@tonic-gate static int
do_drv_dyn_to_devpath(di_node_t node,void * arg)4547c478bd9Sstevel@tonic-gate do_drv_dyn_to_devpath(di_node_t node, void *arg)
4557c478bd9Sstevel@tonic-gate {
4567c478bd9Sstevel@tonic-gate 	int inst, rv, match_minor;
4577c478bd9Sstevel@tonic-gate 	devpath_t *dptp;
4587c478bd9Sstevel@tonic-gate 	char *physpath, *drv;
4597c478bd9Sstevel@tonic-gate 	char *drvinst, *devpath;
4607c478bd9Sstevel@tonic-gate 	const size_t drvlen = MAXPATHLEN;
4617c478bd9Sstevel@tonic-gate 	size_t devlen;
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	dptp = (devpath_t *)arg;
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	assert(dptp->hba_phys != NULL && dptp->dyncomp != NULL);
4667c478bd9Sstevel@tonic-gate 	assert(dptp->path == NULL);
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	/*
4697c478bd9Sstevel@tonic-gate 	 * Skip stub nodes
4707c478bd9Sstevel@tonic-gate 	 */
4717c478bd9Sstevel@tonic-gate 	if (IS_STUB_NODE(node)) {
4727c478bd9Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
4737c478bd9Sstevel@tonic-gate 	}
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	errno = 0;
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 	drv = di_driver_name(node);
4787c478bd9Sstevel@tonic-gate 	inst = di_instance(node);
4797c478bd9Sstevel@tonic-gate 	physpath = di_devfs_path(node);
4807c478bd9Sstevel@tonic-gate 	if (drv == NULL || inst == -1 || physpath == NULL) {
4817c478bd9Sstevel@tonic-gate 		rv = DI_WALK_CONTINUE;
4827c478bd9Sstevel@tonic-gate 		goto out;
4837c478bd9Sstevel@tonic-gate 	}
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	devlen = strlen(DEVICES_DIR) + strlen(physpath) + 1;
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	devpath = calloc(1, devlen);
4887c478bd9Sstevel@tonic-gate 	drvinst = calloc(1, drvlen);
4897c478bd9Sstevel@tonic-gate 	if (devpath == NULL || drvinst == NULL) {
4907c478bd9Sstevel@tonic-gate 		dptp->l_errno = errno;
4917c478bd9Sstevel@tonic-gate 		dptp->ret = SCFGA_LIB_ERR;
4927c478bd9Sstevel@tonic-gate 		rv = DI_WALK_TERMINATE;
4937c478bd9Sstevel@tonic-gate 		goto out;
4947c478bd9Sstevel@tonic-gate 	}
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	(void) snprintf(drvinst, drvlen, "%s%d", drv, inst);
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 	/* Create the physical path */
4997c478bd9Sstevel@tonic-gate 	(void) snprintf(devpath, devlen, "%s%s", DEVICES_DIR, physpath);
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 	/* Skip node if it is the HBA */
5027c478bd9Sstevel@tonic-gate 	match_minor = 0;
5037c478bd9Sstevel@tonic-gate 	if (!dev_cmp(dptp->hba_phys, devpath, match_minor)) {
5047c478bd9Sstevel@tonic-gate 		rv = DI_WALK_CONTINUE;
5057c478bd9Sstevel@tonic-gate 		goto out;
5067c478bd9Sstevel@tonic-gate 	}
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 	/* Compare the base and dynamic components */
5097c478bd9Sstevel@tonic-gate 	if (!hba_dev_cmp(dptp->hba_phys, devpath) &&
5107c478bd9Sstevel@tonic-gate 	    strcmp(dptp->dyncomp, drvinst) == 0) {
5117c478bd9Sstevel@tonic-gate 		dptp->ret = SCFGA_OK;
5127c478bd9Sstevel@tonic-gate 		dptp->path = devpath;
5137c478bd9Sstevel@tonic-gate 		rv = DI_WALK_TERMINATE;
5147c478bd9Sstevel@tonic-gate 	} else {
5157c478bd9Sstevel@tonic-gate 		rv =  DI_WALK_CONTINUE;
5167c478bd9Sstevel@tonic-gate 	}
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	/*FALLTHRU*/
5197c478bd9Sstevel@tonic-gate out:
5207c478bd9Sstevel@tonic-gate 	S_FREE(drvinst);
5217c478bd9Sstevel@tonic-gate 	if (physpath != NULL) di_devfs_path_free(physpath);
5227c478bd9Sstevel@tonic-gate 	if (dptp->ret != SCFGA_OK) S_FREE(devpath);
5237c478bd9Sstevel@tonic-gate 	return (rv);
5247c478bd9Sstevel@tonic-gate }
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate /* readlink wrapper to ensure proper null termination of the results */
5277c478bd9Sstevel@tonic-gate static int
s_readlink(char * link,char * buf,int len)5287c478bd9Sstevel@tonic-gate s_readlink(char *link, char *buf, int len)
5297c478bd9Sstevel@tonic-gate {
5307c478bd9Sstevel@tonic-gate 	int count;
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	count = readlink(link, buf, len - 1);
5337c478bd9Sstevel@tonic-gate 	if (count != -1)
5347c478bd9Sstevel@tonic-gate 		buf[count] = '\0';
5357c478bd9Sstevel@tonic-gate 	return (count);
5367c478bd9Sstevel@tonic-gate }
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate /* Converts a devlink based dynamic component to a path */
5397c478bd9Sstevel@tonic-gate static scfga_ret_t
devlink_dyn_to_devpath(const char * hba_phys,const char * dyncomp,char ** pathpp,int * l_errnop)5407c478bd9Sstevel@tonic-gate devlink_dyn_to_devpath(
5417c478bd9Sstevel@tonic-gate 	const char *hba_phys,
5427c478bd9Sstevel@tonic-gate 	const char *dyncomp,
5437c478bd9Sstevel@tonic-gate 	char **pathpp,
5447c478bd9Sstevel@tonic-gate 	int *l_errnop)
5457c478bd9Sstevel@tonic-gate {
5467c478bd9Sstevel@tonic-gate 	dyn_t dynt = {NULL};
5477c478bd9Sstevel@tonic-gate 	int i;
5487c478bd9Sstevel@tonic-gate 	scfga_ret_t ret;
5497c478bd9Sstevel@tonic-gate 	char buf[PATH_MAX], *path;
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	if (*pathpp != NULL) {
5527c478bd9Sstevel@tonic-gate 		return (SCFGA_LIB_ERR);
5537c478bd9Sstevel@tonic-gate 	}
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 	/* Convert the dynamic component to the corresponding devlink */
5567c478bd9Sstevel@tonic-gate 	dynt.dyncomp = (char *)dyncomp;
5577c478bd9Sstevel@tonic-gate 	dynt.ret = SCFGA_APID_NOEXIST;
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 	for (i = 0; i < N_DYNRULES; i++) {
5607c478bd9Sstevel@tonic-gate 		if (dyncvt_rules[i].dyncomp_to_devlink_p(&dynt)
5617c478bd9Sstevel@tonic-gate 		    != SCFGA_CONTINUE) {
5627c478bd9Sstevel@tonic-gate 			break;
5637c478bd9Sstevel@tonic-gate 		}
5647c478bd9Sstevel@tonic-gate 	}
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 	if (i >= N_DYNRULES) {
5677c478bd9Sstevel@tonic-gate 		dynt.ret = SCFGA_APID_NOEXIST;
5687c478bd9Sstevel@tonic-gate 	}
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	if (dynt.ret != SCFGA_OK) {
5717c478bd9Sstevel@tonic-gate 		/* No symlink or error */
5727c478bd9Sstevel@tonic-gate 		return (dynt.ret);
5737c478bd9Sstevel@tonic-gate 	}
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 	assert(dynt.devlink != NULL);
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	/*
5787c478bd9Sstevel@tonic-gate 	 * Follow devlink to get the physical path
5797c478bd9Sstevel@tonic-gate 	 * Note: Do not use realpath().	It will stat() device
5807c478bd9Sstevel@tonic-gate 	 *	and stat() fails under devfs if device is offline.
5817c478bd9Sstevel@tonic-gate 	 */
5827c478bd9Sstevel@tonic-gate 	errno = 0;
5837c478bd9Sstevel@tonic-gate 	if ((s_readlink(dynt.devlink, buf, PATH_MAX) == -1) ||
5847c478bd9Sstevel@tonic-gate 	    ((path = strstr(buf, "/devices/")) == NULL) ||
5857c478bd9Sstevel@tonic-gate 	    ((*pathpp = strdup(path)) == NULL)) {
5867c478bd9Sstevel@tonic-gate 		*l_errnop = errno;
5877c478bd9Sstevel@tonic-gate 		ret = SCFGA_LIB_ERR;
5887c478bd9Sstevel@tonic-gate 		goto out;
5897c478bd9Sstevel@tonic-gate 	}
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	/* Compare base components as well */
5927c478bd9Sstevel@tonic-gate 	if (!hba_dev_cmp(hba_phys, path)) {
5937c478bd9Sstevel@tonic-gate 		ret = SCFGA_OK;
5947c478bd9Sstevel@tonic-gate 	} else {
5957c478bd9Sstevel@tonic-gate 		/* Mismatched base and dynamic component */
5967c478bd9Sstevel@tonic-gate 		*l_errnop = 0;
5977c478bd9Sstevel@tonic-gate 		ret = SCFGA_APID_NOEXIST;
5987c478bd9Sstevel@tonic-gate 	}
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate 	/*FALLTHRU*/
6017c478bd9Sstevel@tonic-gate out:
6027c478bd9Sstevel@tonic-gate 	S_FREE(dynt.devlink);
6037c478bd9Sstevel@tonic-gate 	if (ret != SCFGA_OK) S_FREE(*pathpp);
6047c478bd9Sstevel@tonic-gate 	return (ret);
6057c478bd9Sstevel@tonic-gate }
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate scfga_ret_t
make_dyncomp(di_node_t node,const char * physpath,char ** dyncompp,int * l_errnop)6087c478bd9Sstevel@tonic-gate make_dyncomp(
6097c478bd9Sstevel@tonic-gate 	di_node_t node,
6107c478bd9Sstevel@tonic-gate 	const char *physpath,
6117c478bd9Sstevel@tonic-gate 	char **dyncompp,
6127c478bd9Sstevel@tonic-gate 	int *l_errnop)
6137c478bd9Sstevel@tonic-gate {
6147c478bd9Sstevel@tonic-gate 	char *devlink = NULL;
6157c478bd9Sstevel@tonic-gate 	scfga_ret_t ret;
6167c478bd9Sstevel@tonic-gate 	di_minor_t minor;
6177c478bd9Sstevel@tonic-gate 	char *path;
6187c478bd9Sstevel@tonic-gate 	char pathbuf[MAXPATHLEN];
6197c478bd9Sstevel@tonic-gate 	int match_minor;
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	if (*dyncompp != NULL) {
6227c478bd9Sstevel@tonic-gate 		return (SCFGA_LIB_ERR);
6237c478bd9Sstevel@tonic-gate 	}
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 	/* tag on minor name */
6267c478bd9Sstevel@tonic-gate 	minor = di_minor_next(node, DI_MINOR_NIL);
6277c478bd9Sstevel@tonic-gate 	if (minor == DI_MINOR_NIL) {
6287c478bd9Sstevel@tonic-gate 		match_minor = 0;
6297c478bd9Sstevel@tonic-gate 		path = (char *)physpath;
6307c478bd9Sstevel@tonic-gate 	} else {
6317c478bd9Sstevel@tonic-gate 		match_minor = 1;
632*4c06356bSdh 		(void) snprintf(pathbuf, MAXPATHLEN, "%s:%s", physpath,
6337c478bd9Sstevel@tonic-gate 		    di_minor_name(minor));
6347c478bd9Sstevel@tonic-gate 		path = pathbuf;
6357c478bd9Sstevel@tonic-gate 	}
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	/* Get the corresponding devlink from the physical path */
6387c478bd9Sstevel@tonic-gate 	ret = physpath_to_devlink(path, &devlink, l_errnop, match_minor);
6397c478bd9Sstevel@tonic-gate 	if (ret == SCFGA_OK) {
6407c478bd9Sstevel@tonic-gate 		assert(devlink != NULL);
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 		/* Create dynamic component. */
6437c478bd9Sstevel@tonic-gate 		ret = devlink_to_dyncomp(devlink, dyncompp, l_errnop);
6447c478bd9Sstevel@tonic-gate 		S_FREE(devlink);
6457c478bd9Sstevel@tonic-gate 		if (ret == SCFGA_OK) {
6467c478bd9Sstevel@tonic-gate 			assert(*dyncompp != NULL);
6477c478bd9Sstevel@tonic-gate 			return (SCFGA_OK);
6487c478bd9Sstevel@tonic-gate 		}
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 		/*
6517c478bd9Sstevel@tonic-gate 		 * Failed to get devlink based dynamic component.
6527c478bd9Sstevel@tonic-gate 		 * Try driver and instance
6537c478bd9Sstevel@tonic-gate 		 */
6547c478bd9Sstevel@tonic-gate 	}
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	ret = drv_to_dyncomp(node, physpath, dyncompp, l_errnop);
6577c478bd9Sstevel@tonic-gate 	assert(ret != SCFGA_OK || *dyncompp != NULL);
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 	return (ret);
6607c478bd9Sstevel@tonic-gate }
6617c478bd9Sstevel@tonic-gate 
662*4c06356bSdh /*
663*4c06356bSdh  * Create a dynamic component of path ap_id for the given path info node.
664*4c06356bSdh  * The caller should free the buffer for the dynamic component.
665*4c06356bSdh  */
666*4c06356bSdh scfga_ret_t
make_path_dyncomp(di_path_t path,char ** dyncompp,int * l_errnop)667*4c06356bSdh make_path_dyncomp(
668*4c06356bSdh 	di_path_t path,
669*4c06356bSdh 	char **dyncompp,
670*4c06356bSdh 	int *l_errnop)
671*4c06356bSdh {
672*4c06356bSdh 	char *pi_addr;
673*4c06356bSdh 
674*4c06356bSdh 	if ((path == DI_PATH_NIL) || (*dyncompp != NULL)) {
675*4c06356bSdh 		return (SCFGA_LIB_ERR);
676*4c06356bSdh 	}
677*4c06356bSdh 
678*4c06356bSdh 	if ((pi_addr = di_path_bus_addr(path)) != NULL) {
679*4c06356bSdh 		*dyncompp = calloc(1, strlen(pi_addr) + 1);
680*4c06356bSdh 		if (*dyncompp == NULL) {
681*4c06356bSdh 			*l_errnop = errno;
682*4c06356bSdh 			return (SCFGA_LIB_ERR);
683*4c06356bSdh 		}
684*4c06356bSdh 		(void) strncpy(*dyncompp, pi_addr, strlen(pi_addr));
685*4c06356bSdh 	} else {
686*4c06356bSdh 		return (SCFGA_LIB_ERR);
687*4c06356bSdh 	}
688*4c06356bSdh 
689*4c06356bSdh 	return (SCFGA_OK);
690*4c06356bSdh }
691*4c06356bSdh 
6927c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6937c478bd9Sstevel@tonic-gate static scfga_ret_t
drv_to_dyncomp(di_node_t node,const char * phys,char ** dyncompp,int * l_errnop)6947c478bd9Sstevel@tonic-gate drv_to_dyncomp(di_node_t node, const char *phys, char **dyncompp, int *l_errnop)
6957c478bd9Sstevel@tonic-gate {
6967c478bd9Sstevel@tonic-gate 	char *drv;
6977c478bd9Sstevel@tonic-gate 	int inst;
6987c478bd9Sstevel@tonic-gate 	const int dynlen = MAXPATHLEN;
6997c478bd9Sstevel@tonic-gate 	scfga_ret_t ret;
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	*l_errnop = 0;
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	if ((*dyncompp = calloc(1, dynlen)) == NULL) {
7047c478bd9Sstevel@tonic-gate 		*l_errnop = errno;
7057c478bd9Sstevel@tonic-gate 		return (SCFGA_LIB_ERR);
7067c478bd9Sstevel@tonic-gate 	}
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	drv = di_driver_name(node);
7097c478bd9Sstevel@tonic-gate 	inst = di_instance(node);
7107c478bd9Sstevel@tonic-gate 	if (drv != NULL && inst != -1) {
7117c478bd9Sstevel@tonic-gate 		if (snprintf(*dyncompp, dynlen, "%s%d", drv, inst) < dynlen) {
7127c478bd9Sstevel@tonic-gate 			return (SCFGA_OK);
7137c478bd9Sstevel@tonic-gate 		} else {
7147c478bd9Sstevel@tonic-gate 			ret = SCFGA_LIB_ERR;
7157c478bd9Sstevel@tonic-gate 		}
7167c478bd9Sstevel@tonic-gate 	} else {
7177c478bd9Sstevel@tonic-gate 		ret = SCFGA_APID_NOEXIST;
7187c478bd9Sstevel@tonic-gate 	}
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	S_FREE(*dyncompp);
7217c478bd9Sstevel@tonic-gate 	return (ret);
7227c478bd9Sstevel@tonic-gate }
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate /* Get a dynamic component from a physical path if possible */
7257c478bd9Sstevel@tonic-gate static scfga_ret_t
devlink_to_dyncomp(char * devlink,char ** dyncompp,int * l_errnop)7267c478bd9Sstevel@tonic-gate devlink_to_dyncomp(char *devlink, char **dyncompp, int *l_errnop)
7277c478bd9Sstevel@tonic-gate {
7287c478bd9Sstevel@tonic-gate 	int i;
7297c478bd9Sstevel@tonic-gate 	dyn_t dynt = {NULL};
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	*l_errnop = 0;
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	if (*dyncompp != NULL) {
7347c478bd9Sstevel@tonic-gate 		return (SCFGA_LIB_ERR);
7357c478bd9Sstevel@tonic-gate 	}
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 	/* Convert devlink to dynamic component */
7387c478bd9Sstevel@tonic-gate 	dynt.devlink = devlink;
7397c478bd9Sstevel@tonic-gate 	dynt.ret = SCFGA_APID_NOEXIST;
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 	for (i = 0; i < N_DYNRULES; i++) {
7427c478bd9Sstevel@tonic-gate 		if (dyncvt_rules[i].devlink_to_dyncomp_p(&dynt)
7437c478bd9Sstevel@tonic-gate 		    != SCFGA_CONTINUE) {
7447c478bd9Sstevel@tonic-gate 			break;
7457c478bd9Sstevel@tonic-gate 		}
7467c478bd9Sstevel@tonic-gate 	}
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	if (i >= N_DYNRULES) {
7497c478bd9Sstevel@tonic-gate 		dynt.ret = SCFGA_APID_NOEXIST;
7507c478bd9Sstevel@tonic-gate 	}
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 	if (dynt.ret == SCFGA_OK) {
7537c478bd9Sstevel@tonic-gate 		assert(dynt.dyncomp != NULL);
7547c478bd9Sstevel@tonic-gate 		*dyncompp = dynt.dyncomp;
7557c478bd9Sstevel@tonic-gate 	}
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	return (dynt.ret);
7587c478bd9Sstevel@tonic-gate }
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate /* For disks remove partition information, (s or p) */
7617c478bd9Sstevel@tonic-gate static scfga_recur_t
disk_devlink_to_dyncomp(dyn_t * dyntp)7627c478bd9Sstevel@tonic-gate disk_devlink_to_dyncomp(dyn_t *dyntp)
7637c478bd9Sstevel@tonic-gate {
7647c478bd9Sstevel@tonic-gate 	char *cp = NULL, *cp1 = NULL;
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	assert(dyntp->devlink != NULL);
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	dyntp->l_errno = 0;
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	if (dyntp->dyncomp != NULL) {
7717c478bd9Sstevel@tonic-gate 		goto lib_err;
7727c478bd9Sstevel@tonic-gate 	}
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 	/* Check if a disk devlink */
7757c478bd9Sstevel@tonic-gate 	if (strncmp(dyntp->devlink, DEV_DSK SLASH, strlen(DEV_DSK SLASH)) &&
7767c478bd9Sstevel@tonic-gate 	    strncmp(dyntp->devlink, DEV_RDSK SLASH, strlen(DEV_RDSK SLASH))) {
7777c478bd9Sstevel@tonic-gate 		return (SCFGA_CONTINUE);
7787c478bd9Sstevel@tonic-gate 	}
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 	cp = dyntp->devlink + strlen(DEV_DIR SLASH);
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 	if ((dyntp->dyncomp = strdup(cp)) == NULL) {
7837c478bd9Sstevel@tonic-gate 		dyntp->l_errno = errno;
7847c478bd9Sstevel@tonic-gate 		goto lib_err;
7857c478bd9Sstevel@tonic-gate 	}
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 	/* Get the leaf component from dsk/cXtYdZsN */
7887c478bd9Sstevel@tonic-gate 	cp1 = strrchr(dyntp->dyncomp, '/');
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 	/* Blank out partition information */
7917c478bd9Sstevel@tonic-gate 	dyntp->ret = SCFGA_OK;
7927c478bd9Sstevel@tonic-gate 	if ((cp = strchr(cp1 + 1, 's')) != NULL) {
7937c478bd9Sstevel@tonic-gate 		*cp = '\0';
7947c478bd9Sstevel@tonic-gate 	} else if ((cp = strchr(cp1 + 1, 'p')) != NULL) {
7957c478bd9Sstevel@tonic-gate 		*cp = '\0';
7967c478bd9Sstevel@tonic-gate 	} else {
7977c478bd9Sstevel@tonic-gate 		S_FREE(dyntp->dyncomp);
7987c478bd9Sstevel@tonic-gate 		dyntp->ret = SCFGA_ERR;
7997c478bd9Sstevel@tonic-gate 	}
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 	return (SCFGA_TERMINATE);
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate lib_err:
8047c478bd9Sstevel@tonic-gate 	dyntp->ret = SCFGA_LIB_ERR;
8057c478bd9Sstevel@tonic-gate 	return (SCFGA_TERMINATE);
8067c478bd9Sstevel@tonic-gate }
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate static scfga_recur_t
disk_dyncomp_to_devlink(dyn_t * dyntp)8107c478bd9Sstevel@tonic-gate disk_dyncomp_to_devlink(dyn_t *dyntp)
8117c478bd9Sstevel@tonic-gate {
8127c478bd9Sstevel@tonic-gate 	char buf[MAXPATHLEN], *cp = NULL;
8137c478bd9Sstevel@tonic-gate 	int i, j;
8147c478bd9Sstevel@tonic-gate 	size_t len;
8157c478bd9Sstevel@tonic-gate 	struct stat sbuf;
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 	assert(dyntp->dyncomp != NULL);
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 	dyntp->l_errno = 0;
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 	if (dyntp->devlink != NULL) {
8227c478bd9Sstevel@tonic-gate 		dyntp->ret = SCFGA_LIB_ERR;
8237c478bd9Sstevel@tonic-gate 		return (SCFGA_TERMINATE);
8247c478bd9Sstevel@tonic-gate 	}
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate 	/* A disk link can only be from DEV_DSK (ignore /dev/rdsk) */
8277c478bd9Sstevel@tonic-gate 	if (strncmp(dyntp->dyncomp, DSK_DIR SLASH, strlen(DSK_DIR SLASH)) != 0)
8287c478bd9Sstevel@tonic-gate 		return (SCFGA_CONTINUE);	/* not a disk link */
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "%s%s", DEV_DIR SLASH,
8317c478bd9Sstevel@tonic-gate 	    dyntp->dyncomp);
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 	len = strlen(buf);
8347c478bd9Sstevel@tonic-gate 	cp = buf + len;
8357c478bd9Sstevel@tonic-gate 	len = sizeof (buf) - len;
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate 	for (i = 0; i < N_SLICE_TYPES; i++) {
8387c478bd9Sstevel@tonic-gate 		for (j = 0; j < disk_slices[i].nslices; j++) {
8397c478bd9Sstevel@tonic-gate 			if (snprintf(cp, len, "%s%d", disk_slices[i].prefix, j)
8407c478bd9Sstevel@tonic-gate 			    >= len) {
8417c478bd9Sstevel@tonic-gate 				continue;
8427c478bd9Sstevel@tonic-gate 			}
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 			if (lstat(buf, &sbuf) != -1 && S_ISLNK(sbuf.st_mode)) {
8457c478bd9Sstevel@tonic-gate 				if ((dyntp->devlink = strdup(buf)) == NULL) {
8467c478bd9Sstevel@tonic-gate 					dyntp->l_errno = errno;
8477c478bd9Sstevel@tonic-gate 					dyntp->ret = SCFGA_LIB_ERR;
8487c478bd9Sstevel@tonic-gate 					return (SCFGA_TERMINATE);
8497c478bd9Sstevel@tonic-gate 				}
8507c478bd9Sstevel@tonic-gate 				dyntp->ret = SCFGA_OK;
8517c478bd9Sstevel@tonic-gate 				return (SCFGA_TERMINATE);
8527c478bd9Sstevel@tonic-gate 			}
8537c478bd9Sstevel@tonic-gate 		}
8547c478bd9Sstevel@tonic-gate 	}
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 	dyntp->ret = SCFGA_APID_NOEXIST;
8577c478bd9Sstevel@tonic-gate 	return (SCFGA_TERMINATE);
8587c478bd9Sstevel@tonic-gate }
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate /* For tapes, remove mode(minor) information from link */
8617c478bd9Sstevel@tonic-gate static scfga_recur_t
tape_devlink_to_dyncomp(dyn_t * dyntp)8627c478bd9Sstevel@tonic-gate tape_devlink_to_dyncomp(dyn_t *dyntp)
8637c478bd9Sstevel@tonic-gate {
8647c478bd9Sstevel@tonic-gate 	char *cp = NULL;
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate 	assert(dyntp->devlink != NULL);
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 	dyntp->l_errno = 0;
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 	if (dyntp->dyncomp != NULL) {
8717c478bd9Sstevel@tonic-gate 		goto lib_err;
8727c478bd9Sstevel@tonic-gate 	}
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 	if (strncmp(dyntp->devlink, DEV_RMT SLASH, strlen(DEV_RMT SLASH))) {
8757c478bd9Sstevel@tonic-gate 		return (SCFGA_CONTINUE);	/* not a tape */
8767c478bd9Sstevel@tonic-gate 	}
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	cp = dyntp->devlink + strlen(DEV_DIR SLASH);
8797c478bd9Sstevel@tonic-gate 	if ((dyntp->dyncomp = strdup(cp)) == NULL) {
8807c478bd9Sstevel@tonic-gate 		dyntp->l_errno = errno;
8817c478bd9Sstevel@tonic-gate 		goto lib_err;
8827c478bd9Sstevel@tonic-gate 	}
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 	/* Get the leaf component from rmt/xyz */
8857c478bd9Sstevel@tonic-gate 	cp = strrchr(dyntp->dyncomp, '/');
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 	/* Remove the mode part */
888*4c06356bSdh 	while (isdigit(*(++cp))) {
889*4c06356bSdh 	};
8907c478bd9Sstevel@tonic-gate 	*cp = '\0';
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 	dyntp->ret = SCFGA_OK;
8947c478bd9Sstevel@tonic-gate 	return (SCFGA_TERMINATE);
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate lib_err:
8977c478bd9Sstevel@tonic-gate 	dyntp->ret = SCFGA_LIB_ERR;
8987c478bd9Sstevel@tonic-gate 	return (SCFGA_TERMINATE);
8997c478bd9Sstevel@tonic-gate }
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate static scfga_recur_t
tape_dyncomp_to_devlink(dyn_t * dyntp)9027c478bd9Sstevel@tonic-gate tape_dyncomp_to_devlink(dyn_t *dyntp)
9037c478bd9Sstevel@tonic-gate {
9047c478bd9Sstevel@tonic-gate 	char buf[MAXPATHLEN], *cp = NULL;
9057c478bd9Sstevel@tonic-gate 	int i;
9067c478bd9Sstevel@tonic-gate 	size_t len = 0;
9077c478bd9Sstevel@tonic-gate 	struct stat sbuf;
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate 	assert(dyntp->dyncomp != NULL);
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 	dyntp->l_errno = 0;
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 	if (dyntp->devlink != NULL) {
9147c478bd9Sstevel@tonic-gate 		goto lib_err;
9157c478bd9Sstevel@tonic-gate 	}
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 	if (strncmp(dyntp->dyncomp, RMT_DIR SLASH, strlen(RMT_DIR SLASH))) {
9187c478bd9Sstevel@tonic-gate 		return (SCFGA_CONTINUE);	/* not a tape */
9197c478bd9Sstevel@tonic-gate 	}
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate 	/* A tape device */
9227c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "%s%s", DEV_DIR SLASH,
9237c478bd9Sstevel@tonic-gate 	    dyntp->dyncomp);
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 	len = strlen(buf);
9267c478bd9Sstevel@tonic-gate 	cp = buf + len;
9277c478bd9Sstevel@tonic-gate 	len = sizeof (buf) - len;
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 	for (i = 0; i < N_TAPE_MODES; i++) {
9307c478bd9Sstevel@tonic-gate 		(void) snprintf(cp, len, "%s", tape_modes[i]);
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 		if (lstat(buf, &sbuf) != -1 && S_ISLNK(sbuf.st_mode)) {
9337c478bd9Sstevel@tonic-gate 			if ((dyntp->devlink = strdup(buf)) == NULL) {
9347c478bd9Sstevel@tonic-gate 				dyntp->l_errno = errno;
9357c478bd9Sstevel@tonic-gate 				goto lib_err;
9367c478bd9Sstevel@tonic-gate 			}
9377c478bd9Sstevel@tonic-gate 			dyntp->ret = SCFGA_OK;
9387c478bd9Sstevel@tonic-gate 			return (SCFGA_TERMINATE);
9397c478bd9Sstevel@tonic-gate 		}
9407c478bd9Sstevel@tonic-gate 	}
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 	dyntp->ret = SCFGA_APID_NOEXIST;
9437c478bd9Sstevel@tonic-gate 	return (SCFGA_TERMINATE);
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate lib_err:
9467c478bd9Sstevel@tonic-gate 	dyntp->ret = SCFGA_LIB_ERR;
9477c478bd9Sstevel@tonic-gate 	return (SCFGA_TERMINATE);
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate }
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate /*
9527c478bd9Sstevel@tonic-gate  * Default rules
9537c478bd9Sstevel@tonic-gate  */
9547c478bd9Sstevel@tonic-gate static scfga_recur_t
def_devlink_to_dyncomp(dyn_t * dyntp)9557c478bd9Sstevel@tonic-gate def_devlink_to_dyncomp(dyn_t *dyntp)
9567c478bd9Sstevel@tonic-gate {
9577c478bd9Sstevel@tonic-gate 	size_t len = 0;
9587c478bd9Sstevel@tonic-gate 	char *cp = NULL;
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate 	assert(dyntp->devlink != NULL);
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 	dyntp->l_errno = 0;
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate 	if (dyntp->dyncomp != NULL) {
9657c478bd9Sstevel@tonic-gate 		dyntp->ret = SCFGA_LIB_ERR;
9667c478bd9Sstevel@tonic-gate 		return (SCFGA_TERMINATE);
9677c478bd9Sstevel@tonic-gate 	}
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 	/* Is it a link in DEV_DIR directory ? */
9707c478bd9Sstevel@tonic-gate 	len = strlen(DEV_DIR SLASH);
9717c478bd9Sstevel@tonic-gate 	if (strncmp(dyntp->devlink, DEV_DIR SLASH, len)) {
9727c478bd9Sstevel@tonic-gate 		return (SCFGA_CONTINUE);
9737c478bd9Sstevel@tonic-gate 	}
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 	/* Check if this is a top level devlink */
9767c478bd9Sstevel@tonic-gate 	if (strchr(dyntp->devlink + len, '/') != NULL) {
9777c478bd9Sstevel@tonic-gate 		/* not top level - Remove DEV_DIR SLASH prefix */
9787c478bd9Sstevel@tonic-gate 		cp = dyntp->devlink + len;
9797c478bd9Sstevel@tonic-gate 	} else {
9807c478bd9Sstevel@tonic-gate 		/* top level, leave DEV_DIR SLASH part in */
9817c478bd9Sstevel@tonic-gate 		cp = dyntp->devlink;
9827c478bd9Sstevel@tonic-gate 	}
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	if ((dyntp->dyncomp = strdup(cp)) == NULL) {
9857c478bd9Sstevel@tonic-gate 		dyntp->l_errno = errno;
9867c478bd9Sstevel@tonic-gate 		dyntp->ret = SCFGA_LIB_ERR;
9877c478bd9Sstevel@tonic-gate 	} else {
9887c478bd9Sstevel@tonic-gate 		dyntp->ret = SCFGA_OK;
9897c478bd9Sstevel@tonic-gate 	}
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 	return (SCFGA_TERMINATE);
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate }
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate static scfga_recur_t
def_dyncomp_to_devlink(dyn_t * dyntp)9967c478bd9Sstevel@tonic-gate def_dyncomp_to_devlink(dyn_t *dyntp)
9977c478bd9Sstevel@tonic-gate {
9987c478bd9Sstevel@tonic-gate 	struct stat sbuf;
9997c478bd9Sstevel@tonic-gate 	int top;
10007c478bd9Sstevel@tonic-gate 	size_t prelen, linklen;
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 	assert(dyntp->dyncomp != NULL);
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate 	dyntp->l_errno = 0;
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 	if (dyntp->devlink != NULL) {
10077c478bd9Sstevel@tonic-gate 		goto lib_err;
10087c478bd9Sstevel@tonic-gate 	}
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate 	prelen = strlen(DEV_DIR SLASH);
10117c478bd9Sstevel@tonic-gate 	linklen = strlen(dyntp->dyncomp) + 1;
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 	/*
10147c478bd9Sstevel@tonic-gate 	 * Check if the dynamic component was derived from a top level entry
10157c478bd9Sstevel@tonic-gate 	 * in "/dev"
10167c478bd9Sstevel@tonic-gate 	 */
10177c478bd9Sstevel@tonic-gate 	if (strncmp(dyntp->dyncomp, DEV_DIR SLASH, prelen) == 0) {
10187c478bd9Sstevel@tonic-gate 		top = 1;
10197c478bd9Sstevel@tonic-gate 	} else if (*dyntp->dyncomp != '/' && linklen > 1 &&
10207c478bd9Sstevel@tonic-gate 	    strchr(dyntp->dyncomp + 1, '/') != NULL) {
10217c478bd9Sstevel@tonic-gate 		top = 0;
10227c478bd9Sstevel@tonic-gate 		linklen += prelen;  /* The "/dev/" needs to be prepended */
10237c478bd9Sstevel@tonic-gate 	} else {
10247c478bd9Sstevel@tonic-gate 		/* Not a dynamic component we handle */
10257c478bd9Sstevel@tonic-gate 		return (SCFGA_CONTINUE);
10267c478bd9Sstevel@tonic-gate 	}
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate 	if ((dyntp->devlink = calloc(1, linklen)) == NULL) {
10297c478bd9Sstevel@tonic-gate 		dyntp->l_errno = errno;
10307c478bd9Sstevel@tonic-gate 		goto lib_err;
10317c478bd9Sstevel@tonic-gate 	}
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 	*dyntp->devlink = '\0';
10347c478bd9Sstevel@tonic-gate 	if (!top) {
10357c478bd9Sstevel@tonic-gate 		(void) strcpy(dyntp->devlink, DEV_DIR SLASH);
10367c478bd9Sstevel@tonic-gate 	}
10377c478bd9Sstevel@tonic-gate 	(void) strcat(dyntp->devlink, dyntp->dyncomp);
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 	if (lstat(dyntp->devlink, &sbuf) != -1 && S_ISLNK(sbuf.st_mode)) {
10407c478bd9Sstevel@tonic-gate 		dyntp->ret = SCFGA_OK;
10417c478bd9Sstevel@tonic-gate 		return (SCFGA_TERMINATE);
10427c478bd9Sstevel@tonic-gate 	}
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate 	S_FREE(dyntp->devlink);
10467c478bd9Sstevel@tonic-gate 	return (SCFGA_CONTINUE);
10477c478bd9Sstevel@tonic-gate 
10487c478bd9Sstevel@tonic-gate lib_err:
10497c478bd9Sstevel@tonic-gate 	dyntp->ret = SCFGA_LIB_ERR;
10507c478bd9Sstevel@tonic-gate 	return (SCFGA_TERMINATE);
10517c478bd9Sstevel@tonic-gate }
1052