xref: /onnv-gate/usr/src/lib/libbrand/common/libbrand.c (revision 7370:e94ec740675f)
12712Snn35248 /*
22712Snn35248  * CDDL HEADER START
32712Snn35248  *
42712Snn35248  * The contents of this file are subject to the terms of the
52712Snn35248  * Common Development and Distribution License (the "License").
62712Snn35248  * You may not use this file except in compliance with the License.
72712Snn35248  *
82712Snn35248  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92712Snn35248  * or http://www.opensolaris.org/os/licensing.
102712Snn35248  * See the License for the specific language governing permissions
112712Snn35248  * and limitations under the License.
122712Snn35248  *
132712Snn35248  * When distributing Covered Code, include this CDDL HEADER in each
142712Snn35248  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152712Snn35248  * If applicable, add the following below this CDDL HEADER, with the
162712Snn35248  * fields enclosed by brackets "[]" replaced with your own identifying
172712Snn35248  * information: Portions Copyright [yyyy] [name of copyright owner]
182712Snn35248  *
192712Snn35248  * CDDL HEADER END
202712Snn35248  */
212712Snn35248 
222712Snn35248 /*
237089Sgjelinek  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
242712Snn35248  * Use is subject to license terms.
252712Snn35248  */
262712Snn35248 
272712Snn35248 #include <assert.h>
282712Snn35248 #include <dirent.h>
292712Snn35248 #include <errno.h>
302712Snn35248 #include <fnmatch.h>
312712Snn35248 #include <signal.h>
322712Snn35248 #include <stdlib.h>
332712Snn35248 #include <unistd.h>
342712Snn35248 #include <strings.h>
352712Snn35248 #include <synch.h>
362712Snn35248 #include <sys/brand.h>
372712Snn35248 #include <sys/fcntl.h>
382712Snn35248 #include <sys/param.h>
392712Snn35248 #include <sys/stat.h>
402712Snn35248 #include <sys/systeminfo.h>
412712Snn35248 #include <sys/types.h>
422712Snn35248 #include <thread.h>
432712Snn35248 #include <zone.h>
442712Snn35248 
452712Snn35248 #include <libbrand_impl.h>
462712Snn35248 #include <libbrand.h>
472712Snn35248 
487089Sgjelinek #define	DTD_ELEM_ATTACH		((const xmlChar *) "attach")
492712Snn35248 #define	DTD_ELEM_BOOT		((const xmlChar *) "boot")
502712Snn35248 #define	DTD_ELEM_BRAND		((const xmlChar *) "brand")
517089Sgjelinek #define	DTD_ELEM_CLONE		((const xmlChar *) "clone")
522712Snn35248 #define	DTD_ELEM_COMMENT	((const xmlChar *) "comment")
537089Sgjelinek #define	DTD_ELEM_DETACH		((const xmlChar *) "detach")
542712Snn35248 #define	DTD_ELEM_DEVICE		((const xmlChar *) "device")
552712Snn35248 #define	DTD_ELEM_GLOBAL_MOUNT	((const xmlChar *) "global_mount")
562712Snn35248 #define	DTD_ELEM_HALT		((const xmlChar *) "halt")
572712Snn35248 #define	DTD_ELEM_INITNAME	((const xmlChar *) "initname")
582712Snn35248 #define	DTD_ELEM_INSTALL	((const xmlChar *) "install")
592712Snn35248 #define	DTD_ELEM_INSTALLOPTS	((const xmlChar *) "installopts")
602712Snn35248 #define	DTD_ELEM_LOGIN_CMD	((const xmlChar *) "login_cmd")
612712Snn35248 #define	DTD_ELEM_MODNAME	((const xmlChar *) "modname")
622712Snn35248 #define	DTD_ELEM_MOUNT		((const xmlChar *) "mount")
634785Sgjelinek #define	DTD_ELEM_POSTATTACH	((const xmlChar *) "postattach")
642712Snn35248 #define	DTD_ELEM_POSTCLONE	((const xmlChar *) "postclone")
654586Sgjelinek #define	DTD_ELEM_POSTINSTALL	((const xmlChar *) "postinstall")
667089Sgjelinek #define	DTD_ELEM_POSTSNAP	((const xmlChar *) "postsnap")
67*7370S<Gerald Jelinek> #define	DTD_ELEM_POSTSTATECHG	((const xmlChar *) "poststatechange")
684785Sgjelinek #define	DTD_ELEM_PREDETACH	((const xmlChar *) "predetach")
697089Sgjelinek #define	DTD_ELEM_PRESNAP	((const xmlChar *) "presnap")
70*7370S<Gerald Jelinek> #define	DTD_ELEM_PRESTATECHG	((const xmlChar *) "prestatechange")
714785Sgjelinek #define	DTD_ELEM_PREUNINSTALL	((const xmlChar *) "preuninstall")
722712Snn35248 #define	DTD_ELEM_PRIVILEGE	((const xmlChar *) "privilege")
73*7370S<Gerald Jelinek> #define	DTD_ELEM_QUERY		((const xmlChar *) "query")
742712Snn35248 #define	DTD_ELEM_SYMLINK	((const xmlChar *) "symlink")
757089Sgjelinek #define	DTD_ELEM_UNINSTALL	((const xmlChar *) "uninstall")
764344Ssl108498 #define	DTD_ELEM_USER_CMD	((const xmlChar *) "user_cmd")
777089Sgjelinek #define	DTD_ELEM_VALIDSNAP	((const xmlChar *) "validatesnap")
782712Snn35248 #define	DTD_ELEM_VERIFY_CFG	((const xmlChar *) "verify_cfg")
792712Snn35248 #define	DTD_ELEM_VERIFY_ADM	((const xmlChar *) "verify_adm")
802712Snn35248 
813448Sdh155122 #define	DTD_ATTR_ALLOWEXCL	((const xmlChar *) "allow-exclusive-ip")
822712Snn35248 #define	DTD_ATTR_ARCH		((const xmlChar *) "arch")
832712Snn35248 #define	DTD_ATTR_DIRECTORY	((const xmlChar *) "directory")
843448Sdh155122 #define	DTD_ATTR_IPTYPE		((const xmlChar *) "ip-type")
852712Snn35248 #define	DTD_ATTR_MATCH		((const xmlChar *) "match")
862712Snn35248 #define	DTD_ATTR_MODE		((const xmlChar *) "mode")
872712Snn35248 #define	DTD_ATTR_NAME		((const xmlChar *) "name")
882712Snn35248 #define	DTD_ATTR_OPT		((const xmlChar *) "opt")
892712Snn35248 #define	DTD_ATTR_PATH		((const xmlChar *) "path")
902712Snn35248 #define	DTD_ATTR_SET		((const xmlChar *) "set")
912712Snn35248 #define	DTD_ATTR_SOURCE		((const xmlChar *) "source")
922712Snn35248 #define	DTD_ATTR_SPECIAL	((const xmlChar *) "special")
932712Snn35248 #define	DTD_ATTR_TARGET		((const xmlChar *) "target")
942712Snn35248 #define	DTD_ATTR_TYPE		((const xmlChar *) "type")
952712Snn35248 
963448Sdh155122 #define	DTD_ENTITY_TRUE		"true"
973448Sdh155122 
982712Snn35248 static volatile boolean_t	libbrand_initialized = B_FALSE;
992712Snn35248 static char			i_curr_arch[MAXNAMELEN];
1002712Snn35248 static char			i_curr_zone[ZONENAME_MAX];
1012712Snn35248 
1022712Snn35248 /*ARGSUSED*/
1032712Snn35248 static void
1042712Snn35248 brand_error_func(void *ctx, const char *msg, ...)
1052712Snn35248 {
1062712Snn35248 	/*
1072712Snn35248 	 * Ignore error messages from libxml
1082712Snn35248 	 */
1092712Snn35248 }
1102712Snn35248 
1112712Snn35248 static boolean_t
1122712Snn35248 libbrand_initialize()
1132712Snn35248 {
1142712Snn35248 	static mutex_t initialize_lock = DEFAULTMUTEX;
1152712Snn35248 
1162712Snn35248 	(void) mutex_lock(&initialize_lock);
1172712Snn35248 
1182712Snn35248 	if (libbrand_initialized) {
1192712Snn35248 		(void) mutex_unlock(&initialize_lock);
1202712Snn35248 		return (B_TRUE);
1212712Snn35248 	}
1222712Snn35248 
1232712Snn35248 	if (sysinfo(SI_ARCHITECTURE, i_curr_arch, sizeof (i_curr_arch)) < 0) {
1242712Snn35248 		(void) mutex_unlock(&initialize_lock);
1252712Snn35248 		return (B_FALSE);
1262712Snn35248 	}
1272712Snn35248 
1282712Snn35248 	if (getzonenamebyid(getzoneid(), i_curr_zone,
1292712Snn35248 	    sizeof (i_curr_zone)) < 0) {
1302712Snn35248 		(void) mutex_unlock(&initialize_lock);
1312712Snn35248 		return (B_FALSE);
1322712Snn35248 	}
1332712Snn35248 
1342712Snn35248 	/*
1352712Snn35248 	 * Note that here we're initializing per-process libxml2
1362712Snn35248 	 * state.  By doing so we're implicitly assuming that
1372712Snn35248 	 * no other code in this process is also trying to
1382712Snn35248 	 * use libxml2.  But in most case we know this not to
1392712Snn35248 	 * be true since we're almost always used in conjunction
1402712Snn35248 	 * with libzonecfg, which also uses libxml2.  Lucky for
1412712Snn35248 	 * us, libzonecfg initializes libxml2 to essentially
1422712Snn35248 	 * the same defaults as we're using below.
1432712Snn35248 	 */
1442712Snn35248 	xmlLineNumbersDefault(1);
1452712Snn35248 	xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
1462712Snn35248 	xmlDoValidityCheckingDefaultValue = 1;
1472712Snn35248 	(void) xmlKeepBlanksDefault(0);
1482712Snn35248 	xmlGetWarningsDefaultValue = 0;
1492712Snn35248 	xmlSetGenericErrorFunc(NULL, brand_error_func);
1502712Snn35248 
1512712Snn35248 	libbrand_initialized = B_TRUE;
1522712Snn35248 	(void) mutex_unlock(&initialize_lock);
1532712Snn35248 	return (B_TRUE);
1542712Snn35248 }
1552712Snn35248 
1562712Snn35248 static const char *
1572712Snn35248 get_curr_arch(void)
1582712Snn35248 {
1592712Snn35248 	if (!libbrand_initialize())
1602712Snn35248 		return (NULL);
1612712Snn35248 
1622712Snn35248 	return (i_curr_arch);
1632712Snn35248 }
1642712Snn35248 
1652712Snn35248 static const char *
1662712Snn35248 get_curr_zone(void)
1672712Snn35248 {
1682712Snn35248 	if (!libbrand_initialize())
1692712Snn35248 		return (NULL);
1702712Snn35248 
1712712Snn35248 	return (i_curr_zone);
1722712Snn35248 }
1732712Snn35248 
1742712Snn35248 /*
1752712Snn35248  * Internal function to open an XML file
1762712Snn35248  *
1772712Snn35248  * Returns the XML doc pointer, or NULL on failure.  It will validate the
1782712Snn35248  * document, as well as removing any comments from the document structure.
1792712Snn35248  */
1802712Snn35248 static xmlDocPtr
1812712Snn35248 open_xml_file(const char *file)
1822712Snn35248 {
1832712Snn35248 	xmlDocPtr doc;
1842712Snn35248 	xmlValidCtxtPtr cvp;
1852712Snn35248 	int valid;
1862712Snn35248 
1872712Snn35248 	if (!libbrand_initialize())
1882712Snn35248 		return (NULL);
1892712Snn35248 
1902712Snn35248 	/*
1912712Snn35248 	 * Parse the file
1922712Snn35248 	 */
1932712Snn35248 	if ((doc = xmlParseFile(file)) == NULL)
1942712Snn35248 		return (NULL);
1952712Snn35248 
1962712Snn35248 	/*
1972712Snn35248 	 * Validate the file
1982712Snn35248 	 */
1992712Snn35248 	if ((cvp = xmlNewValidCtxt()) == NULL) {
2002712Snn35248 		xmlFreeDoc(doc);
2012712Snn35248 		return (NULL);
2022712Snn35248 	}
2032712Snn35248 	cvp->error = brand_error_func;
2042712Snn35248 	cvp->warning = brand_error_func;
2052712Snn35248 	valid = xmlValidateDocument(cvp, doc);
2062712Snn35248 	xmlFreeValidCtxt(cvp);
2072712Snn35248 	if (valid == 0) {
2082712Snn35248 		xmlFreeDoc(doc);
2092712Snn35248 		return (NULL);
2102712Snn35248 	}
2112712Snn35248 
2122712Snn35248 	return (doc);
2132712Snn35248 }
2142712Snn35248 /*
2152712Snn35248  * Open a handle to the named brand.
2162712Snn35248  *
2172712Snn35248  * Returns a handle to the named brand, which is used for all subsequent brand
2182712Snn35248  * interaction, or NULL if unable to open or initialize the brand.
2192712Snn35248  */
2202727Sedp brand_handle_t
2212712Snn35248 brand_open(const char *name)
2222712Snn35248 {
2232727Sedp 	struct brand_handle *bhp;
2242712Snn35248 	char path[MAXPATHLEN];
2252712Snn35248 	xmlNodePtr node;
2262712Snn35248 	xmlChar *property;
2272712Snn35248 	struct stat statbuf;
2282712Snn35248 
2292712Snn35248 	/*
2302712Snn35248 	 * Make sure brand name isn't too long
2312712Snn35248 	 */
2322712Snn35248 	if (strlen(name) >= MAXNAMELEN)
2332712Snn35248 		return (NULL);
2342712Snn35248 
2352712Snn35248 	/*
2362712Snn35248 	 * Check that the brand exists
2372712Snn35248 	 */
2382712Snn35248 	(void) snprintf(path, sizeof (path), "%s/%s", BRAND_DIR, name);
2392712Snn35248 
2402712Snn35248 	if (stat(path, &statbuf) != 0)
2412712Snn35248 		return (NULL);
2422712Snn35248 
2432712Snn35248 	/*
2442712Snn35248 	 * Allocate brand handle
2452712Snn35248 	 */
2462727Sedp 	if ((bhp = malloc(sizeof (struct brand_handle))) == NULL)
2472712Snn35248 		return (NULL);
2482727Sedp 	bzero(bhp, sizeof (struct brand_handle));
2492712Snn35248 
2502712Snn35248 	(void) strcpy(bhp->bh_name, name);
2512712Snn35248 
2522712Snn35248 	/*
2532712Snn35248 	 * Open the configuration file
2542712Snn35248 	 */
2552712Snn35248 	(void) snprintf(path, sizeof (path), "%s/%s/%s", BRAND_DIR, name,
2562712Snn35248 	    BRAND_CONFIG);
2572712Snn35248 	if ((bhp->bh_config = open_xml_file(path)) == NULL) {
2582727Sedp 		brand_close((brand_handle_t)bhp);
2592712Snn35248 		return (NULL);
2602712Snn35248 	}
2612712Snn35248 
2622712Snn35248 	/*
2632712Snn35248 	 * Verify that the name of the brand matches the directory in which it
2642712Snn35248 	 * is installed.
2652712Snn35248 	 */
2662712Snn35248 	if ((node = xmlDocGetRootElement(bhp->bh_config)) == NULL) {
2672727Sedp 		brand_close((brand_handle_t)bhp);
2682712Snn35248 		return (NULL);
2692712Snn35248 	}
2702712Snn35248 
2712712Snn35248 	if (xmlStrcmp(node->name, DTD_ELEM_BRAND) != 0) {
2722727Sedp 		brand_close((brand_handle_t)bhp);
2732712Snn35248 		return (NULL);
2742712Snn35248 	}
2752712Snn35248 
2762712Snn35248 	if ((property = xmlGetProp(node, DTD_ATTR_NAME)) == NULL) {
2772727Sedp 		brand_close((brand_handle_t)bhp);
2782712Snn35248 		return (NULL);
2792712Snn35248 	}
2802712Snn35248 
2812712Snn35248 	if (strcmp((char *)property, name) != 0) {
2822712Snn35248 		xmlFree(property);
2832727Sedp 		brand_close((brand_handle_t)bhp);
2842712Snn35248 		return (NULL);
2852712Snn35248 	}
2862712Snn35248 	xmlFree(property);
2872712Snn35248 
2882712Snn35248 	/*
2892712Snn35248 	 * Open handle to platform configuration file.
2902712Snn35248 	 */
2912712Snn35248 	(void) snprintf(path, sizeof (path), "%s/%s/%s", BRAND_DIR, name,
2922712Snn35248 	    BRAND_PLATFORM);
2932712Snn35248 	if ((bhp->bh_platform = open_xml_file(path)) == NULL) {
2942727Sedp 		brand_close((brand_handle_t)bhp);
2952712Snn35248 		return (NULL);
2962712Snn35248 	}
2972712Snn35248 
2982727Sedp 	return ((brand_handle_t)bhp);
2992712Snn35248 }
3002712Snn35248 
3012712Snn35248 /*
3022712Snn35248  * Closes the given brand handle
3032712Snn35248  */
3042712Snn35248 void
3052727Sedp brand_close(brand_handle_t bh)
3062712Snn35248 {
3072727Sedp 	struct brand_handle *bhp = (struct brand_handle *)bh;
3082712Snn35248 	if (bhp->bh_platform != NULL)
3092712Snn35248 		xmlFreeDoc(bhp->bh_platform);
3102712Snn35248 	if (bhp->bh_config != NULL)
3112712Snn35248 		xmlFreeDoc(bhp->bh_config);
3122712Snn35248 	free(bhp);
3132712Snn35248 }
3142712Snn35248 
3152712Snn35248 static int
3162712Snn35248 i_substitute_tokens(const char *sbuf, char *dbuf, int dbuf_size,
3177089Sgjelinek     const char *zonename, const char *zonepath, const char *username,
3187089Sgjelinek     const char *curr_zone)
3192712Snn35248 {
3207089Sgjelinek 	int dst, src;
3212712Snn35248 
3222712Snn35248 	/*
3232712Snn35248 	 * Walk through the characters, substituting values as needed.
3242712Snn35248 	 */
3252712Snn35248 	dbuf[0] = '\0';
3262712Snn35248 	dst = 0;
3272712Snn35248 	for (src = 0; src < strlen((char *)sbuf) && dst < dbuf_size; src++) {
3282712Snn35248 		if (sbuf[src] != '%') {
3292712Snn35248 			dbuf[dst++] = sbuf[src];
3302712Snn35248 			continue;
3312712Snn35248 		}
3322712Snn35248 
3332712Snn35248 		switch (sbuf[++src]) {
3342712Snn35248 		case '%':
3352712Snn35248 			dst += strlcpy(dbuf + dst, "%", dbuf_size - dst);
3362712Snn35248 			break;
3372712Snn35248 		case 'R':
3387089Sgjelinek 			if (zonepath == NULL)
3392712Snn35248 				break;
3407089Sgjelinek 			dst += strlcpy(dbuf + dst, zonepath, dbuf_size - dst);
3412712Snn35248 			break;
3422712Snn35248 		case 'u':
3432712Snn35248 			if (username == NULL)
3442712Snn35248 				break;
3452712Snn35248 			dst += strlcpy(dbuf + dst, username, dbuf_size - dst);
3462712Snn35248 			break;
3472712Snn35248 		case 'Z':
3482712Snn35248 			if (curr_zone == NULL)
3492712Snn35248 				break;
3502712Snn35248 			/* name of the zone we're running in */
3512712Snn35248 			dst += strlcpy(dbuf + dst, curr_zone, dbuf_size - dst);
3522712Snn35248 			break;
3532712Snn35248 		case 'z':
3542712Snn35248 			/* name of the zone we're operating on */
3552712Snn35248 			if (zonename == NULL)
3562712Snn35248 				break;
3572712Snn35248 			dst += strlcpy(dbuf + dst, zonename, dbuf_size - dst);
3582712Snn35248 			break;
3592712Snn35248 		}
3602712Snn35248 	}
3612712Snn35248 
3622712Snn35248 	if (dst >= dbuf_size)
3632712Snn35248 		return (-1);
3642712Snn35248 
3652712Snn35248 	dbuf[dst] = '\0';
3662712Snn35248 	return (0);
3672712Snn35248 }
3682712Snn35248 
3692712Snn35248 /*
3702712Snn35248  * Retrieve the given tag from the brand.
3712712Snn35248  * Perform the following substitutions as necessary:
3722712Snn35248  *
3732712Snn35248  *	%%	%
3742712Snn35248  *	%u	Username
3752712Snn35248  *	%z	Name of target zone
3762712Snn35248  *	%Z	Name of current zone
3777089Sgjelinek  *	%R	Zonepath of zone
3782712Snn35248  *
3792712Snn35248  * Returns 0 on success, -1 on failure.
3802712Snn35248  */
3812712Snn35248 static int
3822727Sedp brand_get_value(struct brand_handle *bhp, const char *zonename,
3837089Sgjelinek     const char *zonepath, const char *username, const char *curr_zone,
3847089Sgjelinek     char *buf, size_t len, const xmlChar *tagname,
3852712Snn35248     boolean_t substitute, boolean_t optional)
3862712Snn35248 {
3872712Snn35248 	xmlNodePtr node;
3882712Snn35248 	xmlChar *content;
3892712Snn35248 	int err = 0;
3902712Snn35248 
3912712Snn35248 	/*
3922712Snn35248 	 * Retrieve the specified value from the XML doc
3932712Snn35248 	 */
3942712Snn35248 	if ((node = xmlDocGetRootElement(bhp->bh_config)) == NULL)
3952712Snn35248 		return (-1);
3962712Snn35248 
3972712Snn35248 	if (xmlStrcmp(node->name, DTD_ELEM_BRAND) != 0)
3982712Snn35248 		return (-1);
3992712Snn35248 
4002712Snn35248 	for (node = node->xmlChildrenNode; node != NULL;
4012712Snn35248 	    node = node->next) {
4022712Snn35248 		if (xmlStrcmp(node->name, tagname) == 0)
4032712Snn35248 			break;
4042712Snn35248 	}
4052712Snn35248 
4064607Sgjelinek 	if (node == NULL) {
4074607Sgjelinek 		if (optional) {
4084607Sgjelinek 			buf[0] = '\0';
4094607Sgjelinek 			return (0);
4104607Sgjelinek 		} else {
4114607Sgjelinek 			return (-1);
4124607Sgjelinek 		}
4134607Sgjelinek 	}
4142712Snn35248 
4152712Snn35248 	if ((content = xmlNodeGetContent(node)) == NULL)
4162712Snn35248 		return (-1);
4172712Snn35248 
4182712Snn35248 	if (strlen((char *)content) == 0) {
4192712Snn35248 		/*
4202712Snn35248 		 * If the entry in the config file is empty, check to see
4212712Snn35248 		 * whether this is an optional field.  If so, we return the
4222712Snn35248 		 * empty buffer.  If not, we return an error.
4232712Snn35248 		 */
4242712Snn35248 		if (optional) {
4252712Snn35248 			buf[0] = '\0';
4262712Snn35248 		} else {
4272712Snn35248 			err = -1;
4282712Snn35248 		}
4292712Snn35248 	} else {
4302712Snn35248 		/* Substitute token values as needed. */
4312712Snn35248 		if (substitute) {
4322712Snn35248 			if (i_substitute_tokens((char *)content, buf, len,
4337089Sgjelinek 			    zonename, zonepath, username, curr_zone) != 0)
4342712Snn35248 				err = -1;
4352712Snn35248 		} else {
4362712Snn35248 			if (strlcpy(buf, (char *)content, len) >= len)
4372712Snn35248 				err = -1;
4382712Snn35248 		}
4392712Snn35248 	}
4402712Snn35248 
4412712Snn35248 	xmlFree(content);
4422712Snn35248 
4432712Snn35248 	return (err);
4442712Snn35248 }
4452712Snn35248 
4462712Snn35248 int
4477089Sgjelinek brand_get_attach(brand_handle_t bh, const char *zonename,
4487089Sgjelinek     const char *zonepath, char *buf, size_t len)
4492712Snn35248 {
4502727Sedp 	struct brand_handle *bhp = (struct brand_handle *)bh;
4517089Sgjelinek 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
4527089Sgjelinek 	    buf, len, DTD_ELEM_ATTACH, B_TRUE, B_TRUE));
4537089Sgjelinek }
4547089Sgjelinek 
4557089Sgjelinek int
4567089Sgjelinek brand_get_boot(brand_handle_t bh, const char *zonename,
4577089Sgjelinek     const char *zonepath, char *buf, size_t len)
4587089Sgjelinek {
4597089Sgjelinek 	struct brand_handle *bhp = (struct brand_handle *)bh;
4607089Sgjelinek 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
4617089Sgjelinek 	    buf, len, DTD_ELEM_BOOT, B_TRUE, B_TRUE));
4622712Snn35248 }
4632712Snn35248 
4642712Snn35248 int
4652727Sedp brand_get_brandname(brand_handle_t bh, char *buf, size_t len)
4662712Snn35248 {
4672727Sedp 	struct brand_handle *bhp = (struct brand_handle *)bh;
4682712Snn35248 	if (len <= strlen(bhp->bh_name))
4692712Snn35248 		return (-1);
4702712Snn35248 
4712712Snn35248 	(void) strcpy(buf, bhp->bh_name);
4722712Snn35248 
4732712Snn35248 	return (0);
4742712Snn35248 }
4752712Snn35248 
4762712Snn35248 int
4777089Sgjelinek brand_get_clone(brand_handle_t bh, const char *zonename,
4787089Sgjelinek     const char *zonepath, char *buf, size_t len)
4792712Snn35248 {
4802727Sedp 	struct brand_handle *bhp = (struct brand_handle *)bh;
4817089Sgjelinek 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
4827089Sgjelinek 	    buf, len, DTD_ELEM_CLONE, B_TRUE, B_TRUE));
4837089Sgjelinek }
4847089Sgjelinek 
4857089Sgjelinek int
4867089Sgjelinek brand_get_detach(brand_handle_t bh, const char *zonename,
4877089Sgjelinek     const char *zonepath, char *buf, size_t len)
4887089Sgjelinek {
4897089Sgjelinek 	struct brand_handle *bhp = (struct brand_handle *)bh;
4907089Sgjelinek 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
4917089Sgjelinek 	    buf, len, DTD_ELEM_DETACH, B_TRUE, B_TRUE));
4927089Sgjelinek }
4937089Sgjelinek 
4947089Sgjelinek int
4957089Sgjelinek brand_get_halt(brand_handle_t bh, const char *zonename,
4967089Sgjelinek     const char *zonepath, char *buf, size_t len)
4977089Sgjelinek {
4987089Sgjelinek 	struct brand_handle *bhp = (struct brand_handle *)bh;
4997089Sgjelinek 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
5007089Sgjelinek 	    buf, len, DTD_ELEM_HALT, B_TRUE, B_TRUE));
5012712Snn35248 }
5022712Snn35248 
5032712Snn35248 int
5042727Sedp brand_get_initname(brand_handle_t bh, char *buf, size_t len)
5052712Snn35248 {
5062727Sedp 	struct brand_handle *bhp = (struct brand_handle *)bh;
5072712Snn35248 	return (brand_get_value(bhp, NULL, NULL, NULL, NULL,
5087089Sgjelinek 	    buf, len, DTD_ELEM_INITNAME, B_FALSE, B_FALSE));
5092712Snn35248 }
5102712Snn35248 
5112712Snn35248 int
5122727Sedp brand_get_login_cmd(brand_handle_t bh, const char *username,
5132712Snn35248     char *buf, size_t len)
5142712Snn35248 {
5152727Sedp 	struct brand_handle *bhp = (struct brand_handle *)bh;
5162712Snn35248 	const char *curr_zone = get_curr_zone();
5172712Snn35248 	return (brand_get_value(bhp, NULL, NULL, username, curr_zone,
5187089Sgjelinek 	    buf, len, DTD_ELEM_LOGIN_CMD, B_TRUE, B_FALSE));
5192712Snn35248 }
5202712Snn35248 
5212712Snn35248 int
5224344Ssl108498 brand_get_user_cmd(brand_handle_t bh, const char *username,
5234344Ssl108498     char *buf, size_t len)
5244344Ssl108498 {
5254344Ssl108498 	struct brand_handle *bhp = (struct brand_handle *)bh;
5264344Ssl108498 
5274344Ssl108498 	return (brand_get_value(bhp, NULL, NULL, username, NULL,
5287089Sgjelinek 	    buf, len, DTD_ELEM_USER_CMD, B_TRUE, B_FALSE));
5294344Ssl108498 }
5304344Ssl108498 
5314344Ssl108498 int
5322727Sedp brand_get_install(brand_handle_t bh, const char *zonename,
5337089Sgjelinek     const char *zonepath, char *buf, size_t len)
5342712Snn35248 {
5352727Sedp 	struct brand_handle *bhp = (struct brand_handle *)bh;
5367089Sgjelinek 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
5377089Sgjelinek 	    buf, len, DTD_ELEM_INSTALL, B_TRUE, B_FALSE));
5382712Snn35248 }
5392712Snn35248 
5402712Snn35248 int
5412727Sedp brand_get_installopts(brand_handle_t bh, char *buf, size_t len)
5422712Snn35248 {
5432727Sedp 	struct brand_handle *bhp = (struct brand_handle *)bh;
5442712Snn35248 	return (brand_get_value(bhp, NULL, NULL, NULL, NULL,
5457089Sgjelinek 	    buf, len, DTD_ELEM_INSTALLOPTS, B_FALSE, B_TRUE));
5462712Snn35248 }
5472712Snn35248 
5482712Snn35248 int
5492727Sedp brand_get_modname(brand_handle_t bh, char *buf, size_t len)
5502712Snn35248 {
5512727Sedp 	struct brand_handle *bhp = (struct brand_handle *)bh;
5522712Snn35248 	return (brand_get_value(bhp, NULL, NULL, NULL, NULL,
5537089Sgjelinek 	    buf, len, DTD_ELEM_MODNAME, B_FALSE, B_TRUE));
5542712Snn35248 }
5552712Snn35248 
5562712Snn35248 int
5574785Sgjelinek brand_get_postattach(brand_handle_t bh, const char *zonename,
5587089Sgjelinek     const char *zonepath, char *buf, size_t len)
5594785Sgjelinek {
5604785Sgjelinek 	struct brand_handle *bhp = (struct brand_handle *)bh;
5617089Sgjelinek 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
5627089Sgjelinek 	    buf, len, DTD_ELEM_POSTATTACH, B_TRUE, B_TRUE));
5634785Sgjelinek }
5644785Sgjelinek 
5654785Sgjelinek int
5662727Sedp brand_get_postclone(brand_handle_t bh, const char *zonename,
5677089Sgjelinek     const char *zonepath, char *buf, size_t len)
5682712Snn35248 {
5692727Sedp 	struct brand_handle *bhp = (struct brand_handle *)bh;
5707089Sgjelinek 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
5717089Sgjelinek 	    buf, len, DTD_ELEM_POSTCLONE, B_TRUE, B_TRUE));
5722712Snn35248 }
5732712Snn35248 
5742712Snn35248 int
5754586Sgjelinek brand_get_postinstall(brand_handle_t bh, const char *zonename,
5767089Sgjelinek     const char *zonepath, char *buf, size_t len)
5774586Sgjelinek {
5784586Sgjelinek 	struct brand_handle *bhp = (struct brand_handle *)bh;
5797089Sgjelinek 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
5807089Sgjelinek 	    buf, len, DTD_ELEM_POSTINSTALL, B_TRUE, B_TRUE));
5817089Sgjelinek }
5827089Sgjelinek 
5837089Sgjelinek int
5847089Sgjelinek brand_get_postsnap(brand_handle_t bh, const char *zonename,
5857089Sgjelinek     const char *zonepath, char *buf, size_t len)
5867089Sgjelinek {
5877089Sgjelinek 	struct brand_handle *bhp = (struct brand_handle *)bh;
5887089Sgjelinek 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
5897089Sgjelinek 	    buf, len, DTD_ELEM_POSTSNAP, B_TRUE, B_TRUE));
5904586Sgjelinek }
5914586Sgjelinek 
5924586Sgjelinek int
593*7370S<Gerald Jelinek> brand_get_poststatechange(brand_handle_t bh, const char *zonename,
594*7370S<Gerald Jelinek>     const char *zonepath, char *buf, size_t len)
595*7370S<Gerald Jelinek> {
596*7370S<Gerald Jelinek> 	struct brand_handle *bhp = (struct brand_handle *)bh;
597*7370S<Gerald Jelinek> 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
598*7370S<Gerald Jelinek> 	    buf, len, DTD_ELEM_POSTSTATECHG, B_TRUE, B_TRUE));
599*7370S<Gerald Jelinek> }
600*7370S<Gerald Jelinek> 
601*7370S<Gerald Jelinek> int
6024785Sgjelinek brand_get_predetach(brand_handle_t bh, const char *zonename,
6037089Sgjelinek     const char *zonepath, char *buf, size_t len)
6044785Sgjelinek {
6054785Sgjelinek 	struct brand_handle *bhp = (struct brand_handle *)bh;
6067089Sgjelinek 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
6077089Sgjelinek 	    buf, len, DTD_ELEM_PREDETACH, B_TRUE, B_TRUE));
6087089Sgjelinek }
6097089Sgjelinek 
6107089Sgjelinek int
6117089Sgjelinek brand_get_presnap(brand_handle_t bh, const char *zonename,
6127089Sgjelinek     const char *zonepath, char *buf, size_t len)
6137089Sgjelinek {
6147089Sgjelinek 	struct brand_handle *bhp = (struct brand_handle *)bh;
6157089Sgjelinek 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
6167089Sgjelinek 	    buf, len, DTD_ELEM_PRESNAP, B_TRUE, B_TRUE));
6174785Sgjelinek }
6184785Sgjelinek 
6194785Sgjelinek int
620*7370S<Gerald Jelinek> brand_get_prestatechange(brand_handle_t bh, const char *zonename,
621*7370S<Gerald Jelinek>     const char *zonepath, char *buf, size_t len)
622*7370S<Gerald Jelinek> {
623*7370S<Gerald Jelinek> 	struct brand_handle *bhp = (struct brand_handle *)bh;
624*7370S<Gerald Jelinek> 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
625*7370S<Gerald Jelinek> 	    buf, len, DTD_ELEM_PRESTATECHG, B_TRUE, B_TRUE));
626*7370S<Gerald Jelinek> }
627*7370S<Gerald Jelinek> 
628*7370S<Gerald Jelinek> int
6294785Sgjelinek brand_get_preuninstall(brand_handle_t bh, const char *zonename,
6307089Sgjelinek     const char *zonepath, char *buf, size_t len)
6317089Sgjelinek {
6327089Sgjelinek 	struct brand_handle *bhp = (struct brand_handle *)bh;
6337089Sgjelinek 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
6347089Sgjelinek 	    buf, len, DTD_ELEM_PREUNINSTALL, B_TRUE, B_TRUE));
6357089Sgjelinek }
6367089Sgjelinek 
6377089Sgjelinek int
638*7370S<Gerald Jelinek> brand_get_query(brand_handle_t bh, const char *zonename,
639*7370S<Gerald Jelinek>     const char *zonepath, char *buf, size_t len)
640*7370S<Gerald Jelinek> {
641*7370S<Gerald Jelinek> 	struct brand_handle *bhp = (struct brand_handle *)bh;
642*7370S<Gerald Jelinek> 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
643*7370S<Gerald Jelinek> 	    buf, len, DTD_ELEM_QUERY, B_TRUE, B_TRUE));
644*7370S<Gerald Jelinek> }
645*7370S<Gerald Jelinek> 
646*7370S<Gerald Jelinek> int
6477089Sgjelinek brand_get_uninstall(brand_handle_t bh, const char *zonename,
6487089Sgjelinek     const char *zonepath, char *buf, size_t len)
6494785Sgjelinek {
6504785Sgjelinek 	struct brand_handle *bhp = (struct brand_handle *)bh;
6517089Sgjelinek 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
6527089Sgjelinek 	    buf, len, DTD_ELEM_UNINSTALL, B_TRUE, B_TRUE));
6537089Sgjelinek }
6547089Sgjelinek 
6557089Sgjelinek int
6567089Sgjelinek brand_get_validatesnap(brand_handle_t bh, const char *zonename,
6577089Sgjelinek     const char *zonepath, char *buf, size_t len)
6587089Sgjelinek {
6597089Sgjelinek 	struct brand_handle *bhp = (struct brand_handle *)bh;
6607089Sgjelinek 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
6617089Sgjelinek 	    buf, len, DTD_ELEM_VALIDSNAP, B_TRUE, B_TRUE));
6624785Sgjelinek }
6634785Sgjelinek 
6644785Sgjelinek int
6652727Sedp brand_get_verify_cfg(brand_handle_t bh, char *buf, size_t len)
6662712Snn35248 {
6672727Sedp 	struct brand_handle *bhp = (struct brand_handle *)bh;
6682712Snn35248 	return (brand_get_value(bhp, NULL, NULL, NULL, NULL,
6697089Sgjelinek 	    buf, len, DTD_ELEM_VERIFY_CFG, B_FALSE, B_TRUE));
6702712Snn35248 }
6712712Snn35248 
6722712Snn35248 int
6732727Sedp brand_get_verify_adm(brand_handle_t bh, const char *zonename,
6747089Sgjelinek     const char *zonepath, char *buf, size_t len)
6752712Snn35248 {
6762727Sedp 	struct brand_handle *bhp = (struct brand_handle *)bh;
6777089Sgjelinek 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
6787089Sgjelinek 	    buf, len, DTD_ELEM_VERIFY_ADM, B_TRUE, B_TRUE));
6792712Snn35248 }
6802712Snn35248 
6812712Snn35248 int
6822727Sedp brand_is_native(brand_handle_t bh)
6832712Snn35248 {
6842727Sedp 	struct brand_handle *bhp = (struct brand_handle *)bh;
6852712Snn35248 	return ((strcmp(bhp->bh_name, NATIVE_BRAND_NAME) == 0) ? 1 : 0);
6862712Snn35248 }
6872712Snn35248 
6883448Sdh155122 boolean_t
6893448Sdh155122 brand_allow_exclusive_ip(brand_handle_t bh)
6903448Sdh155122 {
6913448Sdh155122 	struct brand_handle	*bhp = (struct brand_handle *)bh;
6923448Sdh155122 	xmlNodePtr		node;
6933448Sdh155122 	xmlChar			*allow_excl;
6943448Sdh155122 	boolean_t		ret;
6953448Sdh155122 
6963448Sdh155122 	assert(bhp != NULL);
6973448Sdh155122 
6983448Sdh155122 	if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL)
6993448Sdh155122 		return (B_FALSE);
7003448Sdh155122 
7013448Sdh155122 	allow_excl = xmlGetProp(node, DTD_ATTR_ALLOWEXCL);
7023448Sdh155122 	if (allow_excl == NULL)
7033448Sdh155122 		return (B_FALSE);
7043448Sdh155122 
7053448Sdh155122 	/* Note: only return B_TRUE if it's "true" */
7063448Sdh155122 	if (strcmp((char *)allow_excl, DTD_ENTITY_TRUE) == 0)
7073448Sdh155122 		ret = B_TRUE;
7083448Sdh155122 	else
7093448Sdh155122 		ret = B_FALSE;
7103448Sdh155122 
7113448Sdh155122 	xmlFree(allow_excl);
7123448Sdh155122 
7133448Sdh155122 	return (ret);
7143448Sdh155122 }
7153448Sdh155122 
7162712Snn35248 /*
7172712Snn35248  * Iterate over brand privileges
7182712Snn35248  *
7192712Snn35248  * Walks the brand config, searching for <privilege> elements, calling the
7202712Snn35248  * specified callback for each.  Returns 0 on success, or -1 on failure.
7212712Snn35248  */
7222712Snn35248 int
7233673Sdh155122 brand_config_iter_privilege(brand_handle_t bh,
7243673Sdh155122     int (*func)(void *, priv_iter_t *), void *data)
7252712Snn35248 {
7262727Sedp 	struct brand_handle	*bhp = (struct brand_handle *)bh;
7272712Snn35248 	xmlNodePtr		node;
7283673Sdh155122 	xmlChar			*name, *set, *iptype;
7293673Sdh155122 	priv_iter_t		priv_iter;
7302712Snn35248 	int			ret;
7312712Snn35248 
7322712Snn35248 	if ((node = xmlDocGetRootElement(bhp->bh_config)) == NULL)
7332712Snn35248 		return (-1);
7342712Snn35248 
7352712Snn35248 	for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
7362712Snn35248 
7372712Snn35248 		if (xmlStrcmp(node->name, DTD_ELEM_PRIVILEGE) != 0)
7382712Snn35248 			continue;
7392712Snn35248 
7402712Snn35248 		name = xmlGetProp(node, DTD_ATTR_NAME);
7412712Snn35248 		set = xmlGetProp(node, DTD_ATTR_SET);
7423673Sdh155122 		iptype = xmlGetProp(node, DTD_ATTR_IPTYPE);
7432712Snn35248 
7443673Sdh155122 		if (name == NULL || set == NULL || iptype == NULL) {
7452712Snn35248 			if (name != NULL)
7462712Snn35248 				xmlFree(name);
7472712Snn35248 			if (set != NULL)
7482712Snn35248 				xmlFree(set);
7493673Sdh155122 			if (iptype != NULL)
7503673Sdh155122 				xmlFree(iptype);
7512712Snn35248 			return (-1);
7522712Snn35248 		}
7532712Snn35248 
7543673Sdh155122 		priv_iter.pi_name = (char *)name;
7553673Sdh155122 		priv_iter.pi_set = (char *)set;
7563673Sdh155122 		priv_iter.pi_iptype = (char *)iptype;
7573673Sdh155122 
7583673Sdh155122 		ret = func(data, &priv_iter);
7592712Snn35248 
7602712Snn35248 		xmlFree(name);
7612712Snn35248 		xmlFree(set);
7623673Sdh155122 		xmlFree(iptype);
7632712Snn35248 
7642712Snn35248 		if (ret != 0)
7652712Snn35248 			return (-1);
7662712Snn35248 	}
7672712Snn35248 
7682712Snn35248 	return (0);
7692712Snn35248 }
7702712Snn35248 
7712712Snn35248 static int
7727089Sgjelinek i_brand_platform_iter_mounts(struct brand_handle *bhp, const char *zonepath,
7732712Snn35248     int (*func)(void *, const char *, const char *, const char *,
7742712Snn35248     const char *), void *data, const xmlChar *mount_type)
7752712Snn35248 {
7762712Snn35248 	xmlNodePtr node;
7772712Snn35248 	xmlChar *special, *dir, *type, *opt;
7782712Snn35248 	char special_exp[MAXPATHLEN];
7792712Snn35248 	char opt_exp[MAXPATHLEN];
7802712Snn35248 	int ret;
7812712Snn35248 
7822712Snn35248 	if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL)
7832712Snn35248 		return (-1);
7842712Snn35248 
7852712Snn35248 	for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
7862712Snn35248 
7872712Snn35248 		if (xmlStrcmp(node->name, mount_type) != 0)
7882712Snn35248 			continue;
7892712Snn35248 
7902712Snn35248 		special = xmlGetProp(node, DTD_ATTR_SPECIAL);
7912712Snn35248 		dir = xmlGetProp(node, DTD_ATTR_DIRECTORY);
7922712Snn35248 		type = xmlGetProp(node, DTD_ATTR_TYPE);
7932712Snn35248 		opt = xmlGetProp(node, DTD_ATTR_OPT);
7942712Snn35248 		if ((special == NULL) || (dir == NULL) || (type == NULL) ||
7952712Snn35248 		    (opt == NULL)) {
7962712Snn35248 			ret = -1;
7972712Snn35248 			goto next;
7982712Snn35248 		}
7992712Snn35248 
8002712Snn35248 		/* Substitute token values as needed. */
8012712Snn35248 		if ((ret = i_substitute_tokens((char *)special,
8022712Snn35248 		    special_exp, sizeof (special_exp),
8037089Sgjelinek 		    NULL, zonepath, NULL, NULL)) != 0)
8042712Snn35248 			goto next;
8052712Snn35248 
8062712Snn35248 		/* opt might not be defined */
8072712Snn35248 		if (strlen((const char *)opt) == 0) {
8082712Snn35248 			xmlFree(opt);
8092712Snn35248 			opt = NULL;
8102712Snn35248 		} else {
8112712Snn35248 			if ((ret = i_substitute_tokens((char *)opt,
8122712Snn35248 			    opt_exp, sizeof (opt_exp),
8137089Sgjelinek 			    NULL, zonepath, NULL, NULL)) != 0)
8142712Snn35248 				goto next;
8152712Snn35248 		}
8162712Snn35248 
8172712Snn35248 		ret = func(data, (char *)special_exp, (char *)dir,
8182712Snn35248 		    (char *)type, ((opt != NULL) ? opt_exp : NULL));
8192712Snn35248 
8202712Snn35248 next:
8212712Snn35248 		if (special != NULL)
8222712Snn35248 			xmlFree(special);
8232712Snn35248 		if (dir != NULL)
8242712Snn35248 			xmlFree(dir);
8252712Snn35248 		if (type != NULL)
8262712Snn35248 			xmlFree(type);
8272712Snn35248 		if (opt != NULL)
8282712Snn35248 			xmlFree(opt);
8292712Snn35248 		if (ret != 0)
8302712Snn35248 			return (-1);
8312712Snn35248 	}
8322712Snn35248 	return (0);
8332712Snn35248 }
8342712Snn35248 
8352712Snn35248 
8362712Snn35248 /*
8372712Snn35248  * Iterate over global platform filesystems
8382712Snn35248  *
8392712Snn35248  * Walks the platform, searching for <global_mount> elements, calling the
8402712Snn35248  * specified callback for each.  Returns 0 on success, or -1 on failure.
8412712Snn35248  *
8422712Snn35248  * Perform the following substitutions as necessary:
8432712Snn35248  *
8447089Sgjelinek  *	%R	Zonepath of zone
8452712Snn35248  */
8462712Snn35248 int
8477089Sgjelinek brand_platform_iter_gmounts(brand_handle_t bh, const char *zonepath,
8482712Snn35248     int (*func)(void *, const char *, const char *, const char *,
8492712Snn35248     const char *), void *data)
8502712Snn35248 {
8512727Sedp 	struct brand_handle *bhp = (struct brand_handle *)bh;
8527089Sgjelinek 	return (i_brand_platform_iter_mounts(bhp, zonepath, func, data,
8532712Snn35248 	    DTD_ELEM_GLOBAL_MOUNT));
8542712Snn35248 }
8552712Snn35248 
8562712Snn35248 /*
8572712Snn35248  * Iterate over non-global zone platform filesystems
8582712Snn35248  *
8592712Snn35248  * Walks the platform, searching for <mount> elements, calling the
8602712Snn35248  * specified callback for each.  Returns 0 on success, or -1 on failure.
8612712Snn35248  */
8622712Snn35248 int
8632727Sedp brand_platform_iter_mounts(brand_handle_t bh, int (*func)(void *,
8642712Snn35248     const char *, const char *, const char *, const char *), void *data)
8652712Snn35248 {
8662727Sedp 	struct brand_handle *bhp = (struct brand_handle *)bh;
8672712Snn35248 	return (i_brand_platform_iter_mounts(bhp, NULL, func, data,
8682712Snn35248 	    DTD_ELEM_MOUNT));
8692712Snn35248 }
8702712Snn35248 
8712712Snn35248 /*
8722712Snn35248  * Iterate over platform symlinks
8732712Snn35248  *
8742712Snn35248  * Walks the platform, searching for <symlink> elements, calling the
8752712Snn35248  * specified callback for each.  Returns 0 on success, or -1 on failure.
8762712Snn35248  */
8772712Snn35248 int
8782727Sedp brand_platform_iter_link(brand_handle_t bh,
8792712Snn35248     int (*func)(void *, const char *, const char *), void *data)
8802712Snn35248 {
8812727Sedp 	struct brand_handle *bhp = (struct brand_handle *)bh;
8822712Snn35248 	xmlNodePtr node;
8832712Snn35248 	xmlChar *source, *target;
8842712Snn35248 	int ret;
8852712Snn35248 
8862712Snn35248 	if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL)
8872712Snn35248 		return (-1);
8882712Snn35248 
8892712Snn35248 	for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
8902712Snn35248 
8912712Snn35248 		if (xmlStrcmp(node->name, DTD_ELEM_SYMLINK) != 0)
8922712Snn35248 			continue;
8932712Snn35248 
8942712Snn35248 		source = xmlGetProp(node, DTD_ATTR_SOURCE);
8952712Snn35248 		target = xmlGetProp(node, DTD_ATTR_TARGET);
8962712Snn35248 
8972712Snn35248 		if (source == NULL || target == NULL) {
8982712Snn35248 			if (source != NULL)
8992712Snn35248 				xmlFree(source);
9002712Snn35248 			if (target != NULL)
9012712Snn35248 				xmlFree(target);
9022712Snn35248 			return (-1);
9032712Snn35248 		}
9042712Snn35248 
9052712Snn35248 		ret = func(data, (char *)source, (char *)target);
9062712Snn35248 
9072712Snn35248 		xmlFree(source);
9082712Snn35248 		xmlFree(target);
9092712Snn35248 
9102712Snn35248 		if (ret != 0)
9112712Snn35248 			return (-1);
9122712Snn35248 	}
9132712Snn35248 
9142712Snn35248 	return (0);
9152712Snn35248 }
9162712Snn35248 
9172712Snn35248 /*
9182712Snn35248  * Iterate over platform devices
9192712Snn35248  *
9202712Snn35248  * Walks the platform, searching for <device> elements, calling the
9212712Snn35248  * specified callback for each.  Returns 0 on success, or -1 on failure.
9222712Snn35248  */
9232712Snn35248 int
9242727Sedp brand_platform_iter_devices(brand_handle_t bh, const char *zonename,
9253448Sdh155122     int (*func)(void *, const char *, const char *), void *data,
9263448Sdh155122     const char *curr_iptype)
9272712Snn35248 {
9282727Sedp 	struct brand_handle	*bhp = (struct brand_handle *)bh;
9292727Sedp 	const char		*curr_arch = get_curr_arch();
9302727Sedp 	xmlNodePtr		node;
9313448Sdh155122 	xmlChar			*match, *name, *arch, *iptype;
9322727Sedp 	char			match_exp[MAXPATHLEN];
9332727Sedp 	boolean_t		err = B_FALSE;
9342727Sedp 	int			ret = 0;
9352712Snn35248 
9362712Snn35248 
9372712Snn35248 	assert(bhp != NULL);
9382712Snn35248 	assert(zonename != NULL);
9392712Snn35248 	assert(func != NULL);
9403448Sdh155122 	assert(curr_iptype != NULL);
9412712Snn35248 
9422712Snn35248 	if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL)
9432712Snn35248 		return (-1);
9442712Snn35248 
9452712Snn35248 	for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
9462712Snn35248 
9472712Snn35248 		if (xmlStrcmp(node->name, DTD_ELEM_DEVICE) != 0)
9482712Snn35248 			continue;
9492712Snn35248 
9502712Snn35248 		match = xmlGetProp(node, DTD_ATTR_MATCH);
9512712Snn35248 		name = xmlGetProp(node, DTD_ATTR_NAME);
9522712Snn35248 		arch = xmlGetProp(node, DTD_ATTR_ARCH);
9533448Sdh155122 		iptype = xmlGetProp(node, DTD_ATTR_IPTYPE);
9543448Sdh155122 		if ((match == NULL) || (name == NULL) || (arch == NULL) ||
9553448Sdh155122 		    (iptype == NULL)) {
9562712Snn35248 			err = B_TRUE;
9572712Snn35248 			goto next;
9582712Snn35248 		}
9592712Snn35248 
9602712Snn35248 		/* check if the arch matches */
9612712Snn35248 		if ((strcmp((char *)arch, "all") != 0) &&
9622712Snn35248 		    (strcmp((char *)arch, curr_arch) != 0))
9632712Snn35248 			goto next;
9642712Snn35248 
9653448Sdh155122 		/* check if the iptype matches */
9663448Sdh155122 		if ((strcmp((char *)iptype, "all") != 0) &&
9673448Sdh155122 		    (strcmp((char *)iptype, curr_iptype) != 0))
9683448Sdh155122 			goto next;
9693448Sdh155122 
9702712Snn35248 		/* Substitute token values as needed. */
9712712Snn35248 		if ((ret = i_substitute_tokens((char *)match,
9722712Snn35248 		    match_exp, sizeof (match_exp),
9737089Sgjelinek 		    zonename, NULL, NULL, NULL)) != 0) {
9742712Snn35248 			err = B_TRUE;
9752712Snn35248 			goto next;
9762712Snn35248 		}
9772712Snn35248 
9782712Snn35248 		/* name might not be defined */
9792712Snn35248 		if (strlen((const char *)name) == 0) {
9802712Snn35248 			xmlFree(name);
9812712Snn35248 			name = NULL;
9822712Snn35248 		}
9832712Snn35248 
9842712Snn35248 		/* invoke the callback */
9852712Snn35248 		ret = func(data, (const char *)match_exp, (const char *)name);
9862712Snn35248 
9872712Snn35248 next:
9882712Snn35248 		if (match != NULL)
9892712Snn35248 			xmlFree(match);
9902712Snn35248 		if (name != NULL)
9912712Snn35248 			xmlFree(name);
9922712Snn35248 		if (arch != NULL)
9932712Snn35248 			xmlFree(arch);
9943448Sdh155122 		if (iptype != NULL)
9953448Sdh155122 			xmlFree(iptype);
9962712Snn35248 		if (err)
9972712Snn35248 			return (-1);
9982712Snn35248 		if (ret != 0)
9992712Snn35248 			return (-1);
10002712Snn35248 	}
10012712Snn35248 
10022712Snn35248 	return (0);
10032712Snn35248 }
1004