1*1ae08745Sheppo /* 2*1ae08745Sheppo * CDDL HEADER START 3*1ae08745Sheppo * 4*1ae08745Sheppo * The contents of this file are subject to the terms of the 5*1ae08745Sheppo * Common Development and Distribution License (the "License"). 6*1ae08745Sheppo * You may not use this file except in compliance with the License. 7*1ae08745Sheppo * 8*1ae08745Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*1ae08745Sheppo * or http://www.opensolaris.org/os/licensing. 10*1ae08745Sheppo * See the License for the specific language governing permissions 11*1ae08745Sheppo * and limitations under the License. 12*1ae08745Sheppo * 13*1ae08745Sheppo * When distributing Covered Code, include this CDDL HEADER in each 14*1ae08745Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*1ae08745Sheppo * If applicable, add the following below this CDDL HEADER, with the 16*1ae08745Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 17*1ae08745Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 18*1ae08745Sheppo * 19*1ae08745Sheppo * CDDL HEADER END 20*1ae08745Sheppo */ 21*1ae08745Sheppo 22*1ae08745Sheppo /* 23*1ae08745Sheppo * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24*1ae08745Sheppo * Use is subject to license terms. 25*1ae08745Sheppo */ 26*1ae08745Sheppo 27*1ae08745Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 28*1ae08745Sheppo 29*1ae08745Sheppo #include <sys/types.h> 30*1ae08745Sheppo #ifdef _KERNEL 31*1ae08745Sheppo #include <sys/systm.h> 32*1ae08745Sheppo #else /* _KERNEL */ 33*1ae08745Sheppo #include <string.h> 34*1ae08745Sheppo #include <strings.h> 35*1ae08745Sheppo #endif /* _KERNEL */ 36*1ae08745Sheppo #include <sys/note.h> 37*1ae08745Sheppo #include <sys/mdesc.h> 38*1ae08745Sheppo #include <sys/mdesc_impl.h> 39*1ae08745Sheppo 40*1ae08745Sheppo #define MDD_FREE_CHECK(mdp, ptr, sz) \ 41*1ae08745Sheppo do { \ 42*1ae08745Sheppo if (ptr) mdp->freep(ptr, sz); \ 43*1ae08745Sheppo _NOTE(CONSTCOND) } while (0) 44*1ae08745Sheppo 45*1ae08745Sheppo #define MD_DIFF_MAGIC 0x4D445F4449464621ull /* 'MD_DIFF!' */ 46*1ae08745Sheppo #define MD_DIFF_NOMATCH (-1) 47*1ae08745Sheppo #define MD_DIFF_MATCH (1) 48*1ae08745Sheppo 49*1ae08745Sheppo typedef struct { 50*1ae08745Sheppo mde_cookie_t *mdep; 51*1ae08745Sheppo uint_t nelem; 52*1ae08745Sheppo } md_diff_t; 53*1ae08745Sheppo 54*1ae08745Sheppo typedef struct { 55*1ae08745Sheppo uint64_t mdd_magic; 56*1ae08745Sheppo md_diff_t added; 57*1ae08745Sheppo md_diff_t removed; 58*1ae08745Sheppo md_diff_t match1; 59*1ae08745Sheppo md_diff_t match2; 60*1ae08745Sheppo void *(*allocp)(size_t); 61*1ae08745Sheppo void (*freep)(void *, size_t); 62*1ae08745Sheppo } md_diff_impl_t; 63*1ae08745Sheppo 64*1ae08745Sheppo /* 65*1ae08745Sheppo * Internal utility functions 66*1ae08745Sheppo */ 67*1ae08745Sheppo static int mdd_scan_for_nodes(md_t *mdp, mde_cookie_t start, 68*1ae08745Sheppo char *compnodep, int *countp, mde_cookie_t **nodespp); 69*1ae08745Sheppo 70*1ae08745Sheppo static boolean_t mdd_any_dup_nodes(md_impl_t *mdp, md_prop_match_t *pmp, 71*1ae08745Sheppo int count, mde_cookie_t *nodesp); 72*1ae08745Sheppo 73*1ae08745Sheppo static int mdd_node_list_match(md_impl_t *md1, md_impl_t *md2, 74*1ae08745Sheppo md_element_t *match_nodep, mde_cookie_t *match_listp, 75*1ae08745Sheppo uint8_t *match_seenp, int start, int end, md_prop_match_t *match_elemsp); 76*1ae08745Sheppo 77*1ae08745Sheppo static int mdd_node_compare(md_impl_t *mdap, md_impl_t *mdbp, 78*1ae08745Sheppo md_element_t *nodeap, md_element_t *nodebp, md_prop_match_t *match_elemsp); 79*1ae08745Sheppo 80*1ae08745Sheppo /* 81*1ae08745Sheppo * Given two DAGs and information about how to uniquely identify 82*1ae08745Sheppo * the nodes of interest, determine which nodes have been added 83*1ae08745Sheppo * to the second MD, removed from the first MD, or exist in both 84*1ae08745Sheppo * MDs. This information is recorded and can be accessed using the 85*1ae08745Sheppo * opaque cookie returned to the caller. 86*1ae08745Sheppo */ 87*1ae08745Sheppo md_diff_cookie_t 88*1ae08745Sheppo md_diff_init(md_t *md1p, mde_cookie_t start1, md_t *md2p, mde_cookie_t start2, 89*1ae08745Sheppo char *compnodep, md_prop_match_t *match_fieldsp) 90*1ae08745Sheppo { 91*1ae08745Sheppo int idx; 92*1ae08745Sheppo md_impl_t *md1 = (md_impl_t *)md1p; 93*1ae08745Sheppo md_impl_t *md2 = (md_impl_t *)md2p; 94*1ae08745Sheppo mde_cookie_t *md1nodesp = NULL; 95*1ae08745Sheppo mde_cookie_t *md2nodesp = NULL; 96*1ae08745Sheppo int md1count = 0; 97*1ae08745Sheppo int md2count = 0; 98*1ae08745Sheppo uint8_t *seenp = NULL; 99*1ae08745Sheppo 100*1ae08745Sheppo /* variables used to gather results */ 101*1ae08745Sheppo md_diff_impl_t *diff_res; 102*1ae08745Sheppo mde_cookie_t *mde_add_scr; 103*1ae08745Sheppo mde_cookie_t *mde_rem_scr; 104*1ae08745Sheppo mde_cookie_t *mde_match1_scr; 105*1ae08745Sheppo mde_cookie_t *mde_match2_scr; 106*1ae08745Sheppo int nadd = 0; 107*1ae08745Sheppo int nrem = 0; 108*1ae08745Sheppo int nmatch = 0; 109*1ae08745Sheppo 110*1ae08745Sheppo /* sanity check params */ 111*1ae08745Sheppo if ((md1p == NULL) || (md2p == NULL)) 112*1ae08745Sheppo return (MD_INVAL_DIFF_COOKIE); 113*1ae08745Sheppo 114*1ae08745Sheppo if ((start1 == MDE_INVAL_ELEM_COOKIE) || 115*1ae08745Sheppo (start2 == MDE_INVAL_ELEM_COOKIE)) 116*1ae08745Sheppo return (MD_INVAL_DIFF_COOKIE); 117*1ae08745Sheppo 118*1ae08745Sheppo if ((compnodep == NULL) || (match_fieldsp == NULL)) 119*1ae08745Sheppo return (MD_INVAL_DIFF_COOKIE); 120*1ae08745Sheppo 121*1ae08745Sheppo /* 122*1ae08745Sheppo * Prepare an array of the matching nodes from the first MD. 123*1ae08745Sheppo */ 124*1ae08745Sheppo if (mdd_scan_for_nodes(md1p, 125*1ae08745Sheppo start1, compnodep, &md1count, &md1nodesp) == -1) 126*1ae08745Sheppo return (MD_INVAL_DIFF_COOKIE); 127*1ae08745Sheppo 128*1ae08745Sheppo /* sanity check that all nodes are unique */ 129*1ae08745Sheppo if (md1nodesp && 130*1ae08745Sheppo mdd_any_dup_nodes(md1, match_fieldsp, md1count, md1nodesp)) { 131*1ae08745Sheppo MDD_FREE_CHECK(md1, md1nodesp, sizeof (mde_cookie_t) * 132*1ae08745Sheppo md1count); 133*1ae08745Sheppo return (MD_INVAL_DIFF_COOKIE); 134*1ae08745Sheppo } 135*1ae08745Sheppo 136*1ae08745Sheppo 137*1ae08745Sheppo /* 138*1ae08745Sheppo * Prepare an array of the matching nodes from the second MD. 139*1ae08745Sheppo */ 140*1ae08745Sheppo if (mdd_scan_for_nodes(md2p, 141*1ae08745Sheppo start2, compnodep, &md2count, &md2nodesp) == -1) 142*1ae08745Sheppo return (MD_INVAL_DIFF_COOKIE); 143*1ae08745Sheppo 144*1ae08745Sheppo /* sanity check that all nodes are unique */ 145*1ae08745Sheppo if (md2nodesp && 146*1ae08745Sheppo mdd_any_dup_nodes(md2, match_fieldsp, md2count, md2nodesp)) { 147*1ae08745Sheppo MDD_FREE_CHECK(md1, md1nodesp, sizeof (mde_cookie_t) * 148*1ae08745Sheppo md1count); 149*1ae08745Sheppo MDD_FREE_CHECK(md2, md2nodesp, sizeof (mde_cookie_t) * 150*1ae08745Sheppo md2count); 151*1ae08745Sheppo return (MD_INVAL_DIFF_COOKIE); 152*1ae08745Sheppo } 153*1ae08745Sheppo 154*1ae08745Sheppo /* setup our result structure */ 155*1ae08745Sheppo diff_res = md1->allocp(sizeof (md_diff_impl_t)); 156*1ae08745Sheppo bzero(diff_res, sizeof (md_diff_impl_t)); 157*1ae08745Sheppo diff_res->allocp = md1->allocp; 158*1ae08745Sheppo diff_res->freep = md1->freep; 159*1ae08745Sheppo diff_res->mdd_magic = MD_DIFF_MAGIC; 160*1ae08745Sheppo 161*1ae08745Sheppo /* 162*1ae08745Sheppo * Special cases for empty lists 163*1ae08745Sheppo */ 164*1ae08745Sheppo if ((md1count == 0) && (md2count != 0)) { 165*1ae08745Sheppo /* all the nodes found were added */ 166*1ae08745Sheppo diff_res->added.mdep = md2nodesp; 167*1ae08745Sheppo diff_res->added.nelem = md2count; 168*1ae08745Sheppo return ((mde_cookie_t)diff_res); 169*1ae08745Sheppo } 170*1ae08745Sheppo 171*1ae08745Sheppo if ((md1count != 0) && (md2count == 0)) { 172*1ae08745Sheppo /* all the nodes found were removed */ 173*1ae08745Sheppo diff_res->removed.mdep = md1nodesp; 174*1ae08745Sheppo diff_res->removed.nelem = md1count; 175*1ae08745Sheppo return ((mde_cookie_t)diff_res); 176*1ae08745Sheppo } 177*1ae08745Sheppo 178*1ae08745Sheppo if ((md1count == 0) && (md2count == 0)) 179*1ae08745Sheppo /* no nodes found */ 180*1ae08745Sheppo return ((mde_cookie_t)diff_res); 181*1ae08745Sheppo 182*1ae08745Sheppo /* 183*1ae08745Sheppo * Both lists have some elements. Allocate some scratch 184*1ae08745Sheppo * buffers to sort them into our three categories, added, 185*1ae08745Sheppo * removed, and matched pairs. 186*1ae08745Sheppo */ 187*1ae08745Sheppo mde_add_scr = diff_res->allocp(sizeof (mde_cookie_t) * md2count); 188*1ae08745Sheppo mde_rem_scr = diff_res->allocp(sizeof (mde_cookie_t) * md1count); 189*1ae08745Sheppo mde_match1_scr = diff_res->allocp(sizeof (mde_cookie_t) * md1count); 190*1ae08745Sheppo mde_match2_scr = diff_res->allocp(sizeof (mde_cookie_t) * md2count); 191*1ae08745Sheppo 192*1ae08745Sheppo /* array of seen flags only needed for md2 */ 193*1ae08745Sheppo seenp = (uint8_t *)diff_res->allocp(sizeof (uint8_t) * md2count); 194*1ae08745Sheppo bzero(seenp, sizeof (uint8_t) * md2count); 195*1ae08745Sheppo 196*1ae08745Sheppo /* 197*1ae08745Sheppo * Make a pass through the md1 node array. Make note of 198*1ae08745Sheppo * any nodes not in the md2 array, indicating that they 199*1ae08745Sheppo * have been removed. Also keep track of the nodes that 200*1ae08745Sheppo * are present in both arrays for the matched pair results. 201*1ae08745Sheppo */ 202*1ae08745Sheppo for (idx = 0; idx < md1count; idx++) { 203*1ae08745Sheppo 204*1ae08745Sheppo md_element_t *elem = &(md1->mdep[md1nodesp[idx]]); 205*1ae08745Sheppo 206*1ae08745Sheppo int match = mdd_node_list_match(md1, md2, elem, md2nodesp, 207*1ae08745Sheppo seenp, 0, md2count - 1, match_fieldsp); 208*1ae08745Sheppo 209*1ae08745Sheppo if (match == MD_DIFF_NOMATCH) 210*1ae08745Sheppo /* record deleted node */ 211*1ae08745Sheppo mde_rem_scr[nrem++] = md1nodesp[idx]; 212*1ae08745Sheppo else { 213*1ae08745Sheppo /* record matched node pair */ 214*1ae08745Sheppo mde_match1_scr[nmatch] = md1nodesp[idx]; 215*1ae08745Sheppo mde_match2_scr[nmatch] = md2nodesp[match]; 216*1ae08745Sheppo nmatch++; 217*1ae08745Sheppo 218*1ae08745Sheppo /* mark that this match has been recorded */ 219*1ae08745Sheppo seenp[match] = 1; 220*1ae08745Sheppo } 221*1ae08745Sheppo } 222*1ae08745Sheppo 223*1ae08745Sheppo /* 224*1ae08745Sheppo * Make a pass through the md2 array. Any nodes that have 225*1ae08745Sheppo * not been marked as seen have been added. 226*1ae08745Sheppo */ 227*1ae08745Sheppo for (idx = 0; idx < md2count; idx++) { 228*1ae08745Sheppo if (!seenp[idx]) 229*1ae08745Sheppo /* record added node */ 230*1ae08745Sheppo mde_add_scr[nadd++] = md2nodesp[idx]; 231*1ae08745Sheppo } 232*1ae08745Sheppo 233*1ae08745Sheppo /* fill in the added node list */ 234*1ae08745Sheppo if (nadd) { 235*1ae08745Sheppo int addsz = sizeof (mde_cookie_t) * nadd; 236*1ae08745Sheppo diff_res->added.mdep = (mde_cookie_t *)diff_res->allocp(addsz); 237*1ae08745Sheppo 238*1ae08745Sheppo bcopy(mde_add_scr, diff_res->added.mdep, addsz); 239*1ae08745Sheppo 240*1ae08745Sheppo diff_res->added.nelem = nadd; 241*1ae08745Sheppo } 242*1ae08745Sheppo 243*1ae08745Sheppo /* fill in the removed node list */ 244*1ae08745Sheppo if (nrem) { 245*1ae08745Sheppo int remsz = sizeof (mde_cookie_t) * nrem; 246*1ae08745Sheppo diff_res->removed.mdep = 247*1ae08745Sheppo (mde_cookie_t *)diff_res->allocp(remsz); 248*1ae08745Sheppo 249*1ae08745Sheppo bcopy(mde_rem_scr, diff_res->removed.mdep, remsz); 250*1ae08745Sheppo diff_res->removed.nelem = nrem; 251*1ae08745Sheppo } 252*1ae08745Sheppo 253*1ae08745Sheppo /* fill in the matching node lists */ 254*1ae08745Sheppo if (nmatch) { 255*1ae08745Sheppo int matchsz = sizeof (mde_cookie_t) * nmatch; 256*1ae08745Sheppo diff_res->match1.mdep = 257*1ae08745Sheppo (mde_cookie_t *)diff_res->allocp(matchsz); 258*1ae08745Sheppo diff_res->match2.mdep = 259*1ae08745Sheppo (mde_cookie_t *)diff_res->allocp(matchsz); 260*1ae08745Sheppo 261*1ae08745Sheppo bcopy(mde_match1_scr, diff_res->match1.mdep, matchsz); 262*1ae08745Sheppo bcopy(mde_match2_scr, diff_res->match2.mdep, matchsz); 263*1ae08745Sheppo diff_res->match1.nelem = nmatch; 264*1ae08745Sheppo diff_res->match2.nelem = nmatch; 265*1ae08745Sheppo } 266*1ae08745Sheppo 267*1ae08745Sheppo /* clean up */ 268*1ae08745Sheppo md1->freep(md1nodesp, sizeof (mde_cookie_t) * md1count); 269*1ae08745Sheppo md2->freep(md2nodesp, sizeof (mde_cookie_t) * md2count); 270*1ae08745Sheppo 271*1ae08745Sheppo diff_res->freep(mde_add_scr, sizeof (mde_cookie_t) * md2count); 272*1ae08745Sheppo diff_res->freep(mde_rem_scr, sizeof (mde_cookie_t) * md1count); 273*1ae08745Sheppo diff_res->freep(mde_match1_scr, sizeof (mde_cookie_t) * md1count); 274*1ae08745Sheppo diff_res->freep(mde_match2_scr, sizeof (mde_cookie_t) * md2count); 275*1ae08745Sheppo 276*1ae08745Sheppo diff_res->freep(seenp, sizeof (uint8_t) * md2count); 277*1ae08745Sheppo 278*1ae08745Sheppo return ((md_diff_cookie_t)diff_res); 279*1ae08745Sheppo } 280*1ae08745Sheppo 281*1ae08745Sheppo /* 282*1ae08745Sheppo * Returns an array of the nodes added to the second MD in a 283*1ae08745Sheppo * previous md_diff_init() call. Returns the number of elements 284*1ae08745Sheppo * in the returned array. If the value is zero, the pointer 285*1ae08745Sheppo * passed back will be NULL. 286*1ae08745Sheppo */ 287*1ae08745Sheppo int 288*1ae08745Sheppo md_diff_added(md_diff_cookie_t mdd, mde_cookie_t **mde_addedp) 289*1ae08745Sheppo { 290*1ae08745Sheppo md_diff_impl_t *mddp = (md_diff_impl_t *)mdd; 291*1ae08745Sheppo 292*1ae08745Sheppo if ((mddp == NULL) || (mddp->mdd_magic != MD_DIFF_MAGIC)) 293*1ae08745Sheppo return (-1); 294*1ae08745Sheppo 295*1ae08745Sheppo *mde_addedp = mddp->added.mdep; 296*1ae08745Sheppo 297*1ae08745Sheppo return (mddp->added.nelem); 298*1ae08745Sheppo } 299*1ae08745Sheppo 300*1ae08745Sheppo /* 301*1ae08745Sheppo * Returns an array of the nodes removed from the first MD in a 302*1ae08745Sheppo * previous md_diff_init() call. Returns the number of elements 303*1ae08745Sheppo * in the returned array. If the value is zero, the pointer 304*1ae08745Sheppo * passed back will be NULL. 305*1ae08745Sheppo */ 306*1ae08745Sheppo int 307*1ae08745Sheppo md_diff_removed(md_diff_cookie_t mdd, mde_cookie_t **mde_removedp) 308*1ae08745Sheppo { 309*1ae08745Sheppo md_diff_impl_t *mddp = (md_diff_impl_t *)mdd; 310*1ae08745Sheppo 311*1ae08745Sheppo if ((mddp == NULL) || (mddp->mdd_magic != MD_DIFF_MAGIC)) 312*1ae08745Sheppo return (-1); 313*1ae08745Sheppo 314*1ae08745Sheppo *mde_removedp = mddp->removed.mdep; 315*1ae08745Sheppo 316*1ae08745Sheppo return (mddp->removed.nelem); 317*1ae08745Sheppo } 318*1ae08745Sheppo 319*1ae08745Sheppo /* 320*1ae08745Sheppo * Returns a pair of parallel arrays that contain nodes that were 321*1ae08745Sheppo * considered matching based on the match criteria passed in to 322*1ae08745Sheppo * a previous md_diff_init() call. Returns the number of elements 323*1ae08745Sheppo * in the arrays. If the value is zero, both pointers passed back 324*1ae08745Sheppo * will be NULL. 325*1ae08745Sheppo */ 326*1ae08745Sheppo int 327*1ae08745Sheppo md_diff_matched(md_diff_cookie_t mdd, mde_cookie_t **mde_match1p, 328*1ae08745Sheppo mde_cookie_t **mde_match2p) 329*1ae08745Sheppo { 330*1ae08745Sheppo md_diff_impl_t *mddp = (md_diff_impl_t *)mdd; 331*1ae08745Sheppo 332*1ae08745Sheppo if ((mddp == NULL) || (mddp->mdd_magic != MD_DIFF_MAGIC)) 333*1ae08745Sheppo return (-1); 334*1ae08745Sheppo 335*1ae08745Sheppo *mde_match1p = mddp->match1.mdep; 336*1ae08745Sheppo *mde_match2p = mddp->match2.mdep; 337*1ae08745Sheppo 338*1ae08745Sheppo return (mddp->match1.nelem); 339*1ae08745Sheppo } 340*1ae08745Sheppo 341*1ae08745Sheppo /* 342*1ae08745Sheppo * Deallocate any storage used to store results of a previous 343*1ae08745Sheppo * md_diff_init() call. Returns 0 on success and -1 on failure. 344*1ae08745Sheppo */ 345*1ae08745Sheppo int 346*1ae08745Sheppo md_diff_fini(md_diff_cookie_t mdd) 347*1ae08745Sheppo { 348*1ae08745Sheppo md_diff_impl_t *mddp = (md_diff_impl_t *)mdd; 349*1ae08745Sheppo 350*1ae08745Sheppo if ((mddp == NULL) || (mddp->mdd_magic != MD_DIFF_MAGIC)) 351*1ae08745Sheppo return (-1); 352*1ae08745Sheppo 353*1ae08745Sheppo mddp->mdd_magic = 0; 354*1ae08745Sheppo 355*1ae08745Sheppo MDD_FREE_CHECK(mddp, mddp->added.mdep, mddp->added.nelem * 356*1ae08745Sheppo sizeof (mde_cookie_t)); 357*1ae08745Sheppo 358*1ae08745Sheppo MDD_FREE_CHECK(mddp, mddp->removed.mdep, mddp->removed.nelem * 359*1ae08745Sheppo sizeof (mde_cookie_t)); 360*1ae08745Sheppo 361*1ae08745Sheppo MDD_FREE_CHECK(mddp, mddp->match1.mdep, mddp->match1.nelem * 362*1ae08745Sheppo sizeof (mde_cookie_t)); 363*1ae08745Sheppo 364*1ae08745Sheppo MDD_FREE_CHECK(mddp, mddp->match2.mdep, mddp->match2.nelem * 365*1ae08745Sheppo sizeof (mde_cookie_t)); 366*1ae08745Sheppo 367*1ae08745Sheppo mddp->freep(mddp, sizeof (md_diff_impl_t)); 368*1ae08745Sheppo 369*1ae08745Sheppo return (0); 370*1ae08745Sheppo } 371*1ae08745Sheppo 372*1ae08745Sheppo /* 373*1ae08745Sheppo * Walk the "fwd" DAG in an MD and return an array of nodes that are 374*1ae08745Sheppo * of the specified type. The start param is used to start the walk 375*1ae08745Sheppo * from an arbitrary location in the DAG. Returns an array of nodes 376*1ae08745Sheppo * as well as a count of the number of nodes in the array. If the 377*1ae08745Sheppo * count is zero, the node pointer will be passed back as NULL. 378*1ae08745Sheppo * 379*1ae08745Sheppo * Returns: 0 success; -1 failure 380*1ae08745Sheppo */ 381*1ae08745Sheppo static int 382*1ae08745Sheppo mdd_scan_for_nodes(md_t *mdp, 383*1ae08745Sheppo mde_cookie_t start, char *compnodep, int *countp, mde_cookie_t **nodespp) 384*1ae08745Sheppo { 385*1ae08745Sheppo mde_str_cookie_t cname; 386*1ae08745Sheppo mde_str_cookie_t aname; 387*1ae08745Sheppo md_impl_t *mdip = (md_impl_t *)mdp; 388*1ae08745Sheppo 389*1ae08745Sheppo if (mdip == NULL) 390*1ae08745Sheppo return (-1); 391*1ae08745Sheppo 392*1ae08745Sheppo cname = md_find_name(mdp, compnodep); 393*1ae08745Sheppo aname = md_find_name(mdp, "fwd"); 394*1ae08745Sheppo 395*1ae08745Sheppo /* get the number of nodes of interest in the DAG */ 396*1ae08745Sheppo *countp = md_scan_dag(mdp, start, cname, aname, NULL); 397*1ae08745Sheppo if (*countp == 0) { 398*1ae08745Sheppo *nodespp = NULL; 399*1ae08745Sheppo return (0); 400*1ae08745Sheppo } 401*1ae08745Sheppo 402*1ae08745Sheppo /* allocate the storage */ 403*1ae08745Sheppo *nodespp = mdip->allocp(sizeof (mde_cookie_t) * (*countp)); 404*1ae08745Sheppo 405*1ae08745Sheppo /* populate our array with the matching nodes */ 406*1ae08745Sheppo (void) md_scan_dag(mdp, start, cname, aname, *nodespp); 407*1ae08745Sheppo 408*1ae08745Sheppo return (0); 409*1ae08745Sheppo } 410*1ae08745Sheppo 411*1ae08745Sheppo /* 412*1ae08745Sheppo * Walk an array of nodes and check if there are any duplicate 413*1ae08745Sheppo * nodes. A duplicate is determined based on the specified match 414*1ae08745Sheppo * criteria. Returns B_TRUE if there are any duplicates and B_FALSE 415*1ae08745Sheppo * otherwise. 416*1ae08745Sheppo */ 417*1ae08745Sheppo static boolean_t 418*1ae08745Sheppo mdd_any_dup_nodes(md_impl_t *mdp, md_prop_match_t *pmp, int count, 419*1ae08745Sheppo mde_cookie_t *nodesp) 420*1ae08745Sheppo { 421*1ae08745Sheppo int idx; 422*1ae08745Sheppo int match; 423*1ae08745Sheppo md_element_t *elem; 424*1ae08745Sheppo 425*1ae08745Sheppo ASSERT(count > 0 || nodesp == NULL); 426*1ae08745Sheppo 427*1ae08745Sheppo for (idx = 0; idx < count; idx++) { 428*1ae08745Sheppo elem = &(mdp->mdep[nodesp[idx]]); 429*1ae08745Sheppo 430*1ae08745Sheppo match = mdd_node_list_match(mdp, mdp, elem, nodesp, NULL, 431*1ae08745Sheppo idx + 1, count - 1, pmp); 432*1ae08745Sheppo 433*1ae08745Sheppo if (match != MD_DIFF_NOMATCH) 434*1ae08745Sheppo return (B_TRUE); 435*1ae08745Sheppo } 436*1ae08745Sheppo 437*1ae08745Sheppo return (B_FALSE); 438*1ae08745Sheppo } 439*1ae08745Sheppo 440*1ae08745Sheppo /* 441*1ae08745Sheppo * Given a node and a array of nodes, compare the node to all elements 442*1ae08745Sheppo * in the specified start-end range of the array. If the node matches 443*1ae08745Sheppo * one of the nodes in the array, return the index of that node. Otherwise 444*1ae08745Sheppo * return MD_DIFF_NOMATCH. 445*1ae08745Sheppo * 446*1ae08745Sheppo * The optional seen array parameter can be used to optimize repeated 447*1ae08745Sheppo * calls to this function. If the seen array indicates that an element 448*1ae08745Sheppo * has already been matched, the full comparison is not necessary. 449*1ae08745Sheppo */ 450*1ae08745Sheppo static int 451*1ae08745Sheppo mdd_node_list_match(md_impl_t *md1, md_impl_t *md2, md_element_t *match_nodep, 452*1ae08745Sheppo mde_cookie_t *match_listp, uint8_t *match_seenp, int start, int end, 453*1ae08745Sheppo md_prop_match_t *match_elemsp) 454*1ae08745Sheppo { 455*1ae08745Sheppo int match; 456*1ae08745Sheppo int idx; 457*1ae08745Sheppo md_element_t *elem; 458*1ae08745Sheppo 459*1ae08745Sheppo for (idx = start; idx <= end; idx++) { 460*1ae08745Sheppo 461*1ae08745Sheppo if ((match_seenp != NULL) && (match_seenp[idx])) 462*1ae08745Sheppo continue; 463*1ae08745Sheppo 464*1ae08745Sheppo elem = &(md2->mdep[match_listp[idx]]); 465*1ae08745Sheppo 466*1ae08745Sheppo match = mdd_node_compare(md1, md2, match_nodep, elem, 467*1ae08745Sheppo match_elemsp); 468*1ae08745Sheppo if (match == MD_DIFF_MATCH) 469*1ae08745Sheppo return (idx); 470*1ae08745Sheppo } 471*1ae08745Sheppo 472*1ae08745Sheppo return (MD_DIFF_NOMATCH); 473*1ae08745Sheppo } 474*1ae08745Sheppo 475*1ae08745Sheppo /* 476*1ae08745Sheppo * Given two nodes and a list of properties, compare the nodes. 477*1ae08745Sheppo * A match is concluded if both nodes have all of the specified 478*1ae08745Sheppo * properties and all the values of those properties are the 479*1ae08745Sheppo * same. Returns MD_DIFF_NOMATCH if the nodes do not match and 480*1ae08745Sheppo * MD_DIFF_MATCH otherwise. 481*1ae08745Sheppo */ 482*1ae08745Sheppo static int 483*1ae08745Sheppo mdd_node_compare(md_impl_t *mdap, md_impl_t *mdbp, md_element_t *nodeap, 484*1ae08745Sheppo md_element_t *nodebp, md_prop_match_t *match_elemsp) 485*1ae08745Sheppo { 486*1ae08745Sheppo md_element_t *ap; 487*1ae08745Sheppo md_element_t *bp; 488*1ae08745Sheppo boolean_t nodea_interest; 489*1ae08745Sheppo boolean_t nodeb_interest; 490*1ae08745Sheppo int idx; 491*1ae08745Sheppo 492*1ae08745Sheppo /* make sure we are starting at the beginning of the nodes */ 493*1ae08745Sheppo if ((MDE_TAG(nodeap) != MDET_NODE) || (MDE_TAG(nodebp) != MDET_NODE)) 494*1ae08745Sheppo return (MD_DIFF_NOMATCH); 495*1ae08745Sheppo 496*1ae08745Sheppo for (idx = 0; match_elemsp[idx].type != MDET_LIST_END; idx++) { 497*1ae08745Sheppo 498*1ae08745Sheppo int type; 499*1ae08745Sheppo 500*1ae08745Sheppo nodea_interest = B_FALSE; 501*1ae08745Sheppo nodeb_interest = B_FALSE; 502*1ae08745Sheppo 503*1ae08745Sheppo type = match_elemsp[idx].type; 504*1ae08745Sheppo 505*1ae08745Sheppo /* 506*1ae08745Sheppo * Check node A for the property of interest 507*1ae08745Sheppo */ 508*1ae08745Sheppo for (ap = nodeap; MDE_TAG(ap) != MDET_NODE_END; ap++) { 509*1ae08745Sheppo char *elemname; 510*1ae08745Sheppo 511*1ae08745Sheppo if (MDE_TAG(ap) != type) 512*1ae08745Sheppo continue; 513*1ae08745Sheppo 514*1ae08745Sheppo elemname = mdap->namep + MDE_NAME(ap); 515*1ae08745Sheppo 516*1ae08745Sheppo if (strcmp(elemname, match_elemsp[idx].namep) == 0) { 517*1ae08745Sheppo /* found the property of interest */ 518*1ae08745Sheppo nodea_interest = B_TRUE; 519*1ae08745Sheppo break; 520*1ae08745Sheppo } 521*1ae08745Sheppo } 522*1ae08745Sheppo 523*1ae08745Sheppo /* node A is not of interest */ 524*1ae08745Sheppo if (!nodea_interest) 525*1ae08745Sheppo return (MD_DIFF_NOMATCH); 526*1ae08745Sheppo 527*1ae08745Sheppo /* 528*1ae08745Sheppo * Check node B for the property of interest 529*1ae08745Sheppo */ 530*1ae08745Sheppo for (bp = nodebp; MDE_TAG(bp) != MDET_NODE_END; bp++) { 531*1ae08745Sheppo char *elemname; 532*1ae08745Sheppo 533*1ae08745Sheppo if (MDE_TAG(bp) != type) 534*1ae08745Sheppo continue; 535*1ae08745Sheppo 536*1ae08745Sheppo elemname = mdbp->namep + MDE_NAME(bp); 537*1ae08745Sheppo 538*1ae08745Sheppo if (strcmp(elemname, match_elemsp[idx].namep) == 0) { 539*1ae08745Sheppo nodeb_interest = B_TRUE; 540*1ae08745Sheppo break; 541*1ae08745Sheppo } 542*1ae08745Sheppo } 543*1ae08745Sheppo 544*1ae08745Sheppo /* node B is not of interest */ 545*1ae08745Sheppo if (!nodeb_interest) 546*1ae08745Sheppo return (MD_DIFF_NOMATCH); 547*1ae08745Sheppo 548*1ae08745Sheppo /* 549*1ae08745Sheppo * Both nodes have the property of interest. The 550*1ae08745Sheppo * nodes are not a match unless the value of that 551*1ae08745Sheppo * property match 552*1ae08745Sheppo */ 553*1ae08745Sheppo switch (type) { 554*1ae08745Sheppo case MDET_PROP_VAL: 555*1ae08745Sheppo if (MDE_PROP_VALUE(ap) != MDE_PROP_VALUE(bp)) 556*1ae08745Sheppo return (MD_DIFF_NOMATCH); 557*1ae08745Sheppo break; 558*1ae08745Sheppo 559*1ae08745Sheppo case MDET_PROP_STR: { 560*1ae08745Sheppo char *stra = (char *)(mdap->datap + 561*1ae08745Sheppo MDE_PROP_DATA_OFFSET(ap)); 562*1ae08745Sheppo char *strb = (char *)(mdbp->datap + 563*1ae08745Sheppo MDE_PROP_DATA_OFFSET(bp)); 564*1ae08745Sheppo 565*1ae08745Sheppo if (strcmp(stra, strb) != 0) 566*1ae08745Sheppo return (MD_DIFF_NOMATCH); 567*1ae08745Sheppo break; 568*1ae08745Sheppo } 569*1ae08745Sheppo 570*1ae08745Sheppo case MDET_PROP_DAT: { 571*1ae08745Sheppo 572*1ae08745Sheppo caddr_t dataa; 573*1ae08745Sheppo caddr_t datab; 574*1ae08745Sheppo 575*1ae08745Sheppo if (MDE_PROP_DATA_LEN(ap) != MDE_PROP_DATA_LEN(bp)) 576*1ae08745Sheppo return (MD_DIFF_NOMATCH); 577*1ae08745Sheppo 578*1ae08745Sheppo dataa = (caddr_t)(mdap->datap + 579*1ae08745Sheppo MDE_PROP_DATA_OFFSET(ap)); 580*1ae08745Sheppo datab = (caddr_t)(mdbp->datap + 581*1ae08745Sheppo MDE_PROP_DATA_OFFSET(bp)); 582*1ae08745Sheppo 583*1ae08745Sheppo if (memcmp(dataa, datab, MDE_PROP_DATA_LEN(ap)) != 0) 584*1ae08745Sheppo return (MD_DIFF_NOMATCH); 585*1ae08745Sheppo 586*1ae08745Sheppo break; 587*1ae08745Sheppo } 588*1ae08745Sheppo 589*1ae08745Sheppo default: 590*1ae08745Sheppo /* unsupported prop type */ 591*1ae08745Sheppo return (MD_DIFF_NOMATCH); 592*1ae08745Sheppo } 593*1ae08745Sheppo } 594*1ae08745Sheppo 595*1ae08745Sheppo /* 596*1ae08745Sheppo * All the specified properties exist in both 597*1ae08745Sheppo * nodes and have the same value. The two nodes 598*1ae08745Sheppo * match. 599*1ae08745Sheppo */ 600*1ae08745Sheppo 601*1ae08745Sheppo return (MD_DIFF_MATCH); 602*1ae08745Sheppo } 603