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