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 struct brand_handle *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 (struct brand_handle))) == NULL) 230 return (NULL); 231 bzero(bhp, sizeof (struct brand_handle)); 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((brand_handle_t)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((brand_handle_t)bhp); 251 return (NULL); 252 } 253 254 if (xmlStrcmp(node->name, DTD_ELEM_BRAND) != 0) { 255 brand_close((brand_handle_t)bhp); 256 return (NULL); 257 } 258 259 if ((property = xmlGetProp(node, DTD_ATTR_NAME)) == NULL) { 260 brand_close((brand_handle_t)bhp); 261 return (NULL); 262 } 263 264 if (strcmp((char *)property, name) != 0) { 265 xmlFree(property); 266 brand_close((brand_handle_t)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((brand_handle_t)bhp); 278 return (NULL); 279 } 280 281 return ((brand_handle_t)bhp); 282 } 283 284 /* 285 * Closes the given brand handle 286 */ 287 void 288 brand_close(brand_handle_t bh) 289 { 290 struct brand_handle *bhp = (struct brand_handle *)bh; 291 if (bhp->bh_platform != NULL) 292 xmlFreeDoc(bhp->bh_platform); 293 if (bhp->bh_config != NULL) 294 xmlFreeDoc(bhp->bh_config); 295 free(bhp); 296 } 297 298 static int 299 i_substitute_tokens(const char *sbuf, char *dbuf, int dbuf_size, 300 const char *zonename, const char *zoneroot, const char *username, 301 const char *curr_zone, int argc, char **argv) 302 { 303 int dst, src, i; 304 305 assert(argc >= 0); 306 assert((argc == 0) || (argv != NULL)); 307 308 /* 309 * Walk through the characters, substituting values as needed. 310 */ 311 dbuf[0] = '\0'; 312 dst = 0; 313 for (src = 0; src < strlen((char *)sbuf) && dst < dbuf_size; src++) { 314 if (sbuf[src] != '%') { 315 dbuf[dst++] = sbuf[src]; 316 continue; 317 } 318 319 switch (sbuf[++src]) { 320 case '%': 321 dst += strlcpy(dbuf + dst, "%", dbuf_size - dst); 322 break; 323 case 'R': 324 if (zoneroot == NULL) 325 break; 326 dst += strlcpy(dbuf + dst, zoneroot, dbuf_size - dst); 327 break; 328 case 'u': 329 if (username == NULL) 330 break; 331 dst += strlcpy(dbuf + dst, username, dbuf_size - dst); 332 break; 333 case 'Z': 334 if (curr_zone == NULL) 335 break; 336 /* name of the zone we're running in */ 337 dst += strlcpy(dbuf + dst, curr_zone, dbuf_size - dst); 338 break; 339 case 'z': 340 /* name of the zone we're operating on */ 341 if (zonename == NULL) 342 break; 343 dst += strlcpy(dbuf + dst, zonename, dbuf_size - dst); 344 break; 345 case '*': 346 if (argv == NULL) 347 break; 348 for (i = 0; i < argc; i++) 349 dst += snprintf(dbuf + dst, dbuf_size - dst, 350 " \"%s\"", argv[i]); 351 break; 352 } 353 } 354 355 if (dst >= dbuf_size) 356 return (-1); 357 358 dbuf[dst] = '\0'; 359 return (0); 360 } 361 362 /* 363 * Retrieve the given tag from the brand. 364 * Perform the following substitutions as necessary: 365 * 366 * %% % 367 * %u Username 368 * %z Name of target zone 369 * %Z Name of current zone 370 * %R Root of zone 371 * %* Additional arguments (argc, argv) 372 * 373 * Returns 0 on success, -1 on failure. 374 */ 375 static int 376 brand_get_value(struct brand_handle *bhp, const char *zonename, 377 const char *zoneroot, const char *username, const char *curr_zone, 378 char *buf, size_t len, int argc, char **argv, const xmlChar *tagname, 379 boolean_t substitute, boolean_t optional) 380 { 381 xmlNodePtr node; 382 xmlChar *content; 383 int err = 0; 384 385 /* 386 * Retrieve the specified value from the XML doc 387 */ 388 if ((node = xmlDocGetRootElement(bhp->bh_config)) == NULL) 389 return (-1); 390 391 if (xmlStrcmp(node->name, DTD_ELEM_BRAND) != 0) 392 return (-1); 393 394 for (node = node->xmlChildrenNode; node != NULL; 395 node = node->next) { 396 if (xmlStrcmp(node->name, tagname) == 0) 397 break; 398 } 399 400 if (node == NULL) 401 return (-1); 402 403 if ((content = xmlNodeGetContent(node)) == NULL) 404 return (-1); 405 406 if (strlen((char *)content) == 0) { 407 /* 408 * If the entry in the config file is empty, check to see 409 * whether this is an optional field. If so, we return the 410 * empty buffer. If not, we return an error. 411 */ 412 if (optional) { 413 buf[0] = '\0'; 414 } else { 415 err = -1; 416 } 417 } else { 418 /* Substitute token values as needed. */ 419 if (substitute) { 420 if (i_substitute_tokens((char *)content, buf, len, 421 zonename, zoneroot, username, curr_zone, 422 argc, argv) != 0) 423 err = -1; 424 } else { 425 if (strlcpy(buf, (char *)content, len) >= len) 426 err = -1; 427 } 428 } 429 430 xmlFree(content); 431 432 return (err); 433 } 434 435 int 436 brand_get_boot(brand_handle_t bh, const char *zonename, 437 const char *zoneroot, char *buf, size_t len, int argc, char **argv) 438 { 439 struct brand_handle *bhp = (struct brand_handle *)bh; 440 return (brand_get_value(bhp, zonename, zoneroot, NULL, NULL, 441 buf, len, argc, argv, DTD_ELEM_BOOT, B_TRUE, B_TRUE)); 442 } 443 444 int 445 brand_get_brandname(brand_handle_t bh, char *buf, size_t len) 446 { 447 struct brand_handle *bhp = (struct brand_handle *)bh; 448 if (len <= strlen(bhp->bh_name)) 449 return (-1); 450 451 (void) strcpy(buf, bhp->bh_name); 452 453 return (0); 454 } 455 456 int 457 brand_get_halt(brand_handle_t bh, const char *zonename, 458 const char *zoneroot, char *buf, size_t len, int argc, char **argv) 459 { 460 struct brand_handle *bhp = (struct brand_handle *)bh; 461 return (brand_get_value(bhp, zonename, zoneroot, NULL, NULL, 462 buf, len, argc, argv, DTD_ELEM_HALT, B_TRUE, B_TRUE)); 463 } 464 465 int 466 brand_get_initname(brand_handle_t bh, char *buf, size_t len) 467 { 468 struct brand_handle *bhp = (struct brand_handle *)bh; 469 return (brand_get_value(bhp, NULL, NULL, NULL, NULL, 470 buf, len, 0, NULL, DTD_ELEM_INITNAME, B_FALSE, B_FALSE)); 471 } 472 473 int 474 brand_get_login_cmd(brand_handle_t bh, const char *username, 475 char *buf, size_t len) 476 { 477 struct brand_handle *bhp = (struct brand_handle *)bh; 478 const char *curr_zone = get_curr_zone(); 479 return (brand_get_value(bhp, NULL, NULL, username, curr_zone, 480 buf, len, 0, NULL, DTD_ELEM_LOGIN_CMD, B_TRUE, B_FALSE)); 481 } 482 483 int 484 brand_get_install(brand_handle_t bh, const char *zonename, 485 const char *zoneroot, char *buf, size_t len, int argc, char **argv) 486 { 487 struct brand_handle *bhp = (struct brand_handle *)bh; 488 return (brand_get_value(bhp, zonename, zoneroot, NULL, NULL, 489 buf, len, argc, argv, DTD_ELEM_INSTALL, B_TRUE, B_FALSE)); 490 } 491 492 int 493 brand_get_installopts(brand_handle_t bh, char *buf, size_t len) 494 { 495 struct brand_handle *bhp = (struct brand_handle *)bh; 496 return (brand_get_value(bhp, NULL, NULL, NULL, NULL, 497 buf, len, 0, NULL, DTD_ELEM_INSTALLOPTS, B_FALSE, B_TRUE)); 498 } 499 500 int 501 brand_get_modname(brand_handle_t bh, char *buf, size_t len) 502 { 503 struct brand_handle *bhp = (struct brand_handle *)bh; 504 return (brand_get_value(bhp, NULL, NULL, NULL, NULL, 505 buf, len, 0, NULL, DTD_ELEM_MODNAME, B_FALSE, B_TRUE)); 506 } 507 508 int 509 brand_get_postclone(brand_handle_t bh, const char *zonename, 510 const char *zoneroot, char *buf, size_t len, int argc, char **argv) 511 { 512 struct brand_handle *bhp = (struct brand_handle *)bh; 513 return (brand_get_value(bhp, zonename, zoneroot, NULL, NULL, 514 buf, len, argc, argv, DTD_ELEM_POSTCLONE, B_TRUE, B_TRUE)); 515 } 516 517 int 518 brand_get_verify_cfg(brand_handle_t bh, char *buf, size_t len) 519 { 520 struct brand_handle *bhp = (struct brand_handle *)bh; 521 return (brand_get_value(bhp, NULL, NULL, NULL, NULL, 522 buf, len, 0, NULL, DTD_ELEM_VERIFY_CFG, B_FALSE, B_TRUE)); 523 } 524 525 int 526 brand_get_verify_adm(brand_handle_t bh, const char *zonename, 527 const char *zoneroot, char *buf, size_t len, int argc, char **argv) 528 { 529 struct brand_handle *bhp = (struct brand_handle *)bh; 530 return (brand_get_value(bhp, zonename, zoneroot, NULL, NULL, 531 buf, len, argc, argv, DTD_ELEM_VERIFY_ADM, B_TRUE, B_TRUE)); 532 } 533 534 int 535 brand_is_native(brand_handle_t bh) 536 { 537 struct brand_handle *bhp = (struct brand_handle *)bh; 538 return ((strcmp(bhp->bh_name, NATIVE_BRAND_NAME) == 0) ? 1 : 0); 539 } 540 541 /* 542 * Iterate over brand privileges 543 * 544 * Walks the brand config, searching for <privilege> elements, calling the 545 * specified callback for each. Returns 0 on success, or -1 on failure. 546 */ 547 int 548 brand_config_iter_privilege(brand_handle_t bh, int (*func)(void *, 549 const char *, const char *), void *data) 550 { 551 struct brand_handle *bhp = (struct brand_handle *)bh; 552 xmlNodePtr node; 553 xmlChar *name, *set; 554 int ret; 555 556 if ((node = xmlDocGetRootElement(bhp->bh_config)) == NULL) 557 return (-1); 558 559 for (node = node->xmlChildrenNode; node != NULL; node = node->next) { 560 561 if (xmlStrcmp(node->name, DTD_ELEM_PRIVILEGE) != 0) 562 continue; 563 564 name = xmlGetProp(node, DTD_ATTR_NAME); 565 set = xmlGetProp(node, DTD_ATTR_SET); 566 567 if (name == NULL || set == NULL) { 568 if (name != NULL) 569 xmlFree(name); 570 if (set != NULL) 571 xmlFree(set); 572 return (-1); 573 } 574 575 ret = func(data, (const char *)name, (const char *)set); 576 577 xmlFree(name); 578 xmlFree(set); 579 580 if (ret != 0) 581 return (-1); 582 } 583 584 return (0); 585 } 586 587 static int 588 i_brand_platform_iter_mounts(struct brand_handle *bhp, const char *zoneroot, 589 int (*func)(void *, const char *, const char *, const char *, 590 const char *), void *data, const xmlChar *mount_type) 591 { 592 xmlNodePtr node; 593 xmlChar *special, *dir, *type, *opt; 594 char special_exp[MAXPATHLEN]; 595 char opt_exp[MAXPATHLEN]; 596 int ret; 597 598 if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL) 599 return (-1); 600 601 for (node = node->xmlChildrenNode; node != NULL; node = node->next) { 602 603 if (xmlStrcmp(node->name, mount_type) != 0) 604 continue; 605 606 special = xmlGetProp(node, DTD_ATTR_SPECIAL); 607 dir = xmlGetProp(node, DTD_ATTR_DIRECTORY); 608 type = xmlGetProp(node, DTD_ATTR_TYPE); 609 opt = xmlGetProp(node, DTD_ATTR_OPT); 610 if ((special == NULL) || (dir == NULL) || (type == NULL) || 611 (opt == NULL)) { 612 ret = -1; 613 goto next; 614 } 615 616 /* Substitute token values as needed. */ 617 if ((ret = i_substitute_tokens((char *)special, 618 special_exp, sizeof (special_exp), 619 NULL, zoneroot, NULL, NULL, 0, NULL)) != 0) 620 goto next; 621 622 /* opt might not be defined */ 623 if (strlen((const char *)opt) == 0) { 624 xmlFree(opt); 625 opt = NULL; 626 } else { 627 if ((ret = i_substitute_tokens((char *)opt, 628 opt_exp, sizeof (opt_exp), 629 NULL, zoneroot, NULL, NULL, 0, NULL)) != 0) 630 goto next; 631 } 632 633 ret = func(data, (char *)special_exp, (char *)dir, 634 (char *)type, ((opt != NULL) ? opt_exp : NULL)); 635 636 next: 637 if (special != NULL) 638 xmlFree(special); 639 if (dir != NULL) 640 xmlFree(dir); 641 if (type != NULL) 642 xmlFree(type); 643 if (opt != NULL) 644 xmlFree(opt); 645 if (ret != 0) 646 return (-1); 647 } 648 return (0); 649 } 650 651 652 /* 653 * Iterate over global platform filesystems 654 * 655 * Walks the platform, searching for <global_mount> elements, calling the 656 * specified callback for each. Returns 0 on success, or -1 on failure. 657 * 658 * Perform the following substitutions as necessary: 659 * 660 * %R Root of zone 661 */ 662 int 663 brand_platform_iter_gmounts(brand_handle_t bh, const char *zoneroot, 664 int (*func)(void *, const char *, const char *, const char *, 665 const char *), void *data) 666 { 667 struct brand_handle *bhp = (struct brand_handle *)bh; 668 return (i_brand_platform_iter_mounts(bhp, zoneroot, func, data, 669 DTD_ELEM_GLOBAL_MOUNT)); 670 } 671 672 /* 673 * Iterate over non-global zone platform filesystems 674 * 675 * Walks the platform, searching for <mount> elements, calling the 676 * specified callback for each. Returns 0 on success, or -1 on failure. 677 */ 678 int 679 brand_platform_iter_mounts(brand_handle_t bh, int (*func)(void *, 680 const char *, const char *, const char *, const char *), void *data) 681 { 682 struct brand_handle *bhp = (struct brand_handle *)bh; 683 return (i_brand_platform_iter_mounts(bhp, NULL, func, data, 684 DTD_ELEM_MOUNT)); 685 } 686 687 /* 688 * Iterate over platform symlinks 689 * 690 * Walks the platform, searching for <symlink> elements, calling the 691 * specified callback for each. Returns 0 on success, or -1 on failure. 692 */ 693 int 694 brand_platform_iter_link(brand_handle_t bh, 695 int (*func)(void *, const char *, const char *), void *data) 696 { 697 struct brand_handle *bhp = (struct brand_handle *)bh; 698 xmlNodePtr node; 699 xmlChar *source, *target; 700 int ret; 701 702 if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL) 703 return (-1); 704 705 for (node = node->xmlChildrenNode; node != NULL; node = node->next) { 706 707 if (xmlStrcmp(node->name, DTD_ELEM_SYMLINK) != 0) 708 continue; 709 710 source = xmlGetProp(node, DTD_ATTR_SOURCE); 711 target = xmlGetProp(node, DTD_ATTR_TARGET); 712 713 if (source == NULL || target == NULL) { 714 if (source != NULL) 715 xmlFree(source); 716 if (target != NULL) 717 xmlFree(target); 718 return (-1); 719 } 720 721 ret = func(data, (char *)source, (char *)target); 722 723 xmlFree(source); 724 xmlFree(target); 725 726 if (ret != 0) 727 return (-1); 728 } 729 730 return (0); 731 } 732 733 /* 734 * Iterate over platform devices 735 * 736 * Walks the platform, searching for <device> elements, calling the 737 * specified callback for each. Returns 0 on success, or -1 on failure. 738 */ 739 int 740 brand_platform_iter_devices(brand_handle_t bh, const char *zonename, 741 int (*func)(void *, const char *, const char *), void *data) 742 { 743 struct brand_handle *bhp = (struct brand_handle *)bh; 744 const char *curr_arch = get_curr_arch(); 745 xmlNodePtr node; 746 xmlChar *match, *name, *arch; 747 char match_exp[MAXPATHLEN]; 748 boolean_t err = B_FALSE; 749 int ret = 0; 750 751 752 assert(bhp != NULL); 753 assert(zonename != NULL); 754 assert(func != NULL); 755 756 if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL) 757 return (-1); 758 759 for (node = node->xmlChildrenNode; node != NULL; node = node->next) { 760 761 if (xmlStrcmp(node->name, DTD_ELEM_DEVICE) != 0) 762 continue; 763 764 match = xmlGetProp(node, DTD_ATTR_MATCH); 765 name = xmlGetProp(node, DTD_ATTR_NAME); 766 arch = xmlGetProp(node, DTD_ATTR_ARCH); 767 if ((match == NULL) || (name == NULL) || (arch == NULL)) { 768 err = B_TRUE; 769 goto next; 770 } 771 772 /* check if the arch matches */ 773 if ((strcmp((char *)arch, "all") != 0) && 774 (strcmp((char *)arch, curr_arch) != 0)) 775 goto next; 776 777 /* Substitute token values as needed. */ 778 if ((ret = i_substitute_tokens((char *)match, 779 match_exp, sizeof (match_exp), 780 zonename, NULL, NULL, NULL, 0, NULL)) != 0) { 781 err = B_TRUE; 782 goto next; 783 } 784 785 /* name might not be defined */ 786 if (strlen((const char *)name) == 0) { 787 xmlFree(name); 788 name = NULL; 789 } 790 791 /* invoke the callback */ 792 ret = func(data, (const char *)match_exp, (const char *)name); 793 794 next: 795 if (match != NULL) 796 xmlFree(match); 797 if (name != NULL) 798 xmlFree(name); 799 if (arch != NULL) 800 xmlFree(arch); 801 if (err) 802 return (-1); 803 if (ret != 0) 804 return (-1); 805 } 806 807 return (0); 808 } 809