| /* |
| * 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 <sys/types.h> |
| #include <sys/param.h> |
| #ifdef _KERNEL |
| #include <sys/systm.h> |
| #else |
| #include <string.h> |
| #include <strings.h> |
| #endif |
| |
| #include <sys/mdesc.h> |
| #include <sys/mdesc_impl.h> |
| |
| 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); |
| } |