1*908f1e13Ssd /*
2*908f1e13Ssd  * CDDL HEADER START
3*908f1e13Ssd  *
4*908f1e13Ssd  * The contents of this file are subject to the terms of the
5*908f1e13Ssd  * Common Development and Distribution License (the "License").
6*908f1e13Ssd  * You may not use this file except in compliance with the License.
7*908f1e13Ssd  *
8*908f1e13Ssd  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*908f1e13Ssd  * or http://www.opensolaris.org/os/licensing.
10*908f1e13Ssd  * See the License for the specific language governing permissions
11*908f1e13Ssd  * and limitations under the License.
12*908f1e13Ssd  *
13*908f1e13Ssd  * When distributing Covered Code, include this CDDL HEADER in each
14*908f1e13Ssd  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*908f1e13Ssd  * If applicable, add the following below this CDDL HEADER, with the
16*908f1e13Ssd  * fields enclosed by brackets "[]" replaced with your own identifying
17*908f1e13Ssd  * information: Portions Copyright [yyyy] [name of copyright owner]
18*908f1e13Ssd  *
19*908f1e13Ssd  * CDDL HEADER END
20*908f1e13Ssd  */
21*908f1e13Ssd 
22*908f1e13Ssd /*
23*908f1e13Ssd  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24*908f1e13Ssd  * Use is subject to license terms.
25*908f1e13Ssd  */
26*908f1e13Ssd 
27*908f1e13Ssd #include <sys/types.h>
28*908f1e13Ssd #include <sys/param.h>
29*908f1e13Ssd #ifdef _KERNEL
30*908f1e13Ssd #include <sys/systm.h>
31*908f1e13Ssd #else
32*908f1e13Ssd #include <string.h>
33*908f1e13Ssd #include <strings.h>
34*908f1e13Ssd #endif
35*908f1e13Ssd 
36*908f1e13Ssd #include <sys/mdesc.h>
37*908f1e13Ssd #include <sys/mdesc_impl.h>
38*908f1e13Ssd 
39*908f1e13Ssd static int
40*908f1e13Ssd mdl_walk_dag(md_impl_t *, mde_cookie_t, mde_cookie_t, mde_str_cookie_t,
41*908f1e13Ssd     mde_str_cookie_t, uint8_t *, md_walk_fn_t, void *, int);
42*908f1e13Ssd 
43*908f1e13Ssd 
44*908f1e13Ssd /*
45*908f1e13Ssd  * Walk the machine description directed graph from a starting
46*908f1e13Ssd  * node searching for nodes of a given node name and using a
47*908f1e13Ssd  * given arc type.  Call a callback function for each node found.
48*908f1e13Ssd  * Each node will be visited only once.
49*908f1e13Ssd  *
50*908f1e13Ssd  * Input		Description
51*908f1e13Ssd  * -------------------	----------------------------------------
52*908f1e13Ssd  * md_t *		Pointer to md session
53*908f1e13Ssd  * mde_cookie_t		Index of the starting node
54*908f1e13Ssd  * mde_str_cookie_t	Node name cookie of the nodes to call
55*908f1e13Ssd  *			the walk function
56*908f1e13Ssd  * mde_str_cookie_t	Arc name cookie of the path to follow
57*908f1e13Ssd  * md_walk_fn_t		The function to call for each node
58*908f1e13Ssd  * void *		Private data to pass to the walker function
59*908f1e13Ssd  *
60*908f1e13Ssd  */
61*908f1e13Ssd int
md_walk_dag(md_t * ptr,mde_cookie_t startnode,mde_str_cookie_t node_name_cookie,mde_str_cookie_t arc_name_cookie,md_walk_fn_t func,void * private)62*908f1e13Ssd md_walk_dag(md_t *ptr, mde_cookie_t startnode,
63*908f1e13Ssd     mde_str_cookie_t node_name_cookie, mde_str_cookie_t arc_name_cookie,
64*908f1e13Ssd     md_walk_fn_t func, void *private)
65*908f1e13Ssd {
66*908f1e13Ssd 	int		res;
67*908f1e13Ssd 	uint8_t		*seenp;
68*908f1e13Ssd 	md_impl_t	*mdp;
69*908f1e13Ssd 	mde_cookie_t	start;
70*908f1e13Ssd 
71*908f1e13Ssd 	mdp = (md_impl_t *)ptr;
72*908f1e13Ssd 	if (mdp == NULL) {
73*908f1e13Ssd 		return (-1);
74*908f1e13Ssd 	}
75*908f1e13Ssd 
76*908f1e13Ssd 	/*
77*908f1e13Ssd 	 * Possible the caller was lazy and didn't check the
78*908f1e13Ssd 	 * validitiy of either the node name or the arc name
79*908f1e13Ssd 	 * on calling ... in which case fail to find any
80*908f1e13Ssd 	 * nodes.
81*908f1e13Ssd 	 * This is distinct, from a fail (-1) since we return
82*908f1e13Ssd 	 * that nothing was found.
83*908f1e13Ssd 	 */
84*908f1e13Ssd 	if (node_name_cookie == MDE_INVAL_STR_COOKIE ||
85*908f1e13Ssd 	    arc_name_cookie == MDE_INVAL_STR_COOKIE) {
86*908f1e13Ssd 		return (0);
87*908f1e13Ssd 	}
88*908f1e13Ssd 
89*908f1e13Ssd 	/*
90*908f1e13Ssd 	 * if we want to start at the top, start at index 0
91*908f1e13Ssd 	 */
92*908f1e13Ssd 	start = startnode;
93*908f1e13Ssd 	if (start == MDE_INVAL_ELEM_COOKIE) {
94*908f1e13Ssd 		start = 0;
95*908f1e13Ssd 	}
96*908f1e13Ssd 
97*908f1e13Ssd 	/*
98*908f1e13Ssd 	 * Scan from the start point until the first node.
99*908f1e13Ssd 	 */
100*908f1e13Ssd 	while (start < mdp->element_count &&
101*908f1e13Ssd 	    MDE_TAG(&mdp->mdep[start]) == MDET_NULL) {
102*908f1e13Ssd 		start++;
103*908f1e13Ssd 	}
104*908f1e13Ssd 
105*908f1e13Ssd 	/*
106*908f1e13Ssd 	 * This was a bogus start point if no node found
107*908f1e13Ssd 	 */
108*908f1e13Ssd 	if (MDE_TAG(&mdp->mdep[start]) != MDET_NODE) {
109*908f1e13Ssd 		return (-1);	/* illegal start node specified */
110*908f1e13Ssd 	}
111*908f1e13Ssd 
112*908f1e13Ssd 	/*
113*908f1e13Ssd 	 * Allocate a recursion detection structure so we only visit
114*908f1e13Ssd 	 * each node once.
115*908f1e13Ssd 	 */
116*908f1e13Ssd 	seenp = (uint8_t *)mdp->allocp(mdp->element_count);
117*908f1e13Ssd 	if (seenp == NULL) {
118*908f1e13Ssd 		return (-1);
119*908f1e13Ssd 	}
120*908f1e13Ssd 	(void) memset(seenp, 0, mdp->element_count);
121*908f1e13Ssd 
122*908f1e13Ssd 	/*
123*908f1e13Ssd 	 * Now build the list of requested nodes.
124*908f1e13Ssd 	 */
125*908f1e13Ssd 	res = mdl_walk_dag(mdp, MDE_INVAL_ELEM_COOKIE, start,
126*908f1e13Ssd 	    node_name_cookie, arc_name_cookie, seenp, func, private, 0);
127*908f1e13Ssd 
128*908f1e13Ssd 	mdp->freep(seenp, mdp->element_count);
129*908f1e13Ssd 
130*908f1e13Ssd 	return (res >= 0 ? 0 : res);
131*908f1e13Ssd }
132*908f1e13Ssd 
133*908f1e13Ssd 
134*908f1e13Ssd static int
mdl_walk_dag(md_impl_t * mdp,mde_cookie_t parentidx,mde_cookie_t nodeidx,mde_str_cookie_t node_name_cookie,mde_str_cookie_t arc_name_cookie,uint8_t * seenp,md_walk_fn_t func,void * private,int level)135*908f1e13Ssd mdl_walk_dag(md_impl_t *mdp, mde_cookie_t parentidx, mde_cookie_t nodeidx,
136*908f1e13Ssd     mde_str_cookie_t node_name_cookie, mde_str_cookie_t arc_name_cookie,
137*908f1e13Ssd     uint8_t *seenp, md_walk_fn_t func, void *private, int level)
138*908f1e13Ssd {
139*908f1e13Ssd 	int		result;
140*908f1e13Ssd 	md_element_t	*mdep;
141*908f1e13Ssd 
142*908f1e13Ssd 	/* Get the node element from the session */
143*908f1e13Ssd 	mdep = &(mdp->mdep[nodeidx]);
144*908f1e13Ssd 
145*908f1e13Ssd 	/* see if cookie is infact a node */
146*908f1e13Ssd 	if (MDE_TAG(mdep) != MDET_NODE) {
147*908f1e13Ssd 		return (MDE_WALK_ERROR);
148*908f1e13Ssd 	}
149*908f1e13Ssd 
150*908f1e13Ssd 	/* have we been here before ? */
151*908f1e13Ssd 	if (seenp[nodeidx]) {
152*908f1e13Ssd 		return (MDE_WALK_NEXT);
153*908f1e13Ssd 	}
154*908f1e13Ssd 	seenp[nodeidx] = 1;
155*908f1e13Ssd 
156*908f1e13Ssd #ifdef	DEBUG_LIBMDESC
157*908f1e13Ssd 	{
158*908f1e13Ssd 		int x;
159*908f1e13Ssd 		for (x = 0; x < level; x++) {
160*908f1e13Ssd 			printf("-");
161*908f1e13Ssd 		}
162*908f1e13Ssd 		printf("%d (%s)\n", nodeidx,
163*908f1e13Ssd 		    (char *)(mdp->datap + MDE_NAME(mdep)));
164*908f1e13Ssd 	}
165*908f1e13Ssd #endif
166*908f1e13Ssd 
167*908f1e13Ssd 	/* is this node of the type we seek ? */
168*908f1e13Ssd 	if (MDE_NAME(mdep) == node_name_cookie) {
169*908f1e13Ssd 		/*
170*908f1e13Ssd 		 * Yes.  Call the callback function.
171*908f1e13Ssd 		 */
172*908f1e13Ssd 		result = (func)((md_t *)mdp, parentidx, nodeidx, private);
173*908f1e13Ssd 		if (result != MDE_WALK_NEXT) {
174*908f1e13Ssd 			return (result);
175*908f1e13Ssd 		}
176*908f1e13Ssd 	}
177*908f1e13Ssd 
178*908f1e13Ssd 	/*
179*908f1e13Ssd 	 * Simply walk the elements in the node.
180*908f1e13Ssd 	 * if we find a matching arc, then recursively call
181*908f1e13Ssd 	 * the subordinate looking for a match
182*908f1e13Ssd 	 */
183*908f1e13Ssd 	result = MDE_WALK_NEXT;
184*908f1e13Ssd 	for (mdep++; MDE_TAG(mdep) != MDET_NODE_END; mdep++) {
185*908f1e13Ssd 		if (MDE_TAG(mdep) == MDET_PROP_ARC &&
186*908f1e13Ssd 		    MDE_NAME(mdep) == arc_name_cookie) {
187*908f1e13Ssd 			/*
188*908f1e13Ssd 			 * The current node becomes the parent node, and the
189*908f1e13Ssd 			 * arc index is the new current node.
190*908f1e13Ssd 			 */
191*908f1e13Ssd 			result = mdl_walk_dag(mdp, nodeidx, mdep->d.prop_idx,
192*908f1e13Ssd 			    node_name_cookie, arc_name_cookie, seenp, func,
193*908f1e13Ssd 			    private, level+1);
194*908f1e13Ssd 			if (result != MDE_WALK_NEXT) {
195*908f1e13Ssd 				/* The walk is complete or terminated. */
196*908f1e13Ssd 				return (result);
197*908f1e13Ssd 			}
198*908f1e13Ssd 		}
199*908f1e13Ssd 	}
200*908f1e13Ssd 
201*908f1e13Ssd 	return (result);
202*908f1e13Ssd }
203