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