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/helper", 2287 "zfs", 2288 NULL 2289 }; 2290 2291 /* 2292 * This function finds everything mounted under a zone's rootpath. 2293 * This returns the number of mounts under rootpath, or -1 on error. 2294 * callback is called once per mount found with the first argument 2295 * pointing to the mount point. 2296 * 2297 * If the callback function returns non-zero zonecfg_find_mounts 2298 * aborts with an error. 2299 */ 2300 2301 int 2302 zonecfg_find_mounts(char *rootpath, int (*callback)(const char *, void *), 2303 void *priv) { 2304 FILE *mnttab; 2305 struct mnttab m; 2306 size_t l; 2307 int zfsl; 2308 int rv = 0; 2309 char zfs_path[MAXPATHLEN]; 2310 2311 assert(rootpath != NULL); 2312 2313 if ((zfsl = snprintf(zfs_path, sizeof (zfs_path), "%s/.zfs/", rootpath)) 2314 >= sizeof (zfs_path)) 2315 return (-1); 2316 2317 l = strlen(rootpath); 2318 2319 mnttab = fopen("/etc/mnttab", "r"); 2320 2321 if (mnttab == NULL) 2322 return (-1); 2323 2324 if (ioctl(fileno(mnttab), MNTIOC_SHOWHIDDEN, NULL) < 0) { 2325 rv = -1; 2326 goto out; 2327 } 2328 2329 while (!getmntent(mnttab, &m)) { 2330 if ((strncmp(rootpath, m.mnt_mountp, l) == 0) && 2331 (m.mnt_mountp[l] == '/') && 2332 (strncmp(zfs_path, m.mnt_mountp, zfsl) != 0)) { 2333 rv++; 2334 if (callback == NULL) 2335 continue; 2336 if (callback(m.mnt_mountp, priv)) { 2337 rv = -1; 2338 goto out; 2339 2340 } 2341 } 2342 } 2343 2344 out: 2345 (void) fclose(mnttab); 2346 return (rv); 2347 } 2348 2349 /* 2350 * This routine is used to determine if a given device should appear in the 2351 * zone represented by 'handle'. First it consults the list of "standard" 2352 * zone devices. Then it scans the user-supplied device entries. 2353 */ 2354 int 2355 zonecfg_match_dev(zone_dochandle_t handle, char *devpath, 2356 struct zone_devtab *out_match) 2357 { 2358 int err; 2359 boolean_t found = B_FALSE; 2360 char match[MAXPATHLEN]; 2361 const char **stdmatch; 2362 xmlNodePtr cur; 2363 2364 if (handle == NULL || devpath == NULL) 2365 return (Z_INVAL); 2366 2367 /* 2368 * Check the "standard" devices which we require to be present. 2369 */ 2370 for (stdmatch = &standard_devs[0]; *stdmatch != NULL; stdmatch++) { 2371 /* 2372 * fnmatch gives us simple but powerful shell-style matching. 2373 */ 2374 if (fnmatch(*stdmatch, devpath, FNM_PATHNAME) == 0) { 2375 if (!out_match) 2376 return (Z_OK); 2377 (void) snprintf(out_match->zone_dev_match, 2378 sizeof (out_match->zone_dev_match), 2379 "/dev/%s", *stdmatch); 2380 return (Z_OK); 2381 } 2382 } 2383 2384 /* 2385 * We got no hits in the set of standard devices. On to the user 2386 * supplied ones. 2387 */ 2388 if ((err = operation_prep(handle)) != Z_OK) { 2389 handle->zone_dh_cur = NULL; 2390 return (err); 2391 } 2392 2393 cur = handle->zone_dh_cur; 2394 cur = cur->xmlChildrenNode; 2395 if (cur == NULL) 2396 return (Z_NO_ENTRY); 2397 handle->zone_dh_cur = cur; 2398 2399 for (; cur != NULL; cur = cur->next) { 2400 char *m; 2401 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE) != 0) 2402 continue; 2403 if ((err = fetchprop(cur, DTD_ATTR_MATCH, match, 2404 sizeof (match))) != Z_OK) { 2405 handle->zone_dh_cur = handle->zone_dh_top; 2406 return (err); 2407 } 2408 m = match; 2409 /* 2410 * fnmatch gives us simple but powerful shell-style matching; 2411 * but first, we need to strip out /dev/ from the matching rule. 2412 */ 2413 if (strncmp(m, "/dev/", 5) == 0) 2414 m += 5; 2415 2416 if (fnmatch(m, devpath, FNM_PATHNAME) == 0) { 2417 found = B_TRUE; 2418 break; 2419 } 2420 } 2421 2422 if (!found) 2423 return (Z_NO_ENTRY); 2424 2425 if (!out_match) 2426 return (Z_OK); 2427 2428 (void) strlcpy(out_match->zone_dev_match, match, 2429 sizeof (out_match->zone_dev_match)); 2430 return (Z_OK); 2431 } 2432 2433 int 2434 zonecfg_lookup_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2435 { 2436 xmlNodePtr cur, firstmatch; 2437 int err; 2438 char name[MAXNAMELEN], type[MAXNAMELEN], value[MAXNAMELEN]; 2439 2440 if (tabptr == NULL) 2441 return (Z_INVAL); 2442 2443 if ((err = operation_prep(handle)) != Z_OK) 2444 return (err); 2445 2446 cur = handle->zone_dh_cur; 2447 firstmatch = NULL; 2448 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2449 if (xmlStrcmp(cur->name, DTD_ELEM_ATTR)) 2450 continue; 2451 if (strlen(tabptr->zone_attr_name) > 0) { 2452 if ((fetchprop(cur, DTD_ATTR_NAME, name, 2453 sizeof (name)) == Z_OK) && 2454 (strcmp(tabptr->zone_attr_name, name) == 0)) { 2455 if (firstmatch == NULL) 2456 firstmatch = cur; 2457 else 2458 return (Z_INSUFFICIENT_SPEC); 2459 } 2460 } 2461 if (strlen(tabptr->zone_attr_type) > 0) { 2462 if ((fetchprop(cur, DTD_ATTR_TYPE, type, 2463 sizeof (type)) == Z_OK)) { 2464 if (strcmp(tabptr->zone_attr_type, type) == 0) { 2465 if (firstmatch == NULL) 2466 firstmatch = cur; 2467 else if (firstmatch != cur) 2468 return (Z_INSUFFICIENT_SPEC); 2469 } else { 2470 /* 2471 * If another property matched but this 2472 * one doesn't then reset firstmatch. 2473 */ 2474 if (firstmatch == cur) 2475 firstmatch = NULL; 2476 } 2477 } 2478 } 2479 if (strlen(tabptr->zone_attr_value) > 0) { 2480 if ((fetchprop(cur, DTD_ATTR_VALUE, value, 2481 sizeof (value)) == Z_OK)) { 2482 if (strcmp(tabptr->zone_attr_value, value) == 2483 0) { 2484 if (firstmatch == NULL) 2485 firstmatch = cur; 2486 else if (firstmatch != cur) 2487 return (Z_INSUFFICIENT_SPEC); 2488 } else { 2489 /* 2490 * If another property matched but this 2491 * one doesn't then reset firstmatch. 2492 */ 2493 if (firstmatch == cur) 2494 firstmatch = NULL; 2495 } 2496 } 2497 } 2498 } 2499 if (firstmatch == NULL) 2500 return (Z_NO_RESOURCE_ID); 2501 2502 cur = firstmatch; 2503 2504 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name, 2505 sizeof (tabptr->zone_attr_name))) != Z_OK) 2506 return (err); 2507 2508 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type, 2509 sizeof (tabptr->zone_attr_type))) != Z_OK) 2510 return (err); 2511 2512 if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value, 2513 sizeof (tabptr->zone_attr_value))) != Z_OK) 2514 return (err); 2515 2516 return (Z_OK); 2517 } 2518 2519 static int 2520 zonecfg_add_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2521 { 2522 xmlNodePtr newnode, cur = handle->zone_dh_cur; 2523 int err; 2524 2525 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ATTR, NULL); 2526 err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_attr_name); 2527 if (err != Z_OK) 2528 return (err); 2529 err = newprop(newnode, DTD_ATTR_TYPE, tabptr->zone_attr_type); 2530 if (err != Z_OK) 2531 return (err); 2532 err = newprop(newnode, DTD_ATTR_VALUE, tabptr->zone_attr_value); 2533 if (err != Z_OK) 2534 return (err); 2535 return (Z_OK); 2536 } 2537 2538 int 2539 zonecfg_add_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2540 { 2541 int err; 2542 2543 if (tabptr == NULL) 2544 return (Z_INVAL); 2545 2546 if ((err = operation_prep(handle)) != Z_OK) 2547 return (err); 2548 2549 if ((err = zonecfg_add_attr_core(handle, tabptr)) != Z_OK) 2550 return (err); 2551 2552 return (Z_OK); 2553 } 2554 2555 static int 2556 zonecfg_delete_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2557 { 2558 xmlNodePtr cur = handle->zone_dh_cur; 2559 int name_match, type_match, value_match; 2560 2561 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2562 if (xmlStrcmp(cur->name, DTD_ELEM_ATTR)) 2563 continue; 2564 2565 name_match = match_prop(cur, DTD_ATTR_NAME, 2566 tabptr->zone_attr_name); 2567 type_match = match_prop(cur, DTD_ATTR_TYPE, 2568 tabptr->zone_attr_type); 2569 value_match = match_prop(cur, DTD_ATTR_VALUE, 2570 tabptr->zone_attr_value); 2571 2572 if (name_match && type_match && value_match) { 2573 xmlUnlinkNode(cur); 2574 xmlFreeNode(cur); 2575 return (Z_OK); 2576 } 2577 } 2578 return (Z_NO_RESOURCE_ID); 2579 } 2580 2581 int 2582 zonecfg_delete_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2583 { 2584 int err; 2585 2586 if (tabptr == NULL) 2587 return (Z_INVAL); 2588 2589 if ((err = operation_prep(handle)) != Z_OK) 2590 return (err); 2591 2592 if ((err = zonecfg_delete_attr_core(handle, tabptr)) != Z_OK) 2593 return (err); 2594 2595 return (Z_OK); 2596 } 2597 2598 int 2599 zonecfg_modify_attr( 2600 zone_dochandle_t handle, 2601 struct zone_attrtab *oldtabptr, 2602 struct zone_attrtab *newtabptr) 2603 { 2604 int err; 2605 2606 if (oldtabptr == NULL || newtabptr == NULL) 2607 return (Z_INVAL); 2608 2609 if ((err = operation_prep(handle)) != Z_OK) 2610 return (err); 2611 2612 if ((err = zonecfg_delete_attr_core(handle, oldtabptr)) != Z_OK) 2613 return (err); 2614 2615 if ((err = zonecfg_add_attr_core(handle, newtabptr)) != Z_OK) 2616 return (err); 2617 2618 return (Z_OK); 2619 } 2620 2621 int 2622 zonecfg_get_attr_boolean(const struct zone_attrtab *attr, boolean_t *value) 2623 { 2624 if (attr == NULL) 2625 return (Z_INVAL); 2626 2627 if (strcmp(attr->zone_attr_type, DTD_ENTITY_BOOLEAN) != 0) 2628 return (Z_INVAL); 2629 2630 if (strcmp(attr->zone_attr_value, DTD_ENTITY_TRUE) == 0) { 2631 *value = B_TRUE; 2632 return (Z_OK); 2633 } 2634 if (strcmp(attr->zone_attr_value, DTD_ENTITY_FALSE) == 0) { 2635 *value = B_FALSE; 2636 return (Z_OK); 2637 } 2638 return (Z_INVAL); 2639 } 2640 2641 int 2642 zonecfg_get_attr_int(const struct zone_attrtab *attr, int64_t *value) 2643 { 2644 long long result; 2645 char *endptr; 2646 2647 if (attr == NULL) 2648 return (Z_INVAL); 2649 2650 if (strcmp(attr->zone_attr_type, DTD_ENTITY_INT) != 0) 2651 return (Z_INVAL); 2652 2653 errno = 0; 2654 result = strtoll(attr->zone_attr_value, &endptr, 10); 2655 if (errno != 0 || *endptr != '\0') 2656 return (Z_INVAL); 2657 *value = result; 2658 return (Z_OK); 2659 } 2660 2661 int 2662 zonecfg_get_attr_string(const struct zone_attrtab *attr, char *value, 2663 size_t val_sz) 2664 { 2665 if (attr == NULL) 2666 return (Z_INVAL); 2667 2668 if (strcmp(attr->zone_attr_type, DTD_ENTITY_STRING) != 0) 2669 return (Z_INVAL); 2670 2671 if (strlcpy(value, attr->zone_attr_value, val_sz) >= val_sz) 2672 return (Z_TOO_BIG); 2673 return (Z_OK); 2674 } 2675 2676 int 2677 zonecfg_get_attr_uint(const struct zone_attrtab *attr, uint64_t *value) 2678 { 2679 unsigned long long result; 2680 long long neg_result; 2681 char *endptr; 2682 2683 if (attr == NULL) 2684 return (Z_INVAL); 2685 2686 if (strcmp(attr->zone_attr_type, DTD_ENTITY_UINT) != 0) 2687 return (Z_INVAL); 2688 2689 errno = 0; 2690 result = strtoull(attr->zone_attr_value, &endptr, 10); 2691 if (errno != 0 || *endptr != '\0') 2692 return (Z_INVAL); 2693 errno = 0; 2694 neg_result = strtoll(attr->zone_attr_value, &endptr, 10); 2695 /* 2696 * Incredibly, strtoull("<negative number>", ...) will not fail but 2697 * return whatever (negative) number cast as a u_longlong_t, so we 2698 * need to look for this here. 2699 */ 2700 if (errno == 0 && neg_result < 0) 2701 return (Z_INVAL); 2702 *value = result; 2703 return (Z_OK); 2704 } 2705 2706 int 2707 zonecfg_lookup_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2708 { 2709 xmlNodePtr cur, val; 2710 char savedname[MAXNAMELEN]; 2711 struct zone_rctlvaltab *valptr; 2712 int err; 2713 2714 if (tabptr->zone_rctl_name == NULL || 2715 strlen(tabptr->zone_rctl_name) == 0) 2716 return (Z_INVAL); 2717 2718 if ((err = operation_prep(handle)) != Z_OK) 2719 return (err); 2720 2721 cur = handle->zone_dh_cur; 2722 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2723 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 2724 continue; 2725 if ((fetchprop(cur, DTD_ATTR_NAME, savedname, 2726 sizeof (savedname)) == Z_OK) && 2727 (strcmp(savedname, tabptr->zone_rctl_name) == 0)) { 2728 tabptr->zone_rctl_valptr = NULL; 2729 for (val = cur->xmlChildrenNode; val != NULL; 2730 val = val->next) { 2731 valptr = (struct zone_rctlvaltab *)malloc( 2732 sizeof (struct zone_rctlvaltab)); 2733 if (valptr == NULL) 2734 return (Z_NOMEM); 2735 if ((fetchprop(val, DTD_ATTR_PRIV, 2736 valptr->zone_rctlval_priv, 2737 sizeof (valptr->zone_rctlval_priv)) != 2738 Z_OK)) 2739 break; 2740 if ((fetchprop(val, DTD_ATTR_LIMIT, 2741 valptr->zone_rctlval_limit, 2742 sizeof (valptr->zone_rctlval_limit)) != 2743 Z_OK)) 2744 break; 2745 if ((fetchprop(val, DTD_ATTR_ACTION, 2746 valptr->zone_rctlval_action, 2747 sizeof (valptr->zone_rctlval_action)) != 2748 Z_OK)) 2749 break; 2750 if (zonecfg_add_rctl_value(tabptr, valptr) != 2751 Z_OK) 2752 break; 2753 } 2754 return (Z_OK); 2755 } 2756 } 2757 return (Z_NO_RESOURCE_ID); 2758 } 2759 2760 static int 2761 zonecfg_add_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2762 { 2763 xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode; 2764 struct zone_rctlvaltab *valptr; 2765 int err; 2766 2767 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_RCTL, NULL); 2768 err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_rctl_name); 2769 if (err != Z_OK) 2770 return (err); 2771 for (valptr = tabptr->zone_rctl_valptr; valptr != NULL; 2772 valptr = valptr->zone_rctlval_next) { 2773 valnode = xmlNewTextChild(newnode, NULL, 2774 DTD_ELEM_RCTLVALUE, NULL); 2775 err = newprop(valnode, DTD_ATTR_PRIV, 2776 valptr->zone_rctlval_priv); 2777 if (err != Z_OK) 2778 return (err); 2779 err = newprop(valnode, DTD_ATTR_LIMIT, 2780 valptr->zone_rctlval_limit); 2781 if (err != Z_OK) 2782 return (err); 2783 err = newprop(valnode, DTD_ATTR_ACTION, 2784 valptr->zone_rctlval_action); 2785 if (err != Z_OK) 2786 return (err); 2787 } 2788 return (Z_OK); 2789 } 2790 2791 int 2792 zonecfg_add_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2793 { 2794 int err; 2795 2796 if (tabptr == NULL || tabptr->zone_rctl_name == NULL) 2797 return (Z_INVAL); 2798 2799 if ((err = operation_prep(handle)) != Z_OK) 2800 return (err); 2801 2802 if ((err = zonecfg_add_rctl_core(handle, tabptr)) != Z_OK) 2803 return (err); 2804 2805 return (Z_OK); 2806 } 2807 2808 static int 2809 zonecfg_delete_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2810 { 2811 xmlNodePtr cur = handle->zone_dh_cur; 2812 xmlChar *savedname; 2813 int name_result; 2814 2815 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2816 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 2817 continue; 2818 2819 savedname = xmlGetProp(cur, DTD_ATTR_NAME); 2820 if (savedname == NULL) /* shouldn't happen */ 2821 continue; 2822 name_result = xmlStrcmp(savedname, 2823 (const xmlChar *) tabptr->zone_rctl_name); 2824 xmlFree(savedname); 2825 2826 if (name_result == 0) { 2827 xmlUnlinkNode(cur); 2828 xmlFreeNode(cur); 2829 return (Z_OK); 2830 } 2831 } 2832 return (Z_NO_RESOURCE_ID); 2833 } 2834 2835 int 2836 zonecfg_delete_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2837 { 2838 int err; 2839 2840 if (tabptr == NULL || tabptr->zone_rctl_name == NULL) 2841 return (Z_INVAL); 2842 2843 if ((err = operation_prep(handle)) != Z_OK) 2844 return (err); 2845 2846 if ((err = zonecfg_delete_rctl_core(handle, tabptr)) != Z_OK) 2847 return (err); 2848 2849 return (Z_OK); 2850 } 2851 2852 int 2853 zonecfg_modify_rctl( 2854 zone_dochandle_t handle, 2855 struct zone_rctltab *oldtabptr, 2856 struct zone_rctltab *newtabptr) 2857 { 2858 int err; 2859 2860 if (oldtabptr == NULL || oldtabptr->zone_rctl_name == NULL || 2861 newtabptr == NULL || newtabptr->zone_rctl_name == NULL) 2862 return (Z_INVAL); 2863 2864 if ((err = operation_prep(handle)) != Z_OK) 2865 return (err); 2866 2867 if ((err = zonecfg_delete_rctl_core(handle, oldtabptr)) != Z_OK) 2868 return (err); 2869 2870 if ((err = zonecfg_add_rctl_core(handle, newtabptr)) != Z_OK) 2871 return (err); 2872 2873 return (Z_OK); 2874 } 2875 2876 int 2877 zonecfg_add_rctl_value( 2878 struct zone_rctltab *tabptr, 2879 struct zone_rctlvaltab *valtabptr) 2880 { 2881 struct zone_rctlvaltab *last, *old, *new; 2882 rctlblk_t *rctlblk = alloca(rctlblk_size()); 2883 2884 last = tabptr->zone_rctl_valptr; 2885 for (old = last; old != NULL; old = old->zone_rctlval_next) 2886 last = old; /* walk to the end of the list */ 2887 new = valtabptr; /* alloc'd by caller */ 2888 new->zone_rctlval_next = NULL; 2889 if (zonecfg_construct_rctlblk(valtabptr, rctlblk) != Z_OK) 2890 return (Z_INVAL); 2891 if (!zonecfg_valid_rctlblk(rctlblk)) 2892 return (Z_INVAL); 2893 if (last == NULL) 2894 tabptr->zone_rctl_valptr = new; 2895 else 2896 last->zone_rctlval_next = new; 2897 return (Z_OK); 2898 } 2899 2900 int 2901 zonecfg_remove_rctl_value( 2902 struct zone_rctltab *tabptr, 2903 struct zone_rctlvaltab *valtabptr) 2904 { 2905 struct zone_rctlvaltab *last, *this, *next; 2906 2907 last = tabptr->zone_rctl_valptr; 2908 for (this = last; this != NULL; this = this->zone_rctlval_next) { 2909 if (strcmp(this->zone_rctlval_priv, 2910 valtabptr->zone_rctlval_priv) == 0 && 2911 strcmp(this->zone_rctlval_limit, 2912 valtabptr->zone_rctlval_limit) == 0 && 2913 strcmp(this->zone_rctlval_action, 2914 valtabptr->zone_rctlval_action) == 0) { 2915 next = this->zone_rctlval_next; 2916 if (this == tabptr->zone_rctl_valptr) 2917 tabptr->zone_rctl_valptr = next; 2918 else 2919 last->zone_rctlval_next = next; 2920 free(this); 2921 return (Z_OK); 2922 } else 2923 last = this; 2924 } 2925 return (Z_NO_PROPERTY_ID); 2926 } 2927 2928 char * 2929 zonecfg_strerror(int errnum) 2930 { 2931 switch (errnum) { 2932 case Z_OK: 2933 return (dgettext(TEXT_DOMAIN, "OK")); 2934 case Z_EMPTY_DOCUMENT: 2935 return (dgettext(TEXT_DOMAIN, "Empty document")); 2936 case Z_WRONG_DOC_TYPE: 2937 return (dgettext(TEXT_DOMAIN, "Wrong document type")); 2938 case Z_BAD_PROPERTY: 2939 return (dgettext(TEXT_DOMAIN, "Bad document property")); 2940 case Z_TEMP_FILE: 2941 return (dgettext(TEXT_DOMAIN, 2942 "Problem creating temporary file")); 2943 case Z_SAVING_FILE: 2944 return (dgettext(TEXT_DOMAIN, "Problem saving file")); 2945 case Z_NO_ENTRY: 2946 return (dgettext(TEXT_DOMAIN, "No such entry")); 2947 case Z_BOGUS_ZONE_NAME: 2948 return (dgettext(TEXT_DOMAIN, "Bogus zone name")); 2949 case Z_REQD_RESOURCE_MISSING: 2950 return (dgettext(TEXT_DOMAIN, "Required resource missing")); 2951 case Z_REQD_PROPERTY_MISSING: 2952 return (dgettext(TEXT_DOMAIN, "Required property missing")); 2953 case Z_BAD_HANDLE: 2954 return (dgettext(TEXT_DOMAIN, "Bad handle")); 2955 case Z_NOMEM: 2956 return (dgettext(TEXT_DOMAIN, "Out of memory")); 2957 case Z_INVAL: 2958 return (dgettext(TEXT_DOMAIN, "Invalid argument")); 2959 case Z_ACCES: 2960 return (dgettext(TEXT_DOMAIN, "Permission denied")); 2961 case Z_TOO_BIG: 2962 return (dgettext(TEXT_DOMAIN, "Argument list too long")); 2963 case Z_MISC_FS: 2964 return (dgettext(TEXT_DOMAIN, 2965 "Miscellaneous file system error")); 2966 case Z_NO_ZONE: 2967 return (dgettext(TEXT_DOMAIN, "No such zone configured")); 2968 case Z_NO_RESOURCE_TYPE: 2969 return (dgettext(TEXT_DOMAIN, "No such resource type")); 2970 case Z_NO_RESOURCE_ID: 2971 return (dgettext(TEXT_DOMAIN, "No such resource with that id")); 2972 case Z_NO_PROPERTY_TYPE: 2973 return (dgettext(TEXT_DOMAIN, "No such property type")); 2974 case Z_NO_PROPERTY_ID: 2975 return (dgettext(TEXT_DOMAIN, "No such property with that id")); 2976 case Z_BAD_ZONE_STATE: 2977 return (dgettext(TEXT_DOMAIN, 2978 "Zone state is invalid for the requested operation")); 2979 case Z_INVALID_DOCUMENT: 2980 return (dgettext(TEXT_DOMAIN, "Invalid document")); 2981 case Z_NAME_IN_USE: 2982 return (dgettext(TEXT_DOMAIN, "Zone name already in use")); 2983 case Z_NO_SUCH_ID: 2984 return (dgettext(TEXT_DOMAIN, "No such zone ID")); 2985 case Z_UPDATING_INDEX: 2986 return (dgettext(TEXT_DOMAIN, "Problem updating index file")); 2987 case Z_LOCKING_FILE: 2988 return (dgettext(TEXT_DOMAIN, "Locking index file")); 2989 case Z_UNLOCKING_FILE: 2990 return (dgettext(TEXT_DOMAIN, "Unlocking index file")); 2991 case Z_INSUFFICIENT_SPEC: 2992 return (dgettext(TEXT_DOMAIN, "Insufficient specification")); 2993 case Z_RESOLVED_PATH: 2994 return (dgettext(TEXT_DOMAIN, "Resolved path mismatch")); 2995 case Z_IPV6_ADDR_PREFIX_LEN: 2996 return (dgettext(TEXT_DOMAIN, 2997 "IPv6 address missing required prefix length")); 2998 case Z_BOGUS_ADDRESS: 2999 return (dgettext(TEXT_DOMAIN, 3000 "Neither an IPv4 nor an IPv6 address nor a host name")); 3001 case Z_PRIV_PROHIBITED: 3002 return (dgettext(TEXT_DOMAIN, 3003 "Specified privilege is prohibited")); 3004 case Z_PRIV_REQUIRED: 3005 return (dgettext(TEXT_DOMAIN, 3006 "Required privilege is missing")); 3007 case Z_PRIV_UNKNOWN: 3008 return (dgettext(TEXT_DOMAIN, 3009 "Specified privilege is unknown")); 3010 default: 3011 return (dgettext(TEXT_DOMAIN, "Unknown error")); 3012 } 3013 } 3014 3015 /* 3016 * Note that the zonecfg_setXent() and zonecfg_endXent() calls are all the 3017 * same, as they just turn around and call zonecfg_setent() / zonecfg_endent(). 3018 */ 3019 3020 static int 3021 zonecfg_setent(zone_dochandle_t handle) 3022 { 3023 xmlNodePtr cur; 3024 int err; 3025 3026 if (handle == NULL) 3027 return (Z_INVAL); 3028 3029 if ((err = operation_prep(handle)) != Z_OK) { 3030 handle->zone_dh_cur = NULL; 3031 return (err); 3032 } 3033 cur = handle->zone_dh_cur; 3034 cur = cur->xmlChildrenNode; 3035 handle->zone_dh_cur = cur; 3036 return (Z_OK); 3037 } 3038 3039 static int 3040 zonecfg_endent(zone_dochandle_t handle) 3041 { 3042 if (handle == NULL) 3043 return (Z_INVAL); 3044 3045 handle->zone_dh_cur = handle->zone_dh_top; 3046 return (Z_OK); 3047 } 3048 3049 int 3050 zonecfg_setfsent(zone_dochandle_t handle) 3051 { 3052 return (zonecfg_setent(handle)); 3053 } 3054 3055 int 3056 zonecfg_getfsent(zone_dochandle_t handle, struct zone_fstab *tabptr) 3057 { 3058 xmlNodePtr cur, options; 3059 char options_str[MAX_MNTOPT_STR]; 3060 int err; 3061 3062 if (handle == NULL) 3063 return (Z_INVAL); 3064 3065 if ((cur = handle->zone_dh_cur) == NULL) 3066 return (Z_NO_ENTRY); 3067 3068 for (; cur != NULL; cur = cur->next) 3069 if (!xmlStrcmp(cur->name, DTD_ELEM_FS)) 3070 break; 3071 if (cur == NULL) { 3072 handle->zone_dh_cur = handle->zone_dh_top; 3073 return (Z_NO_ENTRY); 3074 } 3075 3076 if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special, 3077 sizeof (tabptr->zone_fs_special))) != Z_OK) { 3078 handle->zone_dh_cur = handle->zone_dh_top; 3079 return (err); 3080 } 3081 3082 if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw, 3083 sizeof (tabptr->zone_fs_raw))) != Z_OK) { 3084 handle->zone_dh_cur = handle->zone_dh_top; 3085 return (err); 3086 } 3087 3088 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 3089 sizeof (tabptr->zone_fs_dir))) != Z_OK) { 3090 handle->zone_dh_cur = handle->zone_dh_top; 3091 return (err); 3092 } 3093 3094 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type, 3095 sizeof (tabptr->zone_fs_type))) != Z_OK) { 3096 handle->zone_dh_cur = handle->zone_dh_top; 3097 return (err); 3098 } 3099 3100 /* OK for options to be NULL */ 3101 tabptr->zone_fs_options = NULL; 3102 for (options = cur->xmlChildrenNode; options != NULL; 3103 options = options->next) { 3104 if (fetchprop(options, DTD_ATTR_NAME, options_str, 3105 sizeof (options_str)) != Z_OK) 3106 break; 3107 if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK) 3108 break; 3109 } 3110 3111 handle->zone_dh_cur = cur->next; 3112 return (Z_OK); 3113 } 3114 3115 int 3116 zonecfg_endfsent(zone_dochandle_t handle) 3117 { 3118 return (zonecfg_endent(handle)); 3119 } 3120 3121 int 3122 zonecfg_setipdent(zone_dochandle_t handle) 3123 { 3124 return (zonecfg_setent(handle)); 3125 } 3126 3127 int 3128 zonecfg_getipdent(zone_dochandle_t handle, struct zone_fstab *tabptr) 3129 { 3130 xmlNodePtr cur; 3131 int err; 3132 3133 if (handle == NULL) 3134 return (Z_INVAL); 3135 3136 if ((cur = handle->zone_dh_cur) == NULL) 3137 return (Z_NO_ENTRY); 3138 3139 for (; cur != NULL; cur = cur->next) 3140 if (!xmlStrcmp(cur->name, DTD_ELEM_IPD)) 3141 break; 3142 if (cur == NULL) { 3143 handle->zone_dh_cur = handle->zone_dh_top; 3144 return (Z_NO_ENTRY); 3145 } 3146 3147 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 3148 sizeof (tabptr->zone_fs_dir))) != Z_OK) { 3149 handle->zone_dh_cur = handle->zone_dh_top; 3150 return (err); 3151 } 3152 3153 handle->zone_dh_cur = cur->next; 3154 return (Z_OK); 3155 } 3156 3157 int 3158 zonecfg_endipdent(zone_dochandle_t handle) 3159 { 3160 return (zonecfg_endent(handle)); 3161 } 3162 3163 int 3164 zonecfg_setnwifent(zone_dochandle_t handle) 3165 { 3166 return (zonecfg_setent(handle)); 3167 } 3168 3169 int 3170 zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 3171 { 3172 xmlNodePtr cur; 3173 int err; 3174 3175 if (handle == NULL) 3176 return (Z_INVAL); 3177 3178 if ((cur = handle->zone_dh_cur) == NULL) 3179 return (Z_NO_ENTRY); 3180 3181 for (; cur != NULL; cur = cur->next) 3182 if (!xmlStrcmp(cur->name, DTD_ELEM_NET)) 3183 break; 3184 if (cur == NULL) { 3185 handle->zone_dh_cur = handle->zone_dh_top; 3186 return (Z_NO_ENTRY); 3187 } 3188 3189 if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address, 3190 sizeof (tabptr->zone_nwif_address))) != Z_OK) { 3191 handle->zone_dh_cur = handle->zone_dh_top; 3192 return (err); 3193 } 3194 3195 if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical, 3196 sizeof (tabptr->zone_nwif_physical))) != Z_OK) { 3197 handle->zone_dh_cur = handle->zone_dh_top; 3198 return (err); 3199 } 3200 3201 handle->zone_dh_cur = cur->next; 3202 return (Z_OK); 3203 } 3204 3205 int 3206 zonecfg_endnwifent(zone_dochandle_t handle) 3207 { 3208 return (zonecfg_endent(handle)); 3209 } 3210 3211 int 3212 zonecfg_setdevent(zone_dochandle_t handle) 3213 { 3214 return (zonecfg_setent(handle)); 3215 } 3216 3217 int 3218 zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr) 3219 { 3220 xmlNodePtr cur; 3221 int err; 3222 3223 if (handle == NULL) 3224 return (Z_INVAL); 3225 3226 if ((cur = handle->zone_dh_cur) == NULL) 3227 return (Z_NO_ENTRY); 3228 3229 for (; cur != NULL; cur = cur->next) 3230 if (!xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) 3231 break; 3232 if (cur == NULL) { 3233 handle->zone_dh_cur = handle->zone_dh_top; 3234 return (Z_NO_ENTRY); 3235 } 3236 3237 if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match, 3238 sizeof (tabptr->zone_dev_match))) != Z_OK) { 3239 handle->zone_dh_cur = handle->zone_dh_top; 3240 return (err); 3241 } 3242 3243 handle->zone_dh_cur = cur->next; 3244 return (Z_OK); 3245 } 3246 3247 int 3248 zonecfg_enddevent(zone_dochandle_t handle) 3249 { 3250 return (zonecfg_endent(handle)); 3251 } 3252 3253 int 3254 zonecfg_setrctlent(zone_dochandle_t handle) 3255 { 3256 return (zonecfg_setent(handle)); 3257 } 3258 3259 int 3260 zonecfg_getrctlent(zone_dochandle_t handle, struct zone_rctltab *tabptr) 3261 { 3262 xmlNodePtr cur, val; 3263 struct zone_rctlvaltab *valptr; 3264 int err; 3265 3266 if (handle == NULL) 3267 return (Z_INVAL); 3268 3269 if ((cur = handle->zone_dh_cur) == NULL) 3270 return (Z_NO_ENTRY); 3271 3272 for (; cur != NULL; cur = cur->next) 3273 if (!xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 3274 break; 3275 if (cur == NULL) { 3276 handle->zone_dh_cur = handle->zone_dh_top; 3277 return (Z_NO_ENTRY); 3278 } 3279 3280 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_rctl_name, 3281 sizeof (tabptr->zone_rctl_name))) != Z_OK) { 3282 handle->zone_dh_cur = handle->zone_dh_top; 3283 return (err); 3284 } 3285 3286 tabptr->zone_rctl_valptr = NULL; 3287 for (val = cur->xmlChildrenNode; val != NULL; val = val->next) { 3288 valptr = (struct zone_rctlvaltab *)malloc( 3289 sizeof (struct zone_rctlvaltab)); 3290 if (valptr == NULL) 3291 return (Z_NOMEM); 3292 if (fetchprop(val, DTD_ATTR_PRIV, valptr->zone_rctlval_priv, 3293 sizeof (valptr->zone_rctlval_priv)) != Z_OK) 3294 break; 3295 if (fetchprop(val, DTD_ATTR_LIMIT, valptr->zone_rctlval_limit, 3296 sizeof (valptr->zone_rctlval_limit)) != Z_OK) 3297 break; 3298 if (fetchprop(val, DTD_ATTR_ACTION, valptr->zone_rctlval_action, 3299 sizeof (valptr->zone_rctlval_action)) != Z_OK) 3300 break; 3301 if (zonecfg_add_rctl_value(tabptr, valptr) != Z_OK) 3302 break; 3303 } 3304 3305 handle->zone_dh_cur = cur->next; 3306 return (Z_OK); 3307 } 3308 3309 int 3310 zonecfg_endrctlent(zone_dochandle_t handle) 3311 { 3312 return (zonecfg_endent(handle)); 3313 } 3314 3315 int 3316 zonecfg_setattrent(zone_dochandle_t handle) 3317 { 3318 return (zonecfg_setent(handle)); 3319 } 3320 3321 int 3322 zonecfg_getattrent(zone_dochandle_t handle, struct zone_attrtab *tabptr) 3323 { 3324 xmlNodePtr cur; 3325 int err; 3326 3327 if (handle == NULL) 3328 return (Z_INVAL); 3329 3330 if ((cur = handle->zone_dh_cur) == NULL) 3331 return (Z_NO_ENTRY); 3332 3333 for (; cur != NULL; cur = cur->next) 3334 if (!xmlStrcmp(cur->name, DTD_ELEM_ATTR)) 3335 break; 3336 if (cur == NULL) { 3337 handle->zone_dh_cur = handle->zone_dh_top; 3338 return (Z_NO_ENTRY); 3339 } 3340 3341 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name, 3342 sizeof (tabptr->zone_attr_name))) != Z_OK) { 3343 handle->zone_dh_cur = handle->zone_dh_top; 3344 return (err); 3345 } 3346 3347 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type, 3348 sizeof (tabptr->zone_attr_type))) != Z_OK) { 3349 handle->zone_dh_cur = handle->zone_dh_top; 3350 return (err); 3351 } 3352 3353 if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value, 3354 sizeof (tabptr->zone_attr_value))) != Z_OK) { 3355 handle->zone_dh_cur = handle->zone_dh_top; 3356 return (err); 3357 } 3358 3359 handle->zone_dh_cur = cur->next; 3360 return (Z_OK); 3361 } 3362 3363 int 3364 zonecfg_endattrent(zone_dochandle_t handle) 3365 { 3366 return (zonecfg_endent(handle)); 3367 } 3368 3369 /* 3370 * The privileges available on the system and described in privileges(5) 3371 * fall into four categories with respect to non-global zones; those that 3372 * are required in order for a non-global zone to boot, those which are in 3373 * the default set of privileges available to non-global zones, those 3374 * privileges which should not be allowed to be given to non-global zones 3375 * and all other privileges, which are optional and potentially useful for 3376 * processes executing inside a non-global zone. 3377 * 3378 * When privileges are added to the system, a determination needs to be 3379 * made as to which category the privilege belongs to. Ideally, 3380 * privileges should be fine-grained enough and the mechanisms they cover 3381 * virtualized enough so that they can be made available to non-global 3382 * zones. 3383 */ 3384 3385 /* 3386 * Set of privileges required in order to get a zone booted and init(1M) 3387 * started. These cannot be removed from the zone's privilege set. 3388 */ 3389 static const char *required_priv_list[] = { 3390 PRIV_PROC_EXEC, 3391 PRIV_PROC_FORK, 3392 PRIV_SYS_MOUNT, 3393 NULL 3394 }; 3395 3396 /* 3397 * Default set of privileges considered safe for all non-global zones. 3398 * These privileges are "safe" in the sense that a privileged process in 3399 * the zone cannot affect processes in other non-global zones on the 3400 * system or in the global zone. Privileges which are considered by 3401 * default, "unsafe", include ones which affect a global resource, such as 3402 * the system clock or physical memory. 3403 */ 3404 static const char *default_priv_list[] = { 3405 PRIV_CONTRACT_EVENT, 3406 PRIV_CONTRACT_OBSERVER, 3407 PRIV_FILE_CHOWN, 3408 PRIV_FILE_CHOWN_SELF, 3409 PRIV_FILE_DAC_EXECUTE, 3410 PRIV_FILE_DAC_READ, 3411 PRIV_FILE_DAC_SEARCH, 3412 PRIV_FILE_DAC_WRITE, 3413 PRIV_FILE_OWNER, 3414 PRIV_FILE_SETID, 3415 PRIV_IPC_DAC_READ, 3416 PRIV_IPC_DAC_WRITE, 3417 PRIV_IPC_OWNER, 3418 PRIV_NET_BINDMLP, 3419 PRIV_NET_ICMPACCESS, 3420 PRIV_NET_MAC_AWARE, 3421 PRIV_NET_PRIVADDR, 3422 PRIV_PROC_CHROOT, 3423 PRIV_SYS_AUDIT, 3424 PRIV_PROC_AUDIT, 3425 PRIV_PROC_OWNER, 3426 PRIV_PROC_SETID, 3427 PRIV_PROC_TASKID, 3428 PRIV_SYS_ACCT, 3429 PRIV_SYS_ADMIN, 3430 PRIV_SYS_MOUNT, 3431 PRIV_SYS_NFS, 3432 PRIV_SYS_RESOURCE, 3433 NULL 3434 }; 3435 3436 /* 3437 * Set of privileges not currently permitted within a non-global zone. 3438 * Some of these privileges are overly broad and cover more than one 3439 * mechanism in the system. In other cases, there has not been sufficient 3440 * virtualization in the parts of the system the privilege covers to allow 3441 * its use within a non-global zone. 3442 */ 3443 static const char *prohibited_priv_list[] = { 3444 PRIV_DTRACE_KERNEL, 3445 PRIV_PROC_ZONE, 3446 PRIV_SYS_CONFIG, 3447 PRIV_SYS_DEVICES, 3448 PRIV_SYS_LINKDIR, 3449 PRIV_SYS_NET_CONFIG, 3450 PRIV_SYS_RES_CONFIG, 3451 PRIV_SYS_SUSER_COMPAT, 3452 NULL 3453 }; 3454 3455 /* 3456 * Define some of the tokens that priv_str_to_set(3C) recognizes. Since 3457 * the privilege string separator can be any character, although it is 3458 * usually a comma character, define these here as well in the event that 3459 * they change or are augmented in the future. 3460 */ 3461 #define BASIC_TOKEN "basic" 3462 #define DEFAULT_TOKEN "default" 3463 #define ZONE_TOKEN "zone" 3464 #define TOKEN_PRIV_CHAR ',' 3465 #define TOKEN_PRIV_STR "," 3466 3467 int 3468 zonecfg_default_privset(priv_set_t *privs) 3469 { 3470 const char **strp; 3471 priv_set_t *basic; 3472 3473 basic = priv_str_to_set(BASIC_TOKEN, TOKEN_PRIV_STR, NULL); 3474 if (basic == NULL) 3475 return (errno == ENOMEM ? Z_NOMEM : Z_INVAL); 3476 3477 priv_union(basic, privs); 3478 priv_freeset(basic); 3479 3480 for (strp = default_priv_list; *strp != NULL; strp++) { 3481 if (priv_addset(privs, *strp) != 0) { 3482 return (Z_INVAL); 3483 } 3484 } 3485 return (Z_OK); 3486 } 3487 3488 void 3489 append_priv_token(char *priv, char *str, size_t strlen) 3490 { 3491 if (*str != '\0') 3492 (void) strlcat(str, TOKEN_PRIV_STR, strlen); 3493 (void) strlcat(str, priv, strlen); 3494 } 3495 3496 /* 3497 * Verify that the supplied string is a valid privilege limit set for a 3498 * non-global zone. This string must not only be acceptable to 3499 * priv_str_to_set(3C) which parses it, but it also must resolve to a 3500 * privilege set that includes certain required privileges and lacks 3501 * certain prohibited privileges. 3502 */ 3503 static int 3504 verify_privset(char *privbuf, priv_set_t *privs, char **privname, 3505 boolean_t add_default) 3506 { 3507 char *cp; 3508 char *lasts; 3509 size_t len; 3510 priv_set_t *mergeset; 3511 const char **strp; 3512 char *tmp; 3513 const char *token; 3514 3515 /* 3516 * The verification of the privilege string occurs in several 3517 * phases. In the first phase, the supplied string is scanned for 3518 * the ZONE_TOKEN token which is not support as part of the 3519 * "limitpriv" property. 3520 * 3521 * Duplicate the supplied privilege string since strtok_r(3C) 3522 * tokenizes its input by null-terminating the tokens. 3523 */ 3524 if ((tmp = strdup(privbuf)) == NULL) 3525 return (Z_NOMEM); 3526 for (cp = strtok_r(tmp, TOKEN_PRIV_STR, &lasts); cp != NULL; 3527 cp = strtok_r(NULL, TOKEN_PRIV_STR, &lasts)) { 3528 if (strcmp(cp, ZONE_TOKEN) == 0) { 3529 free(tmp); 3530 if ((*privname = strdup(ZONE_TOKEN)) == NULL) 3531 return (Z_NOMEM); 3532 else 3533 return (Z_PRIV_UNKNOWN); 3534 } 3535 } 3536 free(tmp); 3537 3538 if (add_default) { 3539 /* 3540 * If DEFAULT_TOKEN was specified, a string needs to be 3541 * built containing the privileges from the default, safe 3542 * set along with those of the "limitpriv" property. 3543 */ 3544 len = strlen(privbuf) + sizeof (BASIC_TOKEN) + 2; 3545 for (strp = default_priv_list; *strp != NULL; strp++) 3546 len += strlen(*strp) + 1; 3547 tmp = alloca(len); 3548 *tmp = '\0'; 3549 3550 append_priv_token(BASIC_TOKEN, tmp, len); 3551 for (strp = default_priv_list; *strp != NULL; strp++) 3552 append_priv_token((char *)*strp, tmp, len); 3553 (void) strlcat(tmp, TOKEN_PRIV_STR, len); 3554 (void) strlcat(tmp, privbuf, len); 3555 } else { 3556 tmp = privbuf; 3557 } 3558 3559 3560 /* 3561 * In the next phase, attempt to convert the merged privilege 3562 * string into a privilege set. In the case of an error, either 3563 * there was a memory allocation failure or there was an invalid 3564 * privilege token in the string. In either case, return an 3565 * appropriate error code but in the event of an invalid token, 3566 * allocate a string containing its name and return that back to 3567 * the caller. 3568 */ 3569 mergeset = priv_str_to_set(tmp, TOKEN_PRIV_STR, &token); 3570 if (mergeset == NULL) { 3571 if (token == NULL) 3572 return (Z_NOMEM); 3573 if ((cp = strchr(token, TOKEN_PRIV_CHAR)) != NULL) 3574 *cp = '\0'; 3575 if ((*privname = strdup(token)) == NULL) 3576 return (Z_NOMEM); 3577 else 3578 return (Z_PRIV_UNKNOWN); 3579 } 3580 3581 /* 3582 * Next, verify that none of the prohibited zone privileges are 3583 * present in the merged privilege set. 3584 */ 3585 for (strp = prohibited_priv_list; *strp != NULL; strp++) { 3586 if (priv_ismember(mergeset, *strp)) { 3587 priv_freeset(mergeset); 3588 if ((*privname = strdup(*strp)) == NULL) 3589 return (Z_NOMEM); 3590 else 3591 return (Z_PRIV_PROHIBITED); 3592 } 3593 } 3594 3595 /* 3596 * Finally, verify that all of the required zone privileges are 3597 * present in the merged privilege set. 3598 */ 3599 for (strp = required_priv_list; *strp != NULL; strp++) { 3600 if (!priv_ismember(mergeset, *strp)) { 3601 priv_freeset(mergeset); 3602 if ((*privname = strdup(*strp)) == NULL) 3603 return (Z_NOMEM); 3604 else 3605 return (Z_PRIV_REQUIRED); 3606 } 3607 } 3608 3609 priv_copyset(mergeset, privs); 3610 priv_freeset(mergeset); 3611 return (Z_OK); 3612 } 3613 3614 /* 3615 * Fill in the supplied privilege set with either the default, safe set of 3616 * privileges suitable for a non-global zone, or one based on the 3617 * "limitpriv" property in the zone's configuration. 3618 * 3619 * In the event of an invalid privilege specification in the 3620 * configuration, a string is allocated and returned containing the 3621 * "privilege" causing the issue. It is the caller's responsibility to 3622 * free this memory when it is done with it. 3623 */ 3624 int 3625 zonecfg_get_privset(zone_dochandle_t handle, priv_set_t *privs, 3626 char **privname) 3627 { 3628 char *cp; 3629 int err; 3630 int limitlen; 3631 char *limitpriv = NULL; 3632 3633 /* 3634 * Attempt to lookup the "limitpriv" property. If it does not 3635 * exist or matches the string DEFAULT_TOKEN exactly, then the 3636 * default, safe privilege set is returned. 3637 */ 3638 err = zonecfg_get_limitpriv(handle, &limitpriv); 3639 if (err != Z_OK) 3640 return (err); 3641 limitlen = strlen(limitpriv); 3642 if (limitlen == 0 || strcmp(limitpriv, DEFAULT_TOKEN) == 0) { 3643 free(limitpriv); 3644 return (zonecfg_default_privset(privs)); 3645 } 3646 3647 /* 3648 * Check if the string DEFAULT_TOKEN is the first token in a list 3649 * of privileges. 3650 */ 3651 cp = strchr(limitpriv, TOKEN_PRIV_CHAR); 3652 if (cp != NULL && 3653 strncmp(limitpriv, DEFAULT_TOKEN, cp - limitpriv) == 0) 3654 err = verify_privset(cp + 1, privs, privname, B_TRUE); 3655 else 3656 err = verify_privset(limitpriv, privs, privname, B_FALSE); 3657 3658 free(limitpriv); 3659 return (err); 3660 } 3661 3662 int 3663 zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz) 3664 { 3665 zone_dochandle_t handle; 3666 boolean_t found = B_FALSE; 3667 struct zoneent *ze; 3668 FILE *cookie; 3669 int err; 3670 char *cp; 3671 3672 if (zone_name == NULL) 3673 return (Z_INVAL); 3674 3675 (void) strlcpy(zonepath, zonecfg_root, rp_sz); 3676 cp = zonepath + strlen(zonepath); 3677 while (cp > zonepath && cp[-1] == '/') 3678 *--cp = '\0'; 3679 3680 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) { 3681 if (zonepath[0] == '\0') 3682 (void) strlcpy(zonepath, "/", rp_sz); 3683 return (Z_OK); 3684 } 3685 3686 /* 3687 * First check the index file. Because older versions did not have 3688 * a copy of the zone path, allow for it to be zero length, in which 3689 * case we ignore this result and fall back to the XML files. 3690 */ 3691 cookie = setzoneent(); 3692 while ((ze = getzoneent_private(cookie)) != NULL) { 3693 if (strcmp(ze->zone_name, zone_name) == 0) { 3694 found = B_TRUE; 3695 if (ze->zone_path[0] != '\0') 3696 (void) strlcpy(cp, ze->zone_path, 3697 rp_sz - (cp - zonepath)); 3698 } 3699 free(ze); 3700 if (found) 3701 break; 3702 } 3703 endzoneent(cookie); 3704 if (found && *cp != '\0') 3705 return (Z_OK); 3706 3707 /* Fall back to the XML files. */ 3708 if ((handle = zonecfg_init_handle()) == NULL) 3709 return (Z_NOMEM); 3710 3711 /* 3712 * Check the snapshot first: if a zone is running, its zonepath 3713 * may have changed. 3714 */ 3715 if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) { 3716 if ((err = zonecfg_get_handle(zone_name, handle)) != Z_OK) 3717 return (err); 3718 } 3719 err = zonecfg_get_zonepath(handle, zonepath, rp_sz); 3720 zonecfg_fini_handle(handle); 3721 return (err); 3722 } 3723 3724 int 3725 zone_get_rootpath(char *zone_name, char *rootpath, size_t rp_sz) 3726 { 3727 int err; 3728 3729 /* This function makes sense for non-global zones only. */ 3730 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) 3731 return (Z_BOGUS_ZONE_NAME); 3732 if ((err = zone_get_zonepath(zone_name, rootpath, rp_sz)) != Z_OK) 3733 return (err); 3734 if (strlcat(rootpath, "/root", rp_sz) >= rp_sz) 3735 return (Z_TOO_BIG); 3736 return (Z_OK); 3737 } 3738 3739 static zone_state_t 3740 kernel_state_to_user_state(zoneid_t zoneid, zone_status_t kernel_state) 3741 { 3742 char zoneroot[MAXPATHLEN]; 3743 size_t zlen; 3744 3745 assert(kernel_state <= ZONE_MAX_STATE); 3746 switch (kernel_state) { 3747 case ZONE_IS_UNINITIALIZED: 3748 return (ZONE_STATE_READY); 3749 case ZONE_IS_READY: 3750 /* 3751 * If the zone's root is mounted on $ZONEPATH/lu, then 3752 * it's a mounted scratch zone. 3753 */ 3754 if (zone_getattr(zoneid, ZONE_ATTR_ROOT, zoneroot, 3755 sizeof (zoneroot)) >= 0) { 3756 zlen = strlen(zoneroot); 3757 if (zlen > 3 && 3758 strcmp(zoneroot + zlen - 3, "/lu") == 0) 3759 return (ZONE_STATE_MOUNTED); 3760 } 3761 return (ZONE_STATE_READY); 3762 case ZONE_IS_BOOTING: 3763 case ZONE_IS_RUNNING: 3764 return (ZONE_STATE_RUNNING); 3765 case ZONE_IS_SHUTTING_DOWN: 3766 case ZONE_IS_EMPTY: 3767 return (ZONE_STATE_SHUTTING_DOWN); 3768 case ZONE_IS_DOWN: 3769 case ZONE_IS_DYING: 3770 case ZONE_IS_DEAD: 3771 default: 3772 return (ZONE_STATE_DOWN); 3773 } 3774 /* NOTREACHED */ 3775 } 3776 3777 int 3778 zone_get_state(char *zone_name, zone_state_t *state_num) 3779 { 3780 zone_status_t status; 3781 zoneid_t zone_id; 3782 struct zoneent *ze; 3783 boolean_t found = B_FALSE; 3784 FILE *cookie; 3785 char kernzone[ZONENAME_MAX]; 3786 FILE *fp; 3787 3788 if (zone_name == NULL) 3789 return (Z_INVAL); 3790 3791 /* 3792 * If we're looking at an alternate root, then we need to query the 3793 * kernel using the scratch zone name. 3794 */ 3795 zone_id = -1; 3796 if (*zonecfg_root != '\0' && !zonecfg_is_scratch(zone_name)) { 3797 if ((fp = zonecfg_open_scratch("", B_FALSE)) != NULL) { 3798 if (zonecfg_find_scratch(fp, zone_name, zonecfg_root, 3799 kernzone, sizeof (kernzone)) == 0) 3800 zone_id = getzoneidbyname(kernzone); 3801 zonecfg_close_scratch(fp); 3802 } 3803 } else { 3804 zone_id = getzoneidbyname(zone_name); 3805 } 3806 3807 /* check to see if zone is running */ 3808 if (zone_id != -1 && 3809 zone_getattr(zone_id, ZONE_ATTR_STATUS, &status, 3810 sizeof (status)) >= 0) { 3811 *state_num = kernel_state_to_user_state(zone_id, status); 3812 return (Z_OK); 3813 } 3814 3815 cookie = setzoneent(); 3816 while ((ze = getzoneent_private(cookie)) != NULL) { 3817 if (strcmp(ze->zone_name, zone_name) == 0) { 3818 found = B_TRUE; 3819 *state_num = ze->zone_state; 3820 } 3821 free(ze); 3822 if (found) 3823 break; 3824 } 3825 endzoneent(cookie); 3826 return ((found) ? Z_OK : Z_NO_ZONE); 3827 } 3828 3829 int 3830 zone_set_state(char *zone, zone_state_t state) 3831 { 3832 struct zoneent ze; 3833 3834 if (state != ZONE_STATE_CONFIGURED && state != ZONE_STATE_INSTALLED && 3835 state != ZONE_STATE_INCOMPLETE) 3836 return (Z_INVAL); 3837 3838 bzero(&ze, sizeof (ze)); 3839 (void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name)); 3840 ze.zone_state = state; 3841 (void) strlcpy(ze.zone_path, "", sizeof (ze.zone_path)); 3842 return (putzoneent(&ze, PZE_MODIFY)); 3843 } 3844 3845 /* 3846 * Get id (if any) for specified zone. There are four possible outcomes: 3847 * - If the string corresponds to the numeric id of an active (booted) 3848 * zone, sets *zip to the zone id and returns 0. 3849 * - If the string corresponds to the name of an active (booted) zone, 3850 * sets *zip to the zone id and returns 0. 3851 * - If the string is a name in the configuration but is not booted, 3852 * sets *zip to ZONE_ID_UNDEFINED and returns 0. 3853 * - Otherwise, leaves *zip unchanged and returns -1. 3854 * 3855 * This function acts as an auxiliary filter on the function of the same 3856 * name in libc; the linker binds to this version if libzonecfg exists, 3857 * and the libc version if it doesn't. Any changes to this version of 3858 * the function should probably be reflected in the libc version as well. 3859 */ 3860 int 3861 zone_get_id(const char *str, zoneid_t *zip) 3862 { 3863 zone_dochandle_t hdl; 3864 zoneid_t zoneid; 3865 char *cp; 3866 int err; 3867 3868 /* first try looking for active zone by id */ 3869 errno = 0; 3870 zoneid = (zoneid_t)strtol(str, &cp, 0); 3871 if (errno == 0 && cp != str && *cp == '\0' && 3872 getzonenamebyid(zoneid, NULL, 0) != -1) { 3873 *zip = zoneid; 3874 return (0); 3875 } 3876 3877 /* then look for active zone by name */ 3878 if ((zoneid = getzoneidbyname(str)) != -1) { 3879 *zip = zoneid; 3880 return (0); 3881 } 3882 3883 /* if in global zone, try looking up name in configuration database */ 3884 if (getzoneid() != GLOBAL_ZONEID || 3885 (hdl = zonecfg_init_handle()) == NULL) 3886 return (-1); 3887 3888 if (zonecfg_get_handle(str, hdl) == Z_OK) { 3889 /* zone exists but isn't active */ 3890 *zip = ZONE_ID_UNDEFINED; 3891 err = 0; 3892 } else { 3893 err = -1; 3894 } 3895 3896 zonecfg_fini_handle(hdl); 3897 return (err); 3898 } 3899 3900 char * 3901 zone_state_str(zone_state_t state_num) 3902 { 3903 switch (state_num) { 3904 case ZONE_STATE_CONFIGURED: 3905 return (ZONE_STATE_STR_CONFIGURED); 3906 case ZONE_STATE_INCOMPLETE: 3907 return (ZONE_STATE_STR_INCOMPLETE); 3908 case ZONE_STATE_INSTALLED: 3909 return (ZONE_STATE_STR_INSTALLED); 3910 case ZONE_STATE_READY: 3911 return (ZONE_STATE_STR_READY); 3912 case ZONE_STATE_MOUNTED: 3913 return (ZONE_STATE_STR_MOUNTED); 3914 case ZONE_STATE_RUNNING: 3915 return (ZONE_STATE_STR_RUNNING); 3916 case ZONE_STATE_SHUTTING_DOWN: 3917 return (ZONE_STATE_STR_SHUTTING_DOWN); 3918 case ZONE_STATE_DOWN: 3919 return (ZONE_STATE_STR_DOWN); 3920 default: 3921 return ("unknown"); 3922 } 3923 } 3924 3925 /* 3926 * Given a UUID value, find an associated zone name. This is intended to be 3927 * used by callers who set up some 'default' name (corresponding to the 3928 * expected name for the zone) in the zonename buffer, and thus the function 3929 * doesn't touch this buffer on failure. 3930 */ 3931 int 3932 zonecfg_get_name_by_uuid(const uuid_t uuid, char *zonename, size_t namelen) 3933 { 3934 FILE *fp; 3935 struct zoneent *ze; 3936 3937 /* 3938 * A small amount of subterfuge via casts is necessary here because 3939 * libuuid doesn't use const correctly, but we don't want to export 3940 * this brokenness to our clients. 3941 */ 3942 if (uuid_is_null(*(uuid_t *)&uuid)) 3943 return (Z_NO_ZONE); 3944 if ((fp = setzoneent()) == NULL) 3945 return (Z_NO_ZONE); 3946 while ((ze = getzoneent_private(fp)) != NULL) { 3947 if (uuid_compare(*(uuid_t *)&uuid, ze->zone_uuid) == 0) 3948 break; 3949 free(ze); 3950 } 3951 endzoneent(fp); 3952 if (ze != NULL) { 3953 (void) strlcpy(zonename, ze->zone_name, namelen); 3954 free(ze); 3955 return (Z_OK); 3956 } else { 3957 return (Z_NO_ZONE); 3958 } 3959 } 3960 3961 /* 3962 * Given a zone name, get its UUID. Returns a "NULL" UUID value if the zone 3963 * exists but the file doesn't have a value set yet. Returns an error if the 3964 * zone cannot be located. 3965 */ 3966 int 3967 zonecfg_get_uuid(const char *zonename, uuid_t uuid) 3968 { 3969 FILE *fp; 3970 struct zoneent *ze; 3971 3972 if ((fp = setzoneent()) == NULL) 3973 return (Z_NO_ZONE); 3974 while ((ze = getzoneent_private(fp)) != NULL) { 3975 if (strcmp(ze->zone_name, zonename) == 0) 3976 break; 3977 free(ze); 3978 } 3979 endzoneent(fp); 3980 if (ze != NULL) { 3981 uuid_copy(uuid, ze->zone_uuid); 3982 free(ze); 3983 return (Z_OK); 3984 } else { 3985 return (Z_NO_ZONE); 3986 } 3987 } 3988 3989 /* 3990 * File-system convenience functions. 3991 */ 3992 boolean_t 3993 zonecfg_valid_fs_type(const char *type) 3994 { 3995 /* 3996 * We already know which FS types don't work. 3997 */ 3998 if (strcmp(type, "proc") == 0 || 3999 strcmp(type, "mntfs") == 0 || 4000 strcmp(type, "autofs") == 0 || 4001 strncmp(type, "nfs", sizeof ("nfs") - 1) == 0 || 4002 strcmp(type, "cachefs") == 0) 4003 return (B_FALSE); 4004 /* 4005 * The caller may do more detailed verification to make sure other 4006 * aspects of this filesystem type make sense. 4007 */ 4008 return (B_TRUE); 4009 } 4010 4011 /* 4012 * Generally uninteresting rctl convenience functions. 4013 */ 4014 4015 int 4016 zonecfg_construct_rctlblk(const struct zone_rctlvaltab *rctlval, 4017 rctlblk_t *rctlblk) 4018 { 4019 unsigned long long ull; 4020 char *endp; 4021 rctl_priv_t priv; 4022 rctl_qty_t limit; 4023 uint_t action; 4024 4025 /* Get the privilege */ 4026 if (strcmp(rctlval->zone_rctlval_priv, "basic") == 0) { 4027 priv = RCPRIV_BASIC; 4028 } else if (strcmp(rctlval->zone_rctlval_priv, "privileged") == 0) { 4029 priv = RCPRIV_PRIVILEGED; 4030 } else { 4031 /* Invalid privilege */ 4032 return (Z_INVAL); 4033 } 4034 4035 /* deal with negative input; strtoull(3c) doesn't do what we want */ 4036 if (rctlval->zone_rctlval_limit[0] == '-') 4037 return (Z_INVAL); 4038 /* Get the limit */ 4039 errno = 0; 4040 ull = strtoull(rctlval->zone_rctlval_limit, &endp, 0); 4041 if (errno != 0 || *endp != '\0') { 4042 /* parse failed */ 4043 return (Z_INVAL); 4044 } 4045 limit = (rctl_qty_t)ull; 4046 4047 /* Get the action */ 4048 if (strcmp(rctlval->zone_rctlval_action, "none") == 0) { 4049 action = RCTL_LOCAL_NOACTION; 4050 } else if (strcmp(rctlval->zone_rctlval_action, "signal") == 0) { 4051 action = RCTL_LOCAL_SIGNAL; 4052 } else if (strcmp(rctlval->zone_rctlval_action, "deny") == 0) { 4053 action = RCTL_LOCAL_DENY; 4054 } else { 4055 /* Invalid Action */ 4056 return (Z_INVAL); 4057 } 4058 rctlblk_set_local_action(rctlblk, action, 0); 4059 rctlblk_set_privilege(rctlblk, priv); 4060 rctlblk_set_value(rctlblk, limit); 4061 return (Z_OK); 4062 } 4063 4064 static int 4065 rctl_check(const char *rctlname, void *arg) 4066 { 4067 const char *attrname = arg; 4068 4069 /* 4070 * Returning 1 here is our signal to zonecfg_is_rctl() that it is 4071 * indeed an rctl name recognized by the system. 4072 */ 4073 return (strcmp(rctlname, attrname) == 0 ? 1 : 0); 4074 } 4075 4076 boolean_t 4077 zonecfg_is_rctl(const char *name) 4078 { 4079 return (rctl_walk(rctl_check, (void *)name) == 1); 4080 } 4081 4082 boolean_t 4083 zonecfg_valid_rctlname(const char *name) 4084 { 4085 const char *c; 4086 4087 if (strncmp(name, "zone.", sizeof ("zone.") - 1) != 0) 4088 return (B_FALSE); 4089 if (strlen(name) == sizeof ("zone.") - 1) 4090 return (B_FALSE); 4091 for (c = name + sizeof ("zone.") - 1; *c != '\0'; c++) { 4092 if (!isalpha(*c) && *c != '-') 4093 return (B_FALSE); 4094 } 4095 return (B_TRUE); 4096 } 4097 4098 boolean_t 4099 zonecfg_valid_rctlblk(const rctlblk_t *rctlblk) 4100 { 4101 rctl_priv_t priv = rctlblk_get_privilege((rctlblk_t *)rctlblk); 4102 uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL); 4103 4104 if (priv != RCPRIV_PRIVILEGED) 4105 return (B_FALSE); 4106 if (action != RCTL_LOCAL_NOACTION && action != RCTL_LOCAL_DENY) 4107 return (B_FALSE); 4108 return (B_TRUE); 4109 } 4110 4111 boolean_t 4112 zonecfg_valid_rctl(const char *name, const rctlblk_t *rctlblk) 4113 { 4114 rctlblk_t *current, *next; 4115 rctl_qty_t limit = rctlblk_get_value((rctlblk_t *)rctlblk); 4116 uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL); 4117 uint_t global_flags; 4118 4119 if (!zonecfg_valid_rctlblk(rctlblk)) 4120 return (B_FALSE); 4121 if (!zonecfg_valid_rctlname(name)) 4122 return (B_FALSE); 4123 4124 current = alloca(rctlblk_size()); 4125 if (getrctl(name, NULL, current, RCTL_FIRST) != 0) 4126 return (B_TRUE); /* not an rctl on this system */ 4127 /* 4128 * Make sure the proposed value isn't greater than the current system 4129 * value. 4130 */ 4131 next = alloca(rctlblk_size()); 4132 while (rctlblk_get_privilege(current) != RCPRIV_SYSTEM) { 4133 rctlblk_t *tmp; 4134 4135 if (getrctl(name, current, next, RCTL_NEXT) != 0) 4136 return (B_FALSE); /* shouldn't happen */ 4137 tmp = current; 4138 current = next; 4139 next = tmp; 4140 } 4141 if (limit > rctlblk_get_value(current)) 4142 return (B_FALSE); 4143 4144 /* 4145 * Make sure the proposed action is allowed. 4146 */ 4147 global_flags = rctlblk_get_global_flags(current); 4148 if ((global_flags & RCTL_GLOBAL_DENY_NEVER) && 4149 action == RCTL_LOCAL_DENY) 4150 return (B_FALSE); 4151 if ((global_flags & RCTL_GLOBAL_DENY_ALWAYS) && 4152 action == RCTL_LOCAL_NOACTION) 4153 return (B_FALSE); 4154 4155 return (B_TRUE); 4156 } 4157 4158 /* 4159 * There is always a race condition between reading the initial copy of 4160 * a zones state and its state changing. We address this by providing 4161 * zonecfg_notify_critical_enter and zonecfg_noticy_critical_exit functions. 4162 * When zonecfg_critical_enter is called, sets the state field to LOCKED 4163 * and aquires biglock. Biglock protects against other threads executing 4164 * critical_enter and the state field protects against state changes during 4165 * the critical period. 4166 * 4167 * If any state changes occur, zn_cb will set the failed field of the znotify 4168 * structure. This will cause the critical_exit function to re-lock the 4169 * channel and return an error. Since evsnts may be delayed, the critical_exit 4170 * function "flushes" the queue by putting an event on the queue and waiting for 4171 * zn_cb to notify critical_exit that it received the ping event. 4172 */ 4173 static const char * 4174 string_get_tok(const char *in, char delim, int num) 4175 { 4176 int i = 0; 4177 4178 for (; i < num; in++) { 4179 if (*in == delim) 4180 i++; 4181 if (*in == 0) 4182 return (NULL); 4183 } 4184 return (in); 4185 } 4186 4187 static boolean_t 4188 is_ping(sysevent_t *ev) 4189 { 4190 if (strcmp(sysevent_get_subclass_name(ev), 4191 ZONE_EVENT_PING_SUBCLASS) == 0) { 4192 return (B_TRUE); 4193 } else { 4194 return (B_FALSE); 4195 } 4196 } 4197 4198 static boolean_t 4199 is_my_ping(sysevent_t *ev) 4200 { 4201 const char *sender; 4202 char mypid[sizeof (pid_t) * 3 + 1]; 4203 4204 (void) snprintf(mypid, sizeof (mypid), "%i", getpid()); 4205 sender = string_get_tok(sysevent_get_pub(ev), ':', 3); 4206 if (sender == NULL) 4207 return (B_FALSE); 4208 if (strcmp(sender, mypid) != 0) 4209 return (B_FALSE); 4210 return (B_TRUE); 4211 } 4212 4213 static int 4214 do_callback(struct znotify *zevtchan, sysevent_t *ev) 4215 { 4216 nvlist_t *l; 4217 int zid; 4218 char *zonename; 4219 char *newstate; 4220 char *oldstate; 4221 int ret; 4222 hrtime_t when; 4223 4224 if (strcmp(sysevent_get_subclass_name(ev), 4225 ZONE_EVENT_STATUS_SUBCLASS) == 0) { 4226 4227 if (sysevent_get_attr_list(ev, &l) != 0) { 4228 if (errno == ENOMEM) { 4229 zevtchan->zn_failure_count++; 4230 return (EAGAIN); 4231 } 4232 return (0); 4233 } 4234 ret = 0; 4235 4236 if ((nvlist_lookup_string(l, ZONE_CB_NAME, &zonename) == 0) && 4237 (nvlist_lookup_string(l, ZONE_CB_NEWSTATE, &newstate) 4238 == 0) && 4239 (nvlist_lookup_string(l, ZONE_CB_OLDSTATE, &oldstate) 4240 == 0) && 4241 (nvlist_lookup_uint64(l, ZONE_CB_TIMESTAMP, 4242 (uint64_t *)&when) == 0) && 4243 (nvlist_lookup_int32(l, ZONE_CB_ZONEID, &zid) == 0)) { 4244 ret = zevtchan->zn_callback(zonename, zid, newstate, 4245 oldstate, when, zevtchan->zn_private); 4246 } 4247 4248 zevtchan->zn_failure_count = 0; 4249 nvlist_free(l); 4250 return (ret); 4251 } else { 4252 /* 4253 * We have received an event in an unknown subclass. Ignore. 4254 */ 4255 zevtchan->zn_failure_count = 0; 4256 return (0); 4257 } 4258 } 4259 4260 static int 4261 zn_cb(sysevent_t *ev, void *p) 4262 { 4263 struct znotify *zevtchan = p; 4264 int error; 4265 4266 (void) pthread_mutex_lock(&(zevtchan->zn_mutex)); 4267 4268 if (is_ping(ev) && !is_my_ping(ev)) { 4269 (void) pthread_mutex_unlock((&zevtchan->zn_mutex)); 4270 return (0); 4271 } 4272 4273 if (zevtchan->zn_state == ZN_LOCKED) { 4274 assert(!is_ping(ev)); 4275 zevtchan->zn_failed = B_TRUE; 4276 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4277 return (0); 4278 } 4279 4280 if (zevtchan->zn_state == ZN_PING_INFLIGHT) { 4281 if (is_ping(ev)) { 4282 zevtchan->zn_state = ZN_PING_RECEIVED; 4283 (void) pthread_cond_signal(&(zevtchan->zn_cond)); 4284 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4285 return (0); 4286 } else { 4287 zevtchan->zn_failed = B_TRUE; 4288 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4289 return (0); 4290 } 4291 } 4292 4293 if (zevtchan->zn_state == ZN_UNLOCKED) { 4294 4295 error = do_callback(zevtchan, ev); 4296 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4297 /* 4298 * Every ENOMEM failure causes do_callback to increment 4299 * zn_failure_count and every success causes it to 4300 * set zn_failure_count to zero. If we got EAGAIN, 4301 * we will sleep for zn_failure_count seconds and return 4302 * EAGAIN to gpec to try again. 4303 * 4304 * After 55 seconds, or 10 try's we give up and drop the 4305 * event. 4306 */ 4307 if (error == EAGAIN) { 4308 if (zevtchan->zn_failure_count > ZONE_CB_RETRY_COUNT) { 4309 return (0); 4310 } 4311 (void) sleep(zevtchan->zn_failure_count); 4312 } 4313 return (error); 4314 } 4315 4316 if (zevtchan->zn_state == ZN_PING_RECEIVED) { 4317 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4318 return (0); 4319 } 4320 4321 abort(); 4322 return (0); 4323 } 4324 4325 void 4326 zonecfg_notify_critical_enter(void *h) 4327 { 4328 struct znotify *zevtchan = h; 4329 4330 (void) pthread_mutex_lock(&(zevtchan->zn_bigmutex)); 4331 zevtchan->zn_state = ZN_LOCKED; 4332 } 4333 4334 int 4335 zonecfg_notify_critical_exit(void * h) 4336 { 4337 4338 struct znotify *zevtchan = h; 4339 4340 if (zevtchan->zn_state == ZN_UNLOCKED) 4341 return (0); 4342 4343 (void) pthread_mutex_lock(&(zevtchan->zn_mutex)); 4344 zevtchan->zn_state = ZN_PING_INFLIGHT; 4345 4346 (void) sysevent_evc_publish(zevtchan->zn_eventchan, 4347 ZONE_EVENT_STATUS_CLASS, 4348 ZONE_EVENT_PING_SUBCLASS, ZONE_EVENT_PING_PUBLISHER, 4349 zevtchan->zn_subscriber_id, NULL, EVCH_SLEEP); 4350 4351 while (zevtchan->zn_state != ZN_PING_RECEIVED) { 4352 (void) pthread_cond_wait(&(zevtchan->zn_cond), 4353 &(zevtchan->zn_mutex)); 4354 } 4355 4356 if (zevtchan->zn_failed == B_TRUE) { 4357 zevtchan->zn_state = ZN_LOCKED; 4358 zevtchan->zn_failed = B_FALSE; 4359 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4360 return (1); 4361 } 4362 4363 zevtchan->zn_state = ZN_UNLOCKED; 4364 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4365 (void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex)); 4366 return (0); 4367 } 4368 4369 void 4370 zonecfg_notify_critical_abort(void *h) 4371 { 4372 struct znotify *zevtchan = h; 4373 4374 zevtchan->zn_state = ZN_UNLOCKED; 4375 zevtchan->zn_failed = B_FALSE; 4376 /* 4377 * Don't do anything about zn_lock. If it is held, it could only be 4378 * held by zn_cb and it will be unlocked soon. 4379 */ 4380 (void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex)); 4381 } 4382 4383 void * 4384 zonecfg_notify_bind(int(*func)(const char *zonename, zoneid_t zid, 4385 const char *newstate, const char *oldstate, hrtime_t when, void *p), 4386 void *p) 4387 { 4388 struct znotify *zevtchan; 4389 int i = 1; 4390 int r; 4391 4392 zevtchan = malloc(sizeof (struct znotify)); 4393 4394 if (zevtchan == NULL) 4395 return (NULL); 4396 4397 zevtchan->zn_private = p; 4398 zevtchan->zn_callback = func; 4399 zevtchan->zn_state = ZN_UNLOCKED; 4400 zevtchan->zn_failed = B_FALSE; 4401 4402 if (pthread_mutex_init(&(zevtchan->zn_mutex), NULL)) 4403 goto out3; 4404 if (pthread_cond_init(&(zevtchan->zn_cond), NULL)) { 4405 (void) pthread_mutex_destroy(&(zevtchan->zn_mutex)); 4406 goto out3; 4407 } 4408 if (pthread_mutex_init(&(zevtchan->zn_bigmutex), NULL)) { 4409 (void) pthread_mutex_destroy(&(zevtchan->zn_mutex)); 4410 (void) pthread_cond_destroy(&(zevtchan->zn_cond)); 4411 goto out3; 4412 } 4413 4414 if (sysevent_evc_bind(ZONE_EVENT_CHANNEL, &(zevtchan->zn_eventchan), 4415 0) != 0) 4416 goto out2; 4417 4418 do { 4419 /* 4420 * At 4 digits the subscriber ID gets too long and we have 4421 * no chance of successfully registering. 4422 */ 4423 if (i > 999) 4424 goto out1; 4425 4426 (void) sprintf(zevtchan->zn_subscriber_id, "zone_%li_%i", 4427 getpid() % 999999l, i); 4428 4429 r = sysevent_evc_subscribe(zevtchan->zn_eventchan, 4430 zevtchan->zn_subscriber_id, ZONE_EVENT_STATUS_CLASS, zn_cb, 4431 zevtchan, 0); 4432 4433 i++; 4434 4435 } while (r); 4436 4437 return (zevtchan); 4438 out1: 4439 sysevent_evc_unbind(zevtchan->zn_eventchan); 4440 out2: 4441 (void) pthread_mutex_destroy(&zevtchan->zn_mutex); 4442 (void) pthread_cond_destroy(&zevtchan->zn_cond); 4443 (void) pthread_mutex_destroy(&(zevtchan->zn_bigmutex)); 4444 out3: 4445 free(zevtchan); 4446 4447 return (NULL); 4448 } 4449 4450 void 4451 zonecfg_notify_unbind(void *handle) 4452 { 4453 4454 int ret; 4455 4456 sysevent_evc_unbind(((struct znotify *)handle)->zn_eventchan); 4457 /* 4458 * Check that all evc threads have gone away. This should be 4459 * enforced by sysevent_evc_unbind. 4460 */ 4461 ret = pthread_mutex_trylock(&((struct znotify *)handle)->zn_mutex); 4462 4463 if (ret) 4464 abort(); 4465 4466 (void) pthread_mutex_unlock(&((struct znotify *)handle)->zn_mutex); 4467 (void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_mutex); 4468 (void) pthread_cond_destroy(&((struct znotify *)handle)->zn_cond); 4469 (void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_bigmutex); 4470 4471 free(handle); 4472 } 4473 4474 static int 4475 zonecfg_add_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr) 4476 { 4477 xmlNodePtr newnode, cur = handle->zone_dh_cur; 4478 int err; 4479 4480 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DATASET, NULL); 4481 if ((err = newprop(newnode, DTD_ATTR_NAME, 4482 tabptr->zone_dataset_name)) != Z_OK) 4483 return (err); 4484 return (Z_OK); 4485 } 4486 4487 int 4488 zonecfg_add_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 4489 { 4490 int err; 4491 4492 if (tabptr == NULL) 4493 return (Z_INVAL); 4494 4495 if ((err = operation_prep(handle)) != Z_OK) 4496 return (err); 4497 4498 if ((err = zonecfg_add_ds_core(handle, tabptr)) != Z_OK) 4499 return (err); 4500 4501 return (Z_OK); 4502 } 4503 4504 static int 4505 zonecfg_delete_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr) 4506 { 4507 xmlNodePtr cur = handle->zone_dh_cur; 4508 4509 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 4510 if (xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 4511 continue; 4512 4513 if (match_prop(cur, DTD_ATTR_NAME, 4514 tabptr->zone_dataset_name)) { 4515 xmlUnlinkNode(cur); 4516 xmlFreeNode(cur); 4517 return (Z_OK); 4518 } 4519 } 4520 return (Z_NO_RESOURCE_ID); 4521 } 4522 4523 int 4524 zonecfg_delete_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 4525 { 4526 int err; 4527 4528 if (tabptr == NULL) 4529 return (Z_INVAL); 4530 4531 if ((err = operation_prep(handle)) != Z_OK) 4532 return (err); 4533 4534 if ((err = zonecfg_delete_ds_core(handle, tabptr)) != Z_OK) 4535 return (err); 4536 4537 return (Z_OK); 4538 } 4539 4540 int 4541 zonecfg_modify_ds( 4542 zone_dochandle_t handle, 4543 struct zone_dstab *oldtabptr, 4544 struct zone_dstab *newtabptr) 4545 { 4546 int err; 4547 4548 if (oldtabptr == NULL || newtabptr == NULL) 4549 return (Z_INVAL); 4550 4551 if ((err = operation_prep(handle)) != Z_OK) 4552 return (err); 4553 4554 if ((err = zonecfg_delete_ds_core(handle, oldtabptr)) != Z_OK) 4555 return (err); 4556 4557 if ((err = zonecfg_add_ds_core(handle, newtabptr)) != Z_OK) 4558 return (err); 4559 4560 return (Z_OK); 4561 } 4562 4563 int 4564 zonecfg_lookup_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 4565 { 4566 xmlNodePtr cur, firstmatch; 4567 int err; 4568 char dataset[MAXNAMELEN]; 4569 4570 if (tabptr == NULL) 4571 return (Z_INVAL); 4572 4573 if ((err = operation_prep(handle)) != Z_OK) 4574 return (err); 4575 4576 cur = handle->zone_dh_cur; 4577 firstmatch = NULL; 4578 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 4579 if (xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 4580 continue; 4581 if (strlen(tabptr->zone_dataset_name) > 0) { 4582 if ((fetchprop(cur, DTD_ATTR_NAME, dataset, 4583 sizeof (dataset)) == Z_OK) && 4584 (strcmp(tabptr->zone_dataset_name, 4585 dataset) == 0)) { 4586 if (firstmatch == NULL) 4587 firstmatch = cur; 4588 else 4589 return (Z_INSUFFICIENT_SPEC); 4590 } 4591 } 4592 } 4593 if (firstmatch == NULL) 4594 return (Z_NO_RESOURCE_ID); 4595 4596 cur = firstmatch; 4597 4598 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name, 4599 sizeof (tabptr->zone_dataset_name))) != Z_OK) 4600 return (err); 4601 4602 return (Z_OK); 4603 } 4604 4605 int 4606 zonecfg_setdsent(zone_dochandle_t handle) 4607 { 4608 return (zonecfg_setent(handle)); 4609 } 4610 4611 int 4612 zonecfg_getdsent(zone_dochandle_t handle, struct zone_dstab *tabptr) 4613 { 4614 xmlNodePtr cur; 4615 int err; 4616 4617 if (handle == NULL) 4618 return (Z_INVAL); 4619 4620 if ((cur = handle->zone_dh_cur) == NULL) 4621 return (Z_NO_ENTRY); 4622 4623 for (; cur != NULL; cur = cur->next) 4624 if (!xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 4625 break; 4626 if (cur == NULL) { 4627 handle->zone_dh_cur = handle->zone_dh_top; 4628 return (Z_NO_ENTRY); 4629 } 4630 4631 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name, 4632 sizeof (tabptr->zone_dataset_name))) != Z_OK) { 4633 handle->zone_dh_cur = handle->zone_dh_top; 4634 return (err); 4635 } 4636 4637 handle->zone_dh_cur = cur->next; 4638 return (Z_OK); 4639 } 4640 4641 int 4642 zonecfg_enddsent(zone_dochandle_t handle) 4643 { 4644 return (zonecfg_endent(handle)); 4645 } 4646 4647 int 4648 zonecfg_setpkgent(zone_dochandle_t handle) 4649 { 4650 return (zonecfg_setent(handle)); 4651 } 4652 4653 int 4654 zonecfg_getpkgent(zone_dochandle_t handle, struct zone_pkgtab *tabptr) 4655 { 4656 xmlNodePtr cur; 4657 int err; 4658 4659 if (handle == NULL) 4660 return (Z_INVAL); 4661 4662 if ((cur = handle->zone_dh_cur) == NULL) 4663 return (Z_NO_ENTRY); 4664 4665 for (; cur != NULL; cur = cur->next) 4666 if (!xmlStrcmp(cur->name, DTD_ELEM_PACKAGE)) 4667 break; 4668 if (cur == NULL) { 4669 handle->zone_dh_cur = handle->zone_dh_top; 4670 return (Z_NO_ENTRY); 4671 } 4672 4673 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_pkg_name, 4674 sizeof (tabptr->zone_pkg_name))) != Z_OK) { 4675 handle->zone_dh_cur = handle->zone_dh_top; 4676 return (err); 4677 } 4678 4679 if ((err = fetchprop(cur, DTD_ATTR_VERSION, tabptr->zone_pkg_version, 4680 sizeof (tabptr->zone_pkg_version))) != Z_OK) { 4681 handle->zone_dh_cur = handle->zone_dh_top; 4682 return (err); 4683 } 4684 4685 handle->zone_dh_cur = cur->next; 4686 return (Z_OK); 4687 } 4688 4689 int 4690 zonecfg_endpkgent(zone_dochandle_t handle) 4691 { 4692 return (zonecfg_endent(handle)); 4693 } 4694 4695 int 4696 zonecfg_setpatchent(zone_dochandle_t handle) 4697 { 4698 return (zonecfg_setent(handle)); 4699 } 4700 4701 int 4702 zonecfg_getpatchent(zone_dochandle_t handle, struct zone_patchtab *tabptr) 4703 { 4704 xmlNodePtr cur; 4705 int err; 4706 4707 if (handle == NULL) 4708 return (Z_INVAL); 4709 4710 if ((cur = handle->zone_dh_cur) == NULL) 4711 return (Z_NO_ENTRY); 4712 4713 for (; cur != NULL; cur = cur->next) 4714 if (!xmlStrcmp(cur->name, DTD_ELEM_PATCH)) 4715 break; 4716 if (cur == NULL) { 4717 handle->zone_dh_cur = handle->zone_dh_top; 4718 return (Z_NO_ENTRY); 4719 } 4720 4721 if ((err = fetchprop(cur, DTD_ATTR_ID, tabptr->zone_patch_id, 4722 sizeof (tabptr->zone_patch_id))) != Z_OK) { 4723 handle->zone_dh_cur = handle->zone_dh_top; 4724 return (err); 4725 } 4726 4727 handle->zone_dh_cur = cur->next; 4728 return (Z_OK); 4729 } 4730 4731 int 4732 zonecfg_endpatchent(zone_dochandle_t handle) 4733 { 4734 return (zonecfg_endent(handle)); 4735 } 4736 4737 int 4738 zonecfg_setdevperment(zone_dochandle_t handle) 4739 { 4740 return (zonecfg_setent(handle)); 4741 } 4742 4743 int 4744 zonecfg_getdevperment(zone_dochandle_t handle, struct zone_devpermtab *tabptr) 4745 { 4746 xmlNodePtr cur; 4747 int err; 4748 char buf[128]; 4749 4750 tabptr->zone_devperm_acl = NULL; 4751 4752 if (handle == NULL) 4753 return (Z_INVAL); 4754 4755 if ((cur = handle->zone_dh_cur) == NULL) 4756 return (Z_NO_ENTRY); 4757 4758 for (; cur != NULL; cur = cur->next) 4759 if (!xmlStrcmp(cur->name, DTD_ELEM_DEV_PERM)) 4760 break; 4761 if (cur == NULL) { 4762 handle->zone_dh_cur = handle->zone_dh_top; 4763 return (Z_NO_ENTRY); 4764 } 4765 4766 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_devperm_name, 4767 sizeof (tabptr->zone_devperm_name))) != Z_OK) { 4768 handle->zone_dh_cur = handle->zone_dh_top; 4769 return (err); 4770 } 4771 4772 if ((err = fetchprop(cur, DTD_ATTR_UID, buf, sizeof (buf))) != Z_OK) { 4773 handle->zone_dh_cur = handle->zone_dh_top; 4774 return (err); 4775 } 4776 tabptr->zone_devperm_uid = (uid_t)atol(buf); 4777 4778 if ((err = fetchprop(cur, DTD_ATTR_GID, buf, sizeof (buf))) != Z_OK) { 4779 handle->zone_dh_cur = handle->zone_dh_top; 4780 return (err); 4781 } 4782 tabptr->zone_devperm_gid = (gid_t)atol(buf); 4783 4784 if ((err = fetchprop(cur, DTD_ATTR_MODE, buf, sizeof (buf))) != Z_OK) { 4785 handle->zone_dh_cur = handle->zone_dh_top; 4786 return (err); 4787 } 4788 tabptr->zone_devperm_mode = (mode_t)strtol(buf, (char **)NULL, 8); 4789 4790 if ((err = fetch_alloc_prop(cur, DTD_ATTR_ACL, 4791 &(tabptr->zone_devperm_acl))) != Z_OK) { 4792 handle->zone_dh_cur = handle->zone_dh_top; 4793 return (err); 4794 } 4795 4796 handle->zone_dh_cur = cur->next; 4797 return (Z_OK); 4798 } 4799 4800 int 4801 zonecfg_enddevperment(zone_dochandle_t handle) 4802 { 4803 return (zonecfg_endent(handle)); 4804 } 4805 4806 /* 4807 * Process a list of pkgs from an entry in the contents file, adding each pkg 4808 * name to the list of pkgs. 4809 * 4810 * It is possible for the pkg name to be preceeded by a special character 4811 * which indicates some bookkeeping information for pkging. Check if the 4812 * first char is not an Alpha char. If so, skip over it. 4813 */ 4814 static int 4815 add_pkg_list(char *lastp, char ***plist, int *pcnt) 4816 { 4817 char *p; 4818 int pkg_cnt = *pcnt; 4819 char **pkgs = *plist; 4820 int res = Z_OK; 4821 4822 while ((p = strtok_r(NULL, " ", &lastp)) != NULL) { 4823 char **tmpp; 4824 int i; 4825 4826 /* skip over any special pkg bookkeeping char */ 4827 if (!isalpha(*p)) 4828 p++; 4829 4830 /* Check if the pkg is already in the list */ 4831 for (i = 0; i < pkg_cnt; i++) { 4832 if (strcmp(p, pkgs[i]) == 0) 4833 break; 4834 } 4835 4836 if (i < pkg_cnt) 4837 continue; 4838 4839 /* The pkg is not in the list; add it. */ 4840 if ((tmpp = (char **)realloc(pkgs, 4841 sizeof (char *) * (pkg_cnt + 1))) == NULL) { 4842 res = Z_NOMEM; 4843 break; 4844 } 4845 pkgs = tmpp; 4846 4847 if ((pkgs[pkg_cnt] = strdup(p)) == NULL) { 4848 res = Z_NOMEM; 4849 break; 4850 } 4851 pkg_cnt++; 4852 } 4853 4854 *plist = pkgs; 4855 *pcnt = pkg_cnt; 4856 4857 return (res); 4858 } 4859 4860 /* 4861 * Process an entry from the contents file (type "directory") and if the 4862 * directory path is in the list of paths, add the associated list of pkgs 4863 * to the pkg list. The input parameter "entry" will be broken up by 4864 * the parser within this function so its value will be modified when this 4865 * function exits. 4866 * 4867 * The entries we are looking for will look something like: 4868 * /usr d none 0755 root sys SUNWctpls SUNWidnl SUNWlibCf .... 4869 */ 4870 static int 4871 get_path_pkgs(char *entry, char **paths, int cnt, char ***pkgs, int *pkg_cnt) 4872 { 4873 char *f1; 4874 char *f2; 4875 char *lastp; 4876 int i; 4877 int res = Z_OK; 4878 4879 if ((f1 = strtok_r(entry, " ", &lastp)) == NULL || 4880 (f2 = strtok_r(NULL, " ", &lastp)) == NULL || strcmp(f2, "d") != 0) 4881 return (Z_OK); 4882 4883 /* Check if this directory entry is in the list of paths. */ 4884 for (i = 0; i < cnt; i++) { 4885 if (fnmatch(paths[i], f1, FNM_PATHNAME) == 0) { 4886 /* 4887 * We do want the pkgs for this path. First, skip 4888 * over the next 4 fields in the entry so that we call 4889 * add_pkg_list starting with the pkg names. 4890 */ 4891 int j; 4892 char *nlp; 4893 4894 for (j = 0; j < 4 && 4895 strtok_r(NULL, " ", &lastp) != NULL; j++) 4896 ; 4897 /* 4898 * If there are < 4 fields this entry is corrupt, 4899 * just skip it. 4900 */ 4901 if (j < 4) 4902 return (Z_OK); 4903 4904 /* strip newline from the line */ 4905 nlp = (lastp + strlen(lastp) - 1); 4906 if (*nlp == '\n') 4907 *nlp = '\0'; 4908 4909 res = add_pkg_list(lastp, pkgs, pkg_cnt); 4910 break; 4911 } 4912 } 4913 4914 return (res); 4915 } 4916 4917 /* 4918 * Read an entry from a pkginfo or contents file. Some of these lines can 4919 * either be arbitrarily long or be continued by a backslash at the end of 4920 * the line. This function coalesces lines that are longer than the read 4921 * buffer, and lines that are continued, into one buffer which is returned. 4922 * The caller must free this memory. NULL is returned when we hit EOF or 4923 * if we run out of memory (errno is set to ENOMEM). 4924 */ 4925 static char * 4926 read_pkg_data(FILE *fp) 4927 { 4928 char *start; 4929 char *inp; 4930 char *p; 4931 int char_cnt = 0; 4932 4933 errno = 0; 4934 if ((start = (char *)malloc(PKGINFO_RD_LEN)) == NULL) { 4935 errno = ENOMEM; 4936 return (NULL); 4937 } 4938 4939 inp = start; 4940 while ((p = fgets(inp, PKGINFO_RD_LEN, fp)) != NULL) { 4941 int len; 4942 4943 len = strlen(inp); 4944 if (inp[len - 1] == '\n' && 4945 (len == 1 || inp[len - 2] != '\\')) { 4946 char_cnt = len; 4947 break; 4948 } 4949 4950 if (inp[len - 2] == '\\') 4951 char_cnt += len - 2; 4952 else 4953 char_cnt += PKGINFO_RD_LEN - 1; 4954 4955 if ((p = realloc(start, char_cnt + PKGINFO_RD_LEN)) == NULL) { 4956 errno = ENOMEM; 4957 break; 4958 } 4959 4960 start = p; 4961 inp = start + char_cnt; 4962 } 4963 4964 if (errno == ENOMEM || (p == NULL && char_cnt == 0)) { 4965 free(start); 4966 start = NULL; 4967 } 4968 4969 return (start); 4970 } 4971 4972 static void 4973 free_ipd_pkgs(char **pkgs, int cnt) 4974 { 4975 int i; 4976 4977 for (i = 0; i < cnt; i++) 4978 free(pkgs[i]); 4979 free(pkgs); 4980 } 4981 4982 /* 4983 * Get the list of inherited-pkg-dirs (ipd) for the zone and then get the 4984 * list of pkgs that deliver into those dirs. 4985 */ 4986 static int 4987 get_ipd_pkgs(zone_dochandle_t handle, char ***pkg_list, int *cnt) 4988 { 4989 int res; 4990 struct zone_fstab fstab; 4991 int ipd_cnt = 0; 4992 char **ipds = NULL; 4993 int pkg_cnt = 0; 4994 char **pkgs = NULL; 4995 int i; 4996 4997 if ((res = zonecfg_setipdent(handle)) != Z_OK) 4998 return (res); 4999 5000 while (zonecfg_getipdent(handle, &fstab) == Z_OK) { 5001 char **p; 5002 int len; 5003 5004 if ((p = (char **)realloc(ipds, 5005 sizeof (char *) * (ipd_cnt + 2))) == NULL) { 5006 res = Z_NOMEM; 5007 break; 5008 } 5009 ipds = p; 5010 5011 if ((ipds[ipd_cnt] = strdup(fstab.zone_fs_dir)) == NULL) { 5012 res = Z_NOMEM; 5013 break; 5014 } 5015 ipd_cnt++; 5016 5017 len = strlen(fstab.zone_fs_dir) + 3; 5018 if ((ipds[ipd_cnt] = malloc(len)) == NULL) { 5019 res = Z_NOMEM; 5020 break; 5021 } 5022 5023 (void) snprintf(ipds[ipd_cnt], len, "%s/*", fstab.zone_fs_dir); 5024 ipd_cnt++; 5025 } 5026 5027 (void) zonecfg_endipdent(handle); 5028 5029 if (res != Z_OK) { 5030 for (i = 0; i < ipd_cnt; i++) 5031 free(ipds[i]); 5032 free(ipds); 5033 return (res); 5034 } 5035 5036 /* We only have to process the contents file if we have ipds. */ 5037 if (ipd_cnt > 0) { 5038 FILE *fp; 5039 5040 if ((fp = fopen(CONTENTS_FILE, "r")) != NULL) { 5041 char *buf; 5042 5043 while ((buf = read_pkg_data(fp)) != NULL) { 5044 res = get_path_pkgs(buf, ipds, ipd_cnt, &pkgs, 5045 &pkg_cnt); 5046 free(buf); 5047 if (res != Z_OK) 5048 break; 5049 } 5050 5051 (void) fclose(fp); 5052 } 5053 } 5054 5055 for (i = 0; i < ipd_cnt; i++) 5056 free(ipds[i]); 5057 free(ipds); 5058 5059 if (res != Z_OK) { 5060 free_ipd_pkgs(pkgs, pkg_cnt); 5061 } else { 5062 *pkg_list = pkgs; 5063 *cnt = pkg_cnt; 5064 } 5065 5066 return (res); 5067 } 5068 5069 /* 5070 * Return true if pkg_name is in the list of pkgs that deliver into an 5071 * inherited pkg directory for the zone. 5072 */ 5073 static boolean_t 5074 dir_pkg(char *pkg_name, char **pkg_list, int cnt) 5075 { 5076 int i; 5077 5078 for (i = 0; i < cnt; i++) { 5079 if (strcmp(pkg_name, pkg_list[i]) == 0) 5080 return (B_TRUE); 5081 } 5082 5083 return (B_FALSE); 5084 } 5085 5086 /* 5087 * Start by adding the patch to the sw inventory on the handle. 5088 * 5089 * The info parameter will be the portion of the PATCH_INFO_ entry following 5090 * the '='. For example: 5091 * Installed: Wed Dec 7 07:13:51 PST 2005 From: mum Obsoletes: 120777-03 \ 5092 * 121087-02 119108-07 Requires: 119575-02 119255-06 Incompatibles: 5093 * 5094 * A backed out patch will have an info line of "backed out\n". We should 5095 * skip these patches. 5096 * 5097 * We also want to add the Obsolete and Incompatible patches to the 5098 * sw inventory description of this patch. 5099 */ 5100 static int 5101 add_patch(zone_dochandle_t handle, char *patch, char *info) 5102 { 5103 xmlNodePtr node; 5104 xmlNodePtr cur; 5105 int err; 5106 char *p; 5107 char *lastp; 5108 boolean_t add_info = B_FALSE; 5109 boolean_t obsolete; 5110 5111 if (strcmp(info, "backed out\n") == 0) 5112 return (Z_OK); 5113 5114 if ((err = operation_prep(handle)) != Z_OK) 5115 return (err); 5116 5117 cur = handle->zone_dh_cur; 5118 node = xmlNewTextChild(cur, NULL, DTD_ELEM_PATCH, NULL); 5119 if ((err = newprop(node, DTD_ATTR_ID, patch)) != Z_OK) 5120 return (err); 5121 5122 /* 5123 * Start with the first token. This will probably be "Installed:". 5124 * If we can't tokenize this entry, just return. 5125 */ 5126 if ((p = strtok_r(info, " ", &lastp)) == NULL) 5127 return (Z_OK); 5128 5129 do { 5130 xmlNodePtr new_node; 5131 char *nlp; 5132 5133 if (strcmp(p, "Installed:") == 0 || 5134 strcmp(p, "Requires:") == 0 || 5135 strcmp(p, "From:") == 0) { 5136 add_info = B_FALSE; 5137 continue; 5138 } else if (strcmp(p, "Obsoletes:") == 0) { 5139 obsolete = B_TRUE; 5140 add_info = B_TRUE; 5141 continue; 5142 } else if (strcmp(p, "Incompatibles:") == 0) { 5143 obsolete = B_FALSE; 5144 add_info = B_TRUE; 5145 continue; 5146 } 5147 5148 if (!add_info) 5149 continue; 5150 5151 /* strip newline from last patch in the line */ 5152 nlp = (p + strlen(p) - 1); 5153 if (*nlp == '\n') 5154 *nlp = '\0'; 5155 5156 if (obsolete) 5157 new_node = xmlNewTextChild(node, NULL, 5158 DTD_ELEM_OBSOLETES, NULL); 5159 else 5160 new_node = xmlNewTextChild(node, NULL, 5161 DTD_ELEM_INCOMPATIBLE, NULL); 5162 5163 if ((err = newprop(new_node, DTD_ATTR_ID, p)) != Z_OK) 5164 return (err); 5165 5166 } while ((p = strtok_r(NULL, " ", &lastp)) != NULL); 5167 5168 return (Z_OK); 5169 } 5170 5171 static boolean_t 5172 unique_patch(zone_dochandle_t handle, char *patch) 5173 { 5174 xmlNodePtr cur; 5175 char id[MAXNAMELEN]; 5176 5177 cur = xmlDocGetRootElement(handle->zone_dh_doc); 5178 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 5179 if (xmlStrcmp(cur->name, DTD_ELEM_PATCH) == 0) { 5180 if (fetchprop(cur, DTD_ATTR_ID, id, sizeof (id)) 5181 != Z_OK) 5182 continue; 5183 5184 if (strcmp(patch, id) == 0) 5185 return (B_FALSE); 5186 } 5187 } 5188 5189 return (B_TRUE); 5190 } 5191 5192 /* 5193 * Add the unique patches associated with this pkg to the sw inventory on the 5194 * handle. 5195 * 5196 * We are processing entries of the form: 5197 * PATCH_INFO_121454-02=Installed: Wed Dec 7 07:13:51 PST 2005 From: mum \ 5198 * Obsoletes: 120777-03 121087-02 119108-07 Requires: 119575-02 \ 5199 * 119255-06 Incompatibles: 5200 * 5201 */ 5202 static int 5203 add_patches(zone_dochandle_t handle, struct zone_pkginfo *infop) 5204 { 5205 int i; 5206 int res = Z_OK; 5207 5208 for (i = 0; i < infop->zpi_patch_cnt; i++) { 5209 char *p, *ep; 5210 5211 if (strlen(infop->zpi_patchinfo[i]) < (sizeof (PATCHINFO) - 1)) 5212 continue; 5213 5214 /* Skip over "PATCH_INFO_" to get the patch id. */ 5215 p = infop->zpi_patchinfo[i] + sizeof (PATCHINFO) - 1; 5216 if ((ep = strchr(p, '=')) == NULL) 5217 continue; 5218 5219 *ep = '\0'; 5220 if (unique_patch(handle, p)) 5221 if ((res = add_patch(handle, p, ep + 1)) != Z_OK) 5222 break; 5223 } 5224 5225 return (res); 5226 } 5227 5228 /* 5229 * Add the pkg to the sw inventory on the handle. 5230 */ 5231 static int 5232 add_pkg(zone_dochandle_t handle, char *name, char *version) 5233 { 5234 xmlNodePtr newnode; 5235 xmlNodePtr cur; 5236 int err; 5237 5238 if ((err = operation_prep(handle)) != Z_OK) 5239 return (err); 5240 5241 cur = handle->zone_dh_cur; 5242 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PACKAGE, NULL); 5243 if ((err = newprop(newnode, DTD_ATTR_NAME, name)) != Z_OK) 5244 return (err); 5245 if ((err = newprop(newnode, DTD_ATTR_VERSION, version)) != Z_OK) 5246 return (err); 5247 return (Z_OK); 5248 } 5249 5250 static void 5251 free_pkginfo(struct zone_pkginfo *infop) 5252 { 5253 free(infop->zpi_version); 5254 if (infop->zpi_patch_cnt > 0) { 5255 int i; 5256 5257 for (i = 0; i < infop->zpi_patch_cnt; i++) 5258 free(infop->zpi_patchinfo[i]); 5259 free(infop->zpi_patchinfo); 5260 } 5261 } 5262 5263 /* 5264 * Read the pkginfo file and populate the structure with the data we need 5265 * from this pkg for a sw inventory. 5266 */ 5267 static int 5268 get_pkginfo(char *pkginfo, struct zone_pkginfo *infop) 5269 { 5270 FILE *fp; 5271 char *buf; 5272 int err = 0; 5273 5274 infop->zpi_all_zones = B_FALSE; 5275 infop->zpi_this_zone = B_FALSE; 5276 infop->zpi_version = NULL; 5277 infop->zpi_patch_cnt = 0; 5278 infop->zpi_patchinfo = NULL; 5279 5280 if ((fp = fopen(pkginfo, "r")) == NULL) 5281 return (errno); 5282 5283 while ((buf = read_pkg_data(fp)) != NULL) { 5284 if (strncmp(buf, VERSION, sizeof (VERSION) - 1) == 0) { 5285 int len; 5286 5287 if ((infop->zpi_version = 5288 strdup(buf + sizeof (VERSION) - 1)) == NULL) { 5289 err = ENOMEM; 5290 break; 5291 } 5292 5293 /* remove trailing newline */ 5294 len = strlen(infop->zpi_version); 5295 *(infop->zpi_version + len - 1) = 0; 5296 5297 } else if (strcmp(buf, SUNW_PKG_ALL_ZONES) == 0) { 5298 infop->zpi_all_zones = B_TRUE; 5299 5300 } else if (strcmp(buf, SUNW_PKG_THIS_ZONE) == 0) { 5301 infop->zpi_this_zone = B_TRUE; 5302 5303 } else if (strncmp(buf, PATCHINFO, sizeof (PATCHINFO) - 1) 5304 == 0) { 5305 char **p; 5306 5307 if ((p = (char **)realloc(infop->zpi_patchinfo, 5308 sizeof (char *) * (infop->zpi_patch_cnt + 1))) 5309 == NULL) { 5310 err = ENOMEM; 5311 break; 5312 } 5313 infop->zpi_patchinfo = p; 5314 5315 if ((infop->zpi_patchinfo[infop->zpi_patch_cnt] = 5316 strdup(buf)) == NULL) { 5317 err = ENOMEM; 5318 break; 5319 } 5320 infop->zpi_patch_cnt++; 5321 } 5322 5323 free(buf); 5324 } 5325 5326 free(buf); 5327 5328 if (errno == ENOMEM) { 5329 err = ENOMEM; 5330 /* Clean up anything we did manage to allocate. */ 5331 free_pkginfo(infop); 5332 } 5333 5334 (void) fclose(fp); 5335 5336 return (err); 5337 } 5338 5339 /* 5340 * Take a software inventory of the global zone. We need to get the set of 5341 * packages and patches that are on the global zone that the specified 5342 * non-global zone depends on. The packages we need in the inventory are: 5343 * 5344 * - skip the package if SUNW_PKG_THISZONE is 'true' 5345 * otherwise, 5346 * - add the package if 5347 * a) SUNW_PKG_ALLZONES is 'true', 5348 * or 5349 * b) any file delivered by the package is in a file system that is inherited 5350 * from the global zone. 5351 * If the zone does not inherit any file systems (whole root) 5352 * then (b) will be skipped. 5353 * 5354 * For each of the packages that is being added to the inventory, we will also 5355 * add all of the associated, unique patches to the inventory. 5356 */ 5357 static int 5358 zonecfg_sw_inventory(zone_dochandle_t handle) 5359 { 5360 char pkginfo[MAXPATHLEN]; 5361 int res; 5362 struct dirent *dp; 5363 DIR *dirp; 5364 struct stat buf; 5365 struct zone_pkginfo info; 5366 int pkg_cnt = 0; 5367 char **pkgs = NULL; 5368 5369 if ((res = get_ipd_pkgs(handle, &pkgs, &pkg_cnt)) != Z_OK) 5370 return (res); 5371 5372 if ((dirp = opendir(PKG_PATH)) == NULL) { 5373 free_ipd_pkgs(pkgs, pkg_cnt); 5374 return (Z_OK); 5375 } 5376 5377 while ((dp = readdir(dirp)) != (struct dirent *)0) { 5378 if (strcmp(dp->d_name, ".") == 0 || 5379 strcmp(dp->d_name, "..") == 0) 5380 continue; 5381 5382 (void) snprintf(pkginfo, sizeof (pkginfo), "%s/%s/pkginfo", 5383 PKG_PATH, dp->d_name); 5384 5385 if (stat(pkginfo, &buf) == -1 || !S_ISREG(buf.st_mode)) 5386 continue; 5387 5388 if (get_pkginfo(pkginfo, &info) != 0) { 5389 res = Z_NOMEM; 5390 break; 5391 } 5392 5393 if (!info.zpi_this_zone && 5394 (info.zpi_all_zones || 5395 dir_pkg(dp->d_name, pkgs, pkg_cnt))) { 5396 if ((res = add_pkg(handle, dp->d_name, 5397 info.zpi_version)) == Z_OK) { 5398 if (info.zpi_patch_cnt > 0) 5399 res = add_patches(handle, &info); 5400 } 5401 } 5402 5403 free_pkginfo(&info); 5404 5405 if (res != Z_OK) 5406 break; 5407 } 5408 5409 (void) closedir(dirp); 5410 5411 free_ipd_pkgs(pkgs, pkg_cnt); 5412 5413 if (res == Z_OK) 5414 handle->zone_dh_sw_inv = B_TRUE; 5415 5416 return (res); 5417 } 5418 5419 /* 5420 * zonecfg_devwalk call-back function used during detach to generate the 5421 * dev info in the manifest. 5422 */ 5423 static int 5424 get_detach_dev_entry(const char *name, uid_t uid, gid_t gid, mode_t mode, 5425 const char *acl, void *hdl) 5426 { 5427 zone_dochandle_t handle = (zone_dochandle_t)hdl; 5428 xmlNodePtr newnode; 5429 xmlNodePtr cur; 5430 int err; 5431 char buf[128]; 5432 5433 if ((err = operation_prep(handle)) != Z_OK) 5434 return (err); 5435 5436 cur = handle->zone_dh_cur; 5437 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEV_PERM, NULL); 5438 if ((err = newprop(newnode, DTD_ATTR_NAME, (char *)name)) != Z_OK) 5439 return (err); 5440 (void) snprintf(buf, sizeof (buf), "%lu", uid); 5441 if ((err = newprop(newnode, DTD_ATTR_UID, buf)) != Z_OK) 5442 return (err); 5443 (void) snprintf(buf, sizeof (buf), "%lu", gid); 5444 if ((err = newprop(newnode, DTD_ATTR_GID, buf)) != Z_OK) 5445 return (err); 5446 (void) snprintf(buf, sizeof (buf), "%o", mode); 5447 if ((err = newprop(newnode, DTD_ATTR_MODE, buf)) != Z_OK) 5448 return (err); 5449 if ((err = newprop(newnode, DTD_ATTR_ACL, (char *)acl)) != Z_OK) 5450 return (err); 5451 return (Z_OK); 5452 } 5453 5454 /* 5455 * Get the information required to support detaching a zone. This is 5456 * called on the source system when detaching (the detaching parameter should 5457 * be set to true) and on the destination system before attaching (the 5458 * detaching parameter should be false). 5459 * 5460 * For native Solaris zones, the detach/attach process involves validating 5461 * that the software on the global zone can support the zone when we attach. 5462 * To do this we take a software inventory of the global zone. We also 5463 * have to keep track of the device configuration so that we can properly 5464 * recreate it on the destination. 5465 */ 5466 int 5467 zonecfg_get_detach_info(zone_dochandle_t handle, boolean_t detaching) 5468 { 5469 int res; 5470 5471 if ((res = zonecfg_sw_inventory(handle)) != Z_OK) 5472 return (res); 5473 5474 if (detaching) 5475 res = zonecfg_devwalk(handle, get_detach_dev_entry, handle); 5476 5477 return (res); 5478 } 5479