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