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