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 2006 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 <libsysevent.h> 30 #include <pthread.h> 31 #include <stdlib.h> 32 #include <errno.h> 33 #include <fnmatch.h> 34 #include <strings.h> 35 #include <unistd.h> 36 #include <sys/stat.h> 37 #include <assert.h> 38 #include <libgen.h> 39 #include <libintl.h> 40 #include <alloca.h> 41 #include <ctype.h> 42 #include <sys/mntio.h> 43 #include <sys/mnttab.h> 44 #include <sys/types.h> 45 #include <sys/nvpair.h> 46 #include <sys/acl.h> 47 #include <ftw.h> 48 49 #include <arpa/inet.h> 50 #include <netdb.h> 51 52 #include <libxml/xmlmemory.h> 53 #include <libxml/parser.h> 54 55 #include <libdevinfo.h> 56 #include <uuid/uuid.h> 57 58 #include <dirent.h> 59 60 #include <libzonecfg.h> 61 #include "zonecfg_impl.h" 62 63 64 #define _PATH_TMPFILE "/zonecfg.XXXXXX" 65 #define ZONE_CB_RETRY_COUNT 10 66 #define ZONE_EVENT_PING_SUBCLASS "ping" 67 #define ZONE_EVENT_PING_PUBLISHER "solaris" 68 69 /* Hard-code the DTD element/attribute/entity names just once, here. */ 70 #define DTD_ELEM_ATTR (const xmlChar *) "attr" 71 #define DTD_ELEM_COMMENT (const xmlChar *) "comment" 72 #define DTD_ELEM_DEVICE (const xmlChar *) "device" 73 #define DTD_ELEM_FS (const xmlChar *) "filesystem" 74 #define DTD_ELEM_FSOPTION (const xmlChar *) "fsoption" 75 #define DTD_ELEM_IPD (const xmlChar *) "inherited-pkg-dir" 76 #define DTD_ELEM_NET (const xmlChar *) "network" 77 #define DTD_ELEM_RCTL (const xmlChar *) "rctl" 78 #define DTD_ELEM_RCTLVALUE (const xmlChar *) "rctl-value" 79 #define DTD_ELEM_ZONE (const xmlChar *) "zone" 80 #define DTD_ELEM_DATASET (const xmlChar *) "dataset" 81 #define DTD_ELEM_PACKAGE (const xmlChar *) "package" 82 #define DTD_ELEM_PATCH (const xmlChar *) "patch" 83 #define DTD_ELEM_OBSOLETES (const xmlChar *) "obsoletes" 84 #define DTD_ELEM_INCOMPATIBLE (const xmlChar *) "incompatible" 85 #define DTD_ELEM_DEV_PERM (const xmlChar *) "dev-perm" 86 87 #define DTD_ATTR_ACTION (const xmlChar *) "action" 88 #define DTD_ATTR_ADDRESS (const xmlChar *) "address" 89 #define DTD_ATTR_AUTOBOOT (const xmlChar *) "autoboot" 90 #define DTD_ATTR_DIR (const xmlChar *) "directory" 91 #define DTD_ATTR_LIMIT (const xmlChar *) "limit" 92 #define DTD_ATTR_LIMITPRIV (const xmlChar *) "limitpriv" 93 #define DTD_ATTR_MATCH (const xmlChar *) "match" 94 #define DTD_ATTR_NAME (const xmlChar *) "name" 95 #define DTD_ATTR_PHYSICAL (const xmlChar *) "physical" 96 #define DTD_ATTR_POOL (const xmlChar *) "pool" 97 #define DTD_ATTR_PRIV (const xmlChar *) "priv" 98 #define DTD_ATTR_RAW (const xmlChar *) "raw" 99 #define DTD_ATTR_SPECIAL (const xmlChar *) "special" 100 #define DTD_ATTR_TYPE (const xmlChar *) "type" 101 #define DTD_ATTR_VALUE (const xmlChar *) "value" 102 #define DTD_ATTR_ZONEPATH (const xmlChar *) "zonepath" 103 #define DTD_ATTR_VERSION (const xmlChar *) "version" 104 #define DTD_ATTR_ID (const xmlChar *) "id" 105 #define DTD_ATTR_UID (const xmlChar *) "uid" 106 #define DTD_ATTR_GID (const xmlChar *) "gid" 107 #define DTD_ATTR_MODE (const xmlChar *) "mode" 108 #define DTD_ATTR_ACL (const xmlChar *) "acl" 109 110 #define DTD_ENTITY_BOOLEAN "boolean" 111 #define DTD_ENTITY_DEVPATH "devpath" 112 #define DTD_ENTITY_DRIVER "driver" 113 #define DTD_ENTITY_DRVMIN "drv_min" 114 #define DTD_ENTITY_FALSE "false" 115 #define DTD_ENTITY_INT "int" 116 #define DTD_ENTITY_STRING "string" 117 #define DTD_ENTITY_TRUE "true" 118 #define DTD_ENTITY_UINT "uint" 119 120 #define DTD_ENTITY_BOOL_LEN 6 /* "false" */ 121 122 #define DETACHED "SUNWdetached.xml" 123 #define ATTACH_FORCED "SUNWattached.xml" 124 #define PKG_PATH "/var/sadm/pkg" 125 #define CONTENTS_FILE "/var/sadm/install/contents" 126 #define SUNW_PKG_ALL_ZONES "SUNW_PKG_ALLZONES=true\n" 127 #define SUNW_PKG_THIS_ZONE "SUNW_PKG_THISZONE=true\n" 128 #define VERSION "VERSION=" 129 #define PATCHLIST "PATCHLIST=" 130 #define PATCHINFO "PATCH_INFO_" 131 #define PKGINFO_RD_LEN 128 132 133 struct zone_dochandle { 134 char *zone_dh_rootdir; 135 xmlDocPtr zone_dh_doc; 136 xmlNodePtr zone_dh_cur; 137 xmlNodePtr zone_dh_top; 138 boolean_t zone_dh_newzone; 139 boolean_t zone_dh_snapshot; 140 boolean_t zone_dh_sw_inv; 141 char zone_dh_delete_name[ZONENAME_MAX]; 142 }; 143 144 struct znotify { 145 void * zn_private; 146 evchan_t *zn_eventchan; 147 int (*zn_callback)(const char *zonename, zoneid_t zid, 148 const char *newstate, const char *oldstate, hrtime_t when, void *p); 149 pthread_mutex_t zn_mutex; 150 pthread_cond_t zn_cond; 151 pthread_mutex_t zn_bigmutex; 152 volatile enum {ZN_UNLOCKED, ZN_LOCKED, ZN_PING_INFLIGHT, 153 ZN_PING_RECEIVED} zn_state; 154 char zn_subscriber_id[MAX_SUBID_LEN]; 155 volatile boolean_t zn_failed; 156 int zn_failure_count; 157 }; 158 159 struct zone_pkginfo { 160 boolean_t zpi_all_zones; 161 boolean_t zpi_this_zone; 162 int zpi_patch_cnt; 163 char *zpi_version; 164 char **zpi_patchinfo; 165 }; 166 167 char *zonecfg_root = ""; 168 169 /* 170 * For functions which return int, which is most of the functions herein, 171 * the return values should be from the Z_foo set defined in <libzonecfg.h>. 172 * In some instances, we take pains mapping some libc errno values to Z_foo 173 * values from this set. 174 */ 175 176 /* 177 * Set the root (/) path for all zonecfg configuration files. This is a 178 * private interface used by Live Upgrade extensions to access zone 179 * configuration inside mounted alternate boot environments. 180 */ 181 void 182 zonecfg_set_root(const char *rootpath) 183 { 184 if (*zonecfg_root != '\0') 185 free(zonecfg_root); 186 if (rootpath == NULL || rootpath[0] == '\0' || rootpath[1] == '\0' || 187 (zonecfg_root = strdup(rootpath)) == NULL) 188 zonecfg_root = ""; 189 } 190 191 const char * 192 zonecfg_get_root(void) 193 { 194 return (zonecfg_root); 195 } 196 197 boolean_t 198 zonecfg_in_alt_root(void) 199 { 200 return (*zonecfg_root != '\0'); 201 } 202 203 /* 204 * Callers of the _file_path() functions are expected to have the second 205 * parameter be a (char foo[MAXPATHLEN]). 206 */ 207 208 static boolean_t 209 config_file_path(const char *zonename, char *answer) 210 { 211 return (snprintf(answer, MAXPATHLEN, "%s%s/%s.xml", zonecfg_root, 212 ZONE_CONFIG_ROOT, zonename) < MAXPATHLEN); 213 } 214 215 static boolean_t 216 snap_file_path(const char *zonename, char *answer) 217 { 218 return (snprintf(answer, MAXPATHLEN, "%s%s/%s.snapshot.xml", 219 zonecfg_root, ZONE_SNAPSHOT_ROOT, zonename) < MAXPATHLEN); 220 } 221 222 /*ARGSUSED*/ 223 static void 224 zonecfg_error_func(void *ctx, const char *msg, ...) 225 { 226 /* 227 * This function does nothing by design. Its purpose is to prevent 228 * libxml from dumping unwanted messages to stdout/stderr. 229 */ 230 } 231 232 zone_dochandle_t 233 zonecfg_init_handle(void) 234 { 235 zone_dochandle_t handle = calloc(1, sizeof (struct zone_dochandle)); 236 if (handle == NULL) { 237 errno = Z_NOMEM; 238 return (NULL); 239 } 240 241 /* generic libxml initialization */ 242 xmlLineNumbersDefault(1); 243 xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS; 244 xmlDoValidityCheckingDefaultValue = 1; 245 (void) xmlKeepBlanksDefault(0); 246 xmlGetWarningsDefaultValue = 0; 247 xmlSetGenericErrorFunc(NULL, zonecfg_error_func); 248 249 return (handle); 250 } 251 252 int 253 zonecfg_check_handle(zone_dochandle_t handle) 254 { 255 if (handle == NULL || handle->zone_dh_doc == NULL) 256 return (Z_BAD_HANDLE); 257 return (Z_OK); 258 } 259 260 void 261 zonecfg_fini_handle(zone_dochandle_t handle) 262 { 263 if (zonecfg_check_handle(handle) == Z_OK) 264 xmlFreeDoc(handle->zone_dh_doc); 265 if (handle != NULL) 266 free(handle); 267 } 268 269 static int 270 zonecfg_destroy_impl(char *filename) 271 { 272 if (unlink(filename) == -1) { 273 if (errno == EACCES) 274 return (Z_ACCES); 275 if (errno == ENOENT) 276 return (Z_NO_ZONE); 277 return (Z_MISC_FS); 278 } 279 return (Z_OK); 280 } 281 282 int 283 zonecfg_destroy(const char *zonename, boolean_t force) 284 { 285 char path[MAXPATHLEN]; 286 struct zoneent ze; 287 int err, state_err; 288 zone_state_t state; 289 290 if (!config_file_path(zonename, path)) 291 return (Z_MISC_FS); 292 293 state_err = zone_get_state((char *)zonename, &state); 294 err = access(path, W_OK); 295 296 /* 297 * If there is no file, and no index entry, reliably indicate that no 298 * such zone exists. 299 */ 300 if ((state_err == Z_NO_ZONE) && (err == -1) && (errno == ENOENT)) 301 return (Z_NO_ZONE); 302 303 /* 304 * Handle any other filesystem related errors (except if the XML 305 * file is missing, which we treat silently), unless we're forcing, 306 * in which case we plow on. 307 */ 308 if (err == -1 && errno != ENOENT) { 309 if (errno == EACCES) 310 return (Z_ACCES); 311 else if (!force) 312 return (Z_MISC_FS); 313 } 314 315 if (state > ZONE_STATE_INSTALLED) 316 return (Z_BAD_ZONE_STATE); 317 318 if (!force && state > ZONE_STATE_CONFIGURED) 319 return (Z_BAD_ZONE_STATE); 320 321 /* 322 * Index deletion succeeds even if the entry doesn't exist. So this 323 * will fail only if we've had some more severe problem. 324 */ 325 bzero(&ze, sizeof (ze)); 326 (void) strlcpy(ze.zone_name, zonename, sizeof (ze.zone_name)); 327 if ((err = putzoneent(&ze, PZE_REMOVE)) != Z_OK) 328 if (!force) 329 return (err); 330 331 err = zonecfg_destroy_impl(path); 332 333 /* 334 * Treat failure to find the XML file silently, since, well, it's 335 * gone, and with the index file cleaned up, we're done. 336 */ 337 if (err == Z_OK || err == Z_NO_ZONE) 338 return (Z_OK); 339 return (err); 340 } 341 342 int 343 zonecfg_destroy_snapshot(const char *zonename) 344 { 345 char path[MAXPATHLEN]; 346 347 if (!snap_file_path(zonename, path)) 348 return (Z_MISC_FS); 349 return (zonecfg_destroy_impl(path)); 350 } 351 352 static int 353 getroot(zone_dochandle_t handle, xmlNodePtr *root) 354 { 355 if (zonecfg_check_handle(handle) == Z_BAD_HANDLE) 356 return (Z_BAD_HANDLE); 357 358 *root = xmlDocGetRootElement(handle->zone_dh_doc); 359 360 if (*root == NULL) 361 return (Z_EMPTY_DOCUMENT); 362 363 if (xmlStrcmp((*root)->name, DTD_ELEM_ZONE)) 364 return (Z_WRONG_DOC_TYPE); 365 366 return (Z_OK); 367 } 368 369 static int 370 operation_prep(zone_dochandle_t handle) 371 { 372 xmlNodePtr root; 373 int err; 374 375 if ((err = getroot(handle, &root)) != 0) 376 return (err); 377 378 handle->zone_dh_cur = root; 379 handle->zone_dh_top = root; 380 return (Z_OK); 381 } 382 383 static int 384 fetchprop(xmlNodePtr cur, const xmlChar *propname, char *dst, size_t dstsize) 385 { 386 xmlChar *property; 387 size_t srcsize; 388 389 if ((property = xmlGetProp(cur, propname)) == NULL) 390 return (Z_BAD_PROPERTY); 391 srcsize = strlcpy(dst, (char *)property, dstsize); 392 xmlFree(property); 393 if (srcsize >= dstsize) 394 return (Z_TOO_BIG); 395 return (Z_OK); 396 } 397 398 static int 399 fetch_alloc_prop(xmlNodePtr cur, const xmlChar *propname, char **dst) 400 { 401 xmlChar *property; 402 403 if ((property = xmlGetProp(cur, propname)) == NULL) 404 return (Z_BAD_PROPERTY); 405 if ((*dst = strdup((char *)property)) == NULL) { 406 xmlFree(property); 407 return (Z_NOMEM); 408 } 409 xmlFree(property); 410 return (Z_OK); 411 } 412 413 static int 414 getrootattr(zone_dochandle_t handle, const xmlChar *propname, 415 char *propval, size_t propsize) 416 { 417 xmlNodePtr root; 418 int err; 419 420 if ((err = getroot(handle, &root)) != 0) 421 return (err); 422 423 return (fetchprop(root, propname, propval, propsize)); 424 } 425 426 static int 427 get_alloc_rootattr(zone_dochandle_t handle, const xmlChar *propname, 428 char **propval) 429 { 430 xmlNodePtr root; 431 int err; 432 433 if ((err = getroot(handle, &root)) != 0) 434 return (err); 435 436 return (fetch_alloc_prop(root, propname, propval)); 437 } 438 439 static int 440 setrootattr(zone_dochandle_t handle, const xmlChar *propname, 441 const char *propval) 442 { 443 int err; 444 xmlNodePtr root; 445 446 if (propval == NULL) 447 return (Z_INVAL); 448 449 if ((err = getroot(handle, &root)) != Z_OK) 450 return (err); 451 452 if (xmlSetProp(root, propname, (const xmlChar *) propval) == NULL) 453 return (Z_INVAL); 454 return (Z_OK); 455 } 456 457 static void 458 addcomment(zone_dochandle_t handle, const char *comment) 459 { 460 xmlNodePtr node; 461 node = xmlNewComment((xmlChar *) comment); 462 463 if (node != NULL) 464 (void) xmlAddPrevSibling(handle->zone_dh_top, node); 465 } 466 467 static void 468 stripcomments(zone_dochandle_t handle) 469 { 470 xmlDocPtr top; 471 xmlNodePtr child, next; 472 473 top = handle->zone_dh_doc; 474 for (child = top->xmlChildrenNode; child != NULL; child = next) { 475 next = child->next; 476 if (child->name == NULL) 477 continue; 478 if (xmlStrcmp(child->name, DTD_ELEM_COMMENT) == 0) { 479 next = child->next; 480 xmlUnlinkNode(child); 481 xmlFreeNode(child); 482 } 483 } 484 } 485 486 static void 487 strip_sw_inv(zone_dochandle_t handle) 488 { 489 xmlNodePtr root, child, next; 490 491 root = xmlDocGetRootElement(handle->zone_dh_doc); 492 for (child = root->xmlChildrenNode; child != NULL; child = next) { 493 next = child->next; 494 if (child->name == NULL) 495 continue; 496 if (xmlStrcmp(child->name, DTD_ELEM_PACKAGE) == 0 || 497 xmlStrcmp(child->name, DTD_ELEM_PATCH) == 0) { 498 next = child->next; 499 xmlUnlinkNode(child); 500 xmlFreeNode(child); 501 } 502 } 503 } 504 505 static int 506 zonecfg_get_handle_impl(const char *zonename, const char *filename, 507 zone_dochandle_t handle) 508 { 509 xmlValidCtxtPtr cvp; 510 struct stat statbuf; 511 int valid; 512 513 if (zonename == NULL) 514 return (Z_NO_ZONE); 515 if ((handle->zone_dh_doc = xmlParseFile(filename)) == NULL) { 516 /* distinguish file not found vs. found but not parsed */ 517 if (stat(filename, &statbuf) == 0) 518 return (Z_INVALID_DOCUMENT); 519 return (Z_NO_ZONE); 520 } 521 if ((cvp = xmlNewValidCtxt()) == NULL) 522 return (Z_NOMEM); 523 cvp->error = zonecfg_error_func; 524 cvp->warning = zonecfg_error_func; 525 valid = xmlValidateDocument(cvp, handle->zone_dh_doc); 526 xmlFreeValidCtxt(cvp); 527 if (valid == 0) 528 return (Z_INVALID_DOCUMENT); 529 530 /* delete any comments such as inherited Sun copyright / ident str */ 531 stripcomments(handle); 532 return (Z_OK); 533 } 534 535 int 536 zonecfg_get_handle(const char *zonename, zone_dochandle_t handle) 537 { 538 char path[MAXPATHLEN]; 539 540 if (!config_file_path(zonename, path)) 541 return (Z_MISC_FS); 542 handle->zone_dh_newzone = B_FALSE; 543 544 return (zonecfg_get_handle_impl(zonename, path, handle)); 545 } 546 547 int 548 zonecfg_get_attach_handle(const char *path, const char *zonename, 549 boolean_t preserve_sw, zone_dochandle_t handle) 550 { 551 char migpath[MAXPATHLEN]; 552 int err; 553 struct stat buf; 554 555 if (snprintf(migpath, sizeof (migpath), "%s/root", path) >= 556 sizeof (migpath)) 557 return (Z_NOMEM); 558 559 if (stat(migpath, &buf) == -1 || !S_ISDIR(buf.st_mode)) 560 return (Z_NO_ZONE); 561 562 if (snprintf(migpath, sizeof (migpath), "%s/%s", path, DETACHED) >= 563 sizeof (migpath)) 564 return (Z_NOMEM); 565 566 if ((err = zonecfg_get_handle_impl(zonename, migpath, handle)) != Z_OK) 567 return (err); 568 569 if (!preserve_sw) 570 strip_sw_inv(handle); 571 572 handle->zone_dh_newzone = B_TRUE; 573 if ((err = setrootattr(handle, DTD_ATTR_ZONEPATH, path)) != Z_OK) 574 return (err); 575 576 return (setrootattr(handle, DTD_ATTR_NAME, zonename)); 577 } 578 579 int 580 zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle) 581 { 582 char path[MAXPATHLEN]; 583 584 if (!snap_file_path(zonename, path)) 585 return (Z_MISC_FS); 586 handle->zone_dh_newzone = B_FALSE; 587 return (zonecfg_get_handle_impl(zonename, path, handle)); 588 } 589 590 int 591 zonecfg_get_template_handle(const char *template, const char *zonename, 592 zone_dochandle_t handle) 593 { 594 char path[MAXPATHLEN]; 595 int err; 596 597 if (!config_file_path(template, path)) 598 return (Z_MISC_FS); 599 600 if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK) 601 return (err); 602 handle->zone_dh_newzone = B_TRUE; 603 return (setrootattr(handle, DTD_ATTR_NAME, zonename)); 604 } 605 606 static boolean_t 607 is_renaming(zone_dochandle_t handle) 608 { 609 if (handle->zone_dh_newzone) 610 return (B_FALSE); 611 if (strlen(handle->zone_dh_delete_name) > 0) 612 return (B_TRUE); 613 return (B_FALSE); 614 } 615 616 static boolean_t 617 is_new(zone_dochandle_t handle) 618 { 619 return (handle->zone_dh_newzone || handle->zone_dh_snapshot); 620 } 621 622 static boolean_t 623 is_snapshot(zone_dochandle_t handle) 624 { 625 return (handle->zone_dh_snapshot); 626 } 627 628 /* 629 * It would be great to be able to use libc's ctype(3c) macros, but we 630 * can't, as they are locale sensitive, and it would break our limited thread 631 * safety if this routine had to change the app locale on the fly. 632 */ 633 int 634 zonecfg_validate_zonename(const char *zone) 635 { 636 int i; 637 638 if (strcmp(zone, GLOBAL_ZONENAME) == 0) 639 return (Z_BOGUS_ZONE_NAME); 640 641 if (strlen(zone) >= ZONENAME_MAX) 642 return (Z_BOGUS_ZONE_NAME); 643 644 if (!((zone[0] >= 'a' && zone[0] <= 'z') || 645 (zone[0] >= 'A' && zone[0] <= 'Z') || 646 (zone[0] >= '0' && zone[0] <= '9'))) 647 return (Z_BOGUS_ZONE_NAME); 648 649 for (i = 1; zone[i] != '\0'; i++) { 650 if (!((zone[i] >= 'a' && zone[i] <= 'z') || 651 (zone[i] >= 'A' && zone[i] <= 'Z') || 652 (zone[i] >= '0' && zone[i] <= '9') || 653 (zone[i] == '-') || (zone[i] == '_') || (zone[i] == '.'))) 654 return (Z_BOGUS_ZONE_NAME); 655 } 656 657 return (Z_OK); 658 } 659 660 /* 661 * Changing the zone name requires us to track both the old and new 662 * name of the zone until commit time. 663 */ 664 int 665 zonecfg_get_name(zone_dochandle_t handle, char *name, size_t namesize) 666 { 667 return (getrootattr(handle, DTD_ATTR_NAME, name, namesize)); 668 } 669 670 int 671 zonecfg_set_name(zone_dochandle_t handle, char *name) 672 { 673 zone_state_t state; 674 char curname[ZONENAME_MAX], old_delname[ZONENAME_MAX]; 675 int err; 676 677 if ((err = getrootattr(handle, DTD_ATTR_NAME, curname, 678 sizeof (curname))) != Z_OK) 679 return (err); 680 681 if (strcmp(name, curname) == 0) 682 return (Z_OK); 683 684 /* 685 * Switching zone names to one beginning with SUNW is not permitted. 686 */ 687 if (strncmp(name, "SUNW", 4) == 0) 688 return (Z_BOGUS_ZONE_NAME); 689 690 if ((err = zonecfg_validate_zonename(name)) != Z_OK) 691 return (err); 692 693 /* 694 * Setting the name back to the original name (effectively a revert of 695 * the name) is fine. But if we carry on, we'll falsely identify the 696 * name as "in use," so special case here. 697 */ 698 if (strcmp(name, handle->zone_dh_delete_name) == 0) { 699 err = setrootattr(handle, DTD_ATTR_NAME, name); 700 handle->zone_dh_delete_name[0] = '\0'; 701 return (err); 702 } 703 704 /* Check to see if new name chosen is already in use */ 705 if (zone_get_state(name, &state) != Z_NO_ZONE) 706 return (Z_NAME_IN_USE); 707 708 /* 709 * If this isn't already "new" or in a renaming transition, then 710 * we're initiating a rename here; so stash the "delete name" 711 * (i.e. the name of the zone we'll be removing) for the rename. 712 */ 713 (void) strlcpy(old_delname, handle->zone_dh_delete_name, 714 sizeof (old_delname)); 715 if (!is_new(handle) && !is_renaming(handle)) { 716 /* 717 * Name change is allowed only when the zone we're altering 718 * is not ready or running. 719 */ 720 err = zone_get_state(curname, &state); 721 if (err == Z_OK) { 722 if (state > ZONE_STATE_INSTALLED) 723 return (Z_BAD_ZONE_STATE); 724 } else if (err != Z_NO_ZONE) { 725 return (err); 726 } 727 728 (void) strlcpy(handle->zone_dh_delete_name, curname, 729 sizeof (handle->zone_dh_delete_name)); 730 assert(is_renaming(handle)); 731 } else if (is_renaming(handle)) { 732 err = zone_get_state(handle->zone_dh_delete_name, &state); 733 if (err == Z_OK) { 734 if (state > ZONE_STATE_INSTALLED) 735 return (Z_BAD_ZONE_STATE); 736 } else if (err != Z_NO_ZONE) { 737 return (err); 738 } 739 } 740 741 if ((err = setrootattr(handle, DTD_ATTR_NAME, name)) != Z_OK) { 742 /* 743 * Restore the deletename to whatever it was at the 744 * top of the routine, since we've had a failure. 745 */ 746 (void) strlcpy(handle->zone_dh_delete_name, old_delname, 747 sizeof (handle->zone_dh_delete_name)); 748 return (err); 749 } 750 751 return (Z_OK); 752 } 753 754 int 755 zonecfg_get_zonepath(zone_dochandle_t handle, char *path, size_t pathsize) 756 { 757 size_t len; 758 759 if ((len = strlcpy(path, zonecfg_root, pathsize)) >= pathsize) 760 return (Z_TOO_BIG); 761 return (getrootattr(handle, DTD_ATTR_ZONEPATH, path + len, 762 pathsize - len)); 763 } 764 765 int 766 zonecfg_set_zonepath(zone_dochandle_t handle, char *zonepath) 767 { 768 return (setrootattr(handle, DTD_ATTR_ZONEPATH, zonepath)); 769 } 770 771 int 772 zonecfg_get_autoboot(zone_dochandle_t handle, boolean_t *autoboot) 773 { 774 char autobootstr[DTD_ENTITY_BOOL_LEN]; 775 int ret; 776 777 if ((ret = getrootattr(handle, DTD_ATTR_AUTOBOOT, autobootstr, 778 sizeof (autobootstr))) != Z_OK) 779 return (ret); 780 781 if (strcmp(autobootstr, DTD_ENTITY_TRUE) == 0) 782 *autoboot = B_TRUE; 783 else if (strcmp(autobootstr, DTD_ENTITY_FALSE) == 0) 784 *autoboot = B_FALSE; 785 else 786 ret = Z_BAD_PROPERTY; 787 return (ret); 788 } 789 790 int 791 zonecfg_set_autoboot(zone_dochandle_t handle, boolean_t autoboot) 792 { 793 return (setrootattr(handle, DTD_ATTR_AUTOBOOT, 794 autoboot ? DTD_ENTITY_TRUE : DTD_ENTITY_FALSE)); 795 } 796 797 int 798 zonecfg_get_pool(zone_dochandle_t handle, char *pool, size_t poolsize) 799 { 800 return (getrootattr(handle, DTD_ATTR_POOL, pool, poolsize)); 801 } 802 803 int 804 zonecfg_set_pool(zone_dochandle_t handle, char *pool) 805 { 806 return (setrootattr(handle, DTD_ATTR_POOL, pool)); 807 } 808 809 int 810 zonecfg_get_limitpriv(zone_dochandle_t handle, char **limitpriv) 811 { 812 return (get_alloc_rootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv)); 813 } 814 815 int 816 zonecfg_set_limitpriv(zone_dochandle_t handle, char *limitprivsize) 817 { 818 return (setrootattr(handle, DTD_ATTR_LIMITPRIV, limitprivsize)); 819 } 820 821 /* 822 * /etc/zones/index caches a vital piece of information which is also 823 * in the <zonename>.xml file: the path to the zone. This is for performance, 824 * since we need to walk all zonepath's in order to be able to detect conflicts 825 * (see crosscheck_zonepaths() in the zoneadm command). 826 * 827 * An additional complexity is that when doing a rename, we'd like the entire 828 * index update operation (rename, and potential state changes) to be atomic. 829 * In general, the operation of this function should succeed or fail as 830 * a unit. 831 */ 832 int 833 zonecfg_refresh_index_file(zone_dochandle_t handle) 834 { 835 char name[ZONENAME_MAX], zonepath[MAXPATHLEN]; 836 struct zoneent ze; 837 int err; 838 int opcode; 839 char *zn; 840 841 bzero(&ze, sizeof (ze)); 842 ze.zone_state = -1; /* Preserve existing state in index */ 843 844 if ((err = zonecfg_get_name(handle, name, sizeof (name))) != Z_OK) 845 return (err); 846 (void) strlcpy(ze.zone_name, name, sizeof (ze.zone_name)); 847 848 if ((err = zonecfg_get_zonepath(handle, zonepath, 849 sizeof (zonepath))) != Z_OK) 850 return (err); 851 (void) strlcpy(ze.zone_path, zonepath, sizeof (ze.zone_path)); 852 853 if (is_renaming(handle)) { 854 opcode = PZE_MODIFY; 855 (void) strlcpy(ze.zone_name, handle->zone_dh_delete_name, 856 sizeof (ze.zone_name)); 857 (void) strlcpy(ze.zone_newname, name, sizeof (ze.zone_newname)); 858 } else if (is_new(handle)) { 859 FILE *cookie; 860 /* 861 * Be tolerant of the zone already existing in the index file, 862 * since we might be forcibly overwriting an existing 863 * configuration with a new one (for example 'create -F' 864 * in zonecfg). 865 */ 866 opcode = PZE_ADD; 867 cookie = setzoneent(); 868 while ((zn = getzoneent(cookie)) != NULL) { 869 if (strcmp(zn, name) == 0) { 870 opcode = PZE_MODIFY; 871 free(zn); 872 break; 873 } 874 free(zn); 875 } 876 endzoneent(cookie); 877 ze.zone_state = ZONE_STATE_CONFIGURED; 878 } else { 879 opcode = PZE_MODIFY; 880 } 881 882 if ((err = putzoneent(&ze, opcode)) != Z_OK) 883 return (err); 884 885 return (Z_OK); 886 } 887 888 /* 889 * The goal of this routine is to cause the index file update and the 890 * document save to happen as an atomic operation. We do the document 891 * first, saving a backup copy using a hard link; if that succeeds, we go 892 * on to the index. If that fails, we roll the document back into place. 893 * 894 * Strategy: 895 * 896 * New zone 'foo' configuration: 897 * Create tmpfile (zonecfg.xxxxxx) 898 * Write XML to tmpfile 899 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml) 900 * Add entry to index file 901 * If it fails, delete foo.xml, leaving nothing behind. 902 * 903 * Save existing zone 'foo': 904 * Make backup of foo.xml -> .backup 905 * Create tmpfile (zonecfg.xxxxxx) 906 * Write XML to tmpfile 907 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml) 908 * Modify index file as needed 909 * If it fails, recover from .backup -> foo.xml 910 * 911 * Rename 'foo' to 'bar': 912 * Create tmpfile (zonecfg.xxxxxx) 913 * Write XML to tmpfile 914 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> bar.xml) 915 * Add entry for 'bar' to index file, Remove entry for 'foo' (refresh) 916 * If it fails, delete bar.xml; foo.xml is left behind. 917 */ 918 static int 919 zonecfg_save_impl(zone_dochandle_t handle, char *filename) 920 { 921 char tmpfile[MAXPATHLEN]; 922 char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN]; 923 int tmpfd, err; 924 xmlValidCtxt cvp = { NULL }; 925 boolean_t backup; 926 927 (void) strlcpy(tmpfile, filename, sizeof (tmpfile)); 928 (void) dirname(tmpfile); 929 (void) strlcat(tmpfile, _PATH_TMPFILE, sizeof (tmpfile)); 930 931 tmpfd = mkstemp(tmpfile); 932 if (tmpfd == -1) { 933 (void) unlink(tmpfile); 934 return (Z_TEMP_FILE); 935 } 936 (void) close(tmpfd); 937 938 cvp.error = zonecfg_error_func; 939 cvp.warning = zonecfg_error_func; 940 941 /* 942 * We do a final validation of the document-- but the library has 943 * malfunctioned if it fails to validate, so it's an assert. 944 */ 945 assert(xmlValidateDocument(&cvp, handle->zone_dh_doc) != 0); 946 947 if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0) 948 goto err; 949 950 (void) chmod(tmpfile, 0644); 951 952 /* 953 * In the event we are doing a standard save, hard link a copy of the 954 * original file in .backup.<pid>.filename so we can restore it if 955 * something goes wrong. 956 */ 957 if (!is_new(handle) && !is_renaming(handle)) { 958 backup = B_TRUE; 959 960 (void) strlcpy(bakdir, filename, sizeof (bakdir)); 961 (void) strlcpy(bakbase, filename, sizeof (bakbase)); 962 (void) snprintf(bakfile, sizeof (bakfile), "%s/.backup.%d.%s", 963 dirname(bakdir), getpid(), basename(bakbase)); 964 965 if (link(filename, bakfile) == -1) { 966 err = errno; 967 (void) unlink(tmpfile); 968 if (errno == EACCES) 969 return (Z_ACCES); 970 return (Z_MISC_FS); 971 } 972 } 973 974 /* 975 * Move the new document over top of the old. 976 * i.e.: zonecfg.XXXXXX -> myzone.xml 977 */ 978 if (rename(tmpfile, filename) == -1) { 979 err = errno; 980 (void) unlink(tmpfile); 981 if (backup) 982 (void) unlink(bakfile); 983 if (err == EACCES) 984 return (Z_ACCES); 985 return (Z_MISC_FS); 986 } 987 988 /* 989 * If this is a snapshot, we're done-- don't add an index entry. 990 */ 991 if (is_snapshot(handle)) 992 return (Z_OK); 993 994 /* now update the index file to reflect whatever we just did */ 995 if ((err = zonecfg_refresh_index_file(handle)) != Z_OK) { 996 if (backup) { 997 /* 998 * Try to restore from our backup. 999 */ 1000 (void) unlink(filename); 1001 (void) rename(bakfile, filename); 1002 } else { 1003 /* 1004 * Either the zone is new, in which case we can delete 1005 * new.xml, or we're doing a rename, so ditto. 1006 */ 1007 assert(is_new(handle) || is_renaming(handle)); 1008 (void) unlink(filename); 1009 } 1010 return (Z_UPDATING_INDEX); 1011 } 1012 1013 if (backup) 1014 (void) unlink(bakfile); 1015 1016 return (Z_OK); 1017 1018 err: 1019 (void) unlink(tmpfile); 1020 return (Z_SAVING_FILE); 1021 } 1022 1023 int 1024 zonecfg_save(zone_dochandle_t handle) 1025 { 1026 char zname[ZONENAME_MAX], path[MAXPATHLEN]; 1027 char delpath[MAXPATHLEN]; 1028 int err = Z_SAVING_FILE; 1029 1030 if (zonecfg_check_handle(handle) != Z_OK) 1031 return (Z_BAD_HANDLE); 1032 1033 /* 1034 * We don't support saving snapshots or a tree containing a sw 1035 * inventory at this time. 1036 */ 1037 if (handle->zone_dh_snapshot || handle->zone_dh_sw_inv) 1038 return (Z_INVAL); 1039 1040 if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK) 1041 return (err); 1042 1043 if (!config_file_path(zname, path)) 1044 return (Z_MISC_FS); 1045 1046 addcomment(handle, "\n DO NOT EDIT THIS " 1047 "FILE. Use zonecfg(1M) instead.\n"); 1048 1049 err = zonecfg_save_impl(handle, path); 1050 1051 stripcomments(handle); 1052 1053 if (err != Z_OK) 1054 return (err); 1055 1056 handle->zone_dh_newzone = B_FALSE; 1057 1058 if (is_renaming(handle)) { 1059 if (config_file_path(handle->zone_dh_delete_name, delpath)) 1060 (void) unlink(delpath); 1061 handle->zone_dh_delete_name[0] = '\0'; 1062 } 1063 1064 return (Z_OK); 1065 } 1066 1067 int 1068 zonecfg_detach_save(zone_dochandle_t handle) 1069 { 1070 char zname[ZONENAME_MAX]; 1071 char path[MAXPATHLEN]; 1072 char migpath[MAXPATHLEN]; 1073 xmlValidCtxt cvp = { NULL }; 1074 int err = Z_SAVING_FILE; 1075 1076 if (zonecfg_check_handle(handle) != Z_OK) 1077 return (Z_BAD_HANDLE); 1078 1079 /* 1080 * We can only detach if we have taken a sw inventory. 1081 */ 1082 if (!handle->zone_dh_sw_inv) 1083 return (Z_INVAL); 1084 1085 if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK) 1086 return (err); 1087 1088 if ((err = zone_get_zonepath(zname, path, sizeof (path))) != Z_OK) 1089 return (err); 1090 1091 if (snprintf(migpath, sizeof (migpath), "%s/%s", path, DETACHED) >= 1092 sizeof (migpath)) 1093 return (Z_NOMEM); 1094 1095 if ((err = operation_prep(handle)) != Z_OK) 1096 return (err); 1097 1098 addcomment(handle, "\n DO NOT EDIT THIS FILE. " 1099 "Use zonecfg(1M) and zoneadm(1M) attach.\n"); 1100 1101 cvp.error = zonecfg_error_func; 1102 cvp.warning = zonecfg_error_func; 1103 1104 /* 1105 * We do a final validation of the document-- but the library has 1106 * malfunctioned if it fails to validate, so it's an assert. 1107 */ 1108 assert(xmlValidateDocument(&cvp, handle->zone_dh_doc) != 0); 1109 1110 if (xmlSaveFormatFile(migpath, handle->zone_dh_doc, 1) <= 0) 1111 return (Z_SAVING_FILE); 1112 1113 (void) chmod(migpath, 0644); 1114 1115 stripcomments(handle); 1116 1117 handle->zone_dh_newzone = B_FALSE; 1118 1119 return (Z_OK); 1120 } 1121 1122 boolean_t 1123 zonecfg_detached(const char *path) 1124 { 1125 char migpath[MAXPATHLEN]; 1126 struct stat buf; 1127 1128 if (snprintf(migpath, sizeof (migpath), "%s/%s", path, DETACHED) >= 1129 sizeof (migpath)) 1130 return (B_FALSE); 1131 1132 if (stat(migpath, &buf) != -1) 1133 return (B_TRUE); 1134 1135 return (B_FALSE); 1136 } 1137 1138 void 1139 zonecfg_rm_detached(zone_dochandle_t handle, boolean_t forced) 1140 { 1141 char zname[ZONENAME_MAX]; 1142 char path[MAXPATHLEN]; 1143 char detached[MAXPATHLEN]; 1144 char attached[MAXPATHLEN]; 1145 1146 if (zonecfg_check_handle(handle) != Z_OK) 1147 return; 1148 1149 if (zonecfg_get_name(handle, zname, sizeof (zname)) != Z_OK) 1150 return; 1151 1152 if (zone_get_zonepath(zname, path, sizeof (path)) != Z_OK) 1153 return; 1154 1155 (void) snprintf(detached, sizeof (detached), "%s/%s", path, DETACHED); 1156 (void) snprintf(attached, sizeof (attached), "%s/%s", path, 1157 ATTACH_FORCED); 1158 1159 if (forced) { 1160 (void) rename(detached, attached); 1161 } else { 1162 (void) unlink(attached); 1163 (void) unlink(detached); 1164 } 1165 } 1166 1167 /* 1168 * Special case: if access(2) fails with ENOENT, then try again using 1169 * ZONE_CONFIG_ROOT instead of config_file_path(zonename). This is how we 1170 * work around the case of a config file which has not been created yet: 1171 * the user will need access to the directory so use that as a heuristic. 1172 */ 1173 1174 int 1175 zonecfg_access(const char *zonename, int amode) 1176 { 1177 char path[MAXPATHLEN]; 1178 1179 if (!config_file_path(zonename, path)) 1180 return (Z_INVAL); 1181 if (access(path, amode) == 0) 1182 return (Z_OK); 1183 if (errno == ENOENT) { 1184 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root, 1185 ZONE_CONFIG_ROOT) >= sizeof (path)) 1186 return (Z_INVAL); 1187 if (access(path, amode) == 0) 1188 return (Z_OK); 1189 } 1190 if (errno == EACCES) 1191 return (Z_ACCES); 1192 if (errno == EINVAL) 1193 return (Z_INVAL); 1194 return (Z_MISC_FS); 1195 } 1196 1197 int 1198 zonecfg_create_snapshot(const char *zonename) 1199 { 1200 zone_dochandle_t handle; 1201 char path[MAXPATHLEN], zonepath[MAXPATHLEN], rpath[MAXPATHLEN]; 1202 int error = Z_OK, res; 1203 1204 if ((handle = zonecfg_init_handle()) == NULL) { 1205 return (Z_NOMEM); 1206 } 1207 1208 handle->zone_dh_newzone = B_TRUE; 1209 handle->zone_dh_snapshot = B_TRUE; 1210 1211 if ((error = zonecfg_get_handle(zonename, handle)) != Z_OK) 1212 goto out; 1213 if ((error = operation_prep(handle)) != Z_OK) 1214 goto out; 1215 error = zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)); 1216 if (error != Z_OK) 1217 goto out; 1218 if ((res = resolvepath(zonepath, rpath, sizeof (rpath))) == -1) { 1219 error = Z_RESOLVED_PATH; 1220 goto out; 1221 } 1222 /* 1223 * If the resolved path is not the same as the original path, then 1224 * save the resolved path in the snapshot, thus preventing any 1225 * potential problems down the line when zoneadmd goes to unmount 1226 * file systems and depends on initial string matches with resolved 1227 * paths. 1228 */ 1229 rpath[res] = '\0'; 1230 if (strcmp(zonepath, rpath) != 0) { 1231 if ((error = zonecfg_set_zonepath(handle, rpath)) != Z_OK) 1232 goto out; 1233 } 1234 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root, 1235 ZONE_SNAPSHOT_ROOT) >= sizeof (path)) { 1236 error = Z_MISC_FS; 1237 goto out; 1238 } 1239 if ((mkdir(path, S_IRWXU) == -1) && (errno != EEXIST)) { 1240 error = Z_MISC_FS; 1241 goto out; 1242 } 1243 1244 if (!snap_file_path(zonename, path)) { 1245 error = Z_MISC_FS; 1246 goto out; 1247 } 1248 1249 addcomment(handle, "\n DO NOT EDIT THIS FILE. " 1250 "It is a snapshot of running zone state.\n"); 1251 1252 error = zonecfg_save_impl(handle, path); 1253 1254 stripcomments(handle); 1255 1256 out: 1257 zonecfg_fini_handle(handle); 1258 return (error); 1259 } 1260 1261 static int 1262 newprop(xmlNodePtr node, const xmlChar *attrname, char *src) 1263 { 1264 xmlAttrPtr newattr; 1265 1266 newattr = xmlNewProp(node, attrname, (xmlChar *)src); 1267 if (newattr == NULL) { 1268 xmlUnlinkNode(node); 1269 xmlFreeNode(node); 1270 return (Z_BAD_PROPERTY); 1271 } 1272 return (Z_OK); 1273 } 1274 1275 static int 1276 zonecfg_add_filesystem_core(zone_dochandle_t handle, struct zone_fstab *tabptr) 1277 { 1278 xmlNodePtr newnode, cur = handle->zone_dh_cur, options_node; 1279 zone_fsopt_t *ptr; 1280 int err; 1281 1282 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_FS, NULL); 1283 if ((err = newprop(newnode, DTD_ATTR_SPECIAL, 1284 tabptr->zone_fs_special)) != Z_OK) 1285 return (err); 1286 if (tabptr->zone_fs_raw[0] != '\0' && 1287 (err = newprop(newnode, DTD_ATTR_RAW, tabptr->zone_fs_raw)) != Z_OK) 1288 return (err); 1289 if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK) 1290 return (err); 1291 if ((err = newprop(newnode, DTD_ATTR_TYPE, 1292 tabptr->zone_fs_type)) != Z_OK) 1293 return (err); 1294 if (tabptr->zone_fs_options != NULL) { 1295 for (ptr = tabptr->zone_fs_options; ptr != NULL; 1296 ptr = ptr->zone_fsopt_next) { 1297 options_node = xmlNewTextChild(newnode, NULL, 1298 DTD_ELEM_FSOPTION, NULL); 1299 if ((err = newprop(options_node, DTD_ATTR_NAME, 1300 ptr->zone_fsopt_opt)) != Z_OK) 1301 return (err); 1302 } 1303 } 1304 return (Z_OK); 1305 } 1306 1307 int 1308 zonecfg_add_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr) 1309 { 1310 int err; 1311 1312 if (tabptr == NULL) 1313 return (Z_INVAL); 1314 1315 if ((err = operation_prep(handle)) != Z_OK) 1316 return (err); 1317 1318 if ((err = zonecfg_add_filesystem_core(handle, tabptr)) != Z_OK) 1319 return (err); 1320 1321 return (Z_OK); 1322 } 1323 1324 static int 1325 zonecfg_add_ipd_core(zone_dochandle_t handle, struct zone_fstab *tabptr) 1326 { 1327 xmlNodePtr newnode, cur = handle->zone_dh_cur; 1328 int err; 1329 1330 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_IPD, NULL); 1331 if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK) 1332 return (err); 1333 return (Z_OK); 1334 } 1335 1336 int 1337 zonecfg_add_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr) 1338 { 1339 int err; 1340 1341 if (tabptr == NULL) 1342 return (Z_INVAL); 1343 1344 if ((err = operation_prep(handle)) != Z_OK) 1345 return (err); 1346 1347 if ((err = zonecfg_add_ipd_core(handle, tabptr)) != Z_OK) 1348 return (err); 1349 1350 return (Z_OK); 1351 } 1352 1353 int 1354 zonecfg_add_fs_option(struct zone_fstab *tabptr, char *option) 1355 { 1356 zone_fsopt_t *last, *old, *new; 1357 1358 last = tabptr->zone_fs_options; 1359 for (old = last; old != NULL; old = old->zone_fsopt_next) 1360 last = old; /* walk to the end of the list */ 1361 new = (zone_fsopt_t *)malloc(sizeof (zone_fsopt_t)); 1362 if (new == NULL) 1363 return (Z_NOMEM); 1364 (void) strlcpy(new->zone_fsopt_opt, option, 1365 sizeof (new->zone_fsopt_opt)); 1366 new->zone_fsopt_next = NULL; 1367 if (last == NULL) 1368 tabptr->zone_fs_options = new; 1369 else 1370 last->zone_fsopt_next = new; 1371 return (Z_OK); 1372 } 1373 1374 int 1375 zonecfg_remove_fs_option(struct zone_fstab *tabptr, char *option) 1376 { 1377 zone_fsopt_t *last, *this, *next; 1378 1379 last = tabptr->zone_fs_options; 1380 for (this = last; this != NULL; this = this->zone_fsopt_next) { 1381 if (strcmp(this->zone_fsopt_opt, option) == 0) { 1382 next = this->zone_fsopt_next; 1383 if (this == tabptr->zone_fs_options) 1384 tabptr->zone_fs_options = next; 1385 else 1386 last->zone_fsopt_next = next; 1387 free(this); 1388 return (Z_OK); 1389 } else 1390 last = this; 1391 } 1392 return (Z_NO_PROPERTY_ID); 1393 } 1394 1395 void 1396 zonecfg_free_fs_option_list(zone_fsopt_t *list) 1397 { 1398 zone_fsopt_t *this, *next; 1399 1400 for (this = list; this != NULL; this = next) { 1401 next = this->zone_fsopt_next; 1402 free(this); 1403 } 1404 } 1405 1406 void 1407 zonecfg_free_rctl_value_list(struct zone_rctlvaltab *valtab) 1408 { 1409 if (valtab == NULL) 1410 return; 1411 zonecfg_free_rctl_value_list(valtab->zone_rctlval_next); 1412 free(valtab); 1413 } 1414 1415 static boolean_t 1416 match_prop(xmlNodePtr cur, const xmlChar *attr, char *user_prop) 1417 { 1418 xmlChar *gotten_prop; 1419 int prop_result; 1420 1421 gotten_prop = xmlGetProp(cur, attr); 1422 if (gotten_prop == NULL) /* shouldn't happen */ 1423 return (B_FALSE); 1424 prop_result = xmlStrcmp(gotten_prop, (const xmlChar *) user_prop); 1425 xmlFree(gotten_prop); 1426 return ((prop_result == 0)); 1427 } 1428 1429 static int 1430 zonecfg_delete_filesystem_core(zone_dochandle_t handle, 1431 struct zone_fstab *tabptr) 1432 { 1433 xmlNodePtr cur = handle->zone_dh_cur; 1434 boolean_t dir_match, spec_match, raw_match, type_match; 1435 1436 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1437 if (xmlStrcmp(cur->name, DTD_ELEM_FS)) 1438 continue; 1439 dir_match = match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir); 1440 spec_match = match_prop(cur, DTD_ATTR_SPECIAL, 1441 tabptr->zone_fs_special); 1442 raw_match = match_prop(cur, DTD_ATTR_RAW, 1443 tabptr->zone_fs_raw); 1444 type_match = match_prop(cur, DTD_ATTR_TYPE, 1445 tabptr->zone_fs_type); 1446 if (dir_match && spec_match && raw_match && type_match) { 1447 xmlUnlinkNode(cur); 1448 xmlFreeNode(cur); 1449 return (Z_OK); 1450 } 1451 } 1452 return (Z_NO_RESOURCE_ID); 1453 } 1454 1455 int 1456 zonecfg_delete_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr) 1457 { 1458 int err; 1459 1460 if (tabptr == NULL) 1461 return (Z_INVAL); 1462 1463 if ((err = operation_prep(handle)) != Z_OK) 1464 return (err); 1465 1466 if ((err = zonecfg_delete_filesystem_core(handle, tabptr)) != Z_OK) 1467 return (err); 1468 1469 return (Z_OK); 1470 } 1471 1472 int 1473 zonecfg_modify_filesystem( 1474 zone_dochandle_t handle, 1475 struct zone_fstab *oldtabptr, 1476 struct zone_fstab *newtabptr) 1477 { 1478 int err; 1479 1480 if (oldtabptr == NULL || newtabptr == NULL) 1481 return (Z_INVAL); 1482 1483 if ((err = operation_prep(handle)) != Z_OK) 1484 return (err); 1485 1486 if ((err = zonecfg_delete_filesystem_core(handle, oldtabptr)) != Z_OK) 1487 return (err); 1488 1489 if ((err = zonecfg_add_filesystem_core(handle, newtabptr)) != Z_OK) 1490 return (err); 1491 1492 return (Z_OK); 1493 } 1494 1495 static int 1496 zonecfg_delete_ipd_core(zone_dochandle_t handle, struct zone_fstab *tabptr) 1497 { 1498 xmlNodePtr cur = handle->zone_dh_cur; 1499 1500 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1501 if (xmlStrcmp(cur->name, DTD_ELEM_IPD)) 1502 continue; 1503 if (match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir)) { 1504 xmlUnlinkNode(cur); 1505 xmlFreeNode(cur); 1506 return (Z_OK); 1507 } 1508 } 1509 return (Z_NO_RESOURCE_ID); 1510 } 1511 1512 int 1513 zonecfg_delete_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr) 1514 { 1515 int err; 1516 1517 if (tabptr == NULL) 1518 return (Z_INVAL); 1519 1520 if ((err = operation_prep(handle)) != Z_OK) 1521 return (err); 1522 1523 if ((err = zonecfg_delete_ipd_core(handle, tabptr)) != Z_OK) 1524 return (err); 1525 1526 return (Z_OK); 1527 } 1528 1529 int 1530 zonecfg_modify_ipd(zone_dochandle_t handle, struct zone_fstab *oldtabptr, 1531 struct zone_fstab *newtabptr) 1532 { 1533 int err; 1534 1535 if (oldtabptr == NULL || newtabptr == NULL) 1536 return (Z_INVAL); 1537 1538 if ((err = operation_prep(handle)) != Z_OK) 1539 return (err); 1540 1541 if ((err = zonecfg_delete_ipd_core(handle, oldtabptr)) != Z_OK) 1542 return (err); 1543 1544 if ((err = zonecfg_add_ipd_core(handle, newtabptr)) != Z_OK) 1545 return (err); 1546 1547 return (Z_OK); 1548 } 1549 1550 int 1551 zonecfg_lookup_filesystem( 1552 zone_dochandle_t handle, 1553 struct zone_fstab *tabptr) 1554 { 1555 xmlNodePtr cur, options, firstmatch; 1556 int err; 1557 char dirname[MAXPATHLEN], special[MAXPATHLEN], raw[MAXPATHLEN]; 1558 char type[FSTYPSZ]; 1559 char options_str[MAX_MNTOPT_STR]; 1560 1561 if (tabptr == NULL) 1562 return (Z_INVAL); 1563 1564 if ((err = operation_prep(handle)) != Z_OK) 1565 return (err); 1566 1567 /* 1568 * Walk the list of children looking for matches on any properties 1569 * specified in the fstab parameter. If more than one resource 1570 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return 1571 * Z_NO_RESOURCE_ID. 1572 */ 1573 cur = handle->zone_dh_cur; 1574 firstmatch = NULL; 1575 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1576 if (xmlStrcmp(cur->name, DTD_ELEM_FS)) 1577 continue; 1578 if (strlen(tabptr->zone_fs_dir) > 0) { 1579 if ((fetchprop(cur, DTD_ATTR_DIR, dirname, 1580 sizeof (dirname)) == Z_OK) && 1581 (strcmp(tabptr->zone_fs_dir, dirname) == 0)) { 1582 if (firstmatch == NULL) 1583 firstmatch = cur; 1584 else 1585 return (Z_INSUFFICIENT_SPEC); 1586 } 1587 } 1588 if (strlen(tabptr->zone_fs_special) > 0) { 1589 if ((fetchprop(cur, DTD_ATTR_SPECIAL, special, 1590 sizeof (special)) == Z_OK)) { 1591 if (strcmp(tabptr->zone_fs_special, 1592 special) == 0) { 1593 if (firstmatch == NULL) 1594 firstmatch = cur; 1595 else if (firstmatch != cur) 1596 return (Z_INSUFFICIENT_SPEC); 1597 } else { 1598 /* 1599 * If another property matched but this 1600 * one doesn't then reset firstmatch. 1601 */ 1602 if (firstmatch == cur) 1603 firstmatch = NULL; 1604 } 1605 } 1606 } 1607 if (strlen(tabptr->zone_fs_raw) > 0) { 1608 if ((fetchprop(cur, DTD_ATTR_RAW, raw, 1609 sizeof (raw)) == Z_OK)) { 1610 if (strcmp(tabptr->zone_fs_raw, raw) == 0) { 1611 if (firstmatch == NULL) 1612 firstmatch = cur; 1613 else if (firstmatch != cur) 1614 return (Z_INSUFFICIENT_SPEC); 1615 } else { 1616 /* 1617 * If another property matched but this 1618 * one doesn't then reset firstmatch. 1619 */ 1620 if (firstmatch == cur) 1621 firstmatch = NULL; 1622 } 1623 } 1624 } 1625 if (strlen(tabptr->zone_fs_type) > 0) { 1626 if ((fetchprop(cur, DTD_ATTR_TYPE, type, 1627 sizeof (type)) == Z_OK)) { 1628 if (strcmp(tabptr->zone_fs_type, type) == 0) { 1629 if (firstmatch == NULL) 1630 firstmatch = cur; 1631 else if (firstmatch != cur) 1632 return (Z_INSUFFICIENT_SPEC); 1633 } else { 1634 /* 1635 * If another property matched but this 1636 * one doesn't then reset firstmatch. 1637 */ 1638 if (firstmatch == cur) 1639 firstmatch = NULL; 1640 } 1641 } 1642 } 1643 } 1644 1645 if (firstmatch == NULL) 1646 return (Z_NO_RESOURCE_ID); 1647 1648 cur = firstmatch; 1649 1650 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 1651 sizeof (tabptr->zone_fs_dir))) != Z_OK) 1652 return (err); 1653 1654 if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special, 1655 sizeof (tabptr->zone_fs_special))) != Z_OK) 1656 return (err); 1657 1658 if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw, 1659 sizeof (tabptr->zone_fs_raw))) != Z_OK) 1660 return (err); 1661 1662 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type, 1663 sizeof (tabptr->zone_fs_type))) != Z_OK) 1664 return (err); 1665 1666 /* options are optional */ 1667 tabptr->zone_fs_options = NULL; 1668 for (options = cur->xmlChildrenNode; options != NULL; 1669 options = options->next) { 1670 if ((fetchprop(options, DTD_ATTR_NAME, options_str, 1671 sizeof (options_str)) != Z_OK)) 1672 break; 1673 if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK) 1674 break; 1675 } 1676 return (Z_OK); 1677 } 1678 1679 int 1680 zonecfg_lookup_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr) 1681 { 1682 xmlNodePtr cur, match; 1683 int err; 1684 char dirname[MAXPATHLEN]; 1685 1686 if (tabptr == NULL) 1687 return (Z_INVAL); 1688 1689 if ((err = operation_prep(handle)) != Z_OK) 1690 return (err); 1691 1692 /* 1693 * General algorithm: 1694 * Walk the list of children looking for matches on any properties 1695 * specified in the fstab parameter. If more than one resource 1696 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return 1697 * Z_NO_RESOURCE_ID. 1698 */ 1699 cur = handle->zone_dh_cur; 1700 match = NULL; 1701 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1702 if (xmlStrcmp(cur->name, DTD_ELEM_IPD)) 1703 continue; 1704 if (strlen(tabptr->zone_fs_dir) > 0) { 1705 if ((fetchprop(cur, DTD_ATTR_DIR, dirname, 1706 sizeof (dirname)) == Z_OK) && 1707 (strcmp(tabptr->zone_fs_dir, dirname) == 0)) { 1708 if (match == NULL) 1709 match = cur; 1710 else 1711 return (Z_INSUFFICIENT_SPEC); 1712 } 1713 } 1714 } 1715 1716 if (match == NULL) 1717 return (Z_NO_RESOURCE_ID); 1718 1719 cur = match; 1720 1721 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 1722 sizeof (tabptr->zone_fs_dir))) != Z_OK) 1723 return (err); 1724 1725 return (Z_OK); 1726 } 1727 1728 /* 1729 * Compare two IP addresses in string form. Allow for the possibility that 1730 * one might have "/<prefix-length>" at the end: allow a match on just the 1731 * IP address (or host name) part. 1732 */ 1733 1734 boolean_t 1735 zonecfg_same_net_address(char *a1, char *a2) 1736 { 1737 char *slashp, *slashp1, *slashp2; 1738 int result; 1739 1740 if (strcmp(a1, a2) == 0) 1741 return (B_TRUE); 1742 1743 /* 1744 * If neither has a slash or both do, they need to match to be 1745 * considered the same, but they did not match above, so fail. 1746 */ 1747 slashp1 = strchr(a1, '/'); 1748 slashp2 = strchr(a2, '/'); 1749 if ((slashp1 == NULL && slashp2 == NULL) || 1750 (slashp1 != NULL && slashp2 != NULL)) 1751 return (B_FALSE); 1752 1753 /* 1754 * Only one had a slash: pick that one, zero out the slash, compare 1755 * the "address only" strings, restore the slash, and return the 1756 * result of the comparison. 1757 */ 1758 slashp = (slashp1 == NULL) ? slashp2 : slashp1; 1759 *slashp = '\0'; 1760 result = strcmp(a1, a2); 1761 *slashp = '/'; 1762 return ((result == 0)); 1763 } 1764 1765 int 1766 zonecfg_valid_net_address(char *address, struct lifreq *lifr) 1767 { 1768 struct sockaddr_in *sin4; 1769 struct sockaddr_in6 *sin6; 1770 struct addrinfo hints, *result; 1771 char *slashp = strchr(address, '/'); 1772 1773 bzero(lifr, sizeof (struct lifreq)); 1774 sin4 = (struct sockaddr_in *)&lifr->lifr_addr; 1775 sin6 = (struct sockaddr_in6 *)&lifr->lifr_addr; 1776 if (slashp != NULL) 1777 *slashp = '\0'; 1778 if (inet_pton(AF_INET, address, &sin4->sin_addr) == 1) { 1779 sin4->sin_family = AF_INET; 1780 } else if (inet_pton(AF_INET6, address, &sin6->sin6_addr) == 1) { 1781 if (slashp == NULL) 1782 return (Z_IPV6_ADDR_PREFIX_LEN); 1783 sin6->sin6_family = AF_INET6; 1784 } else { 1785 /* "address" may be a host name */ 1786 (void) memset(&hints, 0, sizeof (hints)); 1787 hints.ai_family = PF_INET; 1788 if (getaddrinfo(address, NULL, &hints, &result) != 0) 1789 return (Z_BOGUS_ADDRESS); 1790 sin4->sin_family = result->ai_family; 1791 1792 (void) memcpy(&sin4->sin_addr, 1793 /* LINTED E_BAD_PTR_CAST_ALIGN */ 1794 &((struct sockaddr_in *)result->ai_addr)->sin_addr, 1795 sizeof (struct in_addr)); 1796 1797 freeaddrinfo(result); 1798 } 1799 return (Z_OK); 1800 } 1801 1802 int 1803 zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 1804 { 1805 xmlNodePtr cur, firstmatch; 1806 int err; 1807 char address[INET6_ADDRSTRLEN], physical[LIFNAMSIZ]; 1808 1809 if (tabptr == NULL) 1810 return (Z_INVAL); 1811 1812 if ((err = operation_prep(handle)) != Z_OK) 1813 return (err); 1814 1815 cur = handle->zone_dh_cur; 1816 firstmatch = NULL; 1817 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1818 if (xmlStrcmp(cur->name, DTD_ELEM_NET)) 1819 continue; 1820 if (strlen(tabptr->zone_nwif_physical) > 0) { 1821 if ((fetchprop(cur, DTD_ATTR_PHYSICAL, physical, 1822 sizeof (physical)) == Z_OK) && 1823 (strcmp(tabptr->zone_nwif_physical, 1824 physical) == 0)) { 1825 if (firstmatch == NULL) 1826 firstmatch = cur; 1827 else 1828 return (Z_INSUFFICIENT_SPEC); 1829 } 1830 } 1831 if (strlen(tabptr->zone_nwif_address) > 0) { 1832 if ((fetchprop(cur, DTD_ATTR_ADDRESS, address, 1833 sizeof (address)) == Z_OK)) { 1834 if (zonecfg_same_net_address( 1835 tabptr->zone_nwif_address, address)) { 1836 if (firstmatch == NULL) 1837 firstmatch = cur; 1838 else if (firstmatch != cur) 1839 return (Z_INSUFFICIENT_SPEC); 1840 } else { 1841 /* 1842 * If another property matched but this 1843 * one doesn't then reset firstmatch. 1844 */ 1845 if (firstmatch == cur) 1846 firstmatch = NULL; 1847 } 1848 } 1849 } 1850 } 1851 if (firstmatch == NULL) 1852 return (Z_NO_RESOURCE_ID); 1853 1854 cur = firstmatch; 1855 1856 if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical, 1857 sizeof (tabptr->zone_nwif_physical))) != Z_OK) 1858 return (err); 1859 1860 if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address, 1861 sizeof (tabptr->zone_nwif_address))) != Z_OK) 1862 return (err); 1863 1864 return (Z_OK); 1865 } 1866 1867 static int 1868 zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 1869 { 1870 xmlNodePtr newnode, cur = handle->zone_dh_cur; 1871 int err; 1872 1873 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL); 1874 if ((err = newprop(newnode, DTD_ATTR_ADDRESS, 1875 tabptr->zone_nwif_address)) != Z_OK) 1876 return (err); 1877 if ((err = newprop(newnode, DTD_ATTR_PHYSICAL, 1878 tabptr->zone_nwif_physical)) != Z_OK) 1879 return (err); 1880 return (Z_OK); 1881 } 1882 1883 int 1884 zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 1885 { 1886 int err; 1887 1888 if (tabptr == NULL) 1889 return (Z_INVAL); 1890 1891 if ((err = operation_prep(handle)) != Z_OK) 1892 return (err); 1893 1894 if ((err = zonecfg_add_nwif_core(handle, tabptr)) != Z_OK) 1895 return (err); 1896 1897 return (Z_OK); 1898 } 1899 1900 static int 1901 zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 1902 { 1903 xmlNodePtr cur = handle->zone_dh_cur; 1904 boolean_t addr_match, phys_match; 1905 1906 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1907 if (xmlStrcmp(cur->name, DTD_ELEM_NET)) 1908 continue; 1909 1910 addr_match = match_prop(cur, DTD_ATTR_ADDRESS, 1911 tabptr->zone_nwif_address); 1912 phys_match = match_prop(cur, DTD_ATTR_PHYSICAL, 1913 tabptr->zone_nwif_physical); 1914 1915 if (addr_match && phys_match) { 1916 xmlUnlinkNode(cur); 1917 xmlFreeNode(cur); 1918 return (Z_OK); 1919 } 1920 } 1921 return (Z_NO_RESOURCE_ID); 1922 } 1923 1924 int 1925 zonecfg_delete_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 1926 { 1927 int err; 1928 1929 if (tabptr == NULL) 1930 return (Z_INVAL); 1931 1932 if ((err = operation_prep(handle)) != Z_OK) 1933 return (err); 1934 1935 if ((err = zonecfg_delete_nwif_core(handle, tabptr)) != Z_OK) 1936 return (err); 1937 1938 return (Z_OK); 1939 } 1940 1941 int 1942 zonecfg_modify_nwif( 1943 zone_dochandle_t handle, 1944 struct zone_nwiftab *oldtabptr, 1945 struct zone_nwiftab *newtabptr) 1946 { 1947 int err; 1948 1949 if (oldtabptr == NULL || newtabptr == NULL) 1950 return (Z_INVAL); 1951 1952 if ((err = operation_prep(handle)) != Z_OK) 1953 return (err); 1954 1955 if ((err = zonecfg_delete_nwif_core(handle, oldtabptr)) != Z_OK) 1956 return (err); 1957 1958 if ((err = zonecfg_add_nwif_core(handle, newtabptr)) != Z_OK) 1959 return (err); 1960 1961 return (Z_OK); 1962 } 1963 1964 int 1965 zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) 1966 { 1967 xmlNodePtr cur, firstmatch; 1968 int err; 1969 char match[MAXPATHLEN]; 1970 1971 if (tabptr == NULL) 1972 return (Z_INVAL); 1973 1974 if ((err = operation_prep(handle)) != Z_OK) 1975 return (err); 1976 1977 cur = handle->zone_dh_cur; 1978 firstmatch = NULL; 1979 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1980 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) 1981 continue; 1982 if (strlen(tabptr->zone_dev_match) == 0) 1983 continue; 1984 1985 if ((fetchprop(cur, DTD_ATTR_MATCH, match, 1986 sizeof (match)) == Z_OK)) { 1987 if (strcmp(tabptr->zone_dev_match, 1988 match) == 0) { 1989 if (firstmatch == NULL) 1990 firstmatch = cur; 1991 else if (firstmatch != cur) 1992 return (Z_INSUFFICIENT_SPEC); 1993 } else { 1994 /* 1995 * If another property matched but this 1996 * one doesn't then reset firstmatch. 1997 */ 1998 if (firstmatch == cur) 1999 firstmatch = NULL; 2000 } 2001 } 2002 } 2003 if (firstmatch == NULL) 2004 return (Z_NO_RESOURCE_ID); 2005 2006 cur = firstmatch; 2007 2008 if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match, 2009 sizeof (tabptr->zone_dev_match))) != Z_OK) 2010 return (err); 2011 2012 return (Z_OK); 2013 } 2014 2015 static int 2016 zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr) 2017 { 2018 xmlNodePtr newnode, cur = handle->zone_dh_cur; 2019 int err; 2020 2021 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL); 2022 2023 if ((err = newprop(newnode, DTD_ATTR_MATCH, 2024 tabptr->zone_dev_match)) != Z_OK) 2025 return (err); 2026 2027 return (Z_OK); 2028 } 2029 2030 int 2031 zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) 2032 { 2033 int err; 2034 2035 if (tabptr == NULL) 2036 return (Z_INVAL); 2037 2038 if ((err = operation_prep(handle)) != Z_OK) 2039 return (err); 2040 2041 if ((err = zonecfg_add_dev_core(handle, tabptr)) != Z_OK) 2042 return (err); 2043 2044 return (Z_OK); 2045 } 2046 2047 static int 2048 zonecfg_delete_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr) 2049 { 2050 xmlNodePtr cur = handle->zone_dh_cur; 2051 int match_match; 2052 2053 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2054 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) 2055 continue; 2056 2057 match_match = match_prop(cur, DTD_ATTR_MATCH, 2058 tabptr->zone_dev_match); 2059 2060 if (match_match) { 2061 xmlUnlinkNode(cur); 2062 xmlFreeNode(cur); 2063 return (Z_OK); 2064 } 2065 } 2066 return (Z_NO_RESOURCE_ID); 2067 } 2068 2069 int 2070 zonecfg_delete_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) 2071 { 2072 int err; 2073 2074 if (tabptr == NULL) 2075 return (Z_INVAL); 2076 2077 if ((err = operation_prep(handle)) != Z_OK) 2078 return (err); 2079 2080 if ((err = zonecfg_delete_dev_core(handle, tabptr)) != Z_OK) 2081 return (err); 2082 2083 return (Z_OK); 2084 } 2085 2086 int 2087 zonecfg_modify_dev( 2088 zone_dochandle_t handle, 2089 struct zone_devtab *oldtabptr, 2090 struct zone_devtab *newtabptr) 2091 { 2092 int err; 2093 2094 if (oldtabptr == NULL || newtabptr == NULL) 2095 return (Z_INVAL); 2096 2097 if ((err = operation_prep(handle)) != Z_OK) 2098 return (err); 2099 2100 if ((err = zonecfg_delete_dev_core(handle, oldtabptr)) != Z_OK) 2101 return (err); 2102 2103 if ((err = zonecfg_add_dev_core(handle, newtabptr)) != Z_OK) 2104 return (err); 2105 2106 return (Z_OK); 2107 } 2108 2109 /* Lock to serialize all zonecfg_devwalks */ 2110 static pthread_mutex_t zonecfg_devwalk_lock = PTHREAD_MUTEX_INITIALIZER; 2111 /* 2112 * Global variables used to pass data from zonecfg_devwalk to the nftw 2113 * call-back (zonecfg_devwalk_cb). g_devwalk_data is really the void* 2114 * parameter and g_devwalk_cb is really the *cb parameter from zonecfg_devwalk. 2115 */ 2116 static void *g_devwalk_data; 2117 static int (*g_devwalk_cb)(const char *, uid_t, gid_t, mode_t, const char *, 2118 void *); 2119 static size_t g_devwalk_skip_prefix; 2120 2121 /* 2122 * This is the nftw call-back function used by zonecfg_devwalk. It is 2123 * responsible for calling the actual call-back that is passed in to 2124 * zonecfg_devwalk as the *cb argument. 2125 */ 2126 /* ARGSUSED2 */ 2127 static int 2128 zonecfg_devwalk_cb(const char *path, const struct stat *st, int f, 2129 struct FTW *ftw) 2130 { 2131 acl_t *acl; 2132 char *acl_txt = NULL; 2133 2134 /* skip all but character and block devices */ 2135 if (!S_ISBLK(st->st_mode) && !S_ISCHR(st->st_mode)) 2136 return (0); 2137 2138 if ((acl_get(path, ACL_NO_TRIVIAL, &acl) == 0) && 2139 acl != NULL) { 2140 acl_txt = acl_totext(acl, ACL_NORESOLVE); 2141 acl_free(acl); 2142 } 2143 2144 if (strlen(path) <= g_devwalk_skip_prefix) 2145 return (0); 2146 2147 g_devwalk_cb(path + g_devwalk_skip_prefix, st->st_uid, st->st_gid, 2148 st->st_mode & S_IAMB, acl_txt != NULL ? acl_txt : "", 2149 g_devwalk_data); 2150 free(acl_txt); 2151 return (0); 2152 } 2153 2154 /* 2155 * Walk the dev tree for the zone specified by hdl and call the call-back (cb) 2156 * function for each entry in the tree. The call-back will be passed the 2157 * name, uid, gid, mode, acl string and the void *data input parameter 2158 * for each dev entry. 2159 * 2160 * Data is passed to the zonecfg_devwalk_cb through the global variables 2161 * g_devwalk_data, *g_devwalk_cb, and g_devwalk_skip_prefix. The 2162 * zonecfg_devwalk_cb function will actually call *cb. 2163 */ 2164 int 2165 zonecfg_devwalk(zone_dochandle_t hdl, 2166 int (*cb)(const char *, uid_t, gid_t, mode_t, const char *, void *), 2167 void *data) 2168 { 2169 char path[MAXPATHLEN]; 2170 int ret; 2171 2172 if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK) 2173 return (ret); 2174 2175 if (strlcat(path, "/dev", sizeof (path)) >= sizeof (path)) 2176 return (Z_TOO_BIG); 2177 g_devwalk_skip_prefix = strlen(path) + 1; 2178 2179 /* 2180 * We have to serialize all zonecfg_devwalks in the same process 2181 * (which should be fine), since nftw() is so badly designed. 2182 */ 2183 (void) pthread_mutex_lock(&zonecfg_devwalk_lock); 2184 2185 g_devwalk_data = data; 2186 g_devwalk_cb = cb; 2187 (void) nftw(path, zonecfg_devwalk_cb, 0, FTW_PHYS); 2188 2189 (void) pthread_mutex_unlock(&zonecfg_devwalk_lock); 2190 return (Z_OK); 2191 } 2192 2193 /* 2194 * Update the owner, group, mode and acl on the specified dev (inpath) for 2195 * the zone (hdl). This function can be used to fix up the dev tree after 2196 * attaching a migrated zone. 2197 */ 2198 int 2199 zonecfg_devperms_apply(zone_dochandle_t hdl, const char *inpath, uid_t owner, 2200 gid_t group, mode_t mode, const char *acltxt) 2201 { 2202 int ret; 2203 char path[MAXPATHLEN]; 2204 struct stat st; 2205 acl_t *aclp; 2206 2207 if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK) 2208 return (ret); 2209 2210 if (strlcat(path, "/dev/", sizeof (path)) >= sizeof (path)) 2211 return (Z_TOO_BIG); 2212 if (strlcat(path, inpath, sizeof (path)) >= sizeof (path)) 2213 return (Z_TOO_BIG); 2214 2215 if (stat(path, &st) == -1) 2216 return (Z_INVAL); 2217 2218 /* make sure we're only touching device nodes */ 2219 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) 2220 return (Z_INVAL); 2221 2222 if (chown(path, owner, group) == -1) 2223 return (Z_SYSTEM); 2224 2225 if (chmod(path, mode) == -1) 2226 return (Z_SYSTEM); 2227 2228 if ((acltxt == NULL) || (strcmp(acltxt, "") == 0)) 2229 return (Z_OK); 2230 2231 if (acl_fromtext(acltxt, &aclp) != 0) 2232 return (Z_SYSTEM); 2233 2234 errno = 0; 2235 if (acl_set(path, aclp) == -1) { 2236 free(aclp); 2237 return (Z_SYSTEM); 2238 } 2239 2240 free(aclp); 2241 return (Z_OK); 2242 } 2243 2244 /* 2245 * This is the set of devices which must be present in every zone. Users 2246 * can augment this list with additional device rules in their zone 2247 * configuration, but at present cannot remove any of the this set of 2248 * standard devices. All matching is done by /dev pathname (the "/dev" 2249 * part is implicit. Try to keep rules which match a large number of 2250 * devices (like the pts rule) first. 2251 */ 2252 static const char *standard_devs[] = { 2253 "pts/*", 2254 "ptmx", 2255 "random", 2256 "urandom", 2257 "poll", 2258 "pool", 2259 "kstat", 2260 "zero", 2261 "null", 2262 "crypto", 2263 "cryptoadm", 2264 "ticots", 2265 "ticotsord", 2266 "ticlts", 2267 "lo0", 2268 "lo1", 2269 "lo2", 2270 "lo3", 2271 "sad/user", 2272 "tty", 2273 "logindmux", 2274 "log", 2275 "conslog", 2276 "arp", 2277 "tcp", 2278 "tcp6", 2279 "udp", 2280 "udp6", 2281 "sysevent", 2282 #ifdef __sparc 2283 "openprom", 2284 #endif 2285 "cpu/self/cpuid", 2286 "dtrace/*", 2287 "dtrace/provider/*", 2288 "zfs", 2289 NULL 2290 }; 2291 2292 /* 2293 * This function finds everything mounted under a zone's rootpath. 2294 * This returns the number of mounts under rootpath, or -1 on error. 2295 * callback is called once per mount found with the first argument 2296 * pointing to the mount point. 2297 * 2298 * If the callback function returns non-zero zonecfg_find_mounts 2299 * aborts with an error. 2300 */ 2301 2302 int 2303 zonecfg_find_mounts(char *rootpath, int (*callback)(const char *, void *), 2304 void *priv) { 2305 FILE *mnttab; 2306 struct mnttab m; 2307 size_t l; 2308 int zfsl; 2309 int rv = 0; 2310 char zfs_path[MAXPATHLEN]; 2311 2312 assert(rootpath != NULL); 2313 2314 if ((zfsl = snprintf(zfs_path, sizeof (zfs_path), "%s/.zfs/", rootpath)) 2315 >= sizeof (zfs_path)) 2316 return (-1); 2317 2318 l = strlen(rootpath); 2319 2320 mnttab = fopen("/etc/mnttab", "r"); 2321 2322 if (mnttab == NULL) 2323 return (-1); 2324 2325 if (ioctl(fileno(mnttab), MNTIOC_SHOWHIDDEN, NULL) < 0) { 2326 rv = -1; 2327 goto out; 2328 } 2329 2330 while (!getmntent(mnttab, &m)) { 2331 if ((strncmp(rootpath, m.mnt_mountp, l) == 0) && 2332 (m.mnt_mountp[l] == '/') && 2333 (strncmp(zfs_path, m.mnt_mountp, zfsl) != 0)) { 2334 rv++; 2335 if (callback == NULL) 2336 continue; 2337 if (callback(m.mnt_mountp, priv)) { 2338 rv = -1; 2339 goto out; 2340 2341 } 2342 } 2343 } 2344 2345 out: 2346 (void) fclose(mnttab); 2347 return (rv); 2348 } 2349 2350 /* 2351 * This routine is used to determine if a given device should appear in the 2352 * zone represented by 'handle'. First it consults the list of "standard" 2353 * zone devices. Then it scans the user-supplied device entries. 2354 */ 2355 int 2356 zonecfg_match_dev(zone_dochandle_t handle, char *devpath, 2357 struct zone_devtab *out_match) 2358 { 2359 int err; 2360 boolean_t found = B_FALSE; 2361 char match[MAXPATHLEN]; 2362 const char **stdmatch; 2363 xmlNodePtr cur; 2364 2365 if (handle == NULL || devpath == NULL) 2366 return (Z_INVAL); 2367 2368 /* 2369 * Check the "standard" devices which we require to be present. 2370 */ 2371 for (stdmatch = &standard_devs[0]; *stdmatch != NULL; stdmatch++) { 2372 /* 2373 * fnmatch gives us simple but powerful shell-style matching. 2374 */ 2375 if (fnmatch(*stdmatch, devpath, FNM_PATHNAME) == 0) { 2376 if (!out_match) 2377 return (Z_OK); 2378 (void) snprintf(out_match->zone_dev_match, 2379 sizeof (out_match->zone_dev_match), 2380 "/dev/%s", *stdmatch); 2381 return (Z_OK); 2382 } 2383 } 2384 2385 /* 2386 * We got no hits in the set of standard devices. On to the user 2387 * supplied ones. 2388 */ 2389 if ((err = operation_prep(handle)) != Z_OK) { 2390 handle->zone_dh_cur = NULL; 2391 return (err); 2392 } 2393 2394 cur = handle->zone_dh_cur; 2395 cur = cur->xmlChildrenNode; 2396 if (cur == NULL) 2397 return (Z_NO_ENTRY); 2398 handle->zone_dh_cur = cur; 2399 2400 for (; cur != NULL; cur = cur->next) { 2401 char *m; 2402 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE) != 0) 2403 continue; 2404 if ((err = fetchprop(cur, DTD_ATTR_MATCH, match, 2405 sizeof (match))) != Z_OK) { 2406 handle->zone_dh_cur = handle->zone_dh_top; 2407 return (err); 2408 } 2409 m = match; 2410 /* 2411 * fnmatch gives us simple but powerful shell-style matching; 2412 * but first, we need to strip out /dev/ from the matching rule. 2413 */ 2414 if (strncmp(m, "/dev/", 5) == 0) 2415 m += 5; 2416 2417 if (fnmatch(m, devpath, FNM_PATHNAME) == 0) { 2418 found = B_TRUE; 2419 break; 2420 } 2421 } 2422 2423 if (!found) 2424 return (Z_NO_ENTRY); 2425 2426 if (!out_match) 2427 return (Z_OK); 2428 2429 (void) strlcpy(out_match->zone_dev_match, match, 2430 sizeof (out_match->zone_dev_match)); 2431 return (Z_OK); 2432 } 2433 2434 int 2435 zonecfg_lookup_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2436 { 2437 xmlNodePtr cur, firstmatch; 2438 int err; 2439 char name[MAXNAMELEN], type[MAXNAMELEN], value[MAXNAMELEN]; 2440 2441 if (tabptr == NULL) 2442 return (Z_INVAL); 2443 2444 if ((err = operation_prep(handle)) != Z_OK) 2445 return (err); 2446 2447 cur = handle->zone_dh_cur; 2448 firstmatch = NULL; 2449 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2450 if (xmlStrcmp(cur->name, DTD_ELEM_ATTR)) 2451 continue; 2452 if (strlen(tabptr->zone_attr_name) > 0) { 2453 if ((fetchprop(cur, DTD_ATTR_NAME, name, 2454 sizeof (name)) == Z_OK) && 2455 (strcmp(tabptr->zone_attr_name, name) == 0)) { 2456 if (firstmatch == NULL) 2457 firstmatch = cur; 2458 else 2459 return (Z_INSUFFICIENT_SPEC); 2460 } 2461 } 2462 if (strlen(tabptr->zone_attr_type) > 0) { 2463 if ((fetchprop(cur, DTD_ATTR_TYPE, type, 2464 sizeof (type)) == Z_OK)) { 2465 if (strcmp(tabptr->zone_attr_type, type) == 0) { 2466 if (firstmatch == NULL) 2467 firstmatch = cur; 2468 else if (firstmatch != cur) 2469 return (Z_INSUFFICIENT_SPEC); 2470 } else { 2471 /* 2472 * If another property matched but this 2473 * one doesn't then reset firstmatch. 2474 */ 2475 if (firstmatch == cur) 2476 firstmatch = NULL; 2477 } 2478 } 2479 } 2480 if (strlen(tabptr->zone_attr_value) > 0) { 2481 if ((fetchprop(cur, DTD_ATTR_VALUE, value, 2482 sizeof (value)) == Z_OK)) { 2483 if (strcmp(tabptr->zone_attr_value, value) == 2484 0) { 2485 if (firstmatch == NULL) 2486 firstmatch = cur; 2487 else if (firstmatch != cur) 2488 return (Z_INSUFFICIENT_SPEC); 2489 } else { 2490 /* 2491 * If another property matched but this 2492 * one doesn't then reset firstmatch. 2493 */ 2494 if (firstmatch == cur) 2495 firstmatch = NULL; 2496 } 2497 } 2498 } 2499 } 2500 if (firstmatch == NULL) 2501 return (Z_NO_RESOURCE_ID); 2502 2503 cur = firstmatch; 2504 2505 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name, 2506 sizeof (tabptr->zone_attr_name))) != Z_OK) 2507 return (err); 2508 2509 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type, 2510 sizeof (tabptr->zone_attr_type))) != Z_OK) 2511 return (err); 2512 2513 if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value, 2514 sizeof (tabptr->zone_attr_value))) != Z_OK) 2515 return (err); 2516 2517 return (Z_OK); 2518 } 2519 2520 static int 2521 zonecfg_add_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2522 { 2523 xmlNodePtr newnode, cur = handle->zone_dh_cur; 2524 int err; 2525 2526 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ATTR, NULL); 2527 err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_attr_name); 2528 if (err != Z_OK) 2529 return (err); 2530 err = newprop(newnode, DTD_ATTR_TYPE, tabptr->zone_attr_type); 2531 if (err != Z_OK) 2532 return (err); 2533 err = newprop(newnode, DTD_ATTR_VALUE, tabptr->zone_attr_value); 2534 if (err != Z_OK) 2535 return (err); 2536 return (Z_OK); 2537 } 2538 2539 int 2540 zonecfg_add_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2541 { 2542 int err; 2543 2544 if (tabptr == NULL) 2545 return (Z_INVAL); 2546 2547 if ((err = operation_prep(handle)) != Z_OK) 2548 return (err); 2549 2550 if ((err = zonecfg_add_attr_core(handle, tabptr)) != Z_OK) 2551 return (err); 2552 2553 return (Z_OK); 2554 } 2555 2556 static int 2557 zonecfg_delete_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2558 { 2559 xmlNodePtr cur = handle->zone_dh_cur; 2560 int name_match, type_match, value_match; 2561 2562 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2563 if (xmlStrcmp(cur->name, DTD_ELEM_ATTR)) 2564 continue; 2565 2566 name_match = match_prop(cur, DTD_ATTR_NAME, 2567 tabptr->zone_attr_name); 2568 type_match = match_prop(cur, DTD_ATTR_TYPE, 2569 tabptr->zone_attr_type); 2570 value_match = match_prop(cur, DTD_ATTR_VALUE, 2571 tabptr->zone_attr_value); 2572 2573 if (name_match && type_match && value_match) { 2574 xmlUnlinkNode(cur); 2575 xmlFreeNode(cur); 2576 return (Z_OK); 2577 } 2578 } 2579 return (Z_NO_RESOURCE_ID); 2580 } 2581 2582 int 2583 zonecfg_delete_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2584 { 2585 int err; 2586 2587 if (tabptr == NULL) 2588 return (Z_INVAL); 2589 2590 if ((err = operation_prep(handle)) != Z_OK) 2591 return (err); 2592 2593 if ((err = zonecfg_delete_attr_core(handle, tabptr)) != Z_OK) 2594 return (err); 2595 2596 return (Z_OK); 2597 } 2598 2599 int 2600 zonecfg_modify_attr( 2601 zone_dochandle_t handle, 2602 struct zone_attrtab *oldtabptr, 2603 struct zone_attrtab *newtabptr) 2604 { 2605 int err; 2606 2607 if (oldtabptr == NULL || newtabptr == NULL) 2608 return (Z_INVAL); 2609 2610 if ((err = operation_prep(handle)) != Z_OK) 2611 return (err); 2612 2613 if ((err = zonecfg_delete_attr_core(handle, oldtabptr)) != Z_OK) 2614 return (err); 2615 2616 if ((err = zonecfg_add_attr_core(handle, newtabptr)) != Z_OK) 2617 return (err); 2618 2619 return (Z_OK); 2620 } 2621 2622 int 2623 zonecfg_get_attr_boolean(const struct zone_attrtab *attr, boolean_t *value) 2624 { 2625 if (attr == NULL) 2626 return (Z_INVAL); 2627 2628 if (strcmp(attr->zone_attr_type, DTD_ENTITY_BOOLEAN) != 0) 2629 return (Z_INVAL); 2630 2631 if (strcmp(attr->zone_attr_value, DTD_ENTITY_TRUE) == 0) { 2632 *value = B_TRUE; 2633 return (Z_OK); 2634 } 2635 if (strcmp(attr->zone_attr_value, DTD_ENTITY_FALSE) == 0) { 2636 *value = B_FALSE; 2637 return (Z_OK); 2638 } 2639 return (Z_INVAL); 2640 } 2641 2642 int 2643 zonecfg_get_attr_int(const struct zone_attrtab *attr, int64_t *value) 2644 { 2645 long long result; 2646 char *endptr; 2647 2648 if (attr == NULL) 2649 return (Z_INVAL); 2650 2651 if (strcmp(attr->zone_attr_type, DTD_ENTITY_INT) != 0) 2652 return (Z_INVAL); 2653 2654 errno = 0; 2655 result = strtoll(attr->zone_attr_value, &endptr, 10); 2656 if (errno != 0 || *endptr != '\0') 2657 return (Z_INVAL); 2658 *value = result; 2659 return (Z_OK); 2660 } 2661 2662 int 2663 zonecfg_get_attr_string(const struct zone_attrtab *attr, char *value, 2664 size_t val_sz) 2665 { 2666 if (attr == NULL) 2667 return (Z_INVAL); 2668 2669 if (strcmp(attr->zone_attr_type, DTD_ENTITY_STRING) != 0) 2670 return (Z_INVAL); 2671 2672 if (strlcpy(value, attr->zone_attr_value, val_sz) >= val_sz) 2673 return (Z_TOO_BIG); 2674 return (Z_OK); 2675 } 2676 2677 int 2678 zonecfg_get_attr_uint(const struct zone_attrtab *attr, uint64_t *value) 2679 { 2680 unsigned long long result; 2681 long long neg_result; 2682 char *endptr; 2683 2684 if (attr == NULL) 2685 return (Z_INVAL); 2686 2687 if (strcmp(attr->zone_attr_type, DTD_ENTITY_UINT) != 0) 2688 return (Z_INVAL); 2689 2690 errno = 0; 2691 result = strtoull(attr->zone_attr_value, &endptr, 10); 2692 if (errno != 0 || *endptr != '\0') 2693 return (Z_INVAL); 2694 errno = 0; 2695 neg_result = strtoll(attr->zone_attr_value, &endptr, 10); 2696 /* 2697 * Incredibly, strtoull("<negative number>", ...) will not fail but 2698 * return whatever (negative) number cast as a u_longlong_t, so we 2699 * need to look for this here. 2700 */ 2701 if (errno == 0 && neg_result < 0) 2702 return (Z_INVAL); 2703 *value = result; 2704 return (Z_OK); 2705 } 2706 2707 int 2708 zonecfg_lookup_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2709 { 2710 xmlNodePtr cur, val; 2711 char savedname[MAXNAMELEN]; 2712 struct zone_rctlvaltab *valptr; 2713 int err; 2714 2715 if (tabptr->zone_rctl_name == NULL || 2716 strlen(tabptr->zone_rctl_name) == 0) 2717 return (Z_INVAL); 2718 2719 if ((err = operation_prep(handle)) != Z_OK) 2720 return (err); 2721 2722 cur = handle->zone_dh_cur; 2723 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2724 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 2725 continue; 2726 if ((fetchprop(cur, DTD_ATTR_NAME, savedname, 2727 sizeof (savedname)) == Z_OK) && 2728 (strcmp(savedname, tabptr->zone_rctl_name) == 0)) { 2729 tabptr->zone_rctl_valptr = NULL; 2730 for (val = cur->xmlChildrenNode; val != NULL; 2731 val = val->next) { 2732 valptr = (struct zone_rctlvaltab *)malloc( 2733 sizeof (struct zone_rctlvaltab)); 2734 if (valptr == NULL) 2735 return (Z_NOMEM); 2736 if ((fetchprop(val, DTD_ATTR_PRIV, 2737 valptr->zone_rctlval_priv, 2738 sizeof (valptr->zone_rctlval_priv)) != 2739 Z_OK)) 2740 break; 2741 if ((fetchprop(val, DTD_ATTR_LIMIT, 2742 valptr->zone_rctlval_limit, 2743 sizeof (valptr->zone_rctlval_limit)) != 2744 Z_OK)) 2745 break; 2746 if ((fetchprop(val, DTD_ATTR_ACTION, 2747 valptr->zone_rctlval_action, 2748 sizeof (valptr->zone_rctlval_action)) != 2749 Z_OK)) 2750 break; 2751 if (zonecfg_add_rctl_value(tabptr, valptr) != 2752 Z_OK) 2753 break; 2754 } 2755 return (Z_OK); 2756 } 2757 } 2758 return (Z_NO_RESOURCE_ID); 2759 } 2760 2761 static int 2762 zonecfg_add_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2763 { 2764 xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode; 2765 struct zone_rctlvaltab *valptr; 2766 int err; 2767 2768 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_RCTL, NULL); 2769 err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_rctl_name); 2770 if (err != Z_OK) 2771 return (err); 2772 for (valptr = tabptr->zone_rctl_valptr; valptr != NULL; 2773 valptr = valptr->zone_rctlval_next) { 2774 valnode = xmlNewTextChild(newnode, NULL, 2775 DTD_ELEM_RCTLVALUE, NULL); 2776 err = newprop(valnode, DTD_ATTR_PRIV, 2777 valptr->zone_rctlval_priv); 2778 if (err != Z_OK) 2779 return (err); 2780 err = newprop(valnode, DTD_ATTR_LIMIT, 2781 valptr->zone_rctlval_limit); 2782 if (err != Z_OK) 2783 return (err); 2784 err = newprop(valnode, DTD_ATTR_ACTION, 2785 valptr->zone_rctlval_action); 2786 if (err != Z_OK) 2787 return (err); 2788 } 2789 return (Z_OK); 2790 } 2791 2792 int 2793 zonecfg_add_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2794 { 2795 int err; 2796 2797 if (tabptr == NULL || tabptr->zone_rctl_name == NULL) 2798 return (Z_INVAL); 2799 2800 if ((err = operation_prep(handle)) != Z_OK) 2801 return (err); 2802 2803 if ((err = zonecfg_add_rctl_core(handle, tabptr)) != Z_OK) 2804 return (err); 2805 2806 return (Z_OK); 2807 } 2808 2809 static int 2810 zonecfg_delete_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2811 { 2812 xmlNodePtr cur = handle->zone_dh_cur; 2813 xmlChar *savedname; 2814 int name_result; 2815 2816 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2817 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 2818 continue; 2819 2820 savedname = xmlGetProp(cur, DTD_ATTR_NAME); 2821 if (savedname == NULL) /* shouldn't happen */ 2822 continue; 2823 name_result = xmlStrcmp(savedname, 2824 (const xmlChar *) tabptr->zone_rctl_name); 2825 xmlFree(savedname); 2826 2827 if (name_result == 0) { 2828 xmlUnlinkNode(cur); 2829 xmlFreeNode(cur); 2830 return (Z_OK); 2831 } 2832 } 2833 return (Z_NO_RESOURCE_ID); 2834 } 2835 2836 int 2837 zonecfg_delete_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2838 { 2839 int err; 2840 2841 if (tabptr == NULL || tabptr->zone_rctl_name == NULL) 2842 return (Z_INVAL); 2843 2844 if ((err = operation_prep(handle)) != Z_OK) 2845 return (err); 2846 2847 if ((err = zonecfg_delete_rctl_core(handle, tabptr)) != Z_OK) 2848 return (err); 2849 2850 return (Z_OK); 2851 } 2852 2853 int 2854 zonecfg_modify_rctl( 2855 zone_dochandle_t handle, 2856 struct zone_rctltab *oldtabptr, 2857 struct zone_rctltab *newtabptr) 2858 { 2859 int err; 2860 2861 if (oldtabptr == NULL || oldtabptr->zone_rctl_name == NULL || 2862 newtabptr == NULL || newtabptr->zone_rctl_name == NULL) 2863 return (Z_INVAL); 2864 2865 if ((err = operation_prep(handle)) != Z_OK) 2866 return (err); 2867 2868 if ((err = zonecfg_delete_rctl_core(handle, oldtabptr)) != Z_OK) 2869 return (err); 2870 2871 if ((err = zonecfg_add_rctl_core(handle, newtabptr)) != Z_OK) 2872 return (err); 2873 2874 return (Z_OK); 2875 } 2876 2877 int 2878 zonecfg_add_rctl_value( 2879 struct zone_rctltab *tabptr, 2880 struct zone_rctlvaltab *valtabptr) 2881 { 2882 struct zone_rctlvaltab *last, *old, *new; 2883 rctlblk_t *rctlblk = alloca(rctlblk_size()); 2884 2885 last = tabptr->zone_rctl_valptr; 2886 for (old = last; old != NULL; old = old->zone_rctlval_next) 2887 last = old; /* walk to the end of the list */ 2888 new = valtabptr; /* alloc'd by caller */ 2889 new->zone_rctlval_next = NULL; 2890 if (zonecfg_construct_rctlblk(valtabptr, rctlblk) != Z_OK) 2891 return (Z_INVAL); 2892 if (!zonecfg_valid_rctlblk(rctlblk)) 2893 return (Z_INVAL); 2894 if (last == NULL) 2895 tabptr->zone_rctl_valptr = new; 2896 else 2897 last->zone_rctlval_next = new; 2898 return (Z_OK); 2899 } 2900 2901 int 2902 zonecfg_remove_rctl_value( 2903 struct zone_rctltab *tabptr, 2904 struct zone_rctlvaltab *valtabptr) 2905 { 2906 struct zone_rctlvaltab *last, *this, *next; 2907 2908 last = tabptr->zone_rctl_valptr; 2909 for (this = last; this != NULL; this = this->zone_rctlval_next) { 2910 if (strcmp(this->zone_rctlval_priv, 2911 valtabptr->zone_rctlval_priv) == 0 && 2912 strcmp(this->zone_rctlval_limit, 2913 valtabptr->zone_rctlval_limit) == 0 && 2914 strcmp(this->zone_rctlval_action, 2915 valtabptr->zone_rctlval_action) == 0) { 2916 next = this->zone_rctlval_next; 2917 if (this == tabptr->zone_rctl_valptr) 2918 tabptr->zone_rctl_valptr = next; 2919 else 2920 last->zone_rctlval_next = next; 2921 free(this); 2922 return (Z_OK); 2923 } else 2924 last = this; 2925 } 2926 return (Z_NO_PROPERTY_ID); 2927 } 2928 2929 char * 2930 zonecfg_strerror(int errnum) 2931 { 2932 switch (errnum) { 2933 case Z_OK: 2934 return (dgettext(TEXT_DOMAIN, "OK")); 2935 case Z_EMPTY_DOCUMENT: 2936 return (dgettext(TEXT_DOMAIN, "Empty document")); 2937 case Z_WRONG_DOC_TYPE: 2938 return (dgettext(TEXT_DOMAIN, "Wrong document type")); 2939 case Z_BAD_PROPERTY: 2940 return (dgettext(TEXT_DOMAIN, "Bad document property")); 2941 case Z_TEMP_FILE: 2942 return (dgettext(TEXT_DOMAIN, 2943 "Problem creating temporary file")); 2944 case Z_SAVING_FILE: 2945 return (dgettext(TEXT_DOMAIN, "Problem saving file")); 2946 case Z_NO_ENTRY: 2947 return (dgettext(TEXT_DOMAIN, "No such entry")); 2948 case Z_BOGUS_ZONE_NAME: 2949 return (dgettext(TEXT_DOMAIN, "Bogus zone name")); 2950 case Z_REQD_RESOURCE_MISSING: 2951 return (dgettext(TEXT_DOMAIN, "Required resource missing")); 2952 case Z_REQD_PROPERTY_MISSING: 2953 return (dgettext(TEXT_DOMAIN, "Required property missing")); 2954 case Z_BAD_HANDLE: 2955 return (dgettext(TEXT_DOMAIN, "Bad handle")); 2956 case Z_NOMEM: 2957 return (dgettext(TEXT_DOMAIN, "Out of memory")); 2958 case Z_INVAL: 2959 return (dgettext(TEXT_DOMAIN, "Invalid argument")); 2960 case Z_ACCES: 2961 return (dgettext(TEXT_DOMAIN, "Permission denied")); 2962 case Z_TOO_BIG: 2963 return (dgettext(TEXT_DOMAIN, "Argument list too long")); 2964 case Z_MISC_FS: 2965 return (dgettext(TEXT_DOMAIN, 2966 "Miscellaneous file system error")); 2967 case Z_NO_ZONE: 2968 return (dgettext(TEXT_DOMAIN, "No such zone configured")); 2969 case Z_NO_RESOURCE_TYPE: 2970 return (dgettext(TEXT_DOMAIN, "No such resource type")); 2971 case Z_NO_RESOURCE_ID: 2972 return (dgettext(TEXT_DOMAIN, "No such resource with that id")); 2973 case Z_NO_PROPERTY_TYPE: 2974 return (dgettext(TEXT_DOMAIN, "No such property type")); 2975 case Z_NO_PROPERTY_ID: 2976 return (dgettext(TEXT_DOMAIN, "No such property with that id")); 2977 case Z_BAD_ZONE_STATE: 2978 return (dgettext(TEXT_DOMAIN, 2979 "Zone state is invalid for the requested operation")); 2980 case Z_INVALID_DOCUMENT: 2981 return (dgettext(TEXT_DOMAIN, "Invalid document")); 2982 case Z_NAME_IN_USE: 2983 return (dgettext(TEXT_DOMAIN, "Zone name already in use")); 2984 case Z_NO_SUCH_ID: 2985 return (dgettext(TEXT_DOMAIN, "No such zone ID")); 2986 case Z_UPDATING_INDEX: 2987 return (dgettext(TEXT_DOMAIN, "Problem updating index file")); 2988 case Z_LOCKING_FILE: 2989 return (dgettext(TEXT_DOMAIN, "Locking index file")); 2990 case Z_UNLOCKING_FILE: 2991 return (dgettext(TEXT_DOMAIN, "Unlocking index file")); 2992 case Z_INSUFFICIENT_SPEC: 2993 return (dgettext(TEXT_DOMAIN, "Insufficient specification")); 2994 case Z_RESOLVED_PATH: 2995 return (dgettext(TEXT_DOMAIN, "Resolved path mismatch")); 2996 case Z_IPV6_ADDR_PREFIX_LEN: 2997 return (dgettext(TEXT_DOMAIN, 2998 "IPv6 address missing required prefix length")); 2999 case Z_BOGUS_ADDRESS: 3000 return (dgettext(TEXT_DOMAIN, 3001 "Neither an IPv4 nor an IPv6 address nor a host name")); 3002 case Z_PRIV_PROHIBITED: 3003 return (dgettext(TEXT_DOMAIN, 3004 "Specified privilege is prohibited")); 3005 case Z_PRIV_REQUIRED: 3006 return (dgettext(TEXT_DOMAIN, 3007 "Required privilege is missing")); 3008 case Z_PRIV_UNKNOWN: 3009 return (dgettext(TEXT_DOMAIN, 3010 "Specified privilege is unknown")); 3011 default: 3012 return (dgettext(TEXT_DOMAIN, "Unknown error")); 3013 } 3014 } 3015 3016 /* 3017 * Note that the zonecfg_setXent() and zonecfg_endXent() calls are all the 3018 * same, as they just turn around and call zonecfg_setent() / zonecfg_endent(). 3019 */ 3020 3021 static int 3022 zonecfg_setent(zone_dochandle_t handle) 3023 { 3024 xmlNodePtr cur; 3025 int err; 3026 3027 if (handle == NULL) 3028 return (Z_INVAL); 3029 3030 if ((err = operation_prep(handle)) != Z_OK) { 3031 handle->zone_dh_cur = NULL; 3032 return (err); 3033 } 3034 cur = handle->zone_dh_cur; 3035 cur = cur->xmlChildrenNode; 3036 handle->zone_dh_cur = cur; 3037 return (Z_OK); 3038 } 3039 3040 static int 3041 zonecfg_endent(zone_dochandle_t handle) 3042 { 3043 if (handle == NULL) 3044 return (Z_INVAL); 3045 3046 handle->zone_dh_cur = handle->zone_dh_top; 3047 return (Z_OK); 3048 } 3049 3050 int 3051 zonecfg_setfsent(zone_dochandle_t handle) 3052 { 3053 return (zonecfg_setent(handle)); 3054 } 3055 3056 int 3057 zonecfg_getfsent(zone_dochandle_t handle, struct zone_fstab *tabptr) 3058 { 3059 xmlNodePtr cur, options; 3060 char options_str[MAX_MNTOPT_STR]; 3061 int err; 3062 3063 if (handle == NULL) 3064 return (Z_INVAL); 3065 3066 if ((cur = handle->zone_dh_cur) == NULL) 3067 return (Z_NO_ENTRY); 3068 3069 for (; cur != NULL; cur = cur->next) 3070 if (!xmlStrcmp(cur->name, DTD_ELEM_FS)) 3071 break; 3072 if (cur == NULL) { 3073 handle->zone_dh_cur = handle->zone_dh_top; 3074 return (Z_NO_ENTRY); 3075 } 3076 3077 if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special, 3078 sizeof (tabptr->zone_fs_special))) != Z_OK) { 3079 handle->zone_dh_cur = handle->zone_dh_top; 3080 return (err); 3081 } 3082 3083 if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw, 3084 sizeof (tabptr->zone_fs_raw))) != Z_OK) { 3085 handle->zone_dh_cur = handle->zone_dh_top; 3086 return (err); 3087 } 3088 3089 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 3090 sizeof (tabptr->zone_fs_dir))) != Z_OK) { 3091 handle->zone_dh_cur = handle->zone_dh_top; 3092 return (err); 3093 } 3094 3095 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type, 3096 sizeof (tabptr->zone_fs_type))) != Z_OK) { 3097 handle->zone_dh_cur = handle->zone_dh_top; 3098 return (err); 3099 } 3100 3101 /* OK for options to be NULL */ 3102 tabptr->zone_fs_options = NULL; 3103 for (options = cur->xmlChildrenNode; options != NULL; 3104 options = options->next) { 3105 if (fetchprop(options, DTD_ATTR_NAME, options_str, 3106 sizeof (options_str)) != Z_OK) 3107 break; 3108 if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK) 3109 break; 3110 } 3111 3112 handle->zone_dh_cur = cur->next; 3113 return (Z_OK); 3114 } 3115 3116 int 3117 zonecfg_endfsent(zone_dochandle_t handle) 3118 { 3119 return (zonecfg_endent(handle)); 3120 } 3121 3122 int 3123 zonecfg_setipdent(zone_dochandle_t handle) 3124 { 3125 return (zonecfg_setent(handle)); 3126 } 3127 3128 int 3129 zonecfg_getipdent(zone_dochandle_t handle, struct zone_fstab *tabptr) 3130 { 3131 xmlNodePtr cur; 3132 int err; 3133 3134 if (handle == NULL) 3135 return (Z_INVAL); 3136 3137 if ((cur = handle->zone_dh_cur) == NULL) 3138 return (Z_NO_ENTRY); 3139 3140 for (; cur != NULL; cur = cur->next) 3141 if (!xmlStrcmp(cur->name, DTD_ELEM_IPD)) 3142 break; 3143 if (cur == NULL) { 3144 handle->zone_dh_cur = handle->zone_dh_top; 3145 return (Z_NO_ENTRY); 3146 } 3147 3148 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 3149 sizeof (tabptr->zone_fs_dir))) != Z_OK) { 3150 handle->zone_dh_cur = handle->zone_dh_top; 3151 return (err); 3152 } 3153 3154 handle->zone_dh_cur = cur->next; 3155 return (Z_OK); 3156 } 3157 3158 int 3159 zonecfg_endipdent(zone_dochandle_t handle) 3160 { 3161 return (zonecfg_endent(handle)); 3162 } 3163 3164 int 3165 zonecfg_setnwifent(zone_dochandle_t handle) 3166 { 3167 return (zonecfg_setent(handle)); 3168 } 3169 3170 int 3171 zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 3172 { 3173 xmlNodePtr cur; 3174 int err; 3175 3176 if (handle == NULL) 3177 return (Z_INVAL); 3178 3179 if ((cur = handle->zone_dh_cur) == NULL) 3180 return (Z_NO_ENTRY); 3181 3182 for (; cur != NULL; cur = cur->next) 3183 if (!xmlStrcmp(cur->name, DTD_ELEM_NET)) 3184 break; 3185 if (cur == NULL) { 3186 handle->zone_dh_cur = handle->zone_dh_top; 3187 return (Z_NO_ENTRY); 3188 } 3189 3190 if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address, 3191 sizeof (tabptr->zone_nwif_address))) != Z_OK) { 3192 handle->zone_dh_cur = handle->zone_dh_top; 3193 return (err); 3194 } 3195 3196 if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical, 3197 sizeof (tabptr->zone_nwif_physical))) != Z_OK) { 3198 handle->zone_dh_cur = handle->zone_dh_top; 3199 return (err); 3200 } 3201 3202 handle->zone_dh_cur = cur->next; 3203 return (Z_OK); 3204 } 3205 3206 int 3207 zonecfg_endnwifent(zone_dochandle_t handle) 3208 { 3209 return (zonecfg_endent(handle)); 3210 } 3211 3212 int 3213 zonecfg_setdevent(zone_dochandle_t handle) 3214 { 3215 return (zonecfg_setent(handle)); 3216 } 3217 3218 int 3219 zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr) 3220 { 3221 xmlNodePtr cur; 3222 int err; 3223 3224 if (handle == NULL) 3225 return (Z_INVAL); 3226 3227 if ((cur = handle->zone_dh_cur) == NULL) 3228 return (Z_NO_ENTRY); 3229 3230 for (; cur != NULL; cur = cur->next) 3231 if (!xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) 3232 break; 3233 if (cur == NULL) { 3234 handle->zone_dh_cur = handle->zone_dh_top; 3235 return (Z_NO_ENTRY); 3236 } 3237 3238 if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match, 3239 sizeof (tabptr->zone_dev_match))) != Z_OK) { 3240 handle->zone_dh_cur = handle->zone_dh_top; 3241 return (err); 3242 } 3243 3244 handle->zone_dh_cur = cur->next; 3245 return (Z_OK); 3246 } 3247 3248 int 3249 zonecfg_enddevent(zone_dochandle_t handle) 3250 { 3251 return (zonecfg_endent(handle)); 3252 } 3253 3254 int 3255 zonecfg_setrctlent(zone_dochandle_t handle) 3256 { 3257 return (zonecfg_setent(handle)); 3258 } 3259 3260 int 3261 zonecfg_getrctlent(zone_dochandle_t handle, struct zone_rctltab *tabptr) 3262 { 3263 xmlNodePtr cur, val; 3264 struct zone_rctlvaltab *valptr; 3265 int err; 3266 3267 if (handle == NULL) 3268 return (Z_INVAL); 3269 3270 if ((cur = handle->zone_dh_cur) == NULL) 3271 return (Z_NO_ENTRY); 3272 3273 for (; cur != NULL; cur = cur->next) 3274 if (!xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 3275 break; 3276 if (cur == NULL) { 3277 handle->zone_dh_cur = handle->zone_dh_top; 3278 return (Z_NO_ENTRY); 3279 } 3280 3281 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_rctl_name, 3282 sizeof (tabptr->zone_rctl_name))) != Z_OK) { 3283 handle->zone_dh_cur = handle->zone_dh_top; 3284 return (err); 3285 } 3286 3287 tabptr->zone_rctl_valptr = NULL; 3288 for (val = cur->xmlChildrenNode; val != NULL; val = val->next) { 3289 valptr = (struct zone_rctlvaltab *)malloc( 3290 sizeof (struct zone_rctlvaltab)); 3291 if (valptr == NULL) 3292 return (Z_NOMEM); 3293 if (fetchprop(val, DTD_ATTR_PRIV, valptr->zone_rctlval_priv, 3294 sizeof (valptr->zone_rctlval_priv)) != Z_OK) 3295 break; 3296 if (fetchprop(val, DTD_ATTR_LIMIT, valptr->zone_rctlval_limit, 3297 sizeof (valptr->zone_rctlval_limit)) != Z_OK) 3298 break; 3299 if (fetchprop(val, DTD_ATTR_ACTION, valptr->zone_rctlval_action, 3300 sizeof (valptr->zone_rctlval_action)) != Z_OK) 3301 break; 3302 if (zonecfg_add_rctl_value(tabptr, valptr) != Z_OK) 3303 break; 3304 } 3305 3306 handle->zone_dh_cur = cur->next; 3307 return (Z_OK); 3308 } 3309 3310 int 3311 zonecfg_endrctlent(zone_dochandle_t handle) 3312 { 3313 return (zonecfg_endent(handle)); 3314 } 3315 3316 int 3317 zonecfg_setattrent(zone_dochandle_t handle) 3318 { 3319 return (zonecfg_setent(handle)); 3320 } 3321 3322 int 3323 zonecfg_getattrent(zone_dochandle_t handle, struct zone_attrtab *tabptr) 3324 { 3325 xmlNodePtr cur; 3326 int err; 3327 3328 if (handle == NULL) 3329 return (Z_INVAL); 3330 3331 if ((cur = handle->zone_dh_cur) == NULL) 3332 return (Z_NO_ENTRY); 3333 3334 for (; cur != NULL; cur = cur->next) 3335 if (!xmlStrcmp(cur->name, DTD_ELEM_ATTR)) 3336 break; 3337 if (cur == NULL) { 3338 handle->zone_dh_cur = handle->zone_dh_top; 3339 return (Z_NO_ENTRY); 3340 } 3341 3342 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name, 3343 sizeof (tabptr->zone_attr_name))) != Z_OK) { 3344 handle->zone_dh_cur = handle->zone_dh_top; 3345 return (err); 3346 } 3347 3348 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type, 3349 sizeof (tabptr->zone_attr_type))) != Z_OK) { 3350 handle->zone_dh_cur = handle->zone_dh_top; 3351 return (err); 3352 } 3353 3354 if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value, 3355 sizeof (tabptr->zone_attr_value))) != Z_OK) { 3356 handle->zone_dh_cur = handle->zone_dh_top; 3357 return (err); 3358 } 3359 3360 handle->zone_dh_cur = cur->next; 3361 return (Z_OK); 3362 } 3363 3364 int 3365 zonecfg_endattrent(zone_dochandle_t handle) 3366 { 3367 return (zonecfg_endent(handle)); 3368 } 3369 3370 /* 3371 * The privileges available on the system and described in privileges(5) 3372 * fall into four categories with respect to non-global zones; those that 3373 * are required in order for a non-global zone to boot, those which are in 3374 * the default set of privileges available to non-global zones, those 3375 * privileges which should not be allowed to be given to non-global zones 3376 * and all other privileges, which are optional and potentially useful for 3377 * processes executing inside a non-global zone. 3378 * 3379 * When privileges are added to the system, a determination needs to be 3380 * made as to which category the privilege belongs to. Ideally, 3381 * privileges should be fine-grained enough and the mechanisms they cover 3382 * virtualized enough so that they can be made available to non-global 3383 * zones. 3384 */ 3385 3386 /* 3387 * Set of privileges required in order to get a zone booted and init(1M) 3388 * started. These cannot be removed from the zone's privilege set. 3389 */ 3390 static const char *required_priv_list[] = { 3391 PRIV_PROC_EXEC, 3392 PRIV_PROC_FORK, 3393 PRIV_SYS_MOUNT, 3394 NULL 3395 }; 3396 3397 /* 3398 * Default set of privileges considered safe for all non-global zones. 3399 * These privileges are "safe" in the sense that a privileged process in 3400 * the zone cannot affect processes in other non-global zones on the 3401 * system or in the global zone. Privileges which are considered by 3402 * default, "unsafe", include ones which affect a global resource, such as 3403 * the system clock or physical memory. 3404 */ 3405 static const char *default_priv_list[] = { 3406 PRIV_CONTRACT_EVENT, 3407 PRIV_CONTRACT_OBSERVER, 3408 PRIV_FILE_CHOWN, 3409 PRIV_FILE_CHOWN_SELF, 3410 PRIV_FILE_DAC_EXECUTE, 3411 PRIV_FILE_DAC_READ, 3412 PRIV_FILE_DAC_SEARCH, 3413 PRIV_FILE_DAC_WRITE, 3414 PRIV_FILE_OWNER, 3415 PRIV_FILE_SETID, 3416 PRIV_IPC_DAC_READ, 3417 PRIV_IPC_DAC_WRITE, 3418 PRIV_IPC_OWNER, 3419 PRIV_NET_BINDMLP, 3420 PRIV_NET_ICMPACCESS, 3421 PRIV_NET_MAC_AWARE, 3422 PRIV_NET_PRIVADDR, 3423 PRIV_PROC_CHROOT, 3424 PRIV_SYS_AUDIT, 3425 PRIV_PROC_AUDIT, 3426 PRIV_PROC_OWNER, 3427 PRIV_PROC_SETID, 3428 PRIV_PROC_TASKID, 3429 PRIV_SYS_ACCT, 3430 PRIV_SYS_ADMIN, 3431 PRIV_SYS_MOUNT, 3432 PRIV_SYS_NFS, 3433 PRIV_SYS_RESOURCE, 3434 NULL 3435 }; 3436 3437 /* 3438 * Set of privileges not currently permitted within a non-global zone. 3439 * Some of these privileges are overly broad and cover more than one 3440 * mechanism in the system. In other cases, there has not been sufficient 3441 * virtualization in the parts of the system the privilege covers to allow 3442 * its use within a non-global zone. 3443 */ 3444 static const char *prohibited_priv_list[] = { 3445 PRIV_DTRACE_KERNEL, 3446 PRIV_PROC_ZONE, 3447 PRIV_SYS_CONFIG, 3448 PRIV_SYS_DEVICES, 3449 PRIV_SYS_LINKDIR, 3450 PRIV_SYS_NET_CONFIG, 3451 PRIV_SYS_RES_CONFIG, 3452 PRIV_SYS_SUSER_COMPAT, 3453 NULL 3454 }; 3455 3456 /* 3457 * Define some of the tokens that priv_str_to_set(3C) recognizes. Since 3458 * the privilege string separator can be any character, although it is 3459 * usually a comma character, define these here as well in the event that 3460 * they change or are augmented in the future. 3461 */ 3462 #define BASIC_TOKEN "basic" 3463 #define DEFAULT_TOKEN "default" 3464 #define ZONE_TOKEN "zone" 3465 #define TOKEN_PRIV_CHAR ',' 3466 #define TOKEN_PRIV_STR "," 3467 3468 int 3469 zonecfg_default_privset(priv_set_t *privs) 3470 { 3471 const char **strp; 3472 priv_set_t *basic; 3473 3474 basic = priv_str_to_set(BASIC_TOKEN, TOKEN_PRIV_STR, NULL); 3475 if (basic == NULL) 3476 return (errno == ENOMEM ? Z_NOMEM : Z_INVAL); 3477 3478 priv_union(basic, privs); 3479 priv_freeset(basic); 3480 3481 for (strp = default_priv_list; *strp != NULL; strp++) { 3482 if (priv_addset(privs, *strp) != 0) { 3483 return (Z_INVAL); 3484 } 3485 } 3486 return (Z_OK); 3487 } 3488 3489 void 3490 append_priv_token(char *priv, char *str, size_t strlen) 3491 { 3492 if (*str != '\0') 3493 (void) strlcat(str, TOKEN_PRIV_STR, strlen); 3494 (void) strlcat(str, priv, strlen); 3495 } 3496 3497 /* 3498 * Verify that the supplied string is a valid privilege limit set for a 3499 * non-global zone. This string must not only be acceptable to 3500 * priv_str_to_set(3C) which parses it, but it also must resolve to a 3501 * privilege set that includes certain required privileges and lacks 3502 * certain prohibited privileges. 3503 */ 3504 static int 3505 verify_privset(char *privbuf, priv_set_t *privs, char **privname, 3506 boolean_t add_default) 3507 { 3508 char *cp; 3509 char *lasts; 3510 size_t len; 3511 priv_set_t *mergeset; 3512 const char **strp; 3513 char *tmp; 3514 const char *token; 3515 3516 /* 3517 * The verification of the privilege string occurs in several 3518 * phases. In the first phase, the supplied string is scanned for 3519 * the ZONE_TOKEN token which is not support as part of the 3520 * "limitpriv" property. 3521 * 3522 * Duplicate the supplied privilege string since strtok_r(3C) 3523 * tokenizes its input by null-terminating the tokens. 3524 */ 3525 if ((tmp = strdup(privbuf)) == NULL) 3526 return (Z_NOMEM); 3527 for (cp = strtok_r(tmp, TOKEN_PRIV_STR, &lasts); cp != NULL; 3528 cp = strtok_r(NULL, TOKEN_PRIV_STR, &lasts)) { 3529 if (strcmp(cp, ZONE_TOKEN) == 0) { 3530 free(tmp); 3531 if ((*privname = strdup(ZONE_TOKEN)) == NULL) 3532 return (Z_NOMEM); 3533 else 3534 return (Z_PRIV_UNKNOWN); 3535 } 3536 } 3537 free(tmp); 3538 3539 if (add_default) { 3540 /* 3541 * If DEFAULT_TOKEN was specified, a string needs to be 3542 * built containing the privileges from the default, safe 3543 * set along with those of the "limitpriv" property. 3544 */ 3545 len = strlen(privbuf) + sizeof (BASIC_TOKEN) + 2; 3546 for (strp = default_priv_list; *strp != NULL; strp++) 3547 len += strlen(*strp) + 1; 3548 tmp = alloca(len); 3549 *tmp = '\0'; 3550 3551 append_priv_token(BASIC_TOKEN, tmp, len); 3552 for (strp = default_priv_list; *strp != NULL; strp++) 3553 append_priv_token((char *)*strp, tmp, len); 3554 (void) strlcat(tmp, TOKEN_PRIV_STR, len); 3555 (void) strlcat(tmp, privbuf, len); 3556 } else { 3557 tmp = privbuf; 3558 } 3559 3560 3561 /* 3562 * In the next phase, attempt to convert the merged privilege 3563 * string into a privilege set. In the case of an error, either 3564 * there was a memory allocation failure or there was an invalid 3565 * privilege token in the string. In either case, return an 3566 * appropriate error code but in the event of an invalid token, 3567 * allocate a string containing its name and return that back to 3568 * the caller. 3569 */ 3570 mergeset = priv_str_to_set(tmp, TOKEN_PRIV_STR, &token); 3571 if (mergeset == NULL) { 3572 if (token == NULL) 3573 return (Z_NOMEM); 3574 if ((cp = strchr(token, TOKEN_PRIV_CHAR)) != NULL) 3575 *cp = '\0'; 3576 if ((*privname = strdup(token)) == NULL) 3577 return (Z_NOMEM); 3578 else 3579 return (Z_PRIV_UNKNOWN); 3580 } 3581 3582 /* 3583 * Next, verify that none of the prohibited zone privileges are 3584 * present in the merged privilege set. 3585 */ 3586 for (strp = prohibited_priv_list; *strp != NULL; strp++) { 3587 if (priv_ismember(mergeset, *strp)) { 3588 priv_freeset(mergeset); 3589 if ((*privname = strdup(*strp)) == NULL) 3590 return (Z_NOMEM); 3591 else 3592 return (Z_PRIV_PROHIBITED); 3593 } 3594 } 3595 3596 /* 3597 * Finally, verify that all of the required zone privileges are 3598 * present in the merged privilege set. 3599 */ 3600 for (strp = required_priv_list; *strp != NULL; strp++) { 3601 if (!priv_ismember(mergeset, *strp)) { 3602 priv_freeset(mergeset); 3603 if ((*privname = strdup(*strp)) == NULL) 3604 return (Z_NOMEM); 3605 else 3606 return (Z_PRIV_REQUIRED); 3607 } 3608 } 3609 3610 priv_copyset(mergeset, privs); 3611 priv_freeset(mergeset); 3612 return (Z_OK); 3613 } 3614 3615 /* 3616 * Fill in the supplied privilege set with either the default, safe set of 3617 * privileges suitable for a non-global zone, or one based on the 3618 * "limitpriv" property in the zone's configuration. 3619 * 3620 * In the event of an invalid privilege specification in the 3621 * configuration, a string is allocated and returned containing the 3622 * "privilege" causing the issue. It is the caller's responsibility to 3623 * free this memory when it is done with it. 3624 */ 3625 int 3626 zonecfg_get_privset(zone_dochandle_t handle, priv_set_t *privs, 3627 char **privname) 3628 { 3629 char *cp; 3630 int err; 3631 int limitlen; 3632 char *limitpriv = NULL; 3633 3634 /* 3635 * Attempt to lookup the "limitpriv" property. If it does not 3636 * exist or matches the string DEFAULT_TOKEN exactly, then the 3637 * default, safe privilege set is returned. 3638 */ 3639 err = zonecfg_get_limitpriv(handle, &limitpriv); 3640 if (err != Z_OK) 3641 return (err); 3642 limitlen = strlen(limitpriv); 3643 if (limitlen == 0 || strcmp(limitpriv, DEFAULT_TOKEN) == 0) { 3644 free(limitpriv); 3645 return (zonecfg_default_privset(privs)); 3646 } 3647 3648 /* 3649 * Check if the string DEFAULT_TOKEN is the first token in a list 3650 * of privileges. 3651 */ 3652 cp = strchr(limitpriv, TOKEN_PRIV_CHAR); 3653 if (cp != NULL && 3654 strncmp(limitpriv, DEFAULT_TOKEN, cp - limitpriv) == 0) 3655 err = verify_privset(cp + 1, privs, privname, B_TRUE); 3656 else 3657 err = verify_privset(limitpriv, privs, privname, B_FALSE); 3658 3659 free(limitpriv); 3660 return (err); 3661 } 3662 3663 int 3664 zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz) 3665 { 3666 zone_dochandle_t handle; 3667 boolean_t found = B_FALSE; 3668 struct zoneent *ze; 3669 FILE *cookie; 3670 int err; 3671 char *cp; 3672 3673 if (zone_name == NULL) 3674 return (Z_INVAL); 3675 3676 (void) strlcpy(zonepath, zonecfg_root, rp_sz); 3677 cp = zonepath + strlen(zonepath); 3678 while (cp > zonepath && cp[-1] == '/') 3679 *--cp = '\0'; 3680 3681 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) { 3682 if (zonepath[0] == '\0') 3683 (void) strlcpy(zonepath, "/", rp_sz); 3684 return (Z_OK); 3685 } 3686 3687 /* 3688 * First check the index file. Because older versions did not have 3689 * a copy of the zone path, allow for it to be zero length, in which 3690 * case we ignore this result and fall back to the XML files. 3691 */ 3692 cookie = setzoneent(); 3693 while ((ze = getzoneent_private(cookie)) != NULL) { 3694 if (strcmp(ze->zone_name, zone_name) == 0) { 3695 found = B_TRUE; 3696 if (ze->zone_path[0] != '\0') 3697 (void) strlcpy(cp, ze->zone_path, 3698 rp_sz - (cp - zonepath)); 3699 } 3700 free(ze); 3701 if (found) 3702 break; 3703 } 3704 endzoneent(cookie); 3705 if (found && *cp != '\0') 3706 return (Z_OK); 3707 3708 /* Fall back to the XML files. */ 3709 if ((handle = zonecfg_init_handle()) == NULL) 3710 return (Z_NOMEM); 3711 3712 /* 3713 * Check the snapshot first: if a zone is running, its zonepath 3714 * may have changed. 3715 */ 3716 if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) { 3717 if ((err = zonecfg_get_handle(zone_name, handle)) != Z_OK) 3718 return (err); 3719 } 3720 err = zonecfg_get_zonepath(handle, zonepath, rp_sz); 3721 zonecfg_fini_handle(handle); 3722 return (err); 3723 } 3724 3725 int 3726 zone_get_rootpath(char *zone_name, char *rootpath, size_t rp_sz) 3727 { 3728 int err; 3729 3730 /* This function makes sense for non-global zones only. */ 3731 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) 3732 return (Z_BOGUS_ZONE_NAME); 3733 if ((err = zone_get_zonepath(zone_name, rootpath, rp_sz)) != Z_OK) 3734 return (err); 3735 if (strlcat(rootpath, "/root", rp_sz) >= rp_sz) 3736 return (Z_TOO_BIG); 3737 return (Z_OK); 3738 } 3739 3740 static zone_state_t 3741 kernel_state_to_user_state(zoneid_t zoneid, zone_status_t kernel_state) 3742 { 3743 char zoneroot[MAXPATHLEN]; 3744 size_t zlen; 3745 3746 assert(kernel_state <= ZONE_MAX_STATE); 3747 switch (kernel_state) { 3748 case ZONE_IS_UNINITIALIZED: 3749 return (ZONE_STATE_READY); 3750 case ZONE_IS_READY: 3751 /* 3752 * If the zone's root is mounted on $ZONEPATH/lu, then 3753 * it's a mounted scratch zone. 3754 */ 3755 if (zone_getattr(zoneid, ZONE_ATTR_ROOT, zoneroot, 3756 sizeof (zoneroot)) >= 0) { 3757 zlen = strlen(zoneroot); 3758 if (zlen > 3 && 3759 strcmp(zoneroot + zlen - 3, "/lu") == 0) 3760 return (ZONE_STATE_MOUNTED); 3761 } 3762 return (ZONE_STATE_READY); 3763 case ZONE_IS_BOOTING: 3764 case ZONE_IS_RUNNING: 3765 return (ZONE_STATE_RUNNING); 3766 case ZONE_IS_SHUTTING_DOWN: 3767 case ZONE_IS_EMPTY: 3768 return (ZONE_STATE_SHUTTING_DOWN); 3769 case ZONE_IS_DOWN: 3770 case ZONE_IS_DYING: 3771 case ZONE_IS_DEAD: 3772 default: 3773 return (ZONE_STATE_DOWN); 3774 } 3775 /* NOTREACHED */ 3776 } 3777 3778 int 3779 zone_get_state(char *zone_name, zone_state_t *state_num) 3780 { 3781 zone_status_t status; 3782 zoneid_t zone_id; 3783 struct zoneent *ze; 3784 boolean_t found = B_FALSE; 3785 FILE *cookie; 3786 char kernzone[ZONENAME_MAX]; 3787 FILE *fp; 3788 3789 if (zone_name == NULL) 3790 return (Z_INVAL); 3791 3792 /* 3793 * If we're looking at an alternate root, then we need to query the 3794 * kernel using the scratch zone name. 3795 */ 3796 zone_id = -1; 3797 if (*zonecfg_root != '\0' && !zonecfg_is_scratch(zone_name)) { 3798 if ((fp = zonecfg_open_scratch("", B_FALSE)) != NULL) { 3799 if (zonecfg_find_scratch(fp, zone_name, zonecfg_root, 3800 kernzone, sizeof (kernzone)) == 0) 3801 zone_id = getzoneidbyname(kernzone); 3802 zonecfg_close_scratch(fp); 3803 } 3804 } else { 3805 zone_id = getzoneidbyname(zone_name); 3806 } 3807 3808 /* check to see if zone is running */ 3809 if (zone_id != -1 && 3810 zone_getattr(zone_id, ZONE_ATTR_STATUS, &status, 3811 sizeof (status)) >= 0) { 3812 *state_num = kernel_state_to_user_state(zone_id, status); 3813 return (Z_OK); 3814 } 3815 3816 cookie = setzoneent(); 3817 while ((ze = getzoneent_private(cookie)) != NULL) { 3818 if (strcmp(ze->zone_name, zone_name) == 0) { 3819 found = B_TRUE; 3820 *state_num = ze->zone_state; 3821 } 3822 free(ze); 3823 if (found) 3824 break; 3825 } 3826 endzoneent(cookie); 3827 return ((found) ? Z_OK : Z_NO_ZONE); 3828 } 3829 3830 int 3831 zone_set_state(char *zone, zone_state_t state) 3832 { 3833 struct zoneent ze; 3834 3835 if (state != ZONE_STATE_CONFIGURED && state != ZONE_STATE_INSTALLED && 3836 state != ZONE_STATE_INCOMPLETE) 3837 return (Z_INVAL); 3838 3839 bzero(&ze, sizeof (ze)); 3840 (void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name)); 3841 ze.zone_state = state; 3842 (void) strlcpy(ze.zone_path, "", sizeof (ze.zone_path)); 3843 return (putzoneent(&ze, PZE_MODIFY)); 3844 } 3845 3846 /* 3847 * Get id (if any) for specified zone. There are four possible outcomes: 3848 * - If the string corresponds to the numeric id of an active (booted) 3849 * zone, sets *zip to the zone id and returns 0. 3850 * - If the string corresponds to the name of an active (booted) zone, 3851 * sets *zip to the zone id and returns 0. 3852 * - If the string is a name in the configuration but is not booted, 3853 * sets *zip to ZONE_ID_UNDEFINED and returns 0. 3854 * - Otherwise, leaves *zip unchanged and returns -1. 3855 * 3856 * This function acts as an auxiliary filter on the function of the same 3857 * name in libc; the linker binds to this version if libzonecfg exists, 3858 * and the libc version if it doesn't. Any changes to this version of 3859 * the function should probably be reflected in the libc version as well. 3860 */ 3861 int 3862 zone_get_id(const char *str, zoneid_t *zip) 3863 { 3864 zone_dochandle_t hdl; 3865 zoneid_t zoneid; 3866 char *cp; 3867 int err; 3868 3869 /* first try looking for active zone by id */ 3870 errno = 0; 3871 zoneid = (zoneid_t)strtol(str, &cp, 0); 3872 if (errno == 0 && cp != str && *cp == '\0' && 3873 getzonenamebyid(zoneid, NULL, 0) != -1) { 3874 *zip = zoneid; 3875 return (0); 3876 } 3877 3878 /* then look for active zone by name */ 3879 if ((zoneid = getzoneidbyname(str)) != -1) { 3880 *zip = zoneid; 3881 return (0); 3882 } 3883 3884 /* if in global zone, try looking up name in configuration database */ 3885 if (getzoneid() != GLOBAL_ZONEID || 3886 (hdl = zonecfg_init_handle()) == NULL) 3887 return (-1); 3888 3889 if (zonecfg_get_handle(str, hdl) == Z_OK) { 3890 /* zone exists but isn't active */ 3891 *zip = ZONE_ID_UNDEFINED; 3892 err = 0; 3893 } else { 3894 err = -1; 3895 } 3896 3897 zonecfg_fini_handle(hdl); 3898 return (err); 3899 } 3900 3901 char * 3902 zone_state_str(zone_state_t state_num) 3903 { 3904 switch (state_num) { 3905 case ZONE_STATE_CONFIGURED: 3906 return (ZONE_STATE_STR_CONFIGURED); 3907 case ZONE_STATE_INCOMPLETE: 3908 return (ZONE_STATE_STR_INCOMPLETE); 3909 case ZONE_STATE_INSTALLED: 3910 return (ZONE_STATE_STR_INSTALLED); 3911 case ZONE_STATE_READY: 3912 return (ZONE_STATE_STR_READY); 3913 case ZONE_STATE_MOUNTED: 3914 return (ZONE_STATE_STR_MOUNTED); 3915 case ZONE_STATE_RUNNING: 3916 return (ZONE_STATE_STR_RUNNING); 3917 case ZONE_STATE_SHUTTING_DOWN: 3918 return (ZONE_STATE_STR_SHUTTING_DOWN); 3919 case ZONE_STATE_DOWN: 3920 return (ZONE_STATE_STR_DOWN); 3921 default: 3922 return ("unknown"); 3923 } 3924 } 3925 3926 /* 3927 * Given a UUID value, find an associated zone name. This is intended to be 3928 * used by callers who set up some 'default' name (corresponding to the 3929 * expected name for the zone) in the zonename buffer, and thus the function 3930 * doesn't touch this buffer on failure. 3931 */ 3932 int 3933 zonecfg_get_name_by_uuid(const uuid_t uuid, char *zonename, size_t namelen) 3934 { 3935 FILE *fp; 3936 struct zoneent *ze; 3937 3938 /* 3939 * A small amount of subterfuge via casts is necessary here because 3940 * libuuid doesn't use const correctly, but we don't want to export 3941 * this brokenness to our clients. 3942 */ 3943 if (uuid_is_null(*(uuid_t *)&uuid)) 3944 return (Z_NO_ZONE); 3945 if ((fp = setzoneent()) == NULL) 3946 return (Z_NO_ZONE); 3947 while ((ze = getzoneent_private(fp)) != NULL) { 3948 if (uuid_compare(*(uuid_t *)&uuid, ze->zone_uuid) == 0) 3949 break; 3950 free(ze); 3951 } 3952 endzoneent(fp); 3953 if (ze != NULL) { 3954 (void) strlcpy(zonename, ze->zone_name, namelen); 3955 free(ze); 3956 return (Z_OK); 3957 } else { 3958 return (Z_NO_ZONE); 3959 } 3960 } 3961 3962 /* 3963 * Given a zone name, get its UUID. Returns a "NULL" UUID value if the zone 3964 * exists but the file doesn't have a value set yet. Returns an error if the 3965 * zone cannot be located. 3966 */ 3967 int 3968 zonecfg_get_uuid(const char *zonename, uuid_t uuid) 3969 { 3970 FILE *fp; 3971 struct zoneent *ze; 3972 3973 if ((fp = setzoneent()) == NULL) 3974 return (Z_NO_ZONE); 3975 while ((ze = getzoneent_private(fp)) != NULL) { 3976 if (strcmp(ze->zone_name, zonename) == 0) 3977 break; 3978 free(ze); 3979 } 3980 endzoneent(fp); 3981 if (ze != NULL) { 3982 uuid_copy(uuid, ze->zone_uuid); 3983 free(ze); 3984 return (Z_OK); 3985 } else { 3986 return (Z_NO_ZONE); 3987 } 3988 } 3989 3990 /* 3991 * File-system convenience functions. 3992 */ 3993 boolean_t 3994 zonecfg_valid_fs_type(const char *type) 3995 { 3996 /* 3997 * We already know which FS types don't work. 3998 */ 3999 if (strcmp(type, "proc") == 0 || 4000 strcmp(type, "mntfs") == 0 || 4001 strcmp(type, "autofs") == 0 || 4002 strncmp(type, "nfs", sizeof ("nfs") - 1) == 0 || 4003 strcmp(type, "cachefs") == 0) 4004 return (B_FALSE); 4005 /* 4006 * The caller may do more detailed verification to make sure other 4007 * aspects of this filesystem type make sense. 4008 */ 4009 return (B_TRUE); 4010 } 4011 4012 /* 4013 * Generally uninteresting rctl convenience functions. 4014 */ 4015 4016 int 4017 zonecfg_construct_rctlblk(const struct zone_rctlvaltab *rctlval, 4018 rctlblk_t *rctlblk) 4019 { 4020 unsigned long long ull; 4021 char *endp; 4022 rctl_priv_t priv; 4023 rctl_qty_t limit; 4024 uint_t action; 4025 4026 /* Get the privilege */ 4027 if (strcmp(rctlval->zone_rctlval_priv, "basic") == 0) { 4028 priv = RCPRIV_BASIC; 4029 } else if (strcmp(rctlval->zone_rctlval_priv, "privileged") == 0) { 4030 priv = RCPRIV_PRIVILEGED; 4031 } else { 4032 /* Invalid privilege */ 4033 return (Z_INVAL); 4034 } 4035 4036 /* deal with negative input; strtoull(3c) doesn't do what we want */ 4037 if (rctlval->zone_rctlval_limit[0] == '-') 4038 return (Z_INVAL); 4039 /* Get the limit */ 4040 errno = 0; 4041 ull = strtoull(rctlval->zone_rctlval_limit, &endp, 0); 4042 if (errno != 0 || *endp != '\0') { 4043 /* parse failed */ 4044 return (Z_INVAL); 4045 } 4046 limit = (rctl_qty_t)ull; 4047 4048 /* Get the action */ 4049 if (strcmp(rctlval->zone_rctlval_action, "none") == 0) { 4050 action = RCTL_LOCAL_NOACTION; 4051 } else if (strcmp(rctlval->zone_rctlval_action, "signal") == 0) { 4052 action = RCTL_LOCAL_SIGNAL; 4053 } else if (strcmp(rctlval->zone_rctlval_action, "deny") == 0) { 4054 action = RCTL_LOCAL_DENY; 4055 } else { 4056 /* Invalid Action */ 4057 return (Z_INVAL); 4058 } 4059 rctlblk_set_local_action(rctlblk, action, 0); 4060 rctlblk_set_privilege(rctlblk, priv); 4061 rctlblk_set_value(rctlblk, limit); 4062 return (Z_OK); 4063 } 4064 4065 static int 4066 rctl_check(const char *rctlname, void *arg) 4067 { 4068 const char *attrname = arg; 4069 4070 /* 4071 * Returning 1 here is our signal to zonecfg_is_rctl() that it is 4072 * indeed an rctl name recognized by the system. 4073 */ 4074 return (strcmp(rctlname, attrname) == 0 ? 1 : 0); 4075 } 4076 4077 boolean_t 4078 zonecfg_is_rctl(const char *name) 4079 { 4080 return (rctl_walk(rctl_check, (void *)name) == 1); 4081 } 4082 4083 boolean_t 4084 zonecfg_valid_rctlname(const char *name) 4085 { 4086 const char *c; 4087 4088 if (strncmp(name, "zone.", sizeof ("zone.") - 1) != 0) 4089 return (B_FALSE); 4090 if (strlen(name) == sizeof ("zone.") - 1) 4091 return (B_FALSE); 4092 for (c = name + sizeof ("zone.") - 1; *c != '\0'; c++) { 4093 if (!isalpha(*c) && *c != '-') 4094 return (B_FALSE); 4095 } 4096 return (B_TRUE); 4097 } 4098 4099 boolean_t 4100 zonecfg_valid_rctlblk(const rctlblk_t *rctlblk) 4101 { 4102 rctl_priv_t priv = rctlblk_get_privilege((rctlblk_t *)rctlblk); 4103 uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL); 4104 4105 if (priv != RCPRIV_PRIVILEGED) 4106 return (B_FALSE); 4107 if (action != RCTL_LOCAL_NOACTION && action != RCTL_LOCAL_DENY) 4108 return (B_FALSE); 4109 return (B_TRUE); 4110 } 4111 4112 boolean_t 4113 zonecfg_valid_rctl(const char *name, const rctlblk_t *rctlblk) 4114 { 4115 rctlblk_t *current, *next; 4116 rctl_qty_t limit = rctlblk_get_value((rctlblk_t *)rctlblk); 4117 uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL); 4118 uint_t global_flags; 4119 4120 if (!zonecfg_valid_rctlblk(rctlblk)) 4121 return (B_FALSE); 4122 if (!zonecfg_valid_rctlname(name)) 4123 return (B_FALSE); 4124 4125 current = alloca(rctlblk_size()); 4126 if (getrctl(name, NULL, current, RCTL_FIRST) != 0) 4127 return (B_TRUE); /* not an rctl on this system */ 4128 /* 4129 * Make sure the proposed value isn't greater than the current system 4130 * value. 4131 */ 4132 next = alloca(rctlblk_size()); 4133 while (rctlblk_get_privilege(current) != RCPRIV_SYSTEM) { 4134 rctlblk_t *tmp; 4135 4136 if (getrctl(name, current, next, RCTL_NEXT) != 0) 4137 return (B_FALSE); /* shouldn't happen */ 4138 tmp = current; 4139 current = next; 4140 next = tmp; 4141 } 4142 if (limit > rctlblk_get_value(current)) 4143 return (B_FALSE); 4144 4145 /* 4146 * Make sure the proposed action is allowed. 4147 */ 4148 global_flags = rctlblk_get_global_flags(current); 4149 if ((global_flags & RCTL_GLOBAL_DENY_NEVER) && 4150 action == RCTL_LOCAL_DENY) 4151 return (B_FALSE); 4152 if ((global_flags & RCTL_GLOBAL_DENY_ALWAYS) && 4153 action == RCTL_LOCAL_NOACTION) 4154 return (B_FALSE); 4155 4156 return (B_TRUE); 4157 } 4158 4159 /* 4160 * There is always a race condition between reading the initial copy of 4161 * a zones state and its state changing. We address this by providing 4162 * zonecfg_notify_critical_enter and zonecfg_noticy_critical_exit functions. 4163 * When zonecfg_critical_enter is called, sets the state field to LOCKED 4164 * and aquires biglock. Biglock protects against other threads executing 4165 * critical_enter and the state field protects against state changes during 4166 * the critical period. 4167 * 4168 * If any state changes occur, zn_cb will set the failed field of the znotify 4169 * structure. This will cause the critical_exit function to re-lock the 4170 * channel and return an error. Since evsnts may be delayed, the critical_exit 4171 * function "flushes" the queue by putting an event on the queue and waiting for 4172 * zn_cb to notify critical_exit that it received the ping event. 4173 */ 4174 static const char * 4175 string_get_tok(const char *in, char delim, int num) 4176 { 4177 int i = 0; 4178 4179 for (; i < num; in++) { 4180 if (*in == delim) 4181 i++; 4182 if (*in == 0) 4183 return (NULL); 4184 } 4185 return (in); 4186 } 4187 4188 static boolean_t 4189 is_ping(sysevent_t *ev) 4190 { 4191 if (strcmp(sysevent_get_subclass_name(ev), 4192 ZONE_EVENT_PING_SUBCLASS) == 0) { 4193 return (B_TRUE); 4194 } else { 4195 return (B_FALSE); 4196 } 4197 } 4198 4199 static boolean_t 4200 is_my_ping(sysevent_t *ev) 4201 { 4202 const char *sender; 4203 char mypid[sizeof (pid_t) * 3 + 1]; 4204 4205 (void) snprintf(mypid, sizeof (mypid), "%i", getpid()); 4206 sender = string_get_tok(sysevent_get_pub(ev), ':', 3); 4207 if (sender == NULL) 4208 return (B_FALSE); 4209 if (strcmp(sender, mypid) != 0) 4210 return (B_FALSE); 4211 return (B_TRUE); 4212 } 4213 4214 static int 4215 do_callback(struct znotify *zevtchan, sysevent_t *ev) 4216 { 4217 nvlist_t *l; 4218 int zid; 4219 char *zonename; 4220 char *newstate; 4221 char *oldstate; 4222 int ret; 4223 hrtime_t when; 4224 4225 if (strcmp(sysevent_get_subclass_name(ev), 4226 ZONE_EVENT_STATUS_SUBCLASS) == 0) { 4227 4228 if (sysevent_get_attr_list(ev, &l) != 0) { 4229 if (errno == ENOMEM) { 4230 zevtchan->zn_failure_count++; 4231 return (EAGAIN); 4232 } 4233 return (0); 4234 } 4235 ret = 0; 4236 4237 if ((nvlist_lookup_string(l, ZONE_CB_NAME, &zonename) == 0) && 4238 (nvlist_lookup_string(l, ZONE_CB_NEWSTATE, &newstate) 4239 == 0) && 4240 (nvlist_lookup_string(l, ZONE_CB_OLDSTATE, &oldstate) 4241 == 0) && 4242 (nvlist_lookup_uint64(l, ZONE_CB_TIMESTAMP, 4243 (uint64_t *)&when) == 0) && 4244 (nvlist_lookup_int32(l, ZONE_CB_ZONEID, &zid) == 0)) { 4245 ret = zevtchan->zn_callback(zonename, zid, newstate, 4246 oldstate, when, zevtchan->zn_private); 4247 } 4248 4249 zevtchan->zn_failure_count = 0; 4250 nvlist_free(l); 4251 return (ret); 4252 } else { 4253 /* 4254 * We have received an event in an unknown subclass. Ignore. 4255 */ 4256 zevtchan->zn_failure_count = 0; 4257 return (0); 4258 } 4259 } 4260 4261 static int 4262 zn_cb(sysevent_t *ev, void *p) 4263 { 4264 struct znotify *zevtchan = p; 4265 int error; 4266 4267 (void) pthread_mutex_lock(&(zevtchan->zn_mutex)); 4268 4269 if (is_ping(ev) && !is_my_ping(ev)) { 4270 (void) pthread_mutex_unlock((&zevtchan->zn_mutex)); 4271 return (0); 4272 } 4273 4274 if (zevtchan->zn_state == ZN_LOCKED) { 4275 assert(!is_ping(ev)); 4276 zevtchan->zn_failed = B_TRUE; 4277 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4278 return (0); 4279 } 4280 4281 if (zevtchan->zn_state == ZN_PING_INFLIGHT) { 4282 if (is_ping(ev)) { 4283 zevtchan->zn_state = ZN_PING_RECEIVED; 4284 (void) pthread_cond_signal(&(zevtchan->zn_cond)); 4285 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4286 return (0); 4287 } else { 4288 zevtchan->zn_failed = B_TRUE; 4289 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4290 return (0); 4291 } 4292 } 4293 4294 if (zevtchan->zn_state == ZN_UNLOCKED) { 4295 4296 error = do_callback(zevtchan, ev); 4297 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4298 /* 4299 * Every ENOMEM failure causes do_callback to increment 4300 * zn_failure_count and every success causes it to 4301 * set zn_failure_count to zero. If we got EAGAIN, 4302 * we will sleep for zn_failure_count seconds and return 4303 * EAGAIN to gpec to try again. 4304 * 4305 * After 55 seconds, or 10 try's we give up and drop the 4306 * event. 4307 */ 4308 if (error == EAGAIN) { 4309 if (zevtchan->zn_failure_count > ZONE_CB_RETRY_COUNT) { 4310 return (0); 4311 } 4312 (void) sleep(zevtchan->zn_failure_count); 4313 } 4314 return (error); 4315 } 4316 4317 if (zevtchan->zn_state == ZN_PING_RECEIVED) { 4318 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4319 return (0); 4320 } 4321 4322 abort(); 4323 return (0); 4324 } 4325 4326 void 4327 zonecfg_notify_critical_enter(void *h) 4328 { 4329 struct znotify *zevtchan = h; 4330 4331 (void) pthread_mutex_lock(&(zevtchan->zn_bigmutex)); 4332 zevtchan->zn_state = ZN_LOCKED; 4333 } 4334 4335 int 4336 zonecfg_notify_critical_exit(void * h) 4337 { 4338 4339 struct znotify *zevtchan = h; 4340 4341 if (zevtchan->zn_state == ZN_UNLOCKED) 4342 return (0); 4343 4344 (void) pthread_mutex_lock(&(zevtchan->zn_mutex)); 4345 zevtchan->zn_state = ZN_PING_INFLIGHT; 4346 4347 (void) sysevent_evc_publish(zevtchan->zn_eventchan, 4348 ZONE_EVENT_STATUS_CLASS, 4349 ZONE_EVENT_PING_SUBCLASS, ZONE_EVENT_PING_PUBLISHER, 4350 zevtchan->zn_subscriber_id, NULL, EVCH_SLEEP); 4351 4352 while (zevtchan->zn_state != ZN_PING_RECEIVED) { 4353 (void) pthread_cond_wait(&(zevtchan->zn_cond), 4354 &(zevtchan->zn_mutex)); 4355 } 4356 4357 if (zevtchan->zn_failed == B_TRUE) { 4358 zevtchan->zn_state = ZN_LOCKED; 4359 zevtchan->zn_failed = B_FALSE; 4360 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4361 return (1); 4362 } 4363 4364 zevtchan->zn_state = ZN_UNLOCKED; 4365 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4366 (void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex)); 4367 return (0); 4368 } 4369 4370 void 4371 zonecfg_notify_critical_abort(void *h) 4372 { 4373 struct znotify *zevtchan = h; 4374 4375 zevtchan->zn_state = ZN_UNLOCKED; 4376 zevtchan->zn_failed = B_FALSE; 4377 /* 4378 * Don't do anything about zn_lock. If it is held, it could only be 4379 * held by zn_cb and it will be unlocked soon. 4380 */ 4381 (void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex)); 4382 } 4383 4384 void * 4385 zonecfg_notify_bind(int(*func)(const char *zonename, zoneid_t zid, 4386 const char *newstate, const char *oldstate, hrtime_t when, void *p), 4387 void *p) 4388 { 4389 struct znotify *zevtchan; 4390 int i = 1; 4391 int r; 4392 4393 zevtchan = malloc(sizeof (struct znotify)); 4394 4395 if (zevtchan == NULL) 4396 return (NULL); 4397 4398 zevtchan->zn_private = p; 4399 zevtchan->zn_callback = func; 4400 zevtchan->zn_state = ZN_UNLOCKED; 4401 zevtchan->zn_failed = B_FALSE; 4402 4403 if (pthread_mutex_init(&(zevtchan->zn_mutex), NULL)) 4404 goto out3; 4405 if (pthread_cond_init(&(zevtchan->zn_cond), NULL)) { 4406 (void) pthread_mutex_destroy(&(zevtchan->zn_mutex)); 4407 goto out3; 4408 } 4409 if (pthread_mutex_init(&(zevtchan->zn_bigmutex), NULL)) { 4410 (void) pthread_mutex_destroy(&(zevtchan->zn_mutex)); 4411 (void) pthread_cond_destroy(&(zevtchan->zn_cond)); 4412 goto out3; 4413 } 4414 4415 if (sysevent_evc_bind(ZONE_EVENT_CHANNEL, &(zevtchan->zn_eventchan), 4416 0) != 0) 4417 goto out2; 4418 4419 do { 4420 /* 4421 * At 4 digits the subscriber ID gets too long and we have 4422 * no chance of successfully registering. 4423 */ 4424 if (i > 999) 4425 goto out1; 4426 4427 (void) sprintf(zevtchan->zn_subscriber_id, "zone_%li_%i", 4428 getpid() % 999999l, i); 4429 4430 r = sysevent_evc_subscribe(zevtchan->zn_eventchan, 4431 zevtchan->zn_subscriber_id, ZONE_EVENT_STATUS_CLASS, zn_cb, 4432 zevtchan, 0); 4433 4434 i++; 4435 4436 } while (r); 4437 4438 return (zevtchan); 4439 out1: 4440 sysevent_evc_unbind(zevtchan->zn_eventchan); 4441 out2: 4442 (void) pthread_mutex_destroy(&zevtchan->zn_mutex); 4443 (void) pthread_cond_destroy(&zevtchan->zn_cond); 4444 (void) pthread_mutex_destroy(&(zevtchan->zn_bigmutex)); 4445 out3: 4446 free(zevtchan); 4447 4448 return (NULL); 4449 } 4450 4451 void 4452 zonecfg_notify_unbind(void *handle) 4453 { 4454 4455 int ret; 4456 4457 sysevent_evc_unbind(((struct znotify *)handle)->zn_eventchan); 4458 /* 4459 * Check that all evc threads have gone away. This should be 4460 * enforced by sysevent_evc_unbind. 4461 */ 4462 ret = pthread_mutex_trylock(&((struct znotify *)handle)->zn_mutex); 4463 4464 if (ret) 4465 abort(); 4466 4467 (void) pthread_mutex_unlock(&((struct znotify *)handle)->zn_mutex); 4468 (void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_mutex); 4469 (void) pthread_cond_destroy(&((struct znotify *)handle)->zn_cond); 4470 (void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_bigmutex); 4471 4472 free(handle); 4473 } 4474 4475 static int 4476 zonecfg_add_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr) 4477 { 4478 xmlNodePtr newnode, cur = handle->zone_dh_cur; 4479 int err; 4480 4481 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DATASET, NULL); 4482 if ((err = newprop(newnode, DTD_ATTR_NAME, 4483 tabptr->zone_dataset_name)) != Z_OK) 4484 return (err); 4485 return (Z_OK); 4486 } 4487 4488 int 4489 zonecfg_add_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 4490 { 4491 int err; 4492 4493 if (tabptr == NULL) 4494 return (Z_INVAL); 4495 4496 if ((err = operation_prep(handle)) != Z_OK) 4497 return (err); 4498 4499 if ((err = zonecfg_add_ds_core(handle, tabptr)) != Z_OK) 4500 return (err); 4501 4502 return (Z_OK); 4503 } 4504 4505 static int 4506 zonecfg_delete_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr) 4507 { 4508 xmlNodePtr cur = handle->zone_dh_cur; 4509 4510 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 4511 if (xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 4512 continue; 4513 4514 if (match_prop(cur, DTD_ATTR_NAME, 4515 tabptr->zone_dataset_name)) { 4516 xmlUnlinkNode(cur); 4517 xmlFreeNode(cur); 4518 return (Z_OK); 4519 } 4520 } 4521 return (Z_NO_RESOURCE_ID); 4522 } 4523 4524 int 4525 zonecfg_delete_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 4526 { 4527 int err; 4528 4529 if (tabptr == NULL) 4530 return (Z_INVAL); 4531 4532 if ((err = operation_prep(handle)) != Z_OK) 4533 return (err); 4534 4535 if ((err = zonecfg_delete_ds_core(handle, tabptr)) != Z_OK) 4536 return (err); 4537 4538 return (Z_OK); 4539 } 4540 4541 int 4542 zonecfg_modify_ds( 4543 zone_dochandle_t handle, 4544 struct zone_dstab *oldtabptr, 4545 struct zone_dstab *newtabptr) 4546 { 4547 int err; 4548 4549 if (oldtabptr == NULL || newtabptr == NULL) 4550 return (Z_INVAL); 4551 4552 if ((err = operation_prep(handle)) != Z_OK) 4553 return (err); 4554 4555 if ((err = zonecfg_delete_ds_core(handle, oldtabptr)) != Z_OK) 4556 return (err); 4557 4558 if ((err = zonecfg_add_ds_core(handle, newtabptr)) != Z_OK) 4559 return (err); 4560 4561 return (Z_OK); 4562 } 4563 4564 int 4565 zonecfg_lookup_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 4566 { 4567 xmlNodePtr cur, firstmatch; 4568 int err; 4569 char dataset[MAXNAMELEN]; 4570 4571 if (tabptr == NULL) 4572 return (Z_INVAL); 4573 4574 if ((err = operation_prep(handle)) != Z_OK) 4575 return (err); 4576 4577 cur = handle->zone_dh_cur; 4578 firstmatch = NULL; 4579 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 4580 if (xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 4581 continue; 4582 if (strlen(tabptr->zone_dataset_name) > 0) { 4583 if ((fetchprop(cur, DTD_ATTR_NAME, dataset, 4584 sizeof (dataset)) == Z_OK) && 4585 (strcmp(tabptr->zone_dataset_name, 4586 dataset) == 0)) { 4587 if (firstmatch == NULL) 4588 firstmatch = cur; 4589 else 4590 return (Z_INSUFFICIENT_SPEC); 4591 } 4592 } 4593 } 4594 if (firstmatch == NULL) 4595 return (Z_NO_RESOURCE_ID); 4596 4597 cur = firstmatch; 4598 4599 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name, 4600 sizeof (tabptr->zone_dataset_name))) != Z_OK) 4601 return (err); 4602 4603 return (Z_OK); 4604 } 4605 4606 int 4607 zonecfg_setdsent(zone_dochandle_t handle) 4608 { 4609 return (zonecfg_setent(handle)); 4610 } 4611 4612 int 4613 zonecfg_getdsent(zone_dochandle_t handle, struct zone_dstab *tabptr) 4614 { 4615 xmlNodePtr cur; 4616 int err; 4617 4618 if (handle == NULL) 4619 return (Z_INVAL); 4620 4621 if ((cur = handle->zone_dh_cur) == NULL) 4622 return (Z_NO_ENTRY); 4623 4624 for (; cur != NULL; cur = cur->next) 4625 if (!xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 4626 break; 4627 if (cur == NULL) { 4628 handle->zone_dh_cur = handle->zone_dh_top; 4629 return (Z_NO_ENTRY); 4630 } 4631 4632 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name, 4633 sizeof (tabptr->zone_dataset_name))) != Z_OK) { 4634 handle->zone_dh_cur = handle->zone_dh_top; 4635 return (err); 4636 } 4637 4638 handle->zone_dh_cur = cur->next; 4639 return (Z_OK); 4640 } 4641 4642 int 4643 zonecfg_enddsent(zone_dochandle_t handle) 4644 { 4645 return (zonecfg_endent(handle)); 4646 } 4647 4648 int 4649 zonecfg_setpkgent(zone_dochandle_t handle) 4650 { 4651 return (zonecfg_setent(handle)); 4652 } 4653 4654 int 4655 zonecfg_getpkgent(zone_dochandle_t handle, struct zone_pkgtab *tabptr) 4656 { 4657 xmlNodePtr cur; 4658 int err; 4659 4660 if (handle == NULL) 4661 return (Z_INVAL); 4662 4663 if ((cur = handle->zone_dh_cur) == NULL) 4664 return (Z_NO_ENTRY); 4665 4666 for (; cur != NULL; cur = cur->next) 4667 if (!xmlStrcmp(cur->name, DTD_ELEM_PACKAGE)) 4668 break; 4669 if (cur == NULL) { 4670 handle->zone_dh_cur = handle->zone_dh_top; 4671 return (Z_NO_ENTRY); 4672 } 4673 4674 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_pkg_name, 4675 sizeof (tabptr->zone_pkg_name))) != Z_OK) { 4676 handle->zone_dh_cur = handle->zone_dh_top; 4677 return (err); 4678 } 4679 4680 if ((err = fetchprop(cur, DTD_ATTR_VERSION, tabptr->zone_pkg_version, 4681 sizeof (tabptr->zone_pkg_version))) != Z_OK) { 4682 handle->zone_dh_cur = handle->zone_dh_top; 4683 return (err); 4684 } 4685 4686 handle->zone_dh_cur = cur->next; 4687 return (Z_OK); 4688 } 4689 4690 int 4691 zonecfg_endpkgent(zone_dochandle_t handle) 4692 { 4693 return (zonecfg_endent(handle)); 4694 } 4695 4696 int 4697 zonecfg_setpatchent(zone_dochandle_t handle) 4698 { 4699 return (zonecfg_setent(handle)); 4700 } 4701 4702 int 4703 zonecfg_getpatchent(zone_dochandle_t handle, struct zone_patchtab *tabptr) 4704 { 4705 xmlNodePtr cur; 4706 int err; 4707 4708 if (handle == NULL) 4709 return (Z_INVAL); 4710 4711 if ((cur = handle->zone_dh_cur) == NULL) 4712 return (Z_NO_ENTRY); 4713 4714 for (; cur != NULL; cur = cur->next) 4715 if (!xmlStrcmp(cur->name, DTD_ELEM_PATCH)) 4716 break; 4717 if (cur == NULL) { 4718 handle->zone_dh_cur = handle->zone_dh_top; 4719 return (Z_NO_ENTRY); 4720 } 4721 4722 if ((err = fetchprop(cur, DTD_ATTR_ID, tabptr->zone_patch_id, 4723 sizeof (tabptr->zone_patch_id))) != Z_OK) { 4724 handle->zone_dh_cur = handle->zone_dh_top; 4725 return (err); 4726 } 4727 4728 handle->zone_dh_cur = cur->next; 4729 return (Z_OK); 4730 } 4731 4732 int 4733 zonecfg_endpatchent(zone_dochandle_t handle) 4734 { 4735 return (zonecfg_endent(handle)); 4736 } 4737 4738 int 4739 zonecfg_setdevperment(zone_dochandle_t handle) 4740 { 4741 return (zonecfg_setent(handle)); 4742 } 4743 4744 int 4745 zonecfg_getdevperment(zone_dochandle_t handle, struct zone_devpermtab *tabptr) 4746 { 4747 xmlNodePtr cur; 4748 int err; 4749 char buf[128]; 4750 4751 tabptr->zone_devperm_acl = NULL; 4752 4753 if (handle == NULL) 4754 return (Z_INVAL); 4755 4756 if ((cur = handle->zone_dh_cur) == NULL) 4757 return (Z_NO_ENTRY); 4758 4759 for (; cur != NULL; cur = cur->next) 4760 if (!xmlStrcmp(cur->name, DTD_ELEM_DEV_PERM)) 4761 break; 4762 if (cur == NULL) { 4763 handle->zone_dh_cur = handle->zone_dh_top; 4764 return (Z_NO_ENTRY); 4765 } 4766 4767 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_devperm_name, 4768 sizeof (tabptr->zone_devperm_name))) != Z_OK) { 4769 handle->zone_dh_cur = handle->zone_dh_top; 4770 return (err); 4771 } 4772 4773 if ((err = fetchprop(cur, DTD_ATTR_UID, buf, sizeof (buf))) != Z_OK) { 4774 handle->zone_dh_cur = handle->zone_dh_top; 4775 return (err); 4776 } 4777 tabptr->zone_devperm_uid = (uid_t)atol(buf); 4778 4779 if ((err = fetchprop(cur, DTD_ATTR_GID, buf, sizeof (buf))) != Z_OK) { 4780 handle->zone_dh_cur = handle->zone_dh_top; 4781 return (err); 4782 } 4783 tabptr->zone_devperm_gid = (gid_t)atol(buf); 4784 4785 if ((err = fetchprop(cur, DTD_ATTR_MODE, buf, sizeof (buf))) != Z_OK) { 4786 handle->zone_dh_cur = handle->zone_dh_top; 4787 return (err); 4788 } 4789 tabptr->zone_devperm_mode = (mode_t)strtol(buf, (char **)NULL, 8); 4790 4791 if ((err = fetch_alloc_prop(cur, DTD_ATTR_ACL, 4792 &(tabptr->zone_devperm_acl))) != Z_OK) { 4793 handle->zone_dh_cur = handle->zone_dh_top; 4794 return (err); 4795 } 4796 4797 handle->zone_dh_cur = cur->next; 4798 return (Z_OK); 4799 } 4800 4801 int 4802 zonecfg_enddevperment(zone_dochandle_t handle) 4803 { 4804 return (zonecfg_endent(handle)); 4805 } 4806 4807 /* 4808 * Process a list of pkgs from an entry in the contents file, adding each pkg 4809 * name to the list of pkgs. 4810 * 4811 * It is possible for the pkg name to be preceeded by a special character 4812 * which indicates some bookkeeping information for pkging. Check if the 4813 * first char is not an Alpha char. If so, skip over it. 4814 */ 4815 static int 4816 add_pkg_list(char *lastp, char ***plist, int *pcnt) 4817 { 4818 char *p; 4819 int pkg_cnt = *pcnt; 4820 char **pkgs = *plist; 4821 int res = Z_OK; 4822 4823 while ((p = strtok_r(NULL, " ", &lastp)) != NULL) { 4824 char **tmpp; 4825 int i; 4826 4827 /* skip over any special pkg bookkeeping char */ 4828 if (!isalpha(*p)) 4829 p++; 4830 4831 /* Check if the pkg is already in the list */ 4832 for (i = 0; i < pkg_cnt; i++) { 4833 if (strcmp(p, pkgs[i]) == 0) 4834 break; 4835 } 4836 4837 if (i < pkg_cnt) 4838 continue; 4839 4840 /* The pkg is not in the list; add it. */ 4841 if ((tmpp = (char **)realloc(pkgs, 4842 sizeof (char *) * (pkg_cnt + 1))) == NULL) { 4843 res = Z_NOMEM; 4844 break; 4845 } 4846 pkgs = tmpp; 4847 4848 if ((pkgs[pkg_cnt] = strdup(p)) == NULL) { 4849 res = Z_NOMEM; 4850 break; 4851 } 4852 pkg_cnt++; 4853 } 4854 4855 *plist = pkgs; 4856 *pcnt = pkg_cnt; 4857 4858 return (res); 4859 } 4860 4861 /* 4862 * Process an entry from the contents file (type "directory") and if the 4863 * directory path is in the list of paths, add the associated list of pkgs 4864 * to the pkg list. The input parameter "entry" will be broken up by 4865 * the parser within this function so its value will be modified when this 4866 * function exits. 4867 * 4868 * The entries we are looking for will look something like: 4869 * /usr d none 0755 root sys SUNWctpls SUNWidnl SUNWlibCf .... 4870 */ 4871 static int 4872 get_path_pkgs(char *entry, char **paths, int cnt, char ***pkgs, int *pkg_cnt) 4873 { 4874 char *f1; 4875 char *f2; 4876 char *lastp; 4877 int i; 4878 int res = Z_OK; 4879 4880 if ((f1 = strtok_r(entry, " ", &lastp)) == NULL || 4881 (f2 = strtok_r(NULL, " ", &lastp)) == NULL || strcmp(f2, "d") != 0) 4882 return (Z_OK); 4883 4884 /* Check if this directory entry is in the list of paths. */ 4885 for (i = 0; i < cnt; i++) { 4886 if (fnmatch(paths[i], f1, FNM_PATHNAME) == 0) { 4887 /* 4888 * We do want the pkgs for this path. First, skip 4889 * over the next 4 fields in the entry so that we call 4890 * add_pkg_list starting with the pkg names. 4891 */ 4892 int j; 4893 char *nlp; 4894 4895 for (j = 0; j < 4 && 4896 strtok_r(NULL, " ", &lastp) != NULL; j++) 4897 ; 4898 /* 4899 * If there are < 4 fields this entry is corrupt, 4900 * just skip it. 4901 */ 4902 if (j < 4) 4903 return (Z_OK); 4904 4905 /* strip newline from the line */ 4906 nlp = (lastp + strlen(lastp) - 1); 4907 if (*nlp == '\n') 4908 *nlp = '\0'; 4909 4910 res = add_pkg_list(lastp, pkgs, pkg_cnt); 4911 break; 4912 } 4913 } 4914 4915 return (res); 4916 } 4917 4918 /* 4919 * Read an entry from a pkginfo or contents file. Some of these lines can 4920 * either be arbitrarily long or be continued by a backslash at the end of 4921 * the line. This function coalesces lines that are longer than the read 4922 * buffer, and lines that are continued, into one buffer which is returned. 4923 * The caller must free this memory. NULL is returned when we hit EOF or 4924 * if we run out of memory (errno is set to ENOMEM). 4925 */ 4926 static char * 4927 read_pkg_data(FILE *fp) 4928 { 4929 char *start; 4930 char *inp; 4931 char *p; 4932 int char_cnt = 0; 4933 4934 errno = 0; 4935 if ((start = (char *)malloc(PKGINFO_RD_LEN)) == NULL) { 4936 errno = ENOMEM; 4937 return (NULL); 4938 } 4939 4940 inp = start; 4941 while ((p = fgets(inp, PKGINFO_RD_LEN, fp)) != NULL) { 4942 int len; 4943 4944 len = strlen(inp); 4945 if (inp[len - 1] == '\n' && 4946 (len == 1 || inp[len - 2] != '\\')) { 4947 char_cnt = len; 4948 break; 4949 } 4950 4951 if (inp[len - 2] == '\\') 4952 char_cnt += len - 2; 4953 else 4954 char_cnt += PKGINFO_RD_LEN - 1; 4955 4956 if ((p = realloc(start, char_cnt + PKGINFO_RD_LEN)) == NULL) { 4957 errno = ENOMEM; 4958 break; 4959 } 4960 4961 start = p; 4962 inp = start + char_cnt; 4963 } 4964 4965 if (errno == ENOMEM || (p == NULL && char_cnt == 0)) { 4966 free(start); 4967 start = NULL; 4968 } 4969 4970 return (start); 4971 } 4972 4973 static void 4974 free_ipd_pkgs(char **pkgs, int cnt) 4975 { 4976 int i; 4977 4978 for (i = 0; i < cnt; i++) 4979 free(pkgs[i]); 4980 free(pkgs); 4981 } 4982 4983 /* 4984 * Get the list of inherited-pkg-dirs (ipd) for the zone and then get the 4985 * list of pkgs that deliver into those dirs. 4986 */ 4987 static int 4988 get_ipd_pkgs(zone_dochandle_t handle, char ***pkg_list, int *cnt) 4989 { 4990 int res; 4991 struct zone_fstab fstab; 4992 int ipd_cnt = 0; 4993 char **ipds = NULL; 4994 int pkg_cnt = 0; 4995 char **pkgs = NULL; 4996 int i; 4997 4998 if ((res = zonecfg_setipdent(handle)) != Z_OK) 4999 return (res); 5000 5001 while (zonecfg_getipdent(handle, &fstab) == Z_OK) { 5002 char **p; 5003 int len; 5004 5005 if ((p = (char **)realloc(ipds, 5006 sizeof (char *) * (ipd_cnt + 2))) == NULL) { 5007 res = Z_NOMEM; 5008 break; 5009 } 5010 ipds = p; 5011 5012 if ((ipds[ipd_cnt] = strdup(fstab.zone_fs_dir)) == NULL) { 5013 res = Z_NOMEM; 5014 break; 5015 } 5016 ipd_cnt++; 5017 5018 len = strlen(fstab.zone_fs_dir) + 3; 5019 if ((ipds[ipd_cnt] = malloc(len)) == NULL) { 5020 res = Z_NOMEM; 5021 break; 5022 } 5023 5024 (void) snprintf(ipds[ipd_cnt], len, "%s/*", fstab.zone_fs_dir); 5025 ipd_cnt++; 5026 } 5027 5028 (void) zonecfg_endipdent(handle); 5029 5030 if (res != Z_OK) { 5031 for (i = 0; i < ipd_cnt; i++) 5032 free(ipds[i]); 5033 free(ipds); 5034 return (res); 5035 } 5036 5037 /* We only have to process the contents file if we have ipds. */ 5038 if (ipd_cnt > 0) { 5039 FILE *fp; 5040 5041 if ((fp = fopen(CONTENTS_FILE, "r")) != NULL) { 5042 char *buf; 5043 5044 while ((buf = read_pkg_data(fp)) != NULL) { 5045 res = get_path_pkgs(buf, ipds, ipd_cnt, &pkgs, 5046 &pkg_cnt); 5047 free(buf); 5048 if (res != Z_OK) 5049 break; 5050 } 5051 5052 (void) fclose(fp); 5053 } 5054 } 5055 5056 for (i = 0; i < ipd_cnt; i++) 5057 free(ipds[i]); 5058 free(ipds); 5059 5060 if (res != Z_OK) { 5061 free_ipd_pkgs(pkgs, pkg_cnt); 5062 } else { 5063 *pkg_list = pkgs; 5064 *cnt = pkg_cnt; 5065 } 5066 5067 return (res); 5068 } 5069 5070 /* 5071 * Return true if pkg_name is in the list of pkgs that deliver into an 5072 * inherited pkg directory for the zone. 5073 */ 5074 static boolean_t 5075 dir_pkg(char *pkg_name, char **pkg_list, int cnt) 5076 { 5077 int i; 5078 5079 for (i = 0; i < cnt; i++) { 5080 if (strcmp(pkg_name, pkg_list[i]) == 0) 5081 return (B_TRUE); 5082 } 5083 5084 return (B_FALSE); 5085 } 5086 5087 /* 5088 * Start by adding the patch to the sw inventory on the handle. 5089 * 5090 * The info parameter will be the portion of the PATCH_INFO_ entry following 5091 * the '='. For example: 5092 * Installed: Wed Dec 7 07:13:51 PST 2005 From: mum Obsoletes: 120777-03 \ 5093 * 121087-02 119108-07 Requires: 119575-02 119255-06 Incompatibles: 5094 * 5095 * A backed out patch will have an info line of "backed out\n". We should 5096 * skip these patches. 5097 * 5098 * We also want to add the Obsolete and Incompatible patches to the 5099 * sw inventory description of this patch. 5100 */ 5101 static int 5102 add_patch(zone_dochandle_t handle, char *patch, char *info) 5103 { 5104 xmlNodePtr node; 5105 xmlNodePtr cur; 5106 int err; 5107 char *p; 5108 char *lastp; 5109 boolean_t add_info = B_FALSE; 5110 boolean_t obsolete; 5111 5112 if (strcmp(info, "backed out\n") == 0) 5113 return (Z_OK); 5114 5115 if ((err = operation_prep(handle)) != Z_OK) 5116 return (err); 5117 5118 cur = handle->zone_dh_cur; 5119 node = xmlNewTextChild(cur, NULL, DTD_ELEM_PATCH, NULL); 5120 if ((err = newprop(node, DTD_ATTR_ID, patch)) != Z_OK) 5121 return (err); 5122 5123 /* 5124 * Start with the first token. This will probably be "Installed:". 5125 * If we can't tokenize this entry, just return. 5126 */ 5127 if ((p = strtok_r(info, " ", &lastp)) == NULL) 5128 return (Z_OK); 5129 5130 do { 5131 xmlNodePtr new_node; 5132 char *nlp; 5133 5134 if (strcmp(p, "Installed:") == 0 || 5135 strcmp(p, "Requires:") == 0 || 5136 strcmp(p, "From:") == 0) { 5137 add_info = B_FALSE; 5138 continue; 5139 } else if (strcmp(p, "Obsoletes:") == 0) { 5140 obsolete = B_TRUE; 5141 add_info = B_TRUE; 5142 continue; 5143 } else if (strcmp(p, "Incompatibles:") == 0) { 5144 obsolete = B_FALSE; 5145 add_info = B_TRUE; 5146 continue; 5147 } 5148 5149 if (!add_info) 5150 continue; 5151 5152 /* strip newline from last patch in the line */ 5153 nlp = (p + strlen(p) - 1); 5154 if (*nlp == '\n') 5155 *nlp = '\0'; 5156 5157 if (obsolete) 5158 new_node = xmlNewTextChild(node, NULL, 5159 DTD_ELEM_OBSOLETES, NULL); 5160 else 5161 new_node = xmlNewTextChild(node, NULL, 5162 DTD_ELEM_INCOMPATIBLE, NULL); 5163 5164 if ((err = newprop(new_node, DTD_ATTR_ID, p)) != Z_OK) 5165 return (err); 5166 5167 } while ((p = strtok_r(NULL, " ", &lastp)) != NULL); 5168 5169 return (Z_OK); 5170 } 5171 5172 static boolean_t 5173 unique_patch(zone_dochandle_t handle, char *patch) 5174 { 5175 xmlNodePtr cur; 5176 char id[MAXNAMELEN]; 5177 5178 cur = xmlDocGetRootElement(handle->zone_dh_doc); 5179 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 5180 if (xmlStrcmp(cur->name, DTD_ELEM_PATCH) == 0) { 5181 if (fetchprop(cur, DTD_ATTR_ID, id, sizeof (id)) 5182 != Z_OK) 5183 continue; 5184 5185 if (strcmp(patch, id) == 0) 5186 return (B_FALSE); 5187 } 5188 } 5189 5190 return (B_TRUE); 5191 } 5192 5193 /* 5194 * Add the unique patches associated with this pkg to the sw inventory on the 5195 * handle. 5196 * 5197 * We are processing entries of the form: 5198 * PATCH_INFO_121454-02=Installed: Wed Dec 7 07:13:51 PST 2005 From: mum \ 5199 * Obsoletes: 120777-03 121087-02 119108-07 Requires: 119575-02 \ 5200 * 119255-06 Incompatibles: 5201 * 5202 */ 5203 static int 5204 add_patches(zone_dochandle_t handle, struct zone_pkginfo *infop) 5205 { 5206 int i; 5207 int res = Z_OK; 5208 5209 for (i = 0; i < infop->zpi_patch_cnt; i++) { 5210 char *p, *ep; 5211 5212 if (strlen(infop->zpi_patchinfo[i]) < (sizeof (PATCHINFO) - 1)) 5213 continue; 5214 5215 /* Skip over "PATCH_INFO_" to get the patch id. */ 5216 p = infop->zpi_patchinfo[i] + sizeof (PATCHINFO) - 1; 5217 if ((ep = strchr(p, '=')) == NULL) 5218 continue; 5219 5220 *ep = '\0'; 5221 if (unique_patch(handle, p)) 5222 if ((res = add_patch(handle, p, ep + 1)) != Z_OK) 5223 break; 5224 } 5225 5226 return (res); 5227 } 5228 5229 /* 5230 * Add the pkg to the sw inventory on the handle. 5231 */ 5232 static int 5233 add_pkg(zone_dochandle_t handle, char *name, char *version) 5234 { 5235 xmlNodePtr newnode; 5236 xmlNodePtr cur; 5237 int err; 5238 5239 if ((err = operation_prep(handle)) != Z_OK) 5240 return (err); 5241 5242 cur = handle->zone_dh_cur; 5243 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PACKAGE, NULL); 5244 if ((err = newprop(newnode, DTD_ATTR_NAME, name)) != Z_OK) 5245 return (err); 5246 if ((err = newprop(newnode, DTD_ATTR_VERSION, version)) != Z_OK) 5247 return (err); 5248 return (Z_OK); 5249 } 5250 5251 static void 5252 free_pkginfo(struct zone_pkginfo *infop) 5253 { 5254 free(infop->zpi_version); 5255 if (infop->zpi_patch_cnt > 0) { 5256 int i; 5257 5258 for (i = 0; i < infop->zpi_patch_cnt; i++) 5259 free(infop->zpi_patchinfo[i]); 5260 free(infop->zpi_patchinfo); 5261 } 5262 } 5263 5264 /* 5265 * Read the pkginfo file and populate the structure with the data we need 5266 * from this pkg for a sw inventory. 5267 */ 5268 static int 5269 get_pkginfo(char *pkginfo, struct zone_pkginfo *infop) 5270 { 5271 FILE *fp; 5272 char *buf; 5273 int err = 0; 5274 5275 infop->zpi_all_zones = B_FALSE; 5276 infop->zpi_this_zone = B_FALSE; 5277 infop->zpi_version = NULL; 5278 infop->zpi_patch_cnt = 0; 5279 infop->zpi_patchinfo = NULL; 5280 5281 if ((fp = fopen(pkginfo, "r")) == NULL) 5282 return (errno); 5283 5284 while ((buf = read_pkg_data(fp)) != NULL) { 5285 if (strncmp(buf, VERSION, sizeof (VERSION) - 1) == 0) { 5286 int len; 5287 5288 if ((infop->zpi_version = 5289 strdup(buf + sizeof (VERSION) - 1)) == NULL) { 5290 err = ENOMEM; 5291 break; 5292 } 5293 5294 /* remove trailing newline */ 5295 len = strlen(infop->zpi_version); 5296 *(infop->zpi_version + len - 1) = 0; 5297 5298 } else if (strcmp(buf, SUNW_PKG_ALL_ZONES) == 0) { 5299 infop->zpi_all_zones = B_TRUE; 5300 5301 } else if (strcmp(buf, SUNW_PKG_THIS_ZONE) == 0) { 5302 infop->zpi_this_zone = B_TRUE; 5303 5304 } else if (strncmp(buf, PATCHINFO, sizeof (PATCHINFO) - 1) 5305 == 0) { 5306 char **p; 5307 5308 if ((p = (char **)realloc(infop->zpi_patchinfo, 5309 sizeof (char *) * (infop->zpi_patch_cnt + 1))) 5310 == NULL) { 5311 err = ENOMEM; 5312 break; 5313 } 5314 infop->zpi_patchinfo = p; 5315 5316 if ((infop->zpi_patchinfo[infop->zpi_patch_cnt] = 5317 strdup(buf)) == NULL) { 5318 err = ENOMEM; 5319 break; 5320 } 5321 infop->zpi_patch_cnt++; 5322 } 5323 5324 free(buf); 5325 } 5326 5327 free(buf); 5328 5329 if (errno == ENOMEM) { 5330 err = ENOMEM; 5331 /* Clean up anything we did manage to allocate. */ 5332 free_pkginfo(infop); 5333 } 5334 5335 (void) fclose(fp); 5336 5337 return (err); 5338 } 5339 5340 /* 5341 * Take a software inventory of the global zone. We need to get the set of 5342 * packages and patches that are on the global zone that the specified 5343 * non-global zone depends on. The packages we need in the inventory are: 5344 * 5345 * - skip the package if SUNW_PKG_THISZONE is 'true' 5346 * otherwise, 5347 * - add the package if 5348 * a) SUNW_PKG_ALLZONES is 'true', 5349 * or 5350 * b) any file delivered by the package is in a file system that is inherited 5351 * from the global zone. 5352 * If the zone does not inherit any file systems (whole root) 5353 * then (b) will be skipped. 5354 * 5355 * For each of the packages that is being added to the inventory, we will also 5356 * add all of the associated, unique patches to the inventory. 5357 */ 5358 static int 5359 zonecfg_sw_inventory(zone_dochandle_t handle) 5360 { 5361 char pkginfo[MAXPATHLEN]; 5362 int res; 5363 struct dirent *dp; 5364 DIR *dirp; 5365 struct stat buf; 5366 struct zone_pkginfo info; 5367 int pkg_cnt = 0; 5368 char **pkgs = NULL; 5369 5370 if ((res = get_ipd_pkgs(handle, &pkgs, &pkg_cnt)) != Z_OK) 5371 return (res); 5372 5373 if ((dirp = opendir(PKG_PATH)) == NULL) { 5374 free_ipd_pkgs(pkgs, pkg_cnt); 5375 return (Z_OK); 5376 } 5377 5378 while ((dp = readdir(dirp)) != (struct dirent *)0) { 5379 if (strcmp(dp->d_name, ".") == 0 || 5380 strcmp(dp->d_name, "..") == 0) 5381 continue; 5382 5383 (void) snprintf(pkginfo, sizeof (pkginfo), "%s/%s/pkginfo", 5384 PKG_PATH, dp->d_name); 5385 5386 if (stat(pkginfo, &buf) == -1 || !S_ISREG(buf.st_mode)) 5387 continue; 5388 5389 if (get_pkginfo(pkginfo, &info) != 0) { 5390 res = Z_NOMEM; 5391 break; 5392 } 5393 5394 if (!info.zpi_this_zone && 5395 (info.zpi_all_zones || 5396 dir_pkg(dp->d_name, pkgs, pkg_cnt))) { 5397 if ((res = add_pkg(handle, dp->d_name, 5398 info.zpi_version)) == Z_OK) { 5399 if (info.zpi_patch_cnt > 0) 5400 res = add_patches(handle, &info); 5401 } 5402 } 5403 5404 free_pkginfo(&info); 5405 5406 if (res != Z_OK) 5407 break; 5408 } 5409 5410 (void) closedir(dirp); 5411 5412 free_ipd_pkgs(pkgs, pkg_cnt); 5413 5414 if (res == Z_OK) 5415 handle->zone_dh_sw_inv = B_TRUE; 5416 5417 return (res); 5418 } 5419 5420 /* 5421 * zonecfg_devwalk call-back function used during detach to generate the 5422 * dev info in the manifest. 5423 */ 5424 static int 5425 get_detach_dev_entry(const char *name, uid_t uid, gid_t gid, mode_t mode, 5426 const char *acl, void *hdl) 5427 { 5428 zone_dochandle_t handle = (zone_dochandle_t)hdl; 5429 xmlNodePtr newnode; 5430 xmlNodePtr cur; 5431 int err; 5432 char buf[128]; 5433 5434 if ((err = operation_prep(handle)) != Z_OK) 5435 return (err); 5436 5437 cur = handle->zone_dh_cur; 5438 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEV_PERM, NULL); 5439 if ((err = newprop(newnode, DTD_ATTR_NAME, (char *)name)) != Z_OK) 5440 return (err); 5441 (void) snprintf(buf, sizeof (buf), "%lu", uid); 5442 if ((err = newprop(newnode, DTD_ATTR_UID, buf)) != Z_OK) 5443 return (err); 5444 (void) snprintf(buf, sizeof (buf), "%lu", gid); 5445 if ((err = newprop(newnode, DTD_ATTR_GID, buf)) != Z_OK) 5446 return (err); 5447 (void) snprintf(buf, sizeof (buf), "%o", mode); 5448 if ((err = newprop(newnode, DTD_ATTR_MODE, buf)) != Z_OK) 5449 return (err); 5450 if ((err = newprop(newnode, DTD_ATTR_ACL, (char *)acl)) != Z_OK) 5451 return (err); 5452 return (Z_OK); 5453 } 5454 5455 /* 5456 * Get the information required to support detaching a zone. This is 5457 * called on the source system when detaching (the detaching parameter should 5458 * be set to true) and on the destination system before attaching (the 5459 * detaching parameter should be false). 5460 * 5461 * For native Solaris zones, the detach/attach process involves validating 5462 * that the software on the global zone can support the zone when we attach. 5463 * To do this we take a software inventory of the global zone. We also 5464 * have to keep track of the device configuration so that we can properly 5465 * recreate it on the destination. 5466 */ 5467 int 5468 zonecfg_get_detach_info(zone_dochandle_t handle, boolean_t detaching) 5469 { 5470 int res; 5471 5472 if ((res = zonecfg_sw_inventory(handle)) != Z_OK) 5473 return (res); 5474 5475 if (detaching) 5476 res = zonecfg_devwalk(handle, get_detach_dev_entry, handle); 5477 5478 return (res); 5479 } 5480