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