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