1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <assert.h> 30 #include <dirent.h> 31 #include <errno.h> 32 #include <fnmatch.h> 33 #include <signal.h> 34 #include <stdlib.h> 35 #include <unistd.h> 36 #include <strings.h> 37 #include <synch.h> 38 #include <sys/brand.h> 39 #include <sys/fcntl.h> 40 #include <sys/param.h> 41 #include <sys/stat.h> 42 #include <sys/systeminfo.h> 43 #include <sys/types.h> 44 #include <thread.h> 45 #include <zone.h> 46 47 #include <libbrand_impl.h> 48 #include <libbrand.h> 49 50 #define DTD_ELEM_BOOT ((const xmlChar *) "boot") 51 #define DTD_ELEM_BRAND ((const xmlChar *) "brand") 52 #define DTD_ELEM_COMMENT ((const xmlChar *) "comment") 53 #define DTD_ELEM_DEVICE ((const xmlChar *) "device") 54 #define DTD_ELEM_GLOBAL_MOUNT ((const xmlChar *) "global_mount") 55 #define DTD_ELEM_HALT ((const xmlChar *) "halt") 56 #define DTD_ELEM_INITNAME ((const xmlChar *) "initname") 57 #define DTD_ELEM_INSTALL ((const xmlChar *) "install") 58 #define DTD_ELEM_INSTALLOPTS ((const xmlChar *) "installopts") 59 #define DTD_ELEM_LOGIN_CMD ((const xmlChar *) "login_cmd") 60 #define DTD_ELEM_MODNAME ((const xmlChar *) "modname") 61 #define DTD_ELEM_MOUNT ((const xmlChar *) "mount") 62 #define DTD_ELEM_POSTCLONE ((const xmlChar *) "postclone") 63 #define DTD_ELEM_PRIVILEGE ((const xmlChar *) "privilege") 64 #define DTD_ELEM_SYMLINK ((const xmlChar *) "symlink") 65 #define DTD_ELEM_VERIFY_CFG ((const xmlChar *) "verify_cfg") 66 #define DTD_ELEM_VERIFY_ADM ((const xmlChar *) "verify_adm") 67 68 #define DTD_ATTR_ARCH ((const xmlChar *) "arch") 69 #define DTD_ATTR_DIRECTORY ((const xmlChar *) "directory") 70 #define DTD_ATTR_MATCH ((const xmlChar *) "match") 71 #define DTD_ATTR_MODE ((const xmlChar *) "mode") 72 #define DTD_ATTR_NAME ((const xmlChar *) "name") 73 #define DTD_ATTR_OPT ((const xmlChar *) "opt") 74 #define DTD_ATTR_PATH ((const xmlChar *) "path") 75 #define DTD_ATTR_SET ((const xmlChar *) "set") 76 #define DTD_ATTR_SOURCE ((const xmlChar *) "source") 77 #define DTD_ATTR_SPECIAL ((const xmlChar *) "special") 78 #define DTD_ATTR_TARGET ((const xmlChar *) "target") 79 #define DTD_ATTR_TYPE ((const xmlChar *) "type") 80 81 static volatile boolean_t libbrand_initialized = B_FALSE; 82 static char i_curr_arch[MAXNAMELEN]; 83 static char i_curr_zone[ZONENAME_MAX]; 84 85 /*ARGSUSED*/ 86 static void 87 brand_error_func(void *ctx, const char *msg, ...) 88 { 89 /* 90 * Ignore error messages from libxml 91 */ 92 } 93 94 static boolean_t 95 libbrand_initialize() 96 { 97 static mutex_t initialize_lock = DEFAULTMUTEX; 98 99 (void) mutex_lock(&initialize_lock); 100 101 if (libbrand_initialized) { 102 (void) mutex_unlock(&initialize_lock); 103 return (B_TRUE); 104 } 105 106 if (sysinfo(SI_ARCHITECTURE, i_curr_arch, sizeof (i_curr_arch)) < 0) { 107 (void) mutex_unlock(&initialize_lock); 108 return (B_FALSE); 109 } 110 111 if (getzonenamebyid(getzoneid(), i_curr_zone, 112 sizeof (i_curr_zone)) < 0) { 113 (void) mutex_unlock(&initialize_lock); 114 return (B_FALSE); 115 } 116 117 /* 118 * Note that here we're initializing per-process libxml2 119 * state. By doing so we're implicitly assuming that 120 * no other code in this process is also trying to 121 * use libxml2. But in most case we know this not to 122 * be true since we're almost always used in conjunction 123 * with libzonecfg, which also uses libxml2. Lucky for 124 * us, libzonecfg initializes libxml2 to essentially 125 * the same defaults as we're using below. 126 */ 127 xmlLineNumbersDefault(1); 128 xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS; 129 xmlDoValidityCheckingDefaultValue = 1; 130 (void) xmlKeepBlanksDefault(0); 131 xmlGetWarningsDefaultValue = 0; 132 xmlSetGenericErrorFunc(NULL, brand_error_func); 133 134 libbrand_initialized = B_TRUE; 135 (void) mutex_unlock(&initialize_lock); 136 return (B_TRUE); 137 } 138 139 static const char * 140 get_curr_arch(void) 141 { 142 if (!libbrand_initialize()) 143 return (NULL); 144 145 return (i_curr_arch); 146 } 147 148 static const char * 149 get_curr_zone(void) 150 { 151 if (!libbrand_initialize()) 152 return (NULL); 153 154 return (i_curr_zone); 155 } 156 157 /* 158 * Internal function to open an XML file 159 * 160 * Returns the XML doc pointer, or NULL on failure. It will validate the 161 * document, as well as removing any comments from the document structure. 162 */ 163 static xmlDocPtr 164 open_xml_file(const char *file) 165 { 166 xmlDocPtr doc; 167 xmlValidCtxtPtr cvp; 168 int valid; 169 170 if (!libbrand_initialize()) 171 return (NULL); 172 173 /* 174 * Parse the file 175 */ 176 if ((doc = xmlParseFile(file)) == NULL) 177 return (NULL); 178 179 /* 180 * Validate the file 181 */ 182 if ((cvp = xmlNewValidCtxt()) == NULL) { 183 xmlFreeDoc(doc); 184 return (NULL); 185 } 186 cvp->error = brand_error_func; 187 cvp->warning = brand_error_func; 188 valid = xmlValidateDocument(cvp, doc); 189 xmlFreeValidCtxt(cvp); 190 if (valid == 0) { 191 xmlFreeDoc(doc); 192 return (NULL); 193 } 194 195 return (doc); 196 } 197 /* 198 * Open a handle to the named brand. 199 * 200 * Returns a handle to the named brand, which is used for all subsequent brand 201 * interaction, or NULL if unable to open or initialize the brand. 202 */ 203 brand_handle_t * 204 brand_open(const char *name) 205 { 206 brand_handle_t *bhp; 207 char path[MAXPATHLEN]; 208 xmlNodePtr node; 209 xmlChar *property; 210 struct stat statbuf; 211 212 /* 213 * Make sure brand name isn't too long 214 */ 215 if (strlen(name) >= MAXNAMELEN) 216 return (NULL); 217 218 /* 219 * Check that the brand exists 220 */ 221 (void) snprintf(path, sizeof (path), "%s/%s", BRAND_DIR, name); 222 223 if (stat(path, &statbuf) != 0) 224 return (NULL); 225 226 /* 227 * Allocate brand handle 228 */ 229 if ((bhp = malloc(sizeof (brand_handle_t))) == NULL) 230 return (NULL); 231 bzero(bhp, sizeof (brand_handle_t)); 232 233 (void) strcpy(bhp->bh_name, name); 234 235 /* 236 * Open the configuration file 237 */ 238 (void) snprintf(path, sizeof (path), "%s/%s/%s", BRAND_DIR, name, 239 BRAND_CONFIG); 240 if ((bhp->bh_config = open_xml_file(path)) == NULL) { 241 brand_close(bhp); 242 return (NULL); 243 } 244 245 /* 246 * Verify that the name of the brand matches the directory in which it 247 * is installed. 248 */ 249 if ((node = xmlDocGetRootElement(bhp->bh_config)) == NULL) { 250 brand_close(bhp); 251 return (NULL); 252 } 253 254 if (xmlStrcmp(node->name, DTD_ELEM_BRAND) != 0) { 255 brand_close(bhp); 256 return (NULL); 257 } 258 259 if ((property = xmlGetProp(node, DTD_ATTR_NAME)) == NULL) { 260 brand_close(bhp); 261 return (NULL); 262 } 263 264 if (strcmp((char *)property, name) != 0) { 265 xmlFree(property); 266 brand_close(bhp); 267 return (NULL); 268 } 269 xmlFree(property); 270 271 /* 272 * Open handle to platform configuration file. 273 */ 274 (void) snprintf(path, sizeof (path), "%s/%s/%s", BRAND_DIR, name, 275 BRAND_PLATFORM); 276 if ((bhp->bh_platform = open_xml_file(path)) == NULL) { 277 brand_close(bhp); 278 return (NULL); 279 } 280 281 return (bhp); 282 } 283 284 /* 285 * Closes the given brand handle 286 */ 287 void 288 brand_close(brand_handle_t *bhp) 289 { 290 if (bhp->bh_platform != NULL) 291 xmlFreeDoc(bhp->bh_platform); 292 if (bhp->bh_config != NULL) 293 xmlFreeDoc(bhp->bh_config); 294 free(bhp); 295 } 296 297 static int 298 i_substitute_tokens(const char *sbuf, char *dbuf, int dbuf_size, 299 const char *zonename, const char *zoneroot, const char *username, 300 const char *curr_zone, int argc, char **argv) 301 { 302 int dst, src, i; 303 304 assert(argc >= 0); 305 assert((argc == 0) || (argv != NULL)); 306 307 /* 308 * Walk through the characters, substituting values as needed. 309 */ 310 dbuf[0] = '\0'; 311 dst = 0; 312 for (src = 0; src < strlen((char *)sbuf) && dst < dbuf_size; src++) { 313 if (sbuf[src] != '%') { 314 dbuf[dst++] = sbuf[src]; 315 continue; 316 } 317 318 switch (sbuf[++src]) { 319 case '%': 320 dst += strlcpy(dbuf + dst, "%", dbuf_size - dst); 321 break; 322 case 'R': 323 if (zoneroot == NULL) 324 break; 325 dst += strlcpy(dbuf + dst, zoneroot, dbuf_size - dst); 326 break; 327 case 'u': 328 if (username == NULL) 329 break; 330 dst += strlcpy(dbuf + dst, username, dbuf_size - dst); 331 break; 332 case 'Z': 333 if (curr_zone == NULL) 334 break; 335 /* name of the zone we're running in */ 336 dst += strlcpy(dbuf + dst, curr_zone, dbuf_size - dst); 337 break; 338 case 'z': 339 /* name of the zone we're operating on */ 340 if (zonename == NULL) 341 break; 342 dst += strlcpy(dbuf + dst, zonename, dbuf_size - dst); 343 break; 344 case '*': 345 if (argv == NULL) 346 break; 347 for (i = 0; i < argc; i++) 348 dst += snprintf(dbuf + dst, dbuf_size - dst, 349 " \"%s\"", argv[i]); 350 break; 351 } 352 } 353 354 if (dst >= dbuf_size) 355 return (-1); 356 357 dbuf[dst] = '\0'; 358 return (0); 359 } 360 361 /* 362 * Retrieve the given tag from the brand. 363 * Perform the following substitutions as necessary: 364 * 365 * %% % 366 * %u Username 367 * %z Name of target zone 368 * %Z Name of current zone 369 * %R Root of zone 370 * %* Additional arguments (argc, argv) 371 * 372 * Returns 0 on success, -1 on failure. 373 */ 374 static int 375 brand_get_value(brand_handle_t *bhp, const char *zonename, 376 const char *zoneroot, const char *username, const char *curr_zone, 377 char *buf, size_t len, int argc, char **argv, const xmlChar *tagname, 378 boolean_t substitute, boolean_t optional) 379 { 380 xmlNodePtr node; 381 xmlChar *content; 382 int err = 0; 383 384 /* 385 * Retrieve the specified value from the XML doc 386 */ 387 if ((node = xmlDocGetRootElement(bhp->bh_config)) == NULL) 388 return (-1); 389 390 if (xmlStrcmp(node->name, DTD_ELEM_BRAND) != 0) 391 return (-1); 392 393 for (node = node->xmlChildrenNode; node != NULL; 394 node = node->next) { 395 if (xmlStrcmp(node->name, tagname) == 0) 396 break; 397 } 398 399 if (node == NULL) 400 return (-1); 401 402 if ((content = xmlNodeGetContent(node)) == NULL) 403 return (-1); 404 405 if (strlen((char *)content) == 0) { 406 /* 407 * If the entry in the config file is empty, check to see 408 * whether this is an optional field. If so, we return the 409 * empty buffer. If not, we return an error. 410 */ 411 if (optional) { 412 buf[0] = '\0'; 413 } else { 414 err = -1; 415 } 416 } else { 417 /* Substitute token values as needed. */ 418 if (substitute) { 419 if (i_substitute_tokens((char *)content, buf, len, 420 zonename, zoneroot, username, curr_zone, 421 argc, argv) != 0) 422 err = -1; 423 } else { 424 if (strlcpy(buf, (char *)content, len) >= len) 425 err = -1; 426 } 427 } 428 429 xmlFree(content); 430 431 return (err); 432 } 433 434 int 435 brand_get_boot(brand_handle_t *bhp, const char *zonename, 436 const char *zoneroot, char *buf, size_t len, int argc, char **argv) 437 { 438 return (brand_get_value(bhp, zonename, zoneroot, NULL, NULL, 439 buf, len, argc, argv, DTD_ELEM_BOOT, B_TRUE, B_TRUE)); 440 } 441 442 int 443 brand_get_brandname(brand_handle_t *bhp, char *buf, size_t len) 444 { 445 if (len <= strlen(bhp->bh_name)) 446 return (-1); 447 448 (void) strcpy(buf, bhp->bh_name); 449 450 return (0); 451 } 452 453 int 454 brand_get_halt(brand_handle_t *bhp, const char *zonename, 455 const char *zoneroot, char *buf, size_t len, int argc, char **argv) 456 { 457 return (brand_get_value(bhp, zonename, zoneroot, NULL, NULL, 458 buf, len, argc, argv, DTD_ELEM_HALT, B_TRUE, B_TRUE)); 459 } 460 461 int 462 brand_get_initname(brand_handle_t *bhp, char *buf, size_t len) 463 { 464 return (brand_get_value(bhp, NULL, NULL, NULL, NULL, 465 buf, len, 0, NULL, DTD_ELEM_INITNAME, B_FALSE, B_FALSE)); 466 } 467 468 int 469 brand_get_login_cmd(brand_handle_t *bhp, const char *username, 470 char *buf, size_t len) 471 { 472 const char *curr_zone = get_curr_zone(); 473 return (brand_get_value(bhp, NULL, NULL, username, curr_zone, 474 buf, len, 0, NULL, DTD_ELEM_LOGIN_CMD, B_TRUE, B_FALSE)); 475 } 476 477 int 478 brand_get_install(brand_handle_t *bhp, const char *zonename, 479 const char *zoneroot, char *buf, size_t len, int argc, char **argv) 480 { 481 return (brand_get_value(bhp, zonename, zoneroot, NULL, NULL, 482 buf, len, argc, argv, DTD_ELEM_INSTALL, B_TRUE, B_FALSE)); 483 } 484 485 int 486 brand_get_installopts(brand_handle_t *bhp, char *buf, size_t len) 487 { 488 return (brand_get_value(bhp, NULL, NULL, NULL, NULL, 489 buf, len, 0, NULL, DTD_ELEM_INSTALLOPTS, B_FALSE, B_TRUE)); 490 } 491 492 int 493 brand_get_modname(brand_handle_t *bhp, char *buf, size_t len) 494 { 495 return (brand_get_value(bhp, NULL, NULL, NULL, NULL, 496 buf, len, 0, NULL, DTD_ELEM_MODNAME, B_FALSE, B_TRUE)); 497 } 498 499 int 500 brand_get_postclone(brand_handle_t *bhp, const char *zonename, 501 const char *zoneroot, char *buf, size_t len, int argc, char **argv) 502 { 503 return (brand_get_value(bhp, zonename, zoneroot, NULL, NULL, 504 buf, len, argc, argv, DTD_ELEM_POSTCLONE, B_TRUE, B_TRUE)); 505 } 506 507 int 508 brand_get_verify_cfg(brand_handle_t *bhp, char *buf, size_t len) 509 { 510 return (brand_get_value(bhp, NULL, NULL, NULL, NULL, 511 buf, len, 0, NULL, DTD_ELEM_VERIFY_CFG, B_FALSE, B_TRUE)); 512 } 513 514 int 515 brand_get_verify_adm(brand_handle_t *bhp, const char *zonename, 516 const char *zoneroot, char *buf, size_t len, int argc, char **argv) 517 { 518 return (brand_get_value(bhp, zonename, zoneroot, NULL, NULL, 519 buf, len, argc, argv, DTD_ELEM_VERIFY_ADM, B_TRUE, B_TRUE)); 520 } 521 522 int 523 brand_is_native(brand_handle_t *bhp) 524 { 525 return ((strcmp(bhp->bh_name, NATIVE_BRAND_NAME) == 0) ? 1 : 0); 526 } 527 528 /* 529 * Iterate over brand privileges 530 * 531 * Walks the brand config, searching for <privilege> elements, calling the 532 * specified callback for each. Returns 0 on success, or -1 on failure. 533 */ 534 int 535 brand_config_iter_privilege(brand_handle_t *bhp, int (*func)(void *, 536 const char *, const char *), void *data) 537 { 538 xmlNodePtr node; 539 xmlChar *name, *set; 540 int ret; 541 542 if ((node = xmlDocGetRootElement(bhp->bh_config)) == NULL) 543 return (-1); 544 545 for (node = node->xmlChildrenNode; node != NULL; node = node->next) { 546 547 if (xmlStrcmp(node->name, DTD_ELEM_PRIVILEGE) != 0) 548 continue; 549 550 name = xmlGetProp(node, DTD_ATTR_NAME); 551 set = xmlGetProp(node, DTD_ATTR_SET); 552 553 if (name == NULL || set == NULL) { 554 if (name != NULL) 555 xmlFree(name); 556 if (set != NULL) 557 xmlFree(set); 558 return (-1); 559 } 560 561 ret = func(data, (const char *)name, (const char *)set); 562 563 xmlFree(name); 564 xmlFree(set); 565 566 if (ret != 0) 567 return (-1); 568 } 569 570 return (0); 571 } 572 573 static int 574 i_brand_platform_iter_mounts(brand_handle_t *bhp, const char *zoneroot, 575 int (*func)(void *, const char *, const char *, const char *, 576 const char *), void *data, const xmlChar *mount_type) 577 { 578 xmlNodePtr node; 579 xmlChar *special, *dir, *type, *opt; 580 char special_exp[MAXPATHLEN]; 581 char opt_exp[MAXPATHLEN]; 582 int ret; 583 584 if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL) 585 return (-1); 586 587 for (node = node->xmlChildrenNode; node != NULL; node = node->next) { 588 589 if (xmlStrcmp(node->name, mount_type) != 0) 590 continue; 591 592 special = xmlGetProp(node, DTD_ATTR_SPECIAL); 593 dir = xmlGetProp(node, DTD_ATTR_DIRECTORY); 594 type = xmlGetProp(node, DTD_ATTR_TYPE); 595 opt = xmlGetProp(node, DTD_ATTR_OPT); 596 if ((special == NULL) || (dir == NULL) || (type == NULL) || 597 (opt == NULL)) { 598 ret = -1; 599 goto next; 600 } 601 602 /* Substitute token values as needed. */ 603 if ((ret = i_substitute_tokens((char *)special, 604 special_exp, sizeof (special_exp), 605 NULL, zoneroot, NULL, NULL, 0, NULL)) != 0) 606 goto next; 607 608 /* opt might not be defined */ 609 if (strlen((const char *)opt) == 0) { 610 xmlFree(opt); 611 opt = NULL; 612 } else { 613 if ((ret = i_substitute_tokens((char *)opt, 614 opt_exp, sizeof (opt_exp), 615 NULL, zoneroot, NULL, NULL, 0, NULL)) != 0) 616 goto next; 617 } 618 619 ret = func(data, (char *)special_exp, (char *)dir, 620 (char *)type, ((opt != NULL) ? opt_exp : NULL)); 621 622 next: 623 if (special != NULL) 624 xmlFree(special); 625 if (dir != NULL) 626 xmlFree(dir); 627 if (type != NULL) 628 xmlFree(type); 629 if (opt != NULL) 630 xmlFree(opt); 631 if (ret != 0) 632 return (-1); 633 } 634 return (0); 635 } 636 637 638 /* 639 * Iterate over global platform filesystems 640 * 641 * Walks the platform, searching for <global_mount> elements, calling the 642 * specified callback for each. Returns 0 on success, or -1 on failure. 643 * 644 * Perform the following substitutions as necessary: 645 * 646 * %R Root of zone 647 */ 648 int 649 brand_platform_iter_gmounts(brand_handle_t *bhp, const char *zoneroot, 650 int (*func)(void *, const char *, const char *, const char *, 651 const char *), void *data) 652 { 653 return (i_brand_platform_iter_mounts(bhp, zoneroot, func, data, 654 DTD_ELEM_GLOBAL_MOUNT)); 655 } 656 657 /* 658 * Iterate over non-global zone platform filesystems 659 * 660 * Walks the platform, searching for <mount> elements, calling the 661 * specified callback for each. Returns 0 on success, or -1 on failure. 662 */ 663 int 664 brand_platform_iter_mounts(brand_handle_t *bhp, int (*func)(void *, 665 const char *, const char *, const char *, const char *), void *data) 666 { 667 return (i_brand_platform_iter_mounts(bhp, NULL, func, data, 668 DTD_ELEM_MOUNT)); 669 } 670 671 /* 672 * Iterate over platform symlinks 673 * 674 * Walks the platform, searching for <symlink> elements, calling the 675 * specified callback for each. Returns 0 on success, or -1 on failure. 676 */ 677 int 678 brand_platform_iter_link(brand_handle_t *bhp, 679 int (*func)(void *, const char *, const char *), void *data) 680 { 681 xmlNodePtr node; 682 xmlChar *source, *target; 683 int ret; 684 685 if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL) 686 return (-1); 687 688 for (node = node->xmlChildrenNode; node != NULL; node = node->next) { 689 690 if (xmlStrcmp(node->name, DTD_ELEM_SYMLINK) != 0) 691 continue; 692 693 source = xmlGetProp(node, DTD_ATTR_SOURCE); 694 target = xmlGetProp(node, DTD_ATTR_TARGET); 695 696 if (source == NULL || target == NULL) { 697 if (source != NULL) 698 xmlFree(source); 699 if (target != NULL) 700 xmlFree(target); 701 return (-1); 702 } 703 704 ret = func(data, (char *)source, (char *)target); 705 706 xmlFree(source); 707 xmlFree(target); 708 709 if (ret != 0) 710 return (-1); 711 } 712 713 return (0); 714 } 715 716 /* 717 * Iterate over platform devices 718 * 719 * Walks the platform, searching for <device> elements, calling the 720 * specified callback for each. Returns 0 on success, or -1 on failure. 721 */ 722 int 723 brand_platform_iter_devices(brand_handle_t *bhp, const char *zonename, 724 int (*func)(void *, const char *, const char *), void *data) 725 { 726 const char *curr_arch = get_curr_arch(); 727 xmlNodePtr node; 728 xmlChar *match, *name, *arch; 729 char match_exp[MAXPATHLEN]; 730 boolean_t err = B_FALSE; 731 int ret = 0; 732 733 734 assert(bhp != NULL); 735 assert(zonename != NULL); 736 assert(func != NULL); 737 738 if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL) 739 return (-1); 740 741 for (node = node->xmlChildrenNode; node != NULL; node = node->next) { 742 743 if (xmlStrcmp(node->name, DTD_ELEM_DEVICE) != 0) 744 continue; 745 746 match = xmlGetProp(node, DTD_ATTR_MATCH); 747 name = xmlGetProp(node, DTD_ATTR_NAME); 748 arch = xmlGetProp(node, DTD_ATTR_ARCH); 749 if ((match == NULL) || (name == NULL) || (arch == NULL)) { 750 err = B_TRUE; 751 goto next; 752 } 753 754 /* check if the arch matches */ 755 if ((strcmp((char *)arch, "all") != 0) && 756 (strcmp((char *)arch, curr_arch) != 0)) 757 goto next; 758 759 /* Substitute token values as needed. */ 760 if ((ret = i_substitute_tokens((char *)match, 761 match_exp, sizeof (match_exp), 762 zonename, NULL, NULL, NULL, 0, NULL)) != 0) { 763 err = B_TRUE; 764 goto next; 765 } 766 767 /* name might not be defined */ 768 if (strlen((const char *)name) == 0) { 769 xmlFree(name); 770 name = NULL; 771 } 772 773 /* invoke the callback */ 774 ret = func(data, (const char *)match_exp, (const char *)name); 775 776 next: 777 if (match != NULL) 778 xmlFree(match); 779 if (name != NULL) 780 xmlFree(name); 781 if (arch != NULL) 782 xmlFree(arch); 783 if (err) 784 return (-1); 785 if (ret != 0) 786 return (-1); 787 } 788 789 return (0); 790 } 791