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, 581 int (*func)(void *, priv_iter_t *), void *data) 582 { 583 struct brand_handle *bhp = (struct brand_handle *)bh; 584 xmlNodePtr node; 585 xmlChar *name, *set, *iptype; 586 priv_iter_t priv_iter; 587 int ret; 588 589 if ((node = xmlDocGetRootElement(bhp->bh_config)) == NULL) 590 return (-1); 591 592 for (node = node->xmlChildrenNode; node != NULL; node = node->next) { 593 594 if (xmlStrcmp(node->name, DTD_ELEM_PRIVILEGE) != 0) 595 continue; 596 597 name = xmlGetProp(node, DTD_ATTR_NAME); 598 set = xmlGetProp(node, DTD_ATTR_SET); 599 iptype = xmlGetProp(node, DTD_ATTR_IPTYPE); 600 601 if (name == NULL || set == NULL || iptype == NULL) { 602 if (name != NULL) 603 xmlFree(name); 604 if (set != NULL) 605 xmlFree(set); 606 if (iptype != NULL) 607 xmlFree(iptype); 608 return (-1); 609 } 610 611 priv_iter.pi_name = (char *)name; 612 priv_iter.pi_set = (char *)set; 613 priv_iter.pi_iptype = (char *)iptype; 614 615 ret = func(data, &priv_iter); 616 617 xmlFree(name); 618 xmlFree(set); 619 xmlFree(iptype); 620 621 if (ret != 0) 622 return (-1); 623 } 624 625 return (0); 626 } 627 628 static int 629 i_brand_platform_iter_mounts(struct brand_handle *bhp, const char *zoneroot, 630 int (*func)(void *, const char *, const char *, const char *, 631 const char *), void *data, const xmlChar *mount_type) 632 { 633 xmlNodePtr node; 634 xmlChar *special, *dir, *type, *opt; 635 char special_exp[MAXPATHLEN]; 636 char opt_exp[MAXPATHLEN]; 637 int ret; 638 639 if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL) 640 return (-1); 641 642 for (node = node->xmlChildrenNode; node != NULL; node = node->next) { 643 644 if (xmlStrcmp(node->name, mount_type) != 0) 645 continue; 646 647 special = xmlGetProp(node, DTD_ATTR_SPECIAL); 648 dir = xmlGetProp(node, DTD_ATTR_DIRECTORY); 649 type = xmlGetProp(node, DTD_ATTR_TYPE); 650 opt = xmlGetProp(node, DTD_ATTR_OPT); 651 if ((special == NULL) || (dir == NULL) || (type == NULL) || 652 (opt == NULL)) { 653 ret = -1; 654 goto next; 655 } 656 657 /* Substitute token values as needed. */ 658 if ((ret = i_substitute_tokens((char *)special, 659 special_exp, sizeof (special_exp), 660 NULL, zoneroot, NULL, NULL, 0, NULL)) != 0) 661 goto next; 662 663 /* opt might not be defined */ 664 if (strlen((const char *)opt) == 0) { 665 xmlFree(opt); 666 opt = NULL; 667 } else { 668 if ((ret = i_substitute_tokens((char *)opt, 669 opt_exp, sizeof (opt_exp), 670 NULL, zoneroot, NULL, NULL, 0, NULL)) != 0) 671 goto next; 672 } 673 674 ret = func(data, (char *)special_exp, (char *)dir, 675 (char *)type, ((opt != NULL) ? opt_exp : NULL)); 676 677 next: 678 if (special != NULL) 679 xmlFree(special); 680 if (dir != NULL) 681 xmlFree(dir); 682 if (type != NULL) 683 xmlFree(type); 684 if (opt != NULL) 685 xmlFree(opt); 686 if (ret != 0) 687 return (-1); 688 } 689 return (0); 690 } 691 692 693 /* 694 * Iterate over global platform filesystems 695 * 696 * Walks the platform, searching for <global_mount> elements, calling the 697 * specified callback for each. Returns 0 on success, or -1 on failure. 698 * 699 * Perform the following substitutions as necessary: 700 * 701 * %R Root of zone 702 */ 703 int 704 brand_platform_iter_gmounts(brand_handle_t bh, const char *zoneroot, 705 int (*func)(void *, const char *, const char *, const char *, 706 const char *), void *data) 707 { 708 struct brand_handle *bhp = (struct brand_handle *)bh; 709 return (i_brand_platform_iter_mounts(bhp, zoneroot, func, data, 710 DTD_ELEM_GLOBAL_MOUNT)); 711 } 712 713 /* 714 * Iterate over non-global zone platform filesystems 715 * 716 * Walks the platform, searching for <mount> elements, calling the 717 * specified callback for each. Returns 0 on success, or -1 on failure. 718 */ 719 int 720 brand_platform_iter_mounts(brand_handle_t bh, int (*func)(void *, 721 const char *, const char *, const char *, const char *), void *data) 722 { 723 struct brand_handle *bhp = (struct brand_handle *)bh; 724 return (i_brand_platform_iter_mounts(bhp, NULL, func, data, 725 DTD_ELEM_MOUNT)); 726 } 727 728 /* 729 * Iterate over platform symlinks 730 * 731 * Walks the platform, searching for <symlink> elements, calling the 732 * specified callback for each. Returns 0 on success, or -1 on failure. 733 */ 734 int 735 brand_platform_iter_link(brand_handle_t bh, 736 int (*func)(void *, const char *, const char *), void *data) 737 { 738 struct brand_handle *bhp = (struct brand_handle *)bh; 739 xmlNodePtr node; 740 xmlChar *source, *target; 741 int ret; 742 743 if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL) 744 return (-1); 745 746 for (node = node->xmlChildrenNode; node != NULL; node = node->next) { 747 748 if (xmlStrcmp(node->name, DTD_ELEM_SYMLINK) != 0) 749 continue; 750 751 source = xmlGetProp(node, DTD_ATTR_SOURCE); 752 target = xmlGetProp(node, DTD_ATTR_TARGET); 753 754 if (source == NULL || target == NULL) { 755 if (source != NULL) 756 xmlFree(source); 757 if (target != NULL) 758 xmlFree(target); 759 return (-1); 760 } 761 762 ret = func(data, (char *)source, (char *)target); 763 764 xmlFree(source); 765 xmlFree(target); 766 767 if (ret != 0) 768 return (-1); 769 } 770 771 return (0); 772 } 773 774 /* 775 * Iterate over platform devices 776 * 777 * Walks the platform, searching for <device> elements, calling the 778 * specified callback for each. Returns 0 on success, or -1 on failure. 779 */ 780 int 781 brand_platform_iter_devices(brand_handle_t bh, const char *zonename, 782 int (*func)(void *, const char *, const char *), void *data, 783 const char *curr_iptype) 784 { 785 struct brand_handle *bhp = (struct brand_handle *)bh; 786 const char *curr_arch = get_curr_arch(); 787 xmlNodePtr node; 788 xmlChar *match, *name, *arch, *iptype; 789 char match_exp[MAXPATHLEN]; 790 boolean_t err = B_FALSE; 791 int ret = 0; 792 793 794 assert(bhp != NULL); 795 assert(zonename != NULL); 796 assert(func != NULL); 797 assert(curr_iptype != NULL); 798 799 if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL) 800 return (-1); 801 802 for (node = node->xmlChildrenNode; node != NULL; node = node->next) { 803 804 if (xmlStrcmp(node->name, DTD_ELEM_DEVICE) != 0) 805 continue; 806 807 match = xmlGetProp(node, DTD_ATTR_MATCH); 808 name = xmlGetProp(node, DTD_ATTR_NAME); 809 arch = xmlGetProp(node, DTD_ATTR_ARCH); 810 iptype = xmlGetProp(node, DTD_ATTR_IPTYPE); 811 if ((match == NULL) || (name == NULL) || (arch == NULL) || 812 (iptype == NULL)) { 813 err = B_TRUE; 814 goto next; 815 } 816 817 /* check if the arch matches */ 818 if ((strcmp((char *)arch, "all") != 0) && 819 (strcmp((char *)arch, curr_arch) != 0)) 820 goto next; 821 822 /* check if the iptype matches */ 823 if ((strcmp((char *)iptype, "all") != 0) && 824 (strcmp((char *)iptype, curr_iptype) != 0)) 825 goto next; 826 827 /* Substitute token values as needed. */ 828 if ((ret = i_substitute_tokens((char *)match, 829 match_exp, sizeof (match_exp), 830 zonename, NULL, NULL, NULL, 0, NULL)) != 0) { 831 err = B_TRUE; 832 goto next; 833 } 834 835 /* name might not be defined */ 836 if (strlen((const char *)name) == 0) { 837 xmlFree(name); 838 name = NULL; 839 } 840 841 /* invoke the callback */ 842 ret = func(data, (const char *)match_exp, (const char *)name); 843 844 next: 845 if (match != NULL) 846 xmlFree(match); 847 if (name != NULL) 848 xmlFree(name); 849 if (arch != NULL) 850 xmlFree(arch); 851 if (iptype != NULL) 852 xmlFree(iptype); 853 if (err) 854 return (-1); 855 if (ret != 0) 856 return (-1); 857 } 858 859 return (0); 860 } 861