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