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