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 (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 25 */ 26 27 #include <assert.h> 28 #include <dirent.h> 29 #include <errno.h> 30 #include <fnmatch.h> 31 #include <signal.h> 32 #include <stdlib.h> 33 #include <unistd.h> 34 #include <strings.h> 35 #include <synch.h> 36 #include <sys/brand.h> 37 #include <sys/fcntl.h> 38 #include <sys/param.h> 39 #include <sys/stat.h> 40 #include <sys/systeminfo.h> 41 #include <sys/types.h> 42 #include <thread.h> 43 #include <zone.h> 44 45 #include <libbrand_impl.h> 46 #include <libbrand.h> 47 48 #define DTD_ELEM_ATTACH ((const xmlChar *) "attach") 49 #define DTD_ELEM_BOOT ((const xmlChar *) "boot") 50 #define DTD_ELEM_BRAND ((const xmlChar *) "brand") 51 #define DTD_ELEM_CLONE ((const xmlChar *) "clone") 52 #define DTD_ELEM_COMMENT ((const xmlChar *) "comment") 53 #define DTD_ELEM_DETACH ((const xmlChar *) "detach") 54 #define DTD_ELEM_DEVICE ((const xmlChar *) "device") 55 #define DTD_ELEM_GLOBAL_MOUNT ((const xmlChar *) "global_mount") 56 #define DTD_ELEM_HALT ((const xmlChar *) "halt") 57 #define DTD_ELEM_INITNAME ((const xmlChar *) "initname") 58 #define DTD_ELEM_INSTALL ((const xmlChar *) "install") 59 #define DTD_ELEM_INSTALLOPTS ((const xmlChar *) "installopts") 60 #define DTD_ELEM_LOGIN_CMD ((const xmlChar *) "login_cmd") 61 #define DTD_ELEM_FORCELOGIN_CMD ((const xmlChar *) "forcedlogin_cmd") 62 #define DTD_ELEM_MODNAME ((const xmlChar *) "modname") 63 #define DTD_ELEM_MOUNT ((const xmlChar *) "mount") 64 #define DTD_ELEM_POSTATTACH ((const xmlChar *) "postattach") 65 #define DTD_ELEM_POSTCLONE ((const xmlChar *) "postclone") 66 #define DTD_ELEM_POSTINSTALL ((const xmlChar *) "postinstall") 67 #define DTD_ELEM_POSTSNAP ((const xmlChar *) "postsnap") 68 #define DTD_ELEM_POSTSTATECHG ((const xmlChar *) "poststatechange") 69 #define DTD_ELEM_PREDETACH ((const xmlChar *) "predetach") 70 #define DTD_ELEM_PRESNAP ((const xmlChar *) "presnap") 71 #define DTD_ELEM_PRESTATECHG ((const xmlChar *) "prestatechange") 72 #define DTD_ELEM_PREUNINSTALL ((const xmlChar *) "preuninstall") 73 #define DTD_ELEM_PRIVILEGE ((const xmlChar *) "privilege") 74 #define DTD_ELEM_QUERY ((const xmlChar *) "query") 75 #define DTD_ELEM_SHUTDOWN ((const xmlChar *) "shutdown") 76 #define DTD_ELEM_SYMLINK ((const xmlChar *) "symlink") 77 #define DTD_ELEM_SYSBOOT ((const xmlChar *) "sysboot") 78 #define DTD_ELEM_UNINSTALL ((const xmlChar *) "uninstall") 79 #define DTD_ELEM_USER_CMD ((const xmlChar *) "user_cmd") 80 #define DTD_ELEM_VALIDSNAP ((const xmlChar *) "validatesnap") 81 #define DTD_ELEM_VERIFY_CFG ((const xmlChar *) "verify_cfg") 82 #define DTD_ELEM_VERIFY_ADM ((const xmlChar *) "verify_adm") 83 84 #define DTD_ATTR_ALLOWEXCL ((const xmlChar *) "allow-exclusive-ip") 85 #define DTD_ATTR_ARCH ((const xmlChar *) "arch") 86 #define DTD_ATTR_DIRECTORY ((const xmlChar *) "directory") 87 #define DTD_ATTR_IPTYPE ((const xmlChar *) "ip-type") 88 #define DTD_ATTR_MATCH ((const xmlChar *) "match") 89 #define DTD_ATTR_MODE ((const xmlChar *) "mode") 90 #define DTD_ATTR_NAME ((const xmlChar *) "name") 91 #define DTD_ATTR_OPT ((const xmlChar *) "opt") 92 #define DTD_ATTR_PATH ((const xmlChar *) "path") 93 #define DTD_ATTR_SET ((const xmlChar *) "set") 94 #define DTD_ATTR_SOURCE ((const xmlChar *) "source") 95 #define DTD_ATTR_SPECIAL ((const xmlChar *) "special") 96 #define DTD_ATTR_TARGET ((const xmlChar *) "target") 97 #define DTD_ATTR_TYPE ((const xmlChar *) "type") 98 99 #define DTD_ENTITY_TRUE "true" 100 101 static volatile boolean_t libbrand_initialized = B_FALSE; 102 static char i_curr_arch[MAXNAMELEN]; 103 static char i_curr_zone[ZONENAME_MAX]; 104 105 /*ARGSUSED*/ 106 static void 107 brand_error_func(void *ctx, const char *msg, ...) 108 { 109 /* 110 * Ignore error messages from libxml 111 */ 112 } 113 114 static boolean_t 115 libbrand_initialize() 116 { 117 static mutex_t initialize_lock = DEFAULTMUTEX; 118 119 (void) mutex_lock(&initialize_lock); 120 121 if (libbrand_initialized) { 122 (void) mutex_unlock(&initialize_lock); 123 return (B_TRUE); 124 } 125 126 if (sysinfo(SI_ARCHITECTURE, i_curr_arch, sizeof (i_curr_arch)) < 0) { 127 (void) mutex_unlock(&initialize_lock); 128 return (B_FALSE); 129 } 130 131 if (getzonenamebyid(getzoneid(), i_curr_zone, 132 sizeof (i_curr_zone)) < 0) { 133 (void) mutex_unlock(&initialize_lock); 134 return (B_FALSE); 135 } 136 137 /* 138 * Note that here we're initializing per-process libxml2 139 * state. By doing so we're implicitly assuming that 140 * no other code in this process is also trying to 141 * use libxml2. But in most case we know this not to 142 * be true since we're almost always used in conjunction 143 * with libzonecfg, which also uses libxml2. Lucky for 144 * us, libzonecfg initializes libxml2 to essentially 145 * the same defaults as we're using below. 146 */ 147 (void) xmlLineNumbersDefault(1); 148 xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS; 149 xmlDoValidityCheckingDefaultValue = 1; 150 (void) xmlKeepBlanksDefault(0); 151 xmlGetWarningsDefaultValue = 0; 152 xmlSetGenericErrorFunc(NULL, brand_error_func); 153 154 libbrand_initialized = B_TRUE; 155 (void) mutex_unlock(&initialize_lock); 156 return (B_TRUE); 157 } 158 159 static const char * 160 get_curr_arch(void) 161 { 162 if (!libbrand_initialize()) 163 return (NULL); 164 165 return (i_curr_arch); 166 } 167 168 static const char * 169 get_curr_zone(void) 170 { 171 if (!libbrand_initialize()) 172 return (NULL); 173 174 return (i_curr_zone); 175 } 176 177 /* 178 * Internal function to open an XML file 179 * 180 * Returns the XML doc pointer, or NULL on failure. It will validate the 181 * document, as well as removing any comments from the document structure. 182 */ 183 static xmlDocPtr 184 open_xml_file(const char *file) 185 { 186 xmlDocPtr doc; 187 xmlValidCtxtPtr cvp; 188 int valid; 189 190 if (!libbrand_initialize()) 191 return (NULL); 192 193 /* 194 * Parse the file 195 */ 196 if ((doc = xmlParseFile(file)) == NULL) 197 return (NULL); 198 199 /* 200 * Validate the file 201 */ 202 if ((cvp = xmlNewValidCtxt()) == NULL) { 203 xmlFreeDoc(doc); 204 return (NULL); 205 } 206 cvp->error = brand_error_func; 207 cvp->warning = brand_error_func; 208 valid = xmlValidateDocument(cvp, doc); 209 xmlFreeValidCtxt(cvp); 210 if (valid == 0) { 211 xmlFreeDoc(doc); 212 return (NULL); 213 } 214 215 return (doc); 216 } 217 /* 218 * Open a handle to the named brand. 219 * 220 * Returns a handle to the named brand, which is used for all subsequent brand 221 * interaction, or NULL if unable to open or initialize the brand. 222 */ 223 brand_handle_t 224 brand_open(const char *name) 225 { 226 struct brand_handle *bhp; 227 char path[MAXPATHLEN]; 228 xmlNodePtr node; 229 xmlChar *property; 230 struct stat statbuf; 231 232 /* 233 * Make sure brand name isn't too long 234 */ 235 if (strlen(name) >= MAXNAMELEN) 236 return (NULL); 237 238 /* 239 * Check that the brand exists 240 */ 241 (void) snprintf(path, sizeof (path), "%s/%s", BRAND_DIR, name); 242 243 if (stat(path, &statbuf) != 0) 244 return (NULL); 245 246 /* 247 * Allocate brand handle 248 */ 249 if ((bhp = malloc(sizeof (struct brand_handle))) == NULL) 250 return (NULL); 251 bzero(bhp, sizeof (struct brand_handle)); 252 253 (void) strcpy(bhp->bh_name, name); 254 255 /* 256 * Open the configuration file 257 */ 258 (void) snprintf(path, sizeof (path), "%s/%s/%s", BRAND_DIR, name, 259 BRAND_CONFIG); 260 if ((bhp->bh_config = open_xml_file(path)) == NULL) { 261 brand_close((brand_handle_t)bhp); 262 return (NULL); 263 } 264 265 /* 266 * Verify that the name of the brand matches the directory in which it 267 * is installed. 268 */ 269 if ((node = xmlDocGetRootElement(bhp->bh_config)) == NULL) { 270 brand_close((brand_handle_t)bhp); 271 return (NULL); 272 } 273 274 if (xmlStrcmp(node->name, DTD_ELEM_BRAND) != 0) { 275 brand_close((brand_handle_t)bhp); 276 return (NULL); 277 } 278 279 if ((property = xmlGetProp(node, DTD_ATTR_NAME)) == NULL) { 280 brand_close((brand_handle_t)bhp); 281 return (NULL); 282 } 283 284 if (strcmp((char *)property, name) != 0) { 285 xmlFree(property); 286 brand_close((brand_handle_t)bhp); 287 return (NULL); 288 } 289 xmlFree(property); 290 291 /* 292 * Open handle to platform configuration file. 293 */ 294 (void) snprintf(path, sizeof (path), "%s/%s/%s", BRAND_DIR, name, 295 BRAND_PLATFORM); 296 if ((bhp->bh_platform = open_xml_file(path)) == NULL) { 297 brand_close((brand_handle_t)bhp); 298 return (NULL); 299 } 300 301 return ((brand_handle_t)bhp); 302 } 303 304 /* 305 * Closes the given brand handle 306 */ 307 void 308 brand_close(brand_handle_t bh) 309 { 310 struct brand_handle *bhp = (struct brand_handle *)bh; 311 if (bhp->bh_platform != NULL) 312 xmlFreeDoc(bhp->bh_platform); 313 if (bhp->bh_config != NULL) 314 xmlFreeDoc(bhp->bh_config); 315 free(bhp); 316 } 317 318 static int 319 i_substitute_tokens(const char *sbuf, char *dbuf, int dbuf_size, 320 const char *zonename, const char *zonepath, const char *username, 321 const char *curr_zone) 322 { 323 int dst, src; 324 325 /* 326 * Walk through the characters, substituting values as needed. 327 */ 328 dbuf[0] = '\0'; 329 dst = 0; 330 for (src = 0; src < strlen((char *)sbuf) && dst < dbuf_size; src++) { 331 if (sbuf[src] != '%') { 332 dbuf[dst++] = sbuf[src]; 333 continue; 334 } 335 336 switch (sbuf[++src]) { 337 case '%': 338 dst += strlcpy(dbuf + dst, "%", dbuf_size - dst); 339 break; 340 case 'R': 341 if (zonepath == NULL) 342 break; 343 dst += strlcpy(dbuf + dst, zonepath, dbuf_size - dst); 344 break; 345 case 'u': 346 if (username == NULL) 347 break; 348 dst += strlcpy(dbuf + dst, username, dbuf_size - dst); 349 break; 350 case 'Z': 351 if (curr_zone == NULL) 352 break; 353 /* name of the zone we're running in */ 354 dst += strlcpy(dbuf + dst, curr_zone, dbuf_size - dst); 355 break; 356 case 'z': 357 /* name of the zone we're operating on */ 358 if (zonename == NULL) 359 break; 360 dst += strlcpy(dbuf + dst, zonename, dbuf_size - dst); 361 break; 362 } 363 } 364 365 if (dst >= dbuf_size) 366 return (-1); 367 368 dbuf[dst] = '\0'; 369 return (0); 370 } 371 372 /* 373 * Retrieve the given tag from the brand. 374 * Perform the following substitutions as necessary: 375 * 376 * %% % 377 * %u Username 378 * %z Name of target zone 379 * %Z Name of current zone 380 * %R Zonepath of zone 381 * 382 * Returns 0 on success, -1 on failure. 383 */ 384 static int 385 brand_get_value(struct brand_handle *bhp, const char *zonename, 386 const char *zonepath, const char *username, const char *curr_zone, 387 char *buf, size_t len, const xmlChar *tagname, 388 boolean_t substitute, boolean_t optional) 389 { 390 xmlNodePtr node; 391 xmlChar *content; 392 int err = 0; 393 394 /* 395 * Retrieve the specified value from the XML doc 396 */ 397 if ((node = xmlDocGetRootElement(bhp->bh_config)) == NULL) 398 return (-1); 399 400 if (xmlStrcmp(node->name, DTD_ELEM_BRAND) != 0) 401 return (-1); 402 403 for (node = node->xmlChildrenNode; node != NULL; 404 node = node->next) { 405 if (xmlStrcmp(node->name, tagname) == 0) 406 break; 407 } 408 409 if (node == NULL) { 410 if (optional) { 411 buf[0] = '\0'; 412 return (0); 413 } else { 414 return (-1); 415 } 416 } 417 418 if ((content = xmlNodeGetContent(node)) == NULL) 419 return (-1); 420 421 if (strlen((char *)content) == 0) { 422 /* 423 * If the entry in the config file is empty, check to see 424 * whether this is an optional field. If so, we return the 425 * empty buffer. If not, we return an error. 426 */ 427 if (optional) { 428 buf[0] = '\0'; 429 } else { 430 err = -1; 431 } 432 } else { 433 /* Substitute token values as needed. */ 434 if (substitute) { 435 if (i_substitute_tokens((char *)content, buf, len, 436 zonename, zonepath, username, curr_zone) != 0) 437 err = -1; 438 } else { 439 if (strlcpy(buf, (char *)content, len) >= len) 440 err = -1; 441 } 442 } 443 444 xmlFree(content); 445 446 return (err); 447 } 448 449 int 450 brand_get_attach(brand_handle_t bh, const char *zonename, 451 const char *zonepath, char *buf, size_t len) 452 { 453 struct brand_handle *bhp = (struct brand_handle *)bh; 454 return (brand_get_value(bhp, zonename, zonepath, NULL, NULL, 455 buf, len, DTD_ELEM_ATTACH, B_TRUE, B_TRUE)); 456 } 457 458 int 459 brand_get_boot(brand_handle_t bh, const char *zonename, 460 const char *zonepath, char *buf, size_t len) 461 { 462 struct brand_handle *bhp = (struct brand_handle *)bh; 463 return (brand_get_value(bhp, zonename, zonepath, NULL, NULL, 464 buf, len, DTD_ELEM_BOOT, B_TRUE, B_TRUE)); 465 } 466 467 int 468 brand_get_brandname(brand_handle_t bh, char *buf, size_t len) 469 { 470 struct brand_handle *bhp = (struct brand_handle *)bh; 471 if (len <= strlen(bhp->bh_name)) 472 return (-1); 473 474 (void) strcpy(buf, bhp->bh_name); 475 476 return (0); 477 } 478 479 int 480 brand_get_clone(brand_handle_t bh, const char *zonename, 481 const char *zonepath, char *buf, size_t len) 482 { 483 struct brand_handle *bhp = (struct brand_handle *)bh; 484 return (brand_get_value(bhp, zonename, zonepath, NULL, NULL, 485 buf, len, DTD_ELEM_CLONE, B_TRUE, B_TRUE)); 486 } 487 488 int 489 brand_get_detach(brand_handle_t bh, const char *zonename, 490 const char *zonepath, char *buf, size_t len) 491 { 492 struct brand_handle *bhp = (struct brand_handle *)bh; 493 return (brand_get_value(bhp, zonename, zonepath, NULL, NULL, 494 buf, len, DTD_ELEM_DETACH, B_TRUE, B_TRUE)); 495 } 496 497 int 498 brand_get_halt(brand_handle_t bh, const char *zonename, 499 const char *zonepath, char *buf, size_t len) 500 { 501 struct brand_handle *bhp = (struct brand_handle *)bh; 502 return (brand_get_value(bhp, zonename, zonepath, NULL, NULL, 503 buf, len, DTD_ELEM_HALT, B_TRUE, B_TRUE)); 504 } 505 506 int 507 brand_get_shutdown(brand_handle_t bh, const char *zonename, 508 const char *zonepath, char *buf, size_t len) 509 { 510 struct brand_handle *bhp = (struct brand_handle *)bh; 511 return (brand_get_value(bhp, zonename, zonepath, NULL, NULL, 512 buf, len, DTD_ELEM_SHUTDOWN, B_TRUE, B_TRUE)); 513 } 514 515 int 516 brand_get_initname(brand_handle_t bh, char *buf, size_t len) 517 { 518 struct brand_handle *bhp = (struct brand_handle *)bh; 519 return (brand_get_value(bhp, NULL, NULL, NULL, NULL, 520 buf, len, DTD_ELEM_INITNAME, B_FALSE, B_FALSE)); 521 } 522 523 int 524 brand_get_login_cmd(brand_handle_t bh, const char *username, 525 char *buf, size_t len) 526 { 527 struct brand_handle *bhp = (struct brand_handle *)bh; 528 const char *curr_zone = get_curr_zone(); 529 return (brand_get_value(bhp, NULL, NULL, username, curr_zone, 530 buf, len, DTD_ELEM_LOGIN_CMD, B_TRUE, B_FALSE)); 531 } 532 533 int 534 brand_get_forcedlogin_cmd(brand_handle_t bh, const char *username, 535 char *buf, size_t len) 536 { 537 struct brand_handle *bhp = (struct brand_handle *)bh; 538 const char *curr_zone = get_curr_zone(); 539 return (brand_get_value(bhp, NULL, NULL, username, curr_zone, 540 buf, len, DTD_ELEM_FORCELOGIN_CMD, B_TRUE, B_FALSE)); 541 } 542 543 int 544 brand_get_user_cmd(brand_handle_t bh, const char *username, 545 char *buf, size_t len) 546 { 547 struct brand_handle *bhp = (struct brand_handle *)bh; 548 549 return (brand_get_value(bhp, NULL, NULL, username, NULL, 550 buf, len, DTD_ELEM_USER_CMD, B_TRUE, B_FALSE)); 551 } 552 553 int 554 brand_get_install(brand_handle_t bh, const char *zonename, 555 const char *zonepath, char *buf, size_t len) 556 { 557 struct brand_handle *bhp = (struct brand_handle *)bh; 558 return (brand_get_value(bhp, zonename, zonepath, NULL, NULL, 559 buf, len, DTD_ELEM_INSTALL, B_TRUE, B_FALSE)); 560 } 561 562 int 563 brand_get_installopts(brand_handle_t bh, char *buf, size_t len) 564 { 565 struct brand_handle *bhp = (struct brand_handle *)bh; 566 return (brand_get_value(bhp, NULL, NULL, NULL, NULL, 567 buf, len, DTD_ELEM_INSTALLOPTS, B_FALSE, B_TRUE)); 568 } 569 570 int 571 brand_get_modname(brand_handle_t bh, char *buf, size_t len) 572 { 573 struct brand_handle *bhp = (struct brand_handle *)bh; 574 return (brand_get_value(bhp, NULL, NULL, NULL, NULL, 575 buf, len, DTD_ELEM_MODNAME, B_FALSE, B_TRUE)); 576 } 577 578 int 579 brand_get_postattach(brand_handle_t bh, const char *zonename, 580 const char *zonepath, char *buf, size_t len) 581 { 582 struct brand_handle *bhp = (struct brand_handle *)bh; 583 return (brand_get_value(bhp, zonename, zonepath, NULL, NULL, 584 buf, len, DTD_ELEM_POSTATTACH, B_TRUE, B_TRUE)); 585 } 586 587 int 588 brand_get_postclone(brand_handle_t bh, const char *zonename, 589 const char *zonepath, char *buf, size_t len) 590 { 591 struct brand_handle *bhp = (struct brand_handle *)bh; 592 return (brand_get_value(bhp, zonename, zonepath, NULL, NULL, 593 buf, len, DTD_ELEM_POSTCLONE, B_TRUE, B_TRUE)); 594 } 595 596 int 597 brand_get_postinstall(brand_handle_t bh, const char *zonename, 598 const char *zonepath, char *buf, size_t len) 599 { 600 struct brand_handle *bhp = (struct brand_handle *)bh; 601 return (brand_get_value(bhp, zonename, zonepath, NULL, NULL, 602 buf, len, DTD_ELEM_POSTINSTALL, B_TRUE, B_TRUE)); 603 } 604 605 int 606 brand_get_postsnap(brand_handle_t bh, const char *zonename, 607 const char *zonepath, char *buf, size_t len) 608 { 609 struct brand_handle *bhp = (struct brand_handle *)bh; 610 return (brand_get_value(bhp, zonename, zonepath, NULL, NULL, 611 buf, len, DTD_ELEM_POSTSNAP, B_TRUE, B_TRUE)); 612 } 613 614 int 615 brand_get_poststatechange(brand_handle_t bh, const char *zonename, 616 const char *zonepath, char *buf, size_t len) 617 { 618 struct brand_handle *bhp = (struct brand_handle *)bh; 619 return (brand_get_value(bhp, zonename, zonepath, NULL, NULL, 620 buf, len, DTD_ELEM_POSTSTATECHG, B_TRUE, B_TRUE)); 621 } 622 623 int 624 brand_get_predetach(brand_handle_t bh, const char *zonename, 625 const char *zonepath, char *buf, size_t len) 626 { 627 struct brand_handle *bhp = (struct brand_handle *)bh; 628 return (brand_get_value(bhp, zonename, zonepath, NULL, NULL, 629 buf, len, DTD_ELEM_PREDETACH, B_TRUE, B_TRUE)); 630 } 631 632 int 633 brand_get_presnap(brand_handle_t bh, const char *zonename, 634 const char *zonepath, char *buf, size_t len) 635 { 636 struct brand_handle *bhp = (struct brand_handle *)bh; 637 return (brand_get_value(bhp, zonename, zonepath, NULL, NULL, 638 buf, len, DTD_ELEM_PRESNAP, B_TRUE, B_TRUE)); 639 } 640 641 int 642 brand_get_prestatechange(brand_handle_t bh, const char *zonename, 643 const char *zonepath, char *buf, size_t len) 644 { 645 struct brand_handle *bhp = (struct brand_handle *)bh; 646 return (brand_get_value(bhp, zonename, zonepath, NULL, NULL, 647 buf, len, DTD_ELEM_PRESTATECHG, B_TRUE, B_TRUE)); 648 } 649 650 int 651 brand_get_preuninstall(brand_handle_t bh, const char *zonename, 652 const char *zonepath, char *buf, size_t len) 653 { 654 struct brand_handle *bhp = (struct brand_handle *)bh; 655 return (brand_get_value(bhp, zonename, zonepath, NULL, NULL, 656 buf, len, DTD_ELEM_PREUNINSTALL, B_TRUE, B_TRUE)); 657 } 658 659 int 660 brand_get_query(brand_handle_t bh, const char *zonename, 661 const char *zonepath, char *buf, size_t len) 662 { 663 struct brand_handle *bhp = (struct brand_handle *)bh; 664 return (brand_get_value(bhp, zonename, zonepath, NULL, NULL, 665 buf, len, DTD_ELEM_QUERY, B_TRUE, B_TRUE)); 666 } 667 668 int 669 brand_get_uninstall(brand_handle_t bh, const char *zonename, 670 const char *zonepath, char *buf, size_t len) 671 { 672 struct brand_handle *bhp = (struct brand_handle *)bh; 673 return (brand_get_value(bhp, zonename, zonepath, NULL, NULL, 674 buf, len, DTD_ELEM_UNINSTALL, B_TRUE, B_TRUE)); 675 } 676 677 int 678 brand_get_validatesnap(brand_handle_t bh, const char *zonename, 679 const char *zonepath, char *buf, size_t len) 680 { 681 struct brand_handle *bhp = (struct brand_handle *)bh; 682 return (brand_get_value(bhp, zonename, zonepath, NULL, NULL, 683 buf, len, DTD_ELEM_VALIDSNAP, B_TRUE, B_TRUE)); 684 } 685 686 int 687 brand_get_verify_cfg(brand_handle_t bh, char *buf, size_t len) 688 { 689 struct brand_handle *bhp = (struct brand_handle *)bh; 690 return (brand_get_value(bhp, NULL, NULL, NULL, NULL, 691 buf, len, DTD_ELEM_VERIFY_CFG, B_FALSE, B_TRUE)); 692 } 693 694 int 695 brand_get_verify_adm(brand_handle_t bh, const char *zonename, 696 const char *zonepath, char *buf, size_t len) 697 { 698 struct brand_handle *bhp = (struct brand_handle *)bh; 699 return (brand_get_value(bhp, zonename, zonepath, NULL, NULL, 700 buf, len, DTD_ELEM_VERIFY_ADM, B_TRUE, B_TRUE)); 701 } 702 703 int 704 brand_get_sysboot(brand_handle_t bh, const char *zonename, 705 const char *zonepath, char *buf, size_t len) 706 { 707 struct brand_handle *bhp = (struct brand_handle *)bh; 708 return (brand_get_value(bhp, zonename, zonepath, NULL, NULL, 709 buf, len, DTD_ELEM_SYSBOOT, B_TRUE, B_TRUE)); 710 } 711 712 boolean_t 713 brand_allow_exclusive_ip(brand_handle_t bh) 714 { 715 struct brand_handle *bhp = (struct brand_handle *)bh; 716 xmlNodePtr node; 717 xmlChar *allow_excl; 718 boolean_t ret; 719 720 assert(bhp != NULL); 721 722 if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL) 723 return (B_FALSE); 724 725 allow_excl = xmlGetProp(node, DTD_ATTR_ALLOWEXCL); 726 if (allow_excl == NULL) 727 return (B_FALSE); 728 729 /* Note: only return B_TRUE if it's "true" */ 730 if (strcmp((char *)allow_excl, DTD_ENTITY_TRUE) == 0) 731 ret = B_TRUE; 732 else 733 ret = B_FALSE; 734 735 xmlFree(allow_excl); 736 737 return (ret); 738 } 739 740 /* 741 * Iterate over brand privileges 742 * 743 * Walks the brand config, searching for <privilege> elements, calling the 744 * specified callback for each. Returns 0 on success, or -1 on failure. 745 */ 746 int 747 brand_config_iter_privilege(brand_handle_t bh, 748 int (*func)(void *, priv_iter_t *), void *data) 749 { 750 struct brand_handle *bhp = (struct brand_handle *)bh; 751 xmlNodePtr node; 752 xmlChar *name, *set, *iptype; 753 priv_iter_t priv_iter; 754 int ret; 755 756 if ((node = xmlDocGetRootElement(bhp->bh_config)) == NULL) 757 return (-1); 758 759 for (node = node->xmlChildrenNode; node != NULL; node = node->next) { 760 761 if (xmlStrcmp(node->name, DTD_ELEM_PRIVILEGE) != 0) 762 continue; 763 764 name = xmlGetProp(node, DTD_ATTR_NAME); 765 set = xmlGetProp(node, DTD_ATTR_SET); 766 iptype = xmlGetProp(node, DTD_ATTR_IPTYPE); 767 768 if (name == NULL || set == NULL || iptype == NULL) { 769 if (name != NULL) 770 xmlFree(name); 771 if (set != NULL) 772 xmlFree(set); 773 if (iptype != NULL) 774 xmlFree(iptype); 775 return (-1); 776 } 777 778 priv_iter.pi_name = (char *)name; 779 priv_iter.pi_set = (char *)set; 780 priv_iter.pi_iptype = (char *)iptype; 781 782 ret = func(data, &priv_iter); 783 784 xmlFree(name); 785 xmlFree(set); 786 xmlFree(iptype); 787 788 if (ret != 0) 789 return (-1); 790 } 791 792 return (0); 793 } 794 795 static int 796 i_brand_platform_iter_mounts(struct brand_handle *bhp, const char *zonepath, 797 int (*func)(void *, const char *, const char *, const char *, 798 const char *), void *data, const xmlChar *mount_type) 799 { 800 xmlNodePtr node; 801 xmlChar *special, *dir, *type, *opt; 802 char special_exp[MAXPATHLEN]; 803 char opt_exp[MAXPATHLEN]; 804 int ret; 805 806 if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL) 807 return (-1); 808 809 for (node = node->xmlChildrenNode; node != NULL; node = node->next) { 810 811 if (xmlStrcmp(node->name, mount_type) != 0) 812 continue; 813 814 special = xmlGetProp(node, DTD_ATTR_SPECIAL); 815 dir = xmlGetProp(node, DTD_ATTR_DIRECTORY); 816 type = xmlGetProp(node, DTD_ATTR_TYPE); 817 opt = xmlGetProp(node, DTD_ATTR_OPT); 818 if ((special == NULL) || (dir == NULL) || (type == NULL) || 819 (opt == NULL)) { 820 ret = -1; 821 goto next; 822 } 823 824 /* Substitute token values as needed. */ 825 if ((ret = i_substitute_tokens((char *)special, 826 special_exp, sizeof (special_exp), 827 NULL, zonepath, NULL, NULL)) != 0) 828 goto next; 829 830 /* opt might not be defined */ 831 if (strlen((const char *)opt) == 0) { 832 xmlFree(opt); 833 opt = NULL; 834 } else { 835 if ((ret = i_substitute_tokens((char *)opt, 836 opt_exp, sizeof (opt_exp), 837 NULL, zonepath, NULL, NULL)) != 0) 838 goto next; 839 } 840 841 ret = func(data, (char *)special_exp, (char *)dir, 842 (char *)type, ((opt != NULL) ? opt_exp : NULL)); 843 844 next: 845 if (special != NULL) 846 xmlFree(special); 847 if (dir != NULL) 848 xmlFree(dir); 849 if (type != NULL) 850 xmlFree(type); 851 if (opt != NULL) 852 xmlFree(opt); 853 if (ret != 0) 854 return (-1); 855 } 856 return (0); 857 } 858 859 860 /* 861 * Iterate over global platform filesystems 862 * 863 * Walks the platform, searching for <global_mount> elements, calling the 864 * specified callback for each. Returns 0 on success, or -1 on failure. 865 * 866 * Perform the following substitutions as necessary: 867 * 868 * %R Zonepath of zone 869 */ 870 int 871 brand_platform_iter_gmounts(brand_handle_t bh, const char *zonepath, 872 int (*func)(void *, const char *, const char *, const char *, 873 const char *), void *data) 874 { 875 struct brand_handle *bhp = (struct brand_handle *)bh; 876 return (i_brand_platform_iter_mounts(bhp, zonepath, func, data, 877 DTD_ELEM_GLOBAL_MOUNT)); 878 } 879 880 /* 881 * Iterate over non-global zone platform filesystems 882 * 883 * Walks the platform, searching for <mount> elements, calling the 884 * specified callback for each. Returns 0 on success, or -1 on failure. 885 */ 886 int 887 brand_platform_iter_mounts(brand_handle_t bh, int (*func)(void *, 888 const char *, const char *, const char *, const char *), void *data) 889 { 890 struct brand_handle *bhp = (struct brand_handle *)bh; 891 return (i_brand_platform_iter_mounts(bhp, NULL, func, data, 892 DTD_ELEM_MOUNT)); 893 } 894 895 /* 896 * Iterate over platform symlinks 897 * 898 * Walks the platform, searching for <symlink> elements, calling the 899 * specified callback for each. Returns 0 on success, or -1 on failure. 900 */ 901 int 902 brand_platform_iter_link(brand_handle_t bh, 903 int (*func)(void *, const char *, const char *), void *data) 904 { 905 struct brand_handle *bhp = (struct brand_handle *)bh; 906 xmlNodePtr node; 907 xmlChar *source, *target; 908 int ret; 909 910 if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL) 911 return (-1); 912 913 for (node = node->xmlChildrenNode; node != NULL; node = node->next) { 914 915 if (xmlStrcmp(node->name, DTD_ELEM_SYMLINK) != 0) 916 continue; 917 918 source = xmlGetProp(node, DTD_ATTR_SOURCE); 919 target = xmlGetProp(node, DTD_ATTR_TARGET); 920 921 if (source == NULL || target == NULL) { 922 if (source != NULL) 923 xmlFree(source); 924 if (target != NULL) 925 xmlFree(target); 926 return (-1); 927 } 928 929 ret = func(data, (char *)source, (char *)target); 930 931 xmlFree(source); 932 xmlFree(target); 933 934 if (ret != 0) 935 return (-1); 936 } 937 938 return (0); 939 } 940 941 /* 942 * Iterate over platform devices 943 * 944 * Walks the platform, searching for <device> elements, calling the 945 * specified callback for each. Returns 0 on success, or -1 on failure. 946 */ 947 int 948 brand_platform_iter_devices(brand_handle_t bh, const char *zonename, 949 int (*func)(void *, const char *, const char *), void *data, 950 const char *curr_iptype) 951 { 952 struct brand_handle *bhp = (struct brand_handle *)bh; 953 const char *curr_arch = get_curr_arch(); 954 xmlNodePtr node; 955 xmlChar *match, *name, *arch, *iptype; 956 char match_exp[MAXPATHLEN]; 957 boolean_t err = B_FALSE; 958 int ret = 0; 959 960 961 assert(bhp != NULL); 962 assert(zonename != NULL); 963 assert(func != NULL); 964 assert(curr_iptype != NULL); 965 966 if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL) 967 return (-1); 968 969 for (node = node->xmlChildrenNode; node != NULL; node = node->next) { 970 971 if (xmlStrcmp(node->name, DTD_ELEM_DEVICE) != 0) 972 continue; 973 974 match = xmlGetProp(node, DTD_ATTR_MATCH); 975 name = xmlGetProp(node, DTD_ATTR_NAME); 976 arch = xmlGetProp(node, DTD_ATTR_ARCH); 977 iptype = xmlGetProp(node, DTD_ATTR_IPTYPE); 978 if ((match == NULL) || (name == NULL) || (arch == NULL) || 979 (iptype == NULL)) { 980 err = B_TRUE; 981 goto next; 982 } 983 984 /* check if the arch matches */ 985 if ((strcmp((char *)arch, "all") != 0) && 986 (strcmp((char *)arch, curr_arch) != 0)) 987 goto next; 988 989 /* check if the iptype matches */ 990 if ((strcmp((char *)iptype, "all") != 0) && 991 (strcmp((char *)iptype, curr_iptype) != 0)) 992 goto next; 993 994 /* Substitute token values as needed. */ 995 if ((ret = i_substitute_tokens((char *)match, 996 match_exp, sizeof (match_exp), 997 zonename, NULL, NULL, NULL)) != 0) { 998 err = B_TRUE; 999 goto next; 1000 } 1001 1002 /* name might not be defined */ 1003 if (strlen((const char *)name) == 0) { 1004 xmlFree(name); 1005 name = NULL; 1006 } 1007 1008 /* invoke the callback */ 1009 ret = func(data, (const char *)match_exp, (const char *)name); 1010 1011 next: 1012 if (match != NULL) 1013 xmlFree(match); 1014 if (name != NULL) 1015 xmlFree(name); 1016 if (arch != NULL) 1017 xmlFree(arch); 1018 if (iptype != NULL) 1019 xmlFree(iptype); 1020 if (err) 1021 return (-1); 1022 if (ret != 0) 1023 return (-1); 1024 } 1025 1026 return (0); 1027 }