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