/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #ifdef _KERNEL #include #else #include #include #endif #include #include static int mdl_walk_dag(md_impl_t *, mde_cookie_t, mde_cookie_t, mde_str_cookie_t, mde_str_cookie_t, uint8_t *, md_walk_fn_t, void *, int); /* * Walk the machine description directed graph from a starting * node searching for nodes of a given node name and using a * given arc type. Call a callback function for each node found. * Each node will be visited only once. * * Input Description * ------------------- ---------------------------------------- * md_t * Pointer to md session * mde_cookie_t Index of the starting node * mde_str_cookie_t Node name cookie of the nodes to call * the walk function * mde_str_cookie_t Arc name cookie of the path to follow * md_walk_fn_t The function to call for each node * void * Private data to pass to the walker function * */ 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) { int res; uint8_t *seenp; md_impl_t *mdp; mde_cookie_t start; mdp = (md_impl_t *)ptr; if (mdp == NULL) { return (-1); } /* * Possible the caller was lazy and didn't check the * validitiy of either the node name or the arc name * on calling ... in which case fail to find any * nodes. * This is distinct, from a fail (-1) since we return * that nothing was found. */ if (node_name_cookie == MDE_INVAL_STR_COOKIE || arc_name_cookie == MDE_INVAL_STR_COOKIE) { return (0); } /* * if we want to start at the top, start at index 0 */ start = startnode; if (start == MDE_INVAL_ELEM_COOKIE) { start = 0; } /* * Scan from the start point until the first node. */ while (start < mdp->element_count && MDE_TAG(&mdp->mdep[start]) == MDET_NULL) { start++; } /* * This was a bogus start point if no node found */ if (MDE_TAG(&mdp->mdep[start]) != MDET_NODE) { return (-1); /* illegal start node specified */ } /* * Allocate a recursion detection structure so we only visit * each node once. */ seenp = (uint8_t *)mdp->allocp(mdp->element_count); if (seenp == NULL) { return (-1); } (void) memset(seenp, 0, mdp->element_count); /* * Now build the list of requested nodes. */ res = mdl_walk_dag(mdp, MDE_INVAL_ELEM_COOKIE, start, node_name_cookie, arc_name_cookie, seenp, func, private, 0); mdp->freep(seenp, mdp->element_count); return (res >= 0 ? 0 : res); } 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) { int result; md_element_t *mdep; /* Get the node element from the session */ mdep = &(mdp->mdep[nodeidx]); /* see if cookie is infact a node */ if (MDE_TAG(mdep) != MDET_NODE) { return (MDE_WALK_ERROR); } /* have we been here before ? */ if (seenp[nodeidx]) { return (MDE_WALK_NEXT); } seenp[nodeidx] = 1; #ifdef DEBUG_LIBMDESC { int x; for (x = 0; x < level; x++) { printf("-"); } printf("%d (%s)\n", nodeidx, (char *)(mdp->datap + MDE_NAME(mdep))); } #endif /* is this node of the type we seek ? */ if (MDE_NAME(mdep) == node_name_cookie) { /* * Yes. Call the callback function. */ result = (func)((md_t *)mdp, parentidx, nodeidx, private); if (result != MDE_WALK_NEXT) { return (result); } } /* * Simply walk the elements in the node. * if we find a matching arc, then recursively call * the subordinate looking for a match */ result = MDE_WALK_NEXT; for (mdep++; MDE_TAG(mdep) != MDET_NODE_END; mdep++) { if (MDE_TAG(mdep) == MDET_PROP_ARC && MDE_NAME(mdep) == arc_name_cookie) { /* * The current node becomes the parent node, and the * arc index is the new current node. */ result = mdl_walk_dag(mdp, nodeidx, mdep->d.prop_idx, node_name_cookie, arc_name_cookie, seenp, func, private, level+1); if (result != MDE_WALK_NEXT) { /* The walk is complete or terminated. */ return (result); } } } return (result); }