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 2008 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 <assert.h> 37 #include <libgen.h> 38 #include <libintl.h> 39 #include <alloca.h> 40 #include <ctype.h> 41 #include <sys/acl.h> 42 #include <sys/stat.h> 43 #include <sys/brand.h> 44 #include <sys/mntio.h> 45 #include <sys/mnttab.h> 46 #include <sys/nvpair.h> 47 #include <sys/types.h> 48 #include <sys/sockio.h> 49 #include <ftw.h> 50 #include <pool.h> 51 #include <libscf.h> 52 #include <libproc.h> 53 #include <sys/priocntl.h> 54 #include <libuutil.h> 55 56 #include <arpa/inet.h> 57 #include <netdb.h> 58 59 #include <libxml/xmlmemory.h> 60 #include <libxml/parser.h> 61 62 #include <libdevinfo.h> 63 #include <uuid/uuid.h> 64 #include <dirent.h> 65 #include <libbrand.h> 66 67 #include <libzonecfg.h> 68 #include "zonecfg_impl.h" 69 70 #define _PATH_TMPFILE "/zonecfg.XXXXXX" 71 #define ZONE_CB_RETRY_COUNT 10 72 #define ZONE_EVENT_PING_SUBCLASS "ping" 73 #define ZONE_EVENT_PING_PUBLISHER "solaris" 74 75 /* Hard-code the DTD element/attribute/entity names just once, here. */ 76 #define DTD_ELEM_ATTR (const xmlChar *) "attr" 77 #define DTD_ELEM_COMMENT (const xmlChar *) "comment" 78 #define DTD_ELEM_DEVICE (const xmlChar *) "device" 79 #define DTD_ELEM_FS (const xmlChar *) "filesystem" 80 #define DTD_ELEM_FSOPTION (const xmlChar *) "fsoption" 81 #define DTD_ELEM_IPD (const xmlChar *) "inherited-pkg-dir" 82 #define DTD_ELEM_NET (const xmlChar *) "network" 83 #define DTD_ELEM_RCTL (const xmlChar *) "rctl" 84 #define DTD_ELEM_RCTLVALUE (const xmlChar *) "rctl-value" 85 #define DTD_ELEM_ZONE (const xmlChar *) "zone" 86 #define DTD_ELEM_DATASET (const xmlChar *) "dataset" 87 #define DTD_ELEM_TMPPOOL (const xmlChar *) "tmp_pool" 88 #define DTD_ELEM_PSET (const xmlChar *) "pset" 89 #define DTD_ELEM_MCAP (const xmlChar *) "mcap" 90 #define DTD_ELEM_PACKAGE (const xmlChar *) "package" 91 #define DTD_ELEM_PATCH (const xmlChar *) "patch" 92 #define DTD_ELEM_OBSOLETES (const xmlChar *) "obsoletes" 93 #define DTD_ELEM_DEV_PERM (const xmlChar *) "dev-perm" 94 95 #define DTD_ATTR_ACTION (const xmlChar *) "action" 96 #define DTD_ATTR_ADDRESS (const xmlChar *) "address" 97 #define DTD_ATTR_AUTOBOOT (const xmlChar *) "autoboot" 98 #define DTD_ATTR_IPTYPE (const xmlChar *) "ip-type" 99 #define DTD_ATTR_DEFROUTER (const xmlChar *) "defrouter" 100 #define DTD_ATTR_DIR (const xmlChar *) "directory" 101 #define DTD_ATTR_LIMIT (const xmlChar *) "limit" 102 #define DTD_ATTR_LIMITPRIV (const xmlChar *) "limitpriv" 103 #define DTD_ATTR_BOOTARGS (const xmlChar *) "bootargs" 104 #define DTD_ATTR_SCHED (const xmlChar *) "scheduling-class" 105 #define DTD_ATTR_MATCH (const xmlChar *) "match" 106 #define DTD_ATTR_NAME (const xmlChar *) "name" 107 #define DTD_ATTR_PHYSICAL (const xmlChar *) "physical" 108 #define DTD_ATTR_POOL (const xmlChar *) "pool" 109 #define DTD_ATTR_PRIV (const xmlChar *) "priv" 110 #define DTD_ATTR_RAW (const xmlChar *) "raw" 111 #define DTD_ATTR_SPECIAL (const xmlChar *) "special" 112 #define DTD_ATTR_TYPE (const xmlChar *) "type" 113 #define DTD_ATTR_VALUE (const xmlChar *) "value" 114 #define DTD_ATTR_ZONEPATH (const xmlChar *) "zonepath" 115 #define DTD_ATTR_NCPU_MIN (const xmlChar *) "ncpu_min" 116 #define DTD_ATTR_NCPU_MAX (const xmlChar *) "ncpu_max" 117 #define DTD_ATTR_IMPORTANCE (const xmlChar *) "importance" 118 #define DTD_ATTR_PHYSCAP (const xmlChar *) "physcap" 119 #define DTD_ATTR_VERSION (const xmlChar *) "version" 120 #define DTD_ATTR_ID (const xmlChar *) "id" 121 #define DTD_ATTR_UID (const xmlChar *) "uid" 122 #define DTD_ATTR_GID (const xmlChar *) "gid" 123 #define DTD_ATTR_MODE (const xmlChar *) "mode" 124 #define DTD_ATTR_ACL (const xmlChar *) "acl" 125 #define DTD_ATTR_BRAND (const xmlChar *) "brand" 126 127 #define DTD_ENTITY_BOOLEAN "boolean" 128 #define DTD_ENTITY_DEVPATH "devpath" 129 #define DTD_ENTITY_DRIVER "driver" 130 #define DTD_ENTITY_DRVMIN "drv_min" 131 #define DTD_ENTITY_FALSE "false" 132 #define DTD_ENTITY_INT "int" 133 #define DTD_ENTITY_STRING "string" 134 #define DTD_ENTITY_TRUE "true" 135 #define DTD_ENTITY_UINT "uint" 136 137 #define DTD_ENTITY_BOOL_LEN 6 /* "false" */ 138 139 #define DETACHED "SUNWdetached.xml" 140 #define ATTACH_FORCED "SUNWattached.xml" 141 #define PKG_PATH "/var/sadm/pkg" 142 #define CONTENTS_FILE "/var/sadm/install/contents" 143 #define SUNW_PKG_ALL_ZONES "SUNW_PKG_ALLZONES=true\n" 144 #define SUNW_PKG_THIS_ZONE "SUNW_PKG_THISZONE=true\n" 145 #define VERSION "VERSION=" 146 #define PATCHLIST "PATCHLIST=" 147 #define PATCHINFO "PATCH_INFO_" 148 #define PKGINFO_RD_LEN 128 149 150 #define TMP_POOL_NAME "SUNWtmp_%s" 151 #define MAX_TMP_POOL_NAME (ZONENAME_MAX + 9) 152 #define RCAP_SERVICE "system/rcap:default" 153 #define POOLD_SERVICE "system/pools/dynamic:default" 154 155 enum zn_ipd_fs {ZONE_IPD, ZONE_FS}; 156 157 /* 158 * rctl alias definitions 159 * 160 * This holds the alias, the full rctl name, the default priv value, action 161 * and lower limit. The functions that handle rctl aliases step through 162 * this table, matching on the alias, and using the full values for setting 163 * the rctl entry as well the limit for validation. 164 */ 165 static struct alias { 166 char *shortname; 167 char *realname; 168 char *priv; 169 char *action; 170 uint64_t low_limit; 171 } aliases[] = { 172 {ALIAS_MAXLWPS, "zone.max-lwps", "privileged", "deny", 100}, 173 {ALIAS_MAXSHMMEM, "zone.max-shm-memory", "privileged", "deny", 0}, 174 {ALIAS_MAXSHMIDS, "zone.max-shm-ids", "privileged", "deny", 0}, 175 {ALIAS_MAXMSGIDS, "zone.max-msg-ids", "privileged", "deny", 0}, 176 {ALIAS_MAXSEMIDS, "zone.max-sem-ids", "privileged", "deny", 0}, 177 {ALIAS_MAXLOCKEDMEM, "zone.max-locked-memory", "privileged", "deny", 0}, 178 {ALIAS_MAXSWAP, "zone.max-swap", "privileged", "deny", 0}, 179 {ALIAS_SHARES, "zone.cpu-shares", "privileged", "none", 0}, 180 {ALIAS_CPUCAP, "zone.cpu-cap", "privileged", "deny", 0}, 181 {NULL, NULL, NULL, NULL, 0} 182 }; 183 184 /* 185 * Structure for applying rctls to a running zone. It allows important 186 * process values to be passed together easily. 187 */ 188 typedef struct pr_info_handle { 189 struct ps_prochandle *pr; 190 pid_t pid; 191 } pr_info_handle_t; 192 193 struct zone_dochandle { 194 char *zone_dh_rootdir; 195 xmlDocPtr zone_dh_doc; 196 xmlNodePtr zone_dh_cur; 197 xmlNodePtr zone_dh_top; 198 boolean_t zone_dh_newzone; 199 boolean_t zone_dh_snapshot; 200 boolean_t zone_dh_sw_inv; 201 char zone_dh_delete_name[ZONENAME_MAX]; 202 }; 203 204 struct znotify { 205 void * zn_private; 206 evchan_t *zn_eventchan; 207 int (*zn_callback)(const char *zonename, zoneid_t zid, 208 const char *newstate, const char *oldstate, hrtime_t when, void *p); 209 pthread_mutex_t zn_mutex; 210 pthread_cond_t zn_cond; 211 pthread_mutex_t zn_bigmutex; 212 volatile enum {ZN_UNLOCKED, ZN_LOCKED, ZN_PING_INFLIGHT, 213 ZN_PING_RECEIVED} zn_state; 214 char zn_subscriber_id[MAX_SUBID_LEN]; 215 volatile boolean_t zn_failed; 216 int zn_failure_count; 217 }; 218 219 struct zone_pkginfo { 220 boolean_t zpi_all_zones; 221 boolean_t zpi_this_zone; 222 int zpi_patch_cnt; 223 char *zpi_version; 224 char **zpi_patchinfo; 225 }; 226 227 typedef struct { 228 uu_avl_node_t patch_node; 229 char *patch_num; 230 char *patch_vers; 231 uu_list_t *obs_patches; 232 } patch_node_t; 233 234 typedef struct { 235 uu_list_node_t link; 236 char *patch_num; 237 } obs_patch_node_t; 238 239 typedef struct { 240 uu_avl_t *obs_patches_avl; 241 zone_dochandle_t handle; 242 int res; 243 } patch_parms_t; 244 245 char *zonecfg_root = ""; 246 247 /* 248 * For functions which return int, which is most of the functions herein, 249 * the return values should be from the Z_foo set defined in <libzonecfg.h>. 250 * In some instances, we take pains mapping some libc errno values to Z_foo 251 * values from this set. 252 */ 253 254 /* 255 * Set the root (/) path for all zonecfg configuration files. This is a 256 * private interface used by Live Upgrade extensions to access zone 257 * configuration inside mounted alternate boot environments. 258 */ 259 void 260 zonecfg_set_root(const char *rootpath) 261 { 262 if (*zonecfg_root != '\0') 263 free(zonecfg_root); 264 if (rootpath == NULL || rootpath[0] == '\0' || rootpath[1] == '\0' || 265 (zonecfg_root = strdup(rootpath)) == NULL) 266 zonecfg_root = ""; 267 } 268 269 const char * 270 zonecfg_get_root(void) 271 { 272 return (zonecfg_root); 273 } 274 275 boolean_t 276 zonecfg_in_alt_root(void) 277 { 278 return (*zonecfg_root != '\0'); 279 } 280 281 /* 282 * Callers of the _file_path() functions are expected to have the second 283 * parameter be a (char foo[MAXPATHLEN]). 284 */ 285 286 static boolean_t 287 config_file_path(const char *zonename, char *answer) 288 { 289 return (snprintf(answer, MAXPATHLEN, "%s%s/%s.xml", zonecfg_root, 290 ZONE_CONFIG_ROOT, zonename) < MAXPATHLEN); 291 } 292 293 static boolean_t 294 snap_file_path(const char *zonename, char *answer) 295 { 296 return (snprintf(answer, MAXPATHLEN, "%s%s/%s.snapshot.xml", 297 zonecfg_root, ZONE_SNAPSHOT_ROOT, zonename) < MAXPATHLEN); 298 } 299 300 /*ARGSUSED*/ 301 static void 302 zonecfg_error_func(void *ctx, const char *msg, ...) 303 { 304 /* 305 * This function does nothing by design. Its purpose is to prevent 306 * libxml from dumping unwanted messages to stdout/stderr. 307 */ 308 } 309 310 zone_dochandle_t 311 zonecfg_init_handle(void) 312 { 313 zone_dochandle_t handle = calloc(1, sizeof (struct zone_dochandle)); 314 if (handle == NULL) { 315 errno = Z_NOMEM; 316 return (NULL); 317 } 318 319 /* generic libxml initialization */ 320 xmlLineNumbersDefault(1); 321 xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS; 322 xmlDoValidityCheckingDefaultValue = 1; 323 (void) xmlKeepBlanksDefault(0); 324 xmlGetWarningsDefaultValue = 0; 325 xmlSetGenericErrorFunc(NULL, zonecfg_error_func); 326 327 return (handle); 328 } 329 330 int 331 zonecfg_check_handle(zone_dochandle_t handle) 332 { 333 if (handle == NULL || handle->zone_dh_doc == NULL) 334 return (Z_BAD_HANDLE); 335 return (Z_OK); 336 } 337 338 void 339 zonecfg_fini_handle(zone_dochandle_t handle) 340 { 341 if (zonecfg_check_handle(handle) == Z_OK) 342 xmlFreeDoc(handle->zone_dh_doc); 343 if (handle != NULL) 344 free(handle); 345 } 346 347 static int 348 zonecfg_destroy_impl(char *filename) 349 { 350 if (unlink(filename) == -1) { 351 if (errno == EACCES) 352 return (Z_ACCES); 353 if (errno == ENOENT) 354 return (Z_NO_ZONE); 355 return (Z_MISC_FS); 356 } 357 return (Z_OK); 358 } 359 360 int 361 zonecfg_destroy(const char *zonename, boolean_t force) 362 { 363 char path[MAXPATHLEN]; 364 struct zoneent ze; 365 int err, state_err; 366 zone_state_t state; 367 368 if (!config_file_path(zonename, path)) 369 return (Z_MISC_FS); 370 371 state_err = zone_get_state((char *)zonename, &state); 372 err = access(path, W_OK); 373 374 /* 375 * If there is no file, and no index entry, reliably indicate that no 376 * such zone exists. 377 */ 378 if ((state_err == Z_NO_ZONE) && (err == -1) && (errno == ENOENT)) 379 return (Z_NO_ZONE); 380 381 /* 382 * Handle any other filesystem related errors (except if the XML 383 * file is missing, which we treat silently), unless we're forcing, 384 * in which case we plow on. 385 */ 386 if (err == -1 && errno != ENOENT) { 387 if (errno == EACCES) 388 return (Z_ACCES); 389 else if (!force) 390 return (Z_MISC_FS); 391 } 392 393 if (state > ZONE_STATE_INSTALLED) 394 return (Z_BAD_ZONE_STATE); 395 396 if (!force && state > ZONE_STATE_CONFIGURED) 397 return (Z_BAD_ZONE_STATE); 398 399 /* 400 * Index deletion succeeds even if the entry doesn't exist. So this 401 * will fail only if we've had some more severe problem. 402 */ 403 bzero(&ze, sizeof (ze)); 404 (void) strlcpy(ze.zone_name, zonename, sizeof (ze.zone_name)); 405 if ((err = putzoneent(&ze, PZE_REMOVE)) != Z_OK) 406 if (!force) 407 return (err); 408 409 err = zonecfg_destroy_impl(path); 410 411 /* 412 * Treat failure to find the XML file silently, since, well, it's 413 * gone, and with the index file cleaned up, we're done. 414 */ 415 if (err == Z_OK || err == Z_NO_ZONE) 416 return (Z_OK); 417 return (err); 418 } 419 420 int 421 zonecfg_destroy_snapshot(const char *zonename) 422 { 423 char path[MAXPATHLEN]; 424 425 if (!snap_file_path(zonename, path)) 426 return (Z_MISC_FS); 427 return (zonecfg_destroy_impl(path)); 428 } 429 430 static int 431 getroot(zone_dochandle_t handle, xmlNodePtr *root) 432 { 433 if (zonecfg_check_handle(handle) == Z_BAD_HANDLE) 434 return (Z_BAD_HANDLE); 435 436 *root = xmlDocGetRootElement(handle->zone_dh_doc); 437 438 if (*root == NULL) 439 return (Z_EMPTY_DOCUMENT); 440 441 if (xmlStrcmp((*root)->name, DTD_ELEM_ZONE)) 442 return (Z_WRONG_DOC_TYPE); 443 444 return (Z_OK); 445 } 446 447 static int 448 operation_prep(zone_dochandle_t handle) 449 { 450 xmlNodePtr root; 451 int err; 452 453 if ((err = getroot(handle, &root)) != 0) 454 return (err); 455 456 handle->zone_dh_cur = root; 457 handle->zone_dh_top = root; 458 return (Z_OK); 459 } 460 461 static int 462 fetchprop(xmlNodePtr cur, const xmlChar *propname, char *dst, size_t dstsize) 463 { 464 xmlChar *property; 465 size_t srcsize; 466 467 if ((property = xmlGetProp(cur, propname)) == NULL) 468 return (Z_BAD_PROPERTY); 469 srcsize = strlcpy(dst, (char *)property, dstsize); 470 xmlFree(property); 471 if (srcsize >= dstsize) 472 return (Z_TOO_BIG); 473 return (Z_OK); 474 } 475 476 static int 477 fetch_alloc_prop(xmlNodePtr cur, const xmlChar *propname, char **dst) 478 { 479 xmlChar *property; 480 481 if ((property = xmlGetProp(cur, propname)) == NULL) 482 return (Z_BAD_PROPERTY); 483 if ((*dst = strdup((char *)property)) == NULL) { 484 xmlFree(property); 485 return (Z_NOMEM); 486 } 487 xmlFree(property); 488 return (Z_OK); 489 } 490 491 static int 492 getrootattr(zone_dochandle_t handle, const xmlChar *propname, 493 char *propval, size_t propsize) 494 { 495 xmlNodePtr root; 496 int err; 497 498 if ((err = getroot(handle, &root)) != 0) 499 return (err); 500 501 return (fetchprop(root, propname, propval, propsize)); 502 } 503 504 static int 505 get_alloc_rootattr(zone_dochandle_t handle, const xmlChar *propname, 506 char **propval) 507 { 508 xmlNodePtr root; 509 int err; 510 511 if ((err = getroot(handle, &root)) != 0) 512 return (err); 513 514 return (fetch_alloc_prop(root, propname, propval)); 515 } 516 517 static int 518 setrootattr(zone_dochandle_t handle, const xmlChar *propname, 519 const char *propval) 520 { 521 int err; 522 xmlNodePtr root; 523 524 if ((err = getroot(handle, &root)) != Z_OK) 525 return (err); 526 527 /* 528 * If we get a null propval remove the property (ignore return since it 529 * may not be set to begin with). 530 */ 531 if (propval == NULL) { 532 (void) xmlUnsetProp(root, propname); 533 } else { 534 if (xmlSetProp(root, propname, (const xmlChar *) propval) 535 == NULL) 536 return (Z_INVAL); 537 } 538 return (Z_OK); 539 } 540 541 static void 542 addcomment(zone_dochandle_t handle, const char *comment) 543 { 544 xmlNodePtr node; 545 node = xmlNewComment((xmlChar *) comment); 546 547 if (node != NULL) 548 (void) xmlAddPrevSibling(handle->zone_dh_top, node); 549 } 550 551 static void 552 stripcomments(zone_dochandle_t handle) 553 { 554 xmlDocPtr top; 555 xmlNodePtr child, next; 556 557 top = handle->zone_dh_doc; 558 for (child = top->xmlChildrenNode; child != NULL; child = next) { 559 next = child->next; 560 if (child->name == NULL) 561 continue; 562 if (xmlStrcmp(child->name, DTD_ELEM_COMMENT) == 0) { 563 next = child->next; 564 xmlUnlinkNode(child); 565 xmlFreeNode(child); 566 } 567 } 568 } 569 570 static void 571 strip_sw_inv(zone_dochandle_t handle) 572 { 573 xmlNodePtr root, child, next; 574 575 root = xmlDocGetRootElement(handle->zone_dh_doc); 576 for (child = root->xmlChildrenNode; child != NULL; child = next) { 577 next = child->next; 578 if (child->name == NULL) 579 continue; 580 if (xmlStrcmp(child->name, DTD_ELEM_PACKAGE) == 0 || 581 xmlStrcmp(child->name, DTD_ELEM_PATCH) == 0) { 582 next = child->next; 583 xmlUnlinkNode(child); 584 xmlFreeNode(child); 585 } 586 } 587 } 588 589 static int 590 zonecfg_get_handle_impl(const char *zonename, const char *filename, 591 zone_dochandle_t handle) 592 { 593 xmlValidCtxtPtr cvp; 594 struct stat statbuf; 595 int valid; 596 597 if (zonename == NULL) 598 return (Z_NO_ZONE); 599 600 if ((handle->zone_dh_doc = xmlParseFile(filename)) == NULL) { 601 /* distinguish file not found vs. found but not parsed */ 602 if (stat(filename, &statbuf) == 0) 603 return (Z_INVALID_DOCUMENT); 604 return (Z_NO_ZONE); 605 } 606 if ((cvp = xmlNewValidCtxt()) == NULL) 607 return (Z_NOMEM); 608 cvp->error = zonecfg_error_func; 609 cvp->warning = zonecfg_error_func; 610 valid = xmlValidateDocument(cvp, handle->zone_dh_doc); 611 xmlFreeValidCtxt(cvp); 612 if (valid == 0) 613 return (Z_INVALID_DOCUMENT); 614 615 /* delete any comments such as inherited Sun copyright / ident str */ 616 stripcomments(handle); 617 return (Z_OK); 618 } 619 620 int 621 zonecfg_get_handle(const char *zonename, zone_dochandle_t handle) 622 { 623 char path[MAXPATHLEN]; 624 625 if (!config_file_path(zonename, path)) 626 return (Z_MISC_FS); 627 handle->zone_dh_newzone = B_FALSE; 628 629 return (zonecfg_get_handle_impl(zonename, path, handle)); 630 } 631 632 int 633 zonecfg_get_attach_handle(const char *path, const char *zonename, 634 boolean_t preserve_sw, zone_dochandle_t handle) 635 { 636 char migpath[MAXPATHLEN]; 637 int err; 638 struct stat buf; 639 640 if (snprintf(migpath, sizeof (migpath), "%s/root", path) >= 641 sizeof (migpath)) 642 return (Z_NOMEM); 643 644 if (stat(migpath, &buf) == -1 || !S_ISDIR(buf.st_mode)) 645 return (Z_NO_ZONE); 646 647 if (snprintf(migpath, sizeof (migpath), "%s/%s", path, DETACHED) >= 648 sizeof (migpath)) 649 return (Z_NOMEM); 650 651 if ((err = zonecfg_get_handle_impl(zonename, migpath, handle)) != Z_OK) 652 return (err); 653 654 if (!preserve_sw) 655 strip_sw_inv(handle); 656 657 handle->zone_dh_newzone = B_TRUE; 658 if ((err = setrootattr(handle, DTD_ATTR_ZONEPATH, path)) != Z_OK) 659 return (err); 660 661 return (setrootattr(handle, DTD_ATTR_NAME, zonename)); 662 } 663 664 int 665 zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle) 666 { 667 char path[MAXPATHLEN]; 668 669 if (!snap_file_path(zonename, path)) 670 return (Z_MISC_FS); 671 handle->zone_dh_newzone = B_FALSE; 672 return (zonecfg_get_handle_impl(zonename, path, handle)); 673 } 674 675 int 676 zonecfg_get_template_handle(const char *template, const char *zonename, 677 zone_dochandle_t handle) 678 { 679 char path[MAXPATHLEN]; 680 int err; 681 682 if (!config_file_path(template, path)) 683 return (Z_MISC_FS); 684 685 if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK) 686 return (err); 687 handle->zone_dh_newzone = B_TRUE; 688 return (setrootattr(handle, DTD_ATTR_NAME, zonename)); 689 } 690 691 int 692 zonecfg_get_xml_handle(const char *path, zone_dochandle_t handle) 693 { 694 struct stat buf; 695 int err; 696 697 if (stat(path, &buf) == -1) 698 return (Z_MISC_FS); 699 700 if ((err = zonecfg_get_handle_impl("xml", path, handle)) != Z_OK) 701 return (err); 702 handle->zone_dh_newzone = B_TRUE; 703 return (Z_OK); 704 } 705 706 /* 707 * Initialize two handles from the manifest read on fd. The rem_handle 708 * is initialized from the input file, including the sw inventory. The 709 * local_handle is initialized with the same zone configuration but with 710 * no sw inventory. 711 */ 712 int 713 zonecfg_attach_manifest(int fd, zone_dochandle_t local_handle, 714 zone_dochandle_t rem_handle) 715 { 716 xmlValidCtxtPtr cvp; 717 int valid; 718 719 /* load the manifest into the handle for the remote system */ 720 if ((rem_handle->zone_dh_doc = xmlReadFd(fd, NULL, NULL, 0)) == NULL) { 721 return (Z_INVALID_DOCUMENT); 722 } 723 if ((cvp = xmlNewValidCtxt()) == NULL) 724 return (Z_NOMEM); 725 cvp->error = zonecfg_error_func; 726 cvp->warning = zonecfg_error_func; 727 valid = xmlValidateDocument(cvp, rem_handle->zone_dh_doc); 728 xmlFreeValidCtxt(cvp); 729 if (valid == 0) 730 return (Z_INVALID_DOCUMENT); 731 732 /* delete any comments such as inherited Sun copyright / ident str */ 733 stripcomments(rem_handle); 734 735 rem_handle->zone_dh_newzone = B_TRUE; 736 rem_handle->zone_dh_sw_inv = B_TRUE; 737 738 /* 739 * Now use the remote system handle to generate a local system handle 740 * with an identical zones configuration but no sw inventory. 741 */ 742 if ((local_handle->zone_dh_doc = xmlCopyDoc(rem_handle->zone_dh_doc, 743 1)) == NULL) { 744 return (Z_INVALID_DOCUMENT); 745 } 746 747 /* 748 * We need to re-run xmlValidateDocument on local_handle to properly 749 * update the in-core representation of the configuration. 750 */ 751 if ((cvp = xmlNewValidCtxt()) == NULL) 752 return (Z_NOMEM); 753 cvp->error = zonecfg_error_func; 754 cvp->warning = zonecfg_error_func; 755 valid = xmlValidateDocument(cvp, local_handle->zone_dh_doc); 756 xmlFreeValidCtxt(cvp); 757 if (valid == 0) 758 return (Z_INVALID_DOCUMENT); 759 760 strip_sw_inv(local_handle); 761 762 local_handle->zone_dh_newzone = B_TRUE; 763 local_handle->zone_dh_sw_inv = B_FALSE; 764 765 return (Z_OK); 766 } 767 768 static boolean_t 769 is_renaming(zone_dochandle_t handle) 770 { 771 if (handle->zone_dh_newzone) 772 return (B_FALSE); 773 if (strlen(handle->zone_dh_delete_name) > 0) 774 return (B_TRUE); 775 return (B_FALSE); 776 } 777 778 static boolean_t 779 is_new(zone_dochandle_t handle) 780 { 781 return (handle->zone_dh_newzone || handle->zone_dh_snapshot); 782 } 783 784 static boolean_t 785 is_snapshot(zone_dochandle_t handle) 786 { 787 return (handle->zone_dh_snapshot); 788 } 789 790 /* 791 * It would be great to be able to use libc's ctype(3c) macros, but we 792 * can't, as they are locale sensitive, and it would break our limited thread 793 * safety if this routine had to change the app locale on the fly. 794 */ 795 int 796 zonecfg_validate_zonename(const char *zone) 797 { 798 int i; 799 800 if (strcmp(zone, GLOBAL_ZONENAME) == 0) 801 return (Z_BOGUS_ZONE_NAME); 802 803 if (strlen(zone) >= ZONENAME_MAX) 804 return (Z_BOGUS_ZONE_NAME); 805 806 if (!((zone[0] >= 'a' && zone[0] <= 'z') || 807 (zone[0] >= 'A' && zone[0] <= 'Z') || 808 (zone[0] >= '0' && zone[0] <= '9'))) 809 return (Z_BOGUS_ZONE_NAME); 810 811 for (i = 1; zone[i] != '\0'; i++) { 812 if (!((zone[i] >= 'a' && zone[i] <= 'z') || 813 (zone[i] >= 'A' && zone[i] <= 'Z') || 814 (zone[i] >= '0' && zone[i] <= '9') || 815 (zone[i] == '-') || (zone[i] == '_') || (zone[i] == '.'))) 816 return (Z_BOGUS_ZONE_NAME); 817 } 818 819 return (Z_OK); 820 } 821 822 /* 823 * Changing the zone name requires us to track both the old and new 824 * name of the zone until commit time. 825 */ 826 int 827 zonecfg_get_name(zone_dochandle_t handle, char *name, size_t namesize) 828 { 829 return (getrootattr(handle, DTD_ATTR_NAME, name, namesize)); 830 } 831 832 int 833 zonecfg_set_name(zone_dochandle_t handle, char *name) 834 { 835 zone_state_t state; 836 char curname[ZONENAME_MAX], old_delname[ZONENAME_MAX]; 837 int err; 838 839 if ((err = getrootattr(handle, DTD_ATTR_NAME, curname, 840 sizeof (curname))) != Z_OK) 841 return (err); 842 843 if (strcmp(name, curname) == 0) 844 return (Z_OK); 845 846 /* 847 * Switching zone names to one beginning with SUNW is not permitted. 848 */ 849 if (strncmp(name, "SUNW", 4) == 0) 850 return (Z_BOGUS_ZONE_NAME); 851 852 if ((err = zonecfg_validate_zonename(name)) != Z_OK) 853 return (err); 854 855 /* 856 * Setting the name back to the original name (effectively a revert of 857 * the name) is fine. But if we carry on, we'll falsely identify the 858 * name as "in use," so special case here. 859 */ 860 if (strcmp(name, handle->zone_dh_delete_name) == 0) { 861 err = setrootattr(handle, DTD_ATTR_NAME, name); 862 handle->zone_dh_delete_name[0] = '\0'; 863 return (err); 864 } 865 866 /* Check to see if new name chosen is already in use */ 867 if (zone_get_state(name, &state) != Z_NO_ZONE) 868 return (Z_NAME_IN_USE); 869 870 /* 871 * If this isn't already "new" or in a renaming transition, then 872 * we're initiating a rename here; so stash the "delete name" 873 * (i.e. the name of the zone we'll be removing) for the rename. 874 */ 875 (void) strlcpy(old_delname, handle->zone_dh_delete_name, 876 sizeof (old_delname)); 877 if (!is_new(handle) && !is_renaming(handle)) { 878 /* 879 * Name change is allowed only when the zone we're altering 880 * is not ready or running. 881 */ 882 err = zone_get_state(curname, &state); 883 if (err == Z_OK) { 884 if (state > ZONE_STATE_INSTALLED) 885 return (Z_BAD_ZONE_STATE); 886 } else if (err != Z_NO_ZONE) { 887 return (err); 888 } 889 890 (void) strlcpy(handle->zone_dh_delete_name, curname, 891 sizeof (handle->zone_dh_delete_name)); 892 assert(is_renaming(handle)); 893 } else if (is_renaming(handle)) { 894 err = zone_get_state(handle->zone_dh_delete_name, &state); 895 if (err == Z_OK) { 896 if (state > ZONE_STATE_INSTALLED) 897 return (Z_BAD_ZONE_STATE); 898 } else if (err != Z_NO_ZONE) { 899 return (err); 900 } 901 } 902 903 if ((err = setrootattr(handle, DTD_ATTR_NAME, name)) != Z_OK) { 904 /* 905 * Restore the deletename to whatever it was at the 906 * top of the routine, since we've had a failure. 907 */ 908 (void) strlcpy(handle->zone_dh_delete_name, old_delname, 909 sizeof (handle->zone_dh_delete_name)); 910 return (err); 911 } 912 913 return (Z_OK); 914 } 915 916 int 917 zonecfg_get_zonepath(zone_dochandle_t handle, char *path, size_t pathsize) 918 { 919 size_t len; 920 921 if ((len = strlcpy(path, zonecfg_root, pathsize)) >= pathsize) 922 return (Z_TOO_BIG); 923 return (getrootattr(handle, DTD_ATTR_ZONEPATH, path + len, 924 pathsize - len)); 925 } 926 927 int 928 zonecfg_set_zonepath(zone_dochandle_t handle, char *zonepath) 929 { 930 size_t len; 931 932 /* 933 * The user deals in absolute paths in the running global zone, but the 934 * internal configuration files deal with boot environment relative 935 * paths. Strip out the alternate root when specified. 936 */ 937 len = strlen(zonecfg_root); 938 if (strncmp(zonepath, zonecfg_root, len) != 0 || zonepath[len] != '/') 939 return (Z_BAD_PROPERTY); 940 zonepath += len; 941 return (setrootattr(handle, DTD_ATTR_ZONEPATH, zonepath)); 942 } 943 944 int 945 zonecfg_get_brand(zone_dochandle_t handle, char *brand, size_t brandsize) 946 { 947 int ret, sz; 948 949 ret = getrootattr(handle, DTD_ATTR_BRAND, brand, brandsize); 950 951 /* If the zone has no brand, it is native. */ 952 if (ret == Z_OK && brand[0] == '\0') { 953 sz = strlcpy(brand, NATIVE_BRAND_NAME, brandsize); 954 if (sz >= brandsize) 955 ret = Z_TOO_BIG; 956 else 957 ret = Z_OK; 958 } 959 960 return (ret); 961 } 962 963 int 964 zonecfg_set_brand(zone_dochandle_t handle, char *brand) 965 { 966 return (setrootattr(handle, DTD_ATTR_BRAND, brand)); 967 } 968 969 int 970 zonecfg_get_autoboot(zone_dochandle_t handle, boolean_t *autoboot) 971 { 972 char autobootstr[DTD_ENTITY_BOOL_LEN]; 973 int ret; 974 975 if ((ret = getrootattr(handle, DTD_ATTR_AUTOBOOT, autobootstr, 976 sizeof (autobootstr))) != Z_OK) 977 return (ret); 978 979 if (strcmp(autobootstr, DTD_ENTITY_TRUE) == 0) 980 *autoboot = B_TRUE; 981 else if (strcmp(autobootstr, DTD_ENTITY_FALSE) == 0) 982 *autoboot = B_FALSE; 983 else 984 ret = Z_BAD_PROPERTY; 985 return (ret); 986 } 987 988 int 989 zonecfg_set_autoboot(zone_dochandle_t handle, boolean_t autoboot) 990 { 991 return (setrootattr(handle, DTD_ATTR_AUTOBOOT, 992 autoboot ? DTD_ENTITY_TRUE : DTD_ENTITY_FALSE)); 993 } 994 995 int 996 zonecfg_get_pool(zone_dochandle_t handle, char *pool, size_t poolsize) 997 { 998 return (getrootattr(handle, DTD_ATTR_POOL, pool, poolsize)); 999 } 1000 1001 int 1002 zonecfg_set_pool(zone_dochandle_t handle, char *pool) 1003 { 1004 return (setrootattr(handle, DTD_ATTR_POOL, pool)); 1005 } 1006 1007 int 1008 zonecfg_get_limitpriv(zone_dochandle_t handle, char **limitpriv) 1009 { 1010 return (get_alloc_rootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv)); 1011 } 1012 1013 int 1014 zonecfg_set_limitpriv(zone_dochandle_t handle, char *limitpriv) 1015 { 1016 return (setrootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv)); 1017 } 1018 1019 int 1020 zonecfg_get_bootargs(zone_dochandle_t handle, char *bargs, size_t bargssize) 1021 { 1022 return (getrootattr(handle, DTD_ATTR_BOOTARGS, bargs, bargssize)); 1023 } 1024 1025 int 1026 zonecfg_set_bootargs(zone_dochandle_t handle, char *bargs) 1027 { 1028 return (setrootattr(handle, DTD_ATTR_BOOTARGS, bargs)); 1029 } 1030 1031 int 1032 zonecfg_get_sched_class(zone_dochandle_t handle, char *sched, size_t schedsize) 1033 { 1034 return (getrootattr(handle, DTD_ATTR_SCHED, sched, schedsize)); 1035 } 1036 1037 int 1038 zonecfg_set_sched(zone_dochandle_t handle, char *sched) 1039 { 1040 return (setrootattr(handle, DTD_ATTR_SCHED, sched)); 1041 } 1042 1043 /* 1044 * /etc/zones/index caches a vital piece of information which is also 1045 * in the <zonename>.xml file: the path to the zone. This is for performance, 1046 * since we need to walk all zonepath's in order to be able to detect conflicts 1047 * (see crosscheck_zonepaths() in the zoneadm command). 1048 * 1049 * An additional complexity is that when doing a rename, we'd like the entire 1050 * index update operation (rename, and potential state changes) to be atomic. 1051 * In general, the operation of this function should succeed or fail as 1052 * a unit. 1053 */ 1054 int 1055 zonecfg_refresh_index_file(zone_dochandle_t handle) 1056 { 1057 char name[ZONENAME_MAX], zonepath[MAXPATHLEN]; 1058 struct zoneent ze; 1059 int err; 1060 int opcode; 1061 char *zn; 1062 1063 bzero(&ze, sizeof (ze)); 1064 ze.zone_state = -1; /* Preserve existing state in index */ 1065 1066 if ((err = zonecfg_get_name(handle, name, sizeof (name))) != Z_OK) 1067 return (err); 1068 (void) strlcpy(ze.zone_name, name, sizeof (ze.zone_name)); 1069 1070 if ((err = zonecfg_get_zonepath(handle, zonepath, 1071 sizeof (zonepath))) != Z_OK) 1072 return (err); 1073 (void) strlcpy(ze.zone_path, zonepath + strlen(zonecfg_root), 1074 sizeof (ze.zone_path)); 1075 1076 if (is_renaming(handle)) { 1077 opcode = PZE_MODIFY; 1078 (void) strlcpy(ze.zone_name, handle->zone_dh_delete_name, 1079 sizeof (ze.zone_name)); 1080 (void) strlcpy(ze.zone_newname, name, sizeof (ze.zone_newname)); 1081 } else if (is_new(handle)) { 1082 FILE *cookie; 1083 /* 1084 * Be tolerant of the zone already existing in the index file, 1085 * since we might be forcibly overwriting an existing 1086 * configuration with a new one (for example 'create -F' 1087 * in zonecfg). 1088 */ 1089 opcode = PZE_ADD; 1090 cookie = setzoneent(); 1091 while ((zn = getzoneent(cookie)) != NULL) { 1092 if (strcmp(zn, name) == 0) { 1093 opcode = PZE_MODIFY; 1094 free(zn); 1095 break; 1096 } 1097 free(zn); 1098 } 1099 endzoneent(cookie); 1100 ze.zone_state = ZONE_STATE_CONFIGURED; 1101 } else { 1102 opcode = PZE_MODIFY; 1103 } 1104 1105 if ((err = putzoneent(&ze, opcode)) != Z_OK) 1106 return (err); 1107 1108 return (Z_OK); 1109 } 1110 1111 /* 1112 * The goal of this routine is to cause the index file update and the 1113 * document save to happen as an atomic operation. We do the document 1114 * first, saving a backup copy using a hard link; if that succeeds, we go 1115 * on to the index. If that fails, we roll the document back into place. 1116 * 1117 * Strategy: 1118 * 1119 * New zone 'foo' configuration: 1120 * Create tmpfile (zonecfg.xxxxxx) 1121 * Write XML to tmpfile 1122 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml) 1123 * Add entry to index file 1124 * If it fails, delete foo.xml, leaving nothing behind. 1125 * 1126 * Save existing zone 'foo': 1127 * Make backup of foo.xml -> .backup 1128 * Create tmpfile (zonecfg.xxxxxx) 1129 * Write XML to tmpfile 1130 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml) 1131 * Modify index file as needed 1132 * If it fails, recover from .backup -> foo.xml 1133 * 1134 * Rename 'foo' to 'bar': 1135 * Create tmpfile (zonecfg.xxxxxx) 1136 * Write XML to tmpfile 1137 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> bar.xml) 1138 * Add entry for 'bar' to index file, Remove entry for 'foo' (refresh) 1139 * If it fails, delete bar.xml; foo.xml is left behind. 1140 */ 1141 static int 1142 zonecfg_save_impl(zone_dochandle_t handle, char *filename) 1143 { 1144 char tmpfile[MAXPATHLEN]; 1145 char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN]; 1146 int tmpfd, err, valid; 1147 xmlValidCtxt cvp = { NULL }; 1148 boolean_t backup; 1149 1150 (void) strlcpy(tmpfile, filename, sizeof (tmpfile)); 1151 (void) dirname(tmpfile); 1152 (void) strlcat(tmpfile, _PATH_TMPFILE, sizeof (tmpfile)); 1153 1154 tmpfd = mkstemp(tmpfile); 1155 if (tmpfd == -1) { 1156 (void) unlink(tmpfile); 1157 return (Z_TEMP_FILE); 1158 } 1159 (void) close(tmpfd); 1160 1161 cvp.error = zonecfg_error_func; 1162 cvp.warning = zonecfg_error_func; 1163 1164 /* 1165 * We do a final validation of the document. Since the library has 1166 * malfunctioned if it fails to validate, we follow-up with an 1167 * assert() that the doc is valid. 1168 */ 1169 valid = xmlValidateDocument(&cvp, handle->zone_dh_doc); 1170 assert(valid != 0); 1171 1172 if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0) 1173 goto err; 1174 1175 (void) chmod(tmpfile, 0644); 1176 1177 /* 1178 * In the event we are doing a standard save, hard link a copy of the 1179 * original file in .backup.<pid>.filename so we can restore it if 1180 * something goes wrong. 1181 */ 1182 if (!is_new(handle) && !is_renaming(handle)) { 1183 backup = B_TRUE; 1184 1185 (void) strlcpy(bakdir, filename, sizeof (bakdir)); 1186 (void) strlcpy(bakbase, filename, sizeof (bakbase)); 1187 (void) snprintf(bakfile, sizeof (bakfile), "%s/.backup.%d.%s", 1188 dirname(bakdir), getpid(), basename(bakbase)); 1189 1190 if (link(filename, bakfile) == -1) { 1191 err = errno; 1192 (void) unlink(tmpfile); 1193 if (errno == EACCES) 1194 return (Z_ACCES); 1195 return (Z_MISC_FS); 1196 } 1197 } 1198 1199 /* 1200 * Move the new document over top of the old. 1201 * i.e.: zonecfg.XXXXXX -> myzone.xml 1202 */ 1203 if (rename(tmpfile, filename) == -1) { 1204 err = errno; 1205 (void) unlink(tmpfile); 1206 if (backup) 1207 (void) unlink(bakfile); 1208 if (err == EACCES) 1209 return (Z_ACCES); 1210 return (Z_MISC_FS); 1211 } 1212 1213 /* 1214 * If this is a snapshot, we're done-- don't add an index entry. 1215 */ 1216 if (is_snapshot(handle)) 1217 return (Z_OK); 1218 1219 /* now update the index file to reflect whatever we just did */ 1220 if ((err = zonecfg_refresh_index_file(handle)) != Z_OK) { 1221 if (backup) { 1222 /* 1223 * Try to restore from our backup. 1224 */ 1225 (void) unlink(filename); 1226 (void) rename(bakfile, filename); 1227 } else { 1228 /* 1229 * Either the zone is new, in which case we can delete 1230 * new.xml, or we're doing a rename, so ditto. 1231 */ 1232 assert(is_new(handle) || is_renaming(handle)); 1233 (void) unlink(filename); 1234 } 1235 return (Z_UPDATING_INDEX); 1236 } 1237 1238 if (backup) 1239 (void) unlink(bakfile); 1240 1241 return (Z_OK); 1242 1243 err: 1244 (void) unlink(tmpfile); 1245 return (Z_SAVING_FILE); 1246 } 1247 1248 int 1249 zonecfg_save(zone_dochandle_t handle) 1250 { 1251 char zname[ZONENAME_MAX], path[MAXPATHLEN]; 1252 char delpath[MAXPATHLEN]; 1253 int err = Z_SAVING_FILE; 1254 1255 if (zonecfg_check_handle(handle) != Z_OK) 1256 return (Z_BAD_HANDLE); 1257 1258 /* 1259 * We don't support saving snapshots or a tree containing a sw 1260 * inventory at this time. 1261 */ 1262 if (handle->zone_dh_snapshot || handle->zone_dh_sw_inv) 1263 return (Z_INVAL); 1264 1265 if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK) 1266 return (err); 1267 1268 if (!config_file_path(zname, path)) 1269 return (Z_MISC_FS); 1270 1271 addcomment(handle, "\n DO NOT EDIT THIS " 1272 "FILE. Use zonecfg(1M) instead.\n"); 1273 1274 err = zonecfg_save_impl(handle, path); 1275 1276 stripcomments(handle); 1277 1278 if (err != Z_OK) 1279 return (err); 1280 1281 handle->zone_dh_newzone = B_FALSE; 1282 1283 if (is_renaming(handle)) { 1284 if (config_file_path(handle->zone_dh_delete_name, delpath)) 1285 (void) unlink(delpath); 1286 handle->zone_dh_delete_name[0] = '\0'; 1287 } 1288 1289 return (Z_OK); 1290 } 1291 1292 int 1293 zonecfg_verify_save(zone_dochandle_t handle, char *filename) 1294 { 1295 int valid; 1296 1297 xmlValidCtxt cvp = { NULL }; 1298 1299 if (zonecfg_check_handle(handle) != Z_OK) 1300 return (Z_BAD_HANDLE); 1301 1302 cvp.error = zonecfg_error_func; 1303 cvp.warning = zonecfg_error_func; 1304 1305 /* 1306 * We do a final validation of the document. Since the library has 1307 * malfunctioned if it fails to validate, we follow-up with an 1308 * assert() that the doc is valid. 1309 */ 1310 valid = xmlValidateDocument(&cvp, handle->zone_dh_doc); 1311 assert(valid != 0); 1312 1313 if (xmlSaveFormatFile(filename, handle->zone_dh_doc, 1) <= 0) 1314 return (Z_SAVING_FILE); 1315 1316 return (Z_OK); 1317 } 1318 1319 int 1320 zonecfg_detach_save(zone_dochandle_t handle, uint_t flags) 1321 { 1322 char zname[ZONENAME_MAX]; 1323 char path[MAXPATHLEN]; 1324 char migpath[MAXPATHLEN]; 1325 xmlValidCtxt cvp = { NULL }; 1326 int err = Z_SAVING_FILE; 1327 int valid; 1328 1329 if (zonecfg_check_handle(handle) != Z_OK) 1330 return (Z_BAD_HANDLE); 1331 1332 /* 1333 * We can only detach if we have taken a sw inventory. 1334 */ 1335 if (!handle->zone_dh_sw_inv) 1336 return (Z_INVAL); 1337 1338 if (flags & ZONE_DRY_RUN) { 1339 (void) strlcpy(migpath, "-", sizeof (migpath)); 1340 } else { 1341 if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) 1342 != Z_OK) 1343 return (err); 1344 1345 if ((err = zone_get_zonepath(zname, path, sizeof (path))) 1346 != Z_OK) 1347 return (err); 1348 1349 if (snprintf(migpath, sizeof (migpath), "%s/%s", path, DETACHED) 1350 >= sizeof (migpath)) 1351 return (Z_NOMEM); 1352 } 1353 1354 if ((err = operation_prep(handle)) != Z_OK) 1355 return (err); 1356 1357 addcomment(handle, "\n DO NOT EDIT THIS FILE. " 1358 "Use zonecfg(1M) and zoneadm(1M) attach.\n"); 1359 1360 cvp.error = zonecfg_error_func; 1361 cvp.warning = zonecfg_error_func; 1362 1363 /* 1364 * We do a final validation of the document. Since the library has 1365 * malfunctioned if it fails to validate, we follow-up with an 1366 * assert() that the doc is valid. 1367 */ 1368 valid = xmlValidateDocument(&cvp, handle->zone_dh_doc); 1369 assert(valid != 0); 1370 1371 if (xmlSaveFormatFile(migpath, handle->zone_dh_doc, 1) <= 0) 1372 return (Z_SAVING_FILE); 1373 1374 if (!(flags & ZONE_DRY_RUN)) 1375 (void) chmod(migpath, 0644); 1376 1377 stripcomments(handle); 1378 1379 handle->zone_dh_newzone = B_FALSE; 1380 1381 return (Z_OK); 1382 } 1383 1384 boolean_t 1385 zonecfg_detached(const char *path) 1386 { 1387 char migpath[MAXPATHLEN]; 1388 struct stat buf; 1389 1390 if (snprintf(migpath, sizeof (migpath), "%s/%s", path, DETACHED) >= 1391 sizeof (migpath)) 1392 return (B_FALSE); 1393 1394 if (stat(migpath, &buf) != -1) 1395 return (B_TRUE); 1396 1397 return (B_FALSE); 1398 } 1399 1400 void 1401 zonecfg_rm_detached(zone_dochandle_t handle, boolean_t forced) 1402 { 1403 char zname[ZONENAME_MAX]; 1404 char path[MAXPATHLEN]; 1405 char detached[MAXPATHLEN]; 1406 char attached[MAXPATHLEN]; 1407 1408 if (zonecfg_check_handle(handle) != Z_OK) 1409 return; 1410 1411 if (zonecfg_get_name(handle, zname, sizeof (zname)) != Z_OK) 1412 return; 1413 1414 if (zone_get_zonepath(zname, path, sizeof (path)) != Z_OK) 1415 return; 1416 1417 (void) snprintf(detached, sizeof (detached), "%s/%s", path, DETACHED); 1418 (void) snprintf(attached, sizeof (attached), "%s/%s", path, 1419 ATTACH_FORCED); 1420 1421 if (forced) { 1422 (void) rename(detached, attached); 1423 } else { 1424 (void) unlink(attached); 1425 (void) unlink(detached); 1426 } 1427 } 1428 1429 /* 1430 * Special case: if access(2) fails with ENOENT, then try again using 1431 * ZONE_CONFIG_ROOT instead of config_file_path(zonename). This is how we 1432 * work around the case of a config file which has not been created yet: 1433 * the user will need access to the directory so use that as a heuristic. 1434 */ 1435 1436 int 1437 zonecfg_access(const char *zonename, int amode) 1438 { 1439 char path[MAXPATHLEN]; 1440 1441 if (!config_file_path(zonename, path)) 1442 return (Z_INVAL); 1443 if (access(path, amode) == 0) 1444 return (Z_OK); 1445 if (errno == ENOENT) { 1446 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root, 1447 ZONE_CONFIG_ROOT) >= sizeof (path)) 1448 return (Z_INVAL); 1449 if (access(path, amode) == 0) 1450 return (Z_OK); 1451 } 1452 if (errno == EACCES) 1453 return (Z_ACCES); 1454 if (errno == EINVAL) 1455 return (Z_INVAL); 1456 return (Z_MISC_FS); 1457 } 1458 1459 int 1460 zonecfg_create_snapshot(const char *zonename) 1461 { 1462 zone_dochandle_t handle; 1463 char path[MAXPATHLEN], zonepath[MAXPATHLEN], rpath[MAXPATHLEN]; 1464 int error = Z_OK, res; 1465 1466 if ((handle = zonecfg_init_handle()) == NULL) { 1467 return (Z_NOMEM); 1468 } 1469 1470 handle->zone_dh_newzone = B_TRUE; 1471 handle->zone_dh_snapshot = B_TRUE; 1472 1473 if ((error = zonecfg_get_handle(zonename, handle)) != Z_OK) 1474 goto out; 1475 if ((error = operation_prep(handle)) != Z_OK) 1476 goto out; 1477 error = zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)); 1478 if (error != Z_OK) 1479 goto out; 1480 if ((res = resolvepath(zonepath, rpath, sizeof (rpath))) == -1) { 1481 error = Z_RESOLVED_PATH; 1482 goto out; 1483 } 1484 /* 1485 * If the resolved path is not the same as the original path, then 1486 * save the resolved path in the snapshot, thus preventing any 1487 * potential problems down the line when zoneadmd goes to unmount 1488 * file systems and depends on initial string matches with resolved 1489 * paths. 1490 */ 1491 rpath[res] = '\0'; 1492 if (strcmp(zonepath, rpath) != 0) { 1493 if ((error = zonecfg_set_zonepath(handle, rpath)) != Z_OK) 1494 goto out; 1495 } 1496 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root, 1497 ZONE_SNAPSHOT_ROOT) >= sizeof (path)) { 1498 error = Z_MISC_FS; 1499 goto out; 1500 } 1501 if ((mkdir(path, S_IRWXU) == -1) && (errno != EEXIST)) { 1502 error = Z_MISC_FS; 1503 goto out; 1504 } 1505 1506 if (!snap_file_path(zonename, path)) { 1507 error = Z_MISC_FS; 1508 goto out; 1509 } 1510 1511 addcomment(handle, "\n DO NOT EDIT THIS FILE. " 1512 "It is a snapshot of running zone state.\n"); 1513 1514 error = zonecfg_save_impl(handle, path); 1515 1516 stripcomments(handle); 1517 1518 out: 1519 zonecfg_fini_handle(handle); 1520 return (error); 1521 } 1522 1523 int 1524 zonecfg_get_iptype(zone_dochandle_t handle, zone_iptype_t *iptypep) 1525 { 1526 char property[10]; /* 10 is big enough for "shared"/"exclusive" */ 1527 int err; 1528 1529 err = getrootattr(handle, DTD_ATTR_IPTYPE, property, sizeof (property)); 1530 if (err == Z_BAD_PROPERTY) { 1531 /* Return default value */ 1532 *iptypep = ZS_SHARED; 1533 return (Z_OK); 1534 } else if (err != Z_OK) { 1535 return (err); 1536 } 1537 1538 if (strlen(property) == 0 || 1539 strcmp(property, "shared") == 0) 1540 *iptypep = ZS_SHARED; 1541 else if (strcmp(property, "exclusive") == 0) 1542 *iptypep = ZS_EXCLUSIVE; 1543 else 1544 return (Z_INVAL); 1545 1546 return (Z_OK); 1547 } 1548 1549 int 1550 zonecfg_set_iptype(zone_dochandle_t handle, zone_iptype_t iptype) 1551 { 1552 xmlNodePtr cur; 1553 1554 if (handle == NULL) 1555 return (Z_INVAL); 1556 1557 cur = xmlDocGetRootElement(handle->zone_dh_doc); 1558 if (cur == NULL) { 1559 return (Z_EMPTY_DOCUMENT); 1560 } 1561 1562 if (xmlStrcmp(cur->name, DTD_ELEM_ZONE) != 0) { 1563 return (Z_WRONG_DOC_TYPE); 1564 } 1565 switch (iptype) { 1566 case ZS_SHARED: 1567 /* 1568 * Since "shared" is the default, we don't write it to the 1569 * configuration file, so that it's easier to migrate those 1570 * zones elsewhere, eg., to systems which are not IP-Instances 1571 * aware. 1572 * xmlUnsetProp only fails when the attribute doesn't exist, 1573 * which we don't care. 1574 */ 1575 (void) xmlUnsetProp(cur, DTD_ATTR_IPTYPE); 1576 break; 1577 case ZS_EXCLUSIVE: 1578 if (xmlSetProp(cur, DTD_ATTR_IPTYPE, 1579 (const xmlChar *) "exclusive") == NULL) 1580 return (Z_INVAL); 1581 break; 1582 } 1583 return (Z_OK); 1584 } 1585 1586 static int 1587 newprop(xmlNodePtr node, const xmlChar *attrname, char *src) 1588 { 1589 xmlAttrPtr newattr; 1590 1591 newattr = xmlNewProp(node, attrname, (xmlChar *)src); 1592 if (newattr == NULL) { 1593 xmlUnlinkNode(node); 1594 xmlFreeNode(node); 1595 return (Z_BAD_PROPERTY); 1596 } 1597 return (Z_OK); 1598 } 1599 1600 static int 1601 zonecfg_add_filesystem_core(zone_dochandle_t handle, struct zone_fstab *tabptr) 1602 { 1603 xmlNodePtr newnode, cur = handle->zone_dh_cur, options_node; 1604 zone_fsopt_t *ptr; 1605 int err; 1606 1607 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_FS, NULL); 1608 if ((err = newprop(newnode, DTD_ATTR_SPECIAL, 1609 tabptr->zone_fs_special)) != Z_OK) 1610 return (err); 1611 if (tabptr->zone_fs_raw[0] != '\0' && 1612 (err = newprop(newnode, DTD_ATTR_RAW, tabptr->zone_fs_raw)) != Z_OK) 1613 return (err); 1614 if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK) 1615 return (err); 1616 if ((err = newprop(newnode, DTD_ATTR_TYPE, 1617 tabptr->zone_fs_type)) != Z_OK) 1618 return (err); 1619 if (tabptr->zone_fs_options != NULL) { 1620 for (ptr = tabptr->zone_fs_options; ptr != NULL; 1621 ptr = ptr->zone_fsopt_next) { 1622 options_node = xmlNewTextChild(newnode, NULL, 1623 DTD_ELEM_FSOPTION, NULL); 1624 if ((err = newprop(options_node, DTD_ATTR_NAME, 1625 ptr->zone_fsopt_opt)) != Z_OK) 1626 return (err); 1627 } 1628 } 1629 return (Z_OK); 1630 } 1631 1632 int 1633 zonecfg_add_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr) 1634 { 1635 int err; 1636 1637 if (tabptr == NULL) 1638 return (Z_INVAL); 1639 1640 if ((err = operation_prep(handle)) != Z_OK) 1641 return (err); 1642 1643 if ((err = zonecfg_add_filesystem_core(handle, tabptr)) != Z_OK) 1644 return (err); 1645 1646 return (Z_OK); 1647 } 1648 1649 static int 1650 zonecfg_add_ipd_core(zone_dochandle_t handle, struct zone_fstab *tabptr) 1651 { 1652 xmlNodePtr newnode, cur = handle->zone_dh_cur; 1653 int err; 1654 1655 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_IPD, NULL); 1656 if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK) 1657 return (err); 1658 return (Z_OK); 1659 } 1660 1661 int 1662 zonecfg_add_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr) 1663 { 1664 int err; 1665 1666 if (tabptr == NULL) 1667 return (Z_INVAL); 1668 1669 if ((err = operation_prep(handle)) != Z_OK) 1670 return (err); 1671 1672 if ((err = zonecfg_add_ipd_core(handle, tabptr)) != Z_OK) 1673 return (err); 1674 1675 return (Z_OK); 1676 } 1677 1678 int 1679 zonecfg_add_fs_option(struct zone_fstab *tabptr, char *option) 1680 { 1681 zone_fsopt_t *last, *old, *new; 1682 1683 last = tabptr->zone_fs_options; 1684 for (old = last; old != NULL; old = old->zone_fsopt_next) 1685 last = old; /* walk to the end of the list */ 1686 new = (zone_fsopt_t *)malloc(sizeof (zone_fsopt_t)); 1687 if (new == NULL) 1688 return (Z_NOMEM); 1689 (void) strlcpy(new->zone_fsopt_opt, option, 1690 sizeof (new->zone_fsopt_opt)); 1691 new->zone_fsopt_next = NULL; 1692 if (last == NULL) 1693 tabptr->zone_fs_options = new; 1694 else 1695 last->zone_fsopt_next = new; 1696 return (Z_OK); 1697 } 1698 1699 int 1700 zonecfg_remove_fs_option(struct zone_fstab *tabptr, char *option) 1701 { 1702 zone_fsopt_t *last, *this, *next; 1703 1704 last = tabptr->zone_fs_options; 1705 for (this = last; this != NULL; this = this->zone_fsopt_next) { 1706 if (strcmp(this->zone_fsopt_opt, option) == 0) { 1707 next = this->zone_fsopt_next; 1708 if (this == tabptr->zone_fs_options) 1709 tabptr->zone_fs_options = next; 1710 else 1711 last->zone_fsopt_next = next; 1712 free(this); 1713 return (Z_OK); 1714 } else 1715 last = this; 1716 } 1717 return (Z_NO_PROPERTY_ID); 1718 } 1719 1720 void 1721 zonecfg_free_fs_option_list(zone_fsopt_t *list) 1722 { 1723 zone_fsopt_t *this, *next; 1724 1725 for (this = list; this != NULL; this = next) { 1726 next = this->zone_fsopt_next; 1727 free(this); 1728 } 1729 } 1730 1731 void 1732 zonecfg_free_rctl_value_list(struct zone_rctlvaltab *valtab) 1733 { 1734 if (valtab == NULL) 1735 return; 1736 zonecfg_free_rctl_value_list(valtab->zone_rctlval_next); 1737 free(valtab); 1738 } 1739 1740 static boolean_t 1741 match_prop(xmlNodePtr cur, const xmlChar *attr, char *user_prop) 1742 { 1743 xmlChar *gotten_prop; 1744 int prop_result; 1745 1746 gotten_prop = xmlGetProp(cur, attr); 1747 if (gotten_prop == NULL) /* shouldn't happen */ 1748 return (B_FALSE); 1749 prop_result = xmlStrcmp(gotten_prop, (const xmlChar *) user_prop); 1750 xmlFree(gotten_prop); 1751 return ((prop_result == 0)); 1752 } 1753 1754 static int 1755 zonecfg_delete_filesystem_core(zone_dochandle_t handle, 1756 struct zone_fstab *tabptr) 1757 { 1758 xmlNodePtr cur = handle->zone_dh_cur; 1759 boolean_t dir_match, spec_match, raw_match, type_match; 1760 1761 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1762 if (xmlStrcmp(cur->name, DTD_ELEM_FS)) 1763 continue; 1764 dir_match = match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir); 1765 spec_match = match_prop(cur, DTD_ATTR_SPECIAL, 1766 tabptr->zone_fs_special); 1767 raw_match = match_prop(cur, DTD_ATTR_RAW, 1768 tabptr->zone_fs_raw); 1769 type_match = match_prop(cur, DTD_ATTR_TYPE, 1770 tabptr->zone_fs_type); 1771 if (dir_match && spec_match && raw_match && type_match) { 1772 xmlUnlinkNode(cur); 1773 xmlFreeNode(cur); 1774 return (Z_OK); 1775 } 1776 } 1777 return (Z_NO_RESOURCE_ID); 1778 } 1779 1780 int 1781 zonecfg_delete_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr) 1782 { 1783 int err; 1784 1785 if (tabptr == NULL) 1786 return (Z_INVAL); 1787 1788 if ((err = operation_prep(handle)) != Z_OK) 1789 return (err); 1790 1791 if ((err = zonecfg_delete_filesystem_core(handle, tabptr)) != Z_OK) 1792 return (err); 1793 1794 return (Z_OK); 1795 } 1796 1797 int 1798 zonecfg_modify_filesystem( 1799 zone_dochandle_t handle, 1800 struct zone_fstab *oldtabptr, 1801 struct zone_fstab *newtabptr) 1802 { 1803 int err; 1804 1805 if (oldtabptr == NULL || newtabptr == NULL) 1806 return (Z_INVAL); 1807 1808 if ((err = operation_prep(handle)) != Z_OK) 1809 return (err); 1810 1811 if ((err = zonecfg_delete_filesystem_core(handle, oldtabptr)) != Z_OK) 1812 return (err); 1813 1814 if ((err = zonecfg_add_filesystem_core(handle, newtabptr)) != Z_OK) 1815 return (err); 1816 1817 return (Z_OK); 1818 } 1819 1820 static int 1821 zonecfg_delete_ipd_core(zone_dochandle_t handle, struct zone_fstab *tabptr) 1822 { 1823 xmlNodePtr cur = handle->zone_dh_cur; 1824 1825 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1826 if (xmlStrcmp(cur->name, DTD_ELEM_IPD)) 1827 continue; 1828 if (match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir)) { 1829 xmlUnlinkNode(cur); 1830 xmlFreeNode(cur); 1831 return (Z_OK); 1832 } 1833 } 1834 return (Z_NO_RESOURCE_ID); 1835 } 1836 1837 int 1838 zonecfg_delete_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr) 1839 { 1840 int err; 1841 1842 if (tabptr == NULL) 1843 return (Z_INVAL); 1844 1845 if ((err = operation_prep(handle)) != Z_OK) 1846 return (err); 1847 1848 if ((err = zonecfg_delete_ipd_core(handle, tabptr)) != Z_OK) 1849 return (err); 1850 1851 return (Z_OK); 1852 } 1853 1854 int 1855 zonecfg_modify_ipd(zone_dochandle_t handle, struct zone_fstab *oldtabptr, 1856 struct zone_fstab *newtabptr) 1857 { 1858 int err; 1859 1860 if (oldtabptr == NULL || newtabptr == NULL) 1861 return (Z_INVAL); 1862 1863 if ((err = operation_prep(handle)) != Z_OK) 1864 return (err); 1865 1866 if ((err = zonecfg_delete_ipd_core(handle, oldtabptr)) != Z_OK) 1867 return (err); 1868 1869 if ((err = zonecfg_add_ipd_core(handle, newtabptr)) != Z_OK) 1870 return (err); 1871 1872 return (Z_OK); 1873 } 1874 1875 int 1876 zonecfg_lookup_filesystem( 1877 zone_dochandle_t handle, 1878 struct zone_fstab *tabptr) 1879 { 1880 xmlNodePtr cur, options, firstmatch; 1881 int err; 1882 char dirname[MAXPATHLEN], special[MAXPATHLEN], raw[MAXPATHLEN]; 1883 char type[FSTYPSZ]; 1884 char options_str[MAX_MNTOPT_STR]; 1885 1886 if (tabptr == NULL) 1887 return (Z_INVAL); 1888 1889 if ((err = operation_prep(handle)) != Z_OK) 1890 return (err); 1891 1892 /* 1893 * Walk the list of children looking for matches on any properties 1894 * specified in the fstab parameter. If more than one resource 1895 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return 1896 * Z_NO_RESOURCE_ID. 1897 */ 1898 cur = handle->zone_dh_cur; 1899 firstmatch = NULL; 1900 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1901 if (xmlStrcmp(cur->name, DTD_ELEM_FS)) 1902 continue; 1903 if (strlen(tabptr->zone_fs_dir) > 0) { 1904 if ((fetchprop(cur, DTD_ATTR_DIR, dirname, 1905 sizeof (dirname)) == Z_OK) && 1906 (strcmp(tabptr->zone_fs_dir, dirname) == 0)) { 1907 if (firstmatch == NULL) 1908 firstmatch = cur; 1909 else 1910 return (Z_INSUFFICIENT_SPEC); 1911 } 1912 } 1913 if (strlen(tabptr->zone_fs_special) > 0) { 1914 if ((fetchprop(cur, DTD_ATTR_SPECIAL, special, 1915 sizeof (special)) == Z_OK)) { 1916 if (strcmp(tabptr->zone_fs_special, 1917 special) == 0) { 1918 if (firstmatch == NULL) 1919 firstmatch = cur; 1920 else if (firstmatch != cur) 1921 return (Z_INSUFFICIENT_SPEC); 1922 } else { 1923 /* 1924 * If another property matched but this 1925 * one doesn't then reset firstmatch. 1926 */ 1927 if (firstmatch == cur) 1928 firstmatch = NULL; 1929 } 1930 } 1931 } 1932 if (strlen(tabptr->zone_fs_raw) > 0) { 1933 if ((fetchprop(cur, DTD_ATTR_RAW, raw, 1934 sizeof (raw)) == Z_OK)) { 1935 if (strcmp(tabptr->zone_fs_raw, raw) == 0) { 1936 if (firstmatch == NULL) 1937 firstmatch = cur; 1938 else if (firstmatch != cur) 1939 return (Z_INSUFFICIENT_SPEC); 1940 } else { 1941 /* 1942 * If another property matched but this 1943 * one doesn't then reset firstmatch. 1944 */ 1945 if (firstmatch == cur) 1946 firstmatch = NULL; 1947 } 1948 } 1949 } 1950 if (strlen(tabptr->zone_fs_type) > 0) { 1951 if ((fetchprop(cur, DTD_ATTR_TYPE, type, 1952 sizeof (type)) == Z_OK)) { 1953 if (strcmp(tabptr->zone_fs_type, type) == 0) { 1954 if (firstmatch == NULL) 1955 firstmatch = cur; 1956 else if (firstmatch != cur) 1957 return (Z_INSUFFICIENT_SPEC); 1958 } else { 1959 /* 1960 * If another property matched but this 1961 * one doesn't then reset firstmatch. 1962 */ 1963 if (firstmatch == cur) 1964 firstmatch = NULL; 1965 } 1966 } 1967 } 1968 } 1969 1970 if (firstmatch == NULL) 1971 return (Z_NO_RESOURCE_ID); 1972 1973 cur = firstmatch; 1974 1975 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 1976 sizeof (tabptr->zone_fs_dir))) != Z_OK) 1977 return (err); 1978 1979 if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special, 1980 sizeof (tabptr->zone_fs_special))) != Z_OK) 1981 return (err); 1982 1983 if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw, 1984 sizeof (tabptr->zone_fs_raw))) != Z_OK) 1985 return (err); 1986 1987 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type, 1988 sizeof (tabptr->zone_fs_type))) != Z_OK) 1989 return (err); 1990 1991 /* options are optional */ 1992 tabptr->zone_fs_options = NULL; 1993 for (options = cur->xmlChildrenNode; options != NULL; 1994 options = options->next) { 1995 if ((fetchprop(options, DTD_ATTR_NAME, options_str, 1996 sizeof (options_str)) != Z_OK)) 1997 break; 1998 if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK) 1999 break; 2000 } 2001 return (Z_OK); 2002 } 2003 2004 int 2005 zonecfg_lookup_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr) 2006 { 2007 xmlNodePtr cur, match; 2008 int err; 2009 char dirname[MAXPATHLEN]; 2010 2011 if (tabptr == NULL) 2012 return (Z_INVAL); 2013 2014 if ((err = operation_prep(handle)) != Z_OK) 2015 return (err); 2016 2017 /* 2018 * General algorithm: 2019 * Walk the list of children looking for matches on any properties 2020 * specified in the fstab parameter. If more than one resource 2021 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return 2022 * Z_NO_RESOURCE_ID. 2023 */ 2024 cur = handle->zone_dh_cur; 2025 match = NULL; 2026 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2027 if (xmlStrcmp(cur->name, DTD_ELEM_IPD)) 2028 continue; 2029 if (strlen(tabptr->zone_fs_dir) > 0) { 2030 if ((fetchprop(cur, DTD_ATTR_DIR, dirname, 2031 sizeof (dirname)) == Z_OK) && 2032 (strcmp(tabptr->zone_fs_dir, dirname) == 0)) { 2033 if (match == NULL) 2034 match = cur; 2035 else 2036 return (Z_INSUFFICIENT_SPEC); 2037 } 2038 } 2039 } 2040 2041 if (match == NULL) 2042 return (Z_NO_RESOURCE_ID); 2043 2044 cur = match; 2045 2046 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 2047 sizeof (tabptr->zone_fs_dir))) != Z_OK) 2048 return (err); 2049 2050 return (Z_OK); 2051 } 2052 2053 /* 2054 * Compare two IP addresses in string form. Allow for the possibility that 2055 * one might have "/<prefix-length>" at the end: allow a match on just the 2056 * IP address (or host name) part. 2057 */ 2058 2059 boolean_t 2060 zonecfg_same_net_address(char *a1, char *a2) 2061 { 2062 char *slashp, *slashp1, *slashp2; 2063 int result; 2064 2065 if (strcmp(a1, a2) == 0) 2066 return (B_TRUE); 2067 2068 /* 2069 * If neither has a slash or both do, they need to match to be 2070 * considered the same, but they did not match above, so fail. 2071 */ 2072 slashp1 = strchr(a1, '/'); 2073 slashp2 = strchr(a2, '/'); 2074 if ((slashp1 == NULL && slashp2 == NULL) || 2075 (slashp1 != NULL && slashp2 != NULL)) 2076 return (B_FALSE); 2077 2078 /* 2079 * Only one had a slash: pick that one, zero out the slash, compare 2080 * the "address only" strings, restore the slash, and return the 2081 * result of the comparison. 2082 */ 2083 slashp = (slashp1 == NULL) ? slashp2 : slashp1; 2084 *slashp = '\0'; 2085 result = strcmp(a1, a2); 2086 *slashp = '/'; 2087 return ((result == 0)); 2088 } 2089 2090 int 2091 zonecfg_valid_net_address(char *address, struct lifreq *lifr) 2092 { 2093 struct sockaddr_in *sin4; 2094 struct sockaddr_in6 *sin6; 2095 struct addrinfo hints, *result; 2096 char *slashp = strchr(address, '/'); 2097 2098 bzero(lifr, sizeof (struct lifreq)); 2099 sin4 = (struct sockaddr_in *)&lifr->lifr_addr; 2100 sin6 = (struct sockaddr_in6 *)&lifr->lifr_addr; 2101 if (slashp != NULL) 2102 *slashp = '\0'; 2103 if (inet_pton(AF_INET, address, &sin4->sin_addr) == 1) { 2104 sin4->sin_family = AF_INET; 2105 } else if (inet_pton(AF_INET6, address, &sin6->sin6_addr) == 1) { 2106 if (slashp == NULL) 2107 return (Z_IPV6_ADDR_PREFIX_LEN); 2108 sin6->sin6_family = AF_INET6; 2109 } else { 2110 /* "address" may be a host name */ 2111 (void) memset(&hints, 0, sizeof (hints)); 2112 hints.ai_family = PF_INET; 2113 if (getaddrinfo(address, NULL, &hints, &result) != 0) 2114 return (Z_BOGUS_ADDRESS); 2115 sin4->sin_family = result->ai_family; 2116 2117 (void) memcpy(&sin4->sin_addr, 2118 /* LINTED E_BAD_PTR_CAST_ALIGN */ 2119 &((struct sockaddr_in *)result->ai_addr)->sin_addr, 2120 sizeof (struct in_addr)); 2121 2122 freeaddrinfo(result); 2123 } 2124 return (Z_OK); 2125 } 2126 2127 boolean_t 2128 zonecfg_ifname_exists(sa_family_t af, char *ifname) 2129 { 2130 struct lifreq lifr; 2131 int so; 2132 int save_errno; 2133 2134 (void) memset(&lifr, 0, sizeof (lifr)); 2135 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 2136 lifr.lifr_addr.ss_family = af; 2137 if ((so = socket(af, SOCK_DGRAM, 0)) < 0) { 2138 /* Odd - can't tell if the ifname exists */ 2139 return (B_FALSE); 2140 } 2141 if (ioctl(so, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 2142 save_errno = errno; 2143 (void) close(so); 2144 errno = save_errno; 2145 return (B_FALSE); 2146 } 2147 (void) close(so); 2148 return (B_TRUE); 2149 } 2150 2151 int 2152 zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 2153 { 2154 xmlNodePtr cur, firstmatch; 2155 int err; 2156 char address[INET6_ADDRSTRLEN], physical[LIFNAMSIZ]; 2157 2158 if (tabptr == NULL) 2159 return (Z_INVAL); 2160 2161 if ((err = operation_prep(handle)) != Z_OK) 2162 return (err); 2163 2164 cur = handle->zone_dh_cur; 2165 firstmatch = NULL; 2166 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2167 if (xmlStrcmp(cur->name, DTD_ELEM_NET)) 2168 continue; 2169 if (strlen(tabptr->zone_nwif_physical) > 0) { 2170 if ((fetchprop(cur, DTD_ATTR_PHYSICAL, physical, 2171 sizeof (physical)) == Z_OK) && 2172 (strcmp(tabptr->zone_nwif_physical, 2173 physical) == 0)) { 2174 if (firstmatch == NULL) 2175 firstmatch = cur; 2176 else 2177 return (Z_INSUFFICIENT_SPEC); 2178 } 2179 } 2180 if (strlen(tabptr->zone_nwif_address) > 0) { 2181 if ((fetchprop(cur, DTD_ATTR_ADDRESS, address, 2182 sizeof (address)) == Z_OK)) { 2183 if (zonecfg_same_net_address( 2184 tabptr->zone_nwif_address, address)) { 2185 if (firstmatch == NULL) 2186 firstmatch = cur; 2187 else if (firstmatch != cur) 2188 return (Z_INSUFFICIENT_SPEC); 2189 } else { 2190 /* 2191 * If another property matched but this 2192 * one doesn't then reset firstmatch. 2193 */ 2194 if (firstmatch == cur) 2195 firstmatch = NULL; 2196 } 2197 } 2198 } 2199 } 2200 if (firstmatch == NULL) 2201 return (Z_NO_RESOURCE_ID); 2202 2203 cur = firstmatch; 2204 2205 if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical, 2206 sizeof (tabptr->zone_nwif_physical))) != Z_OK) 2207 return (err); 2208 2209 if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address, 2210 sizeof (tabptr->zone_nwif_address))) != Z_OK) 2211 return (err); 2212 2213 if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER, 2214 tabptr->zone_nwif_defrouter, 2215 sizeof (tabptr->zone_nwif_defrouter))) != Z_OK) 2216 return (err); 2217 2218 return (Z_OK); 2219 } 2220 2221 static int 2222 zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 2223 { 2224 xmlNodePtr newnode, cur = handle->zone_dh_cur; 2225 int err; 2226 2227 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL); 2228 if ((err = newprop(newnode, DTD_ATTR_ADDRESS, 2229 tabptr->zone_nwif_address)) != Z_OK) 2230 return (err); 2231 if ((err = newprop(newnode, DTD_ATTR_PHYSICAL, 2232 tabptr->zone_nwif_physical)) != Z_OK) 2233 return (err); 2234 /* 2235 * Do not add this property when it is not set, for backwards 2236 * compatibility and because it is optional. 2237 */ 2238 if ((strlen(tabptr->zone_nwif_defrouter) > 0) && 2239 ((err = newprop(newnode, DTD_ATTR_DEFROUTER, 2240 tabptr->zone_nwif_defrouter)) != Z_OK)) 2241 return (err); 2242 return (Z_OK); 2243 } 2244 2245 int 2246 zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 2247 { 2248 int err; 2249 2250 if (tabptr == NULL) 2251 return (Z_INVAL); 2252 2253 if ((err = operation_prep(handle)) != Z_OK) 2254 return (err); 2255 2256 if ((err = zonecfg_add_nwif_core(handle, tabptr)) != Z_OK) 2257 return (err); 2258 2259 return (Z_OK); 2260 } 2261 2262 static int 2263 zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 2264 { 2265 xmlNodePtr cur = handle->zone_dh_cur; 2266 boolean_t addr_match, phys_match; 2267 2268 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2269 if (xmlStrcmp(cur->name, DTD_ELEM_NET)) 2270 continue; 2271 2272 addr_match = match_prop(cur, DTD_ATTR_ADDRESS, 2273 tabptr->zone_nwif_address); 2274 phys_match = match_prop(cur, DTD_ATTR_PHYSICAL, 2275 tabptr->zone_nwif_physical); 2276 2277 if (addr_match && phys_match) { 2278 xmlUnlinkNode(cur); 2279 xmlFreeNode(cur); 2280 return (Z_OK); 2281 } 2282 } 2283 return (Z_NO_RESOURCE_ID); 2284 } 2285 2286 int 2287 zonecfg_delete_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 2288 { 2289 int err; 2290 2291 if (tabptr == NULL) 2292 return (Z_INVAL); 2293 2294 if ((err = operation_prep(handle)) != Z_OK) 2295 return (err); 2296 2297 if ((err = zonecfg_delete_nwif_core(handle, tabptr)) != Z_OK) 2298 return (err); 2299 2300 return (Z_OK); 2301 } 2302 2303 int 2304 zonecfg_modify_nwif( 2305 zone_dochandle_t handle, 2306 struct zone_nwiftab *oldtabptr, 2307 struct zone_nwiftab *newtabptr) 2308 { 2309 int err; 2310 2311 if (oldtabptr == NULL || newtabptr == NULL) 2312 return (Z_INVAL); 2313 2314 if ((err = operation_prep(handle)) != Z_OK) 2315 return (err); 2316 2317 if ((err = zonecfg_delete_nwif_core(handle, oldtabptr)) != Z_OK) 2318 return (err); 2319 2320 if ((err = zonecfg_add_nwif_core(handle, newtabptr)) != Z_OK) 2321 return (err); 2322 2323 return (Z_OK); 2324 } 2325 2326 int 2327 zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) 2328 { 2329 xmlNodePtr cur, firstmatch; 2330 int err; 2331 char match[MAXPATHLEN]; 2332 2333 if (tabptr == NULL) 2334 return (Z_INVAL); 2335 2336 if ((err = operation_prep(handle)) != Z_OK) 2337 return (err); 2338 2339 cur = handle->zone_dh_cur; 2340 firstmatch = NULL; 2341 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2342 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) 2343 continue; 2344 if (strlen(tabptr->zone_dev_match) == 0) 2345 continue; 2346 2347 if ((fetchprop(cur, DTD_ATTR_MATCH, match, 2348 sizeof (match)) == Z_OK)) { 2349 if (strcmp(tabptr->zone_dev_match, 2350 match) == 0) { 2351 if (firstmatch == NULL) 2352 firstmatch = cur; 2353 else if (firstmatch != cur) 2354 return (Z_INSUFFICIENT_SPEC); 2355 } else { 2356 /* 2357 * If another property matched but this 2358 * one doesn't then reset firstmatch. 2359 */ 2360 if (firstmatch == cur) 2361 firstmatch = NULL; 2362 } 2363 } 2364 } 2365 if (firstmatch == NULL) 2366 return (Z_NO_RESOURCE_ID); 2367 2368 cur = firstmatch; 2369 2370 if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match, 2371 sizeof (tabptr->zone_dev_match))) != Z_OK) 2372 return (err); 2373 2374 return (Z_OK); 2375 } 2376 2377 static int 2378 zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr) 2379 { 2380 xmlNodePtr newnode, cur = handle->zone_dh_cur; 2381 int err; 2382 2383 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL); 2384 2385 if ((err = newprop(newnode, DTD_ATTR_MATCH, 2386 tabptr->zone_dev_match)) != Z_OK) 2387 return (err); 2388 2389 return (Z_OK); 2390 } 2391 2392 int 2393 zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) 2394 { 2395 int err; 2396 2397 if (tabptr == NULL) 2398 return (Z_INVAL); 2399 2400 if ((err = operation_prep(handle)) != Z_OK) 2401 return (err); 2402 2403 if ((err = zonecfg_add_dev_core(handle, tabptr)) != Z_OK) 2404 return (err); 2405 2406 return (Z_OK); 2407 } 2408 2409 static int 2410 zonecfg_delete_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr) 2411 { 2412 xmlNodePtr cur = handle->zone_dh_cur; 2413 int match_match; 2414 2415 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2416 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) 2417 continue; 2418 2419 match_match = match_prop(cur, DTD_ATTR_MATCH, 2420 tabptr->zone_dev_match); 2421 2422 if (match_match) { 2423 xmlUnlinkNode(cur); 2424 xmlFreeNode(cur); 2425 return (Z_OK); 2426 } 2427 } 2428 return (Z_NO_RESOURCE_ID); 2429 } 2430 2431 int 2432 zonecfg_delete_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) 2433 { 2434 int err; 2435 2436 if (tabptr == NULL) 2437 return (Z_INVAL); 2438 2439 if ((err = operation_prep(handle)) != Z_OK) 2440 return (err); 2441 2442 if ((err = zonecfg_delete_dev_core(handle, tabptr)) != Z_OK) 2443 return (err); 2444 2445 return (Z_OK); 2446 } 2447 2448 int 2449 zonecfg_modify_dev( 2450 zone_dochandle_t handle, 2451 struct zone_devtab *oldtabptr, 2452 struct zone_devtab *newtabptr) 2453 { 2454 int err; 2455 2456 if (oldtabptr == NULL || newtabptr == NULL) 2457 return (Z_INVAL); 2458 2459 if ((err = operation_prep(handle)) != Z_OK) 2460 return (err); 2461 2462 if ((err = zonecfg_delete_dev_core(handle, oldtabptr)) != Z_OK) 2463 return (err); 2464 2465 if ((err = zonecfg_add_dev_core(handle, newtabptr)) != Z_OK) 2466 return (err); 2467 2468 return (Z_OK); 2469 } 2470 2471 /* Lock to serialize all zonecfg_devwalks */ 2472 static pthread_mutex_t zonecfg_devwalk_lock = PTHREAD_MUTEX_INITIALIZER; 2473 /* 2474 * Global variables used to pass data from zonecfg_devwalk to the nftw 2475 * call-back (zonecfg_devwalk_cb). g_devwalk_data is really the void* 2476 * parameter and g_devwalk_cb is really the *cb parameter from zonecfg_devwalk. 2477 */ 2478 static void *g_devwalk_data; 2479 static int (*g_devwalk_cb)(const char *, uid_t, gid_t, mode_t, const char *, 2480 void *); 2481 static size_t g_devwalk_skip_prefix; 2482 2483 /* 2484 * This is the nftw call-back function used by zonecfg_devwalk. It is 2485 * responsible for calling the actual call-back that is passed in to 2486 * zonecfg_devwalk as the *cb argument. 2487 */ 2488 /* ARGSUSED2 */ 2489 static int 2490 zonecfg_devwalk_cb(const char *path, const struct stat *st, int f, 2491 struct FTW *ftw) 2492 { 2493 acl_t *acl; 2494 char *acl_txt = NULL; 2495 2496 /* skip all but character and block devices */ 2497 if (!S_ISBLK(st->st_mode) && !S_ISCHR(st->st_mode)) 2498 return (0); 2499 2500 if ((acl_get(path, ACL_NO_TRIVIAL, &acl) == 0) && 2501 acl != NULL) { 2502 acl_txt = acl_totext(acl, ACL_NORESOLVE); 2503 acl_free(acl); 2504 } 2505 2506 if (strlen(path) <= g_devwalk_skip_prefix) 2507 return (0); 2508 2509 g_devwalk_cb(path + g_devwalk_skip_prefix, st->st_uid, st->st_gid, 2510 st->st_mode & S_IAMB, acl_txt != NULL ? acl_txt : "", 2511 g_devwalk_data); 2512 free(acl_txt); 2513 return (0); 2514 } 2515 2516 /* 2517 * Walk the dev tree for the zone specified by hdl and call the call-back (cb) 2518 * function for each entry in the tree. The call-back will be passed the 2519 * name, uid, gid, mode, acl string and the void *data input parameter 2520 * for each dev entry. 2521 * 2522 * Data is passed to the zonecfg_devwalk_cb through the global variables 2523 * g_devwalk_data, *g_devwalk_cb, and g_devwalk_skip_prefix. The 2524 * zonecfg_devwalk_cb function will actually call *cb. 2525 */ 2526 int 2527 zonecfg_devwalk(zone_dochandle_t hdl, 2528 int (*cb)(const char *, uid_t, gid_t, mode_t, const char *, void *), 2529 void *data) 2530 { 2531 char path[MAXPATHLEN]; 2532 int ret; 2533 2534 if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK) 2535 return (ret); 2536 2537 if (strlcat(path, "/dev", sizeof (path)) >= sizeof (path)) 2538 return (Z_TOO_BIG); 2539 g_devwalk_skip_prefix = strlen(path) + 1; 2540 2541 /* 2542 * We have to serialize all zonecfg_devwalks in the same process 2543 * (which should be fine), since nftw() is so badly designed. 2544 */ 2545 (void) pthread_mutex_lock(&zonecfg_devwalk_lock); 2546 2547 g_devwalk_data = data; 2548 g_devwalk_cb = cb; 2549 (void) nftw(path, zonecfg_devwalk_cb, 0, FTW_PHYS); 2550 2551 (void) pthread_mutex_unlock(&zonecfg_devwalk_lock); 2552 return (Z_OK); 2553 } 2554 2555 /* 2556 * Update the owner, group, mode and acl on the specified dev (inpath) for 2557 * the zone (hdl). This function can be used to fix up the dev tree after 2558 * attaching a migrated zone. 2559 */ 2560 int 2561 zonecfg_devperms_apply(zone_dochandle_t hdl, const char *inpath, uid_t owner, 2562 gid_t group, mode_t mode, const char *acltxt) 2563 { 2564 int ret; 2565 char path[MAXPATHLEN]; 2566 struct stat st; 2567 acl_t *aclp; 2568 2569 if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK) 2570 return (ret); 2571 2572 if (strlcat(path, "/dev/", sizeof (path)) >= sizeof (path)) 2573 return (Z_TOO_BIG); 2574 if (strlcat(path, inpath, sizeof (path)) >= sizeof (path)) 2575 return (Z_TOO_BIG); 2576 2577 if (stat(path, &st) == -1) 2578 return (Z_INVAL); 2579 2580 /* make sure we're only touching device nodes */ 2581 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) 2582 return (Z_INVAL); 2583 2584 if (chown(path, owner, group) == -1) 2585 return (Z_SYSTEM); 2586 2587 if (chmod(path, mode) == -1) 2588 return (Z_SYSTEM); 2589 2590 if ((acltxt == NULL) || (strcmp(acltxt, "") == 0)) 2591 return (Z_OK); 2592 2593 if (acl_fromtext(acltxt, &aclp) != 0) 2594 return (Z_SYSTEM); 2595 2596 errno = 0; 2597 if (acl_set(path, aclp) == -1) { 2598 free(aclp); 2599 return (Z_SYSTEM); 2600 } 2601 2602 free(aclp); 2603 return (Z_OK); 2604 } 2605 2606 /* 2607 * This function finds everything mounted under a zone's rootpath. 2608 * This returns the number of mounts under rootpath, or -1 on error. 2609 * callback is called once per mount found with the first argument 2610 * pointing to the mount point. 2611 * 2612 * If the callback function returns non-zero zonecfg_find_mounts 2613 * aborts with an error. 2614 */ 2615 int 2616 zonecfg_find_mounts(char *rootpath, int (*callback)(const char *, void *), 2617 void *priv) { 2618 FILE *mnttab; 2619 struct mnttab m; 2620 size_t l; 2621 int zfsl; 2622 int rv = 0; 2623 char zfs_path[MAXPATHLEN]; 2624 2625 assert(rootpath != NULL); 2626 2627 if ((zfsl = snprintf(zfs_path, sizeof (zfs_path), "%s/.zfs/", rootpath)) 2628 >= sizeof (zfs_path)) 2629 return (-1); 2630 2631 l = strlen(rootpath); 2632 2633 mnttab = fopen("/etc/mnttab", "r"); 2634 2635 if (mnttab == NULL) 2636 return (-1); 2637 2638 if (ioctl(fileno(mnttab), MNTIOC_SHOWHIDDEN, NULL) < 0) { 2639 rv = -1; 2640 goto out; 2641 } 2642 2643 while (!getmntent(mnttab, &m)) { 2644 if ((strncmp(rootpath, m.mnt_mountp, l) == 0) && 2645 (m.mnt_mountp[l] == '/') && 2646 (strncmp(zfs_path, m.mnt_mountp, zfsl) != 0)) { 2647 rv++; 2648 if (callback == NULL) 2649 continue; 2650 if (callback(m.mnt_mountp, priv)) { 2651 rv = -1; 2652 goto out; 2653 2654 } 2655 } 2656 } 2657 2658 out: 2659 (void) fclose(mnttab); 2660 return (rv); 2661 } 2662 2663 int 2664 zonecfg_lookup_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2665 { 2666 xmlNodePtr cur, firstmatch; 2667 int err; 2668 char name[MAXNAMELEN], type[MAXNAMELEN], value[MAXNAMELEN]; 2669 2670 if (tabptr == NULL) 2671 return (Z_INVAL); 2672 2673 if ((err = operation_prep(handle)) != Z_OK) 2674 return (err); 2675 2676 cur = handle->zone_dh_cur; 2677 firstmatch = NULL; 2678 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2679 if (xmlStrcmp(cur->name, DTD_ELEM_ATTR)) 2680 continue; 2681 if (strlen(tabptr->zone_attr_name) > 0) { 2682 if ((fetchprop(cur, DTD_ATTR_NAME, name, 2683 sizeof (name)) == Z_OK) && 2684 (strcmp(tabptr->zone_attr_name, name) == 0)) { 2685 if (firstmatch == NULL) 2686 firstmatch = cur; 2687 else 2688 return (Z_INSUFFICIENT_SPEC); 2689 } 2690 } 2691 if (strlen(tabptr->zone_attr_type) > 0) { 2692 if ((fetchprop(cur, DTD_ATTR_TYPE, type, 2693 sizeof (type)) == Z_OK)) { 2694 if (strcmp(tabptr->zone_attr_type, type) == 0) { 2695 if (firstmatch == NULL) 2696 firstmatch = cur; 2697 else if (firstmatch != cur) 2698 return (Z_INSUFFICIENT_SPEC); 2699 } else { 2700 /* 2701 * If another property matched but this 2702 * one doesn't then reset firstmatch. 2703 */ 2704 if (firstmatch == cur) 2705 firstmatch = NULL; 2706 } 2707 } 2708 } 2709 if (strlen(tabptr->zone_attr_value) > 0) { 2710 if ((fetchprop(cur, DTD_ATTR_VALUE, value, 2711 sizeof (value)) == Z_OK)) { 2712 if (strcmp(tabptr->zone_attr_value, value) == 2713 0) { 2714 if (firstmatch == NULL) 2715 firstmatch = cur; 2716 else if (firstmatch != cur) 2717 return (Z_INSUFFICIENT_SPEC); 2718 } else { 2719 /* 2720 * If another property matched but this 2721 * one doesn't then reset firstmatch. 2722 */ 2723 if (firstmatch == cur) 2724 firstmatch = NULL; 2725 } 2726 } 2727 } 2728 } 2729 if (firstmatch == NULL) 2730 return (Z_NO_RESOURCE_ID); 2731 2732 cur = firstmatch; 2733 2734 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name, 2735 sizeof (tabptr->zone_attr_name))) != Z_OK) 2736 return (err); 2737 2738 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type, 2739 sizeof (tabptr->zone_attr_type))) != Z_OK) 2740 return (err); 2741 2742 if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value, 2743 sizeof (tabptr->zone_attr_value))) != Z_OK) 2744 return (err); 2745 2746 return (Z_OK); 2747 } 2748 2749 static int 2750 zonecfg_add_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2751 { 2752 xmlNodePtr newnode, cur = handle->zone_dh_cur; 2753 int err; 2754 2755 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ATTR, NULL); 2756 err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_attr_name); 2757 if (err != Z_OK) 2758 return (err); 2759 err = newprop(newnode, DTD_ATTR_TYPE, tabptr->zone_attr_type); 2760 if (err != Z_OK) 2761 return (err); 2762 err = newprop(newnode, DTD_ATTR_VALUE, tabptr->zone_attr_value); 2763 if (err != Z_OK) 2764 return (err); 2765 return (Z_OK); 2766 } 2767 2768 int 2769 zonecfg_add_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2770 { 2771 int err; 2772 2773 if (tabptr == NULL) 2774 return (Z_INVAL); 2775 2776 if ((err = operation_prep(handle)) != Z_OK) 2777 return (err); 2778 2779 if ((err = zonecfg_add_attr_core(handle, tabptr)) != Z_OK) 2780 return (err); 2781 2782 return (Z_OK); 2783 } 2784 2785 static int 2786 zonecfg_delete_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2787 { 2788 xmlNodePtr cur = handle->zone_dh_cur; 2789 int name_match, type_match, value_match; 2790 2791 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2792 if (xmlStrcmp(cur->name, DTD_ELEM_ATTR)) 2793 continue; 2794 2795 name_match = match_prop(cur, DTD_ATTR_NAME, 2796 tabptr->zone_attr_name); 2797 type_match = match_prop(cur, DTD_ATTR_TYPE, 2798 tabptr->zone_attr_type); 2799 value_match = match_prop(cur, DTD_ATTR_VALUE, 2800 tabptr->zone_attr_value); 2801 2802 if (name_match && type_match && value_match) { 2803 xmlUnlinkNode(cur); 2804 xmlFreeNode(cur); 2805 return (Z_OK); 2806 } 2807 } 2808 return (Z_NO_RESOURCE_ID); 2809 } 2810 2811 int 2812 zonecfg_delete_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2813 { 2814 int err; 2815 2816 if (tabptr == NULL) 2817 return (Z_INVAL); 2818 2819 if ((err = operation_prep(handle)) != Z_OK) 2820 return (err); 2821 2822 if ((err = zonecfg_delete_attr_core(handle, tabptr)) != Z_OK) 2823 return (err); 2824 2825 return (Z_OK); 2826 } 2827 2828 int 2829 zonecfg_modify_attr( 2830 zone_dochandle_t handle, 2831 struct zone_attrtab *oldtabptr, 2832 struct zone_attrtab *newtabptr) 2833 { 2834 int err; 2835 2836 if (oldtabptr == NULL || newtabptr == NULL) 2837 return (Z_INVAL); 2838 2839 if ((err = operation_prep(handle)) != Z_OK) 2840 return (err); 2841 2842 if ((err = zonecfg_delete_attr_core(handle, oldtabptr)) != Z_OK) 2843 return (err); 2844 2845 if ((err = zonecfg_add_attr_core(handle, newtabptr)) != Z_OK) 2846 return (err); 2847 2848 return (Z_OK); 2849 } 2850 2851 int 2852 zonecfg_get_attr_boolean(const struct zone_attrtab *attr, boolean_t *value) 2853 { 2854 if (attr == NULL) 2855 return (Z_INVAL); 2856 2857 if (strcmp(attr->zone_attr_type, DTD_ENTITY_BOOLEAN) != 0) 2858 return (Z_INVAL); 2859 2860 if (strcmp(attr->zone_attr_value, DTD_ENTITY_TRUE) == 0) { 2861 *value = B_TRUE; 2862 return (Z_OK); 2863 } 2864 if (strcmp(attr->zone_attr_value, DTD_ENTITY_FALSE) == 0) { 2865 *value = B_FALSE; 2866 return (Z_OK); 2867 } 2868 return (Z_INVAL); 2869 } 2870 2871 int 2872 zonecfg_get_attr_int(const struct zone_attrtab *attr, int64_t *value) 2873 { 2874 long long result; 2875 char *endptr; 2876 2877 if (attr == NULL) 2878 return (Z_INVAL); 2879 2880 if (strcmp(attr->zone_attr_type, DTD_ENTITY_INT) != 0) 2881 return (Z_INVAL); 2882 2883 errno = 0; 2884 result = strtoll(attr->zone_attr_value, &endptr, 10); 2885 if (errno != 0 || *endptr != '\0') 2886 return (Z_INVAL); 2887 *value = result; 2888 return (Z_OK); 2889 } 2890 2891 int 2892 zonecfg_get_attr_string(const struct zone_attrtab *attr, char *value, 2893 size_t val_sz) 2894 { 2895 if (attr == NULL) 2896 return (Z_INVAL); 2897 2898 if (strcmp(attr->zone_attr_type, DTD_ENTITY_STRING) != 0) 2899 return (Z_INVAL); 2900 2901 if (strlcpy(value, attr->zone_attr_value, val_sz) >= val_sz) 2902 return (Z_TOO_BIG); 2903 return (Z_OK); 2904 } 2905 2906 int 2907 zonecfg_get_attr_uint(const struct zone_attrtab *attr, uint64_t *value) 2908 { 2909 unsigned long long result; 2910 long long neg_result; 2911 char *endptr; 2912 2913 if (attr == NULL) 2914 return (Z_INVAL); 2915 2916 if (strcmp(attr->zone_attr_type, DTD_ENTITY_UINT) != 0) 2917 return (Z_INVAL); 2918 2919 errno = 0; 2920 result = strtoull(attr->zone_attr_value, &endptr, 10); 2921 if (errno != 0 || *endptr != '\0') 2922 return (Z_INVAL); 2923 errno = 0; 2924 neg_result = strtoll(attr->zone_attr_value, &endptr, 10); 2925 /* 2926 * Incredibly, strtoull("<negative number>", ...) will not fail but 2927 * return whatever (negative) number cast as a u_longlong_t, so we 2928 * need to look for this here. 2929 */ 2930 if (errno == 0 && neg_result < 0) 2931 return (Z_INVAL); 2932 *value = result; 2933 return (Z_OK); 2934 } 2935 2936 int 2937 zonecfg_lookup_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2938 { 2939 xmlNodePtr cur, val; 2940 char savedname[MAXNAMELEN]; 2941 struct zone_rctlvaltab *valptr; 2942 int err; 2943 2944 if (tabptr->zone_rctl_name == NULL || 2945 strlen(tabptr->zone_rctl_name) == 0) 2946 return (Z_INVAL); 2947 2948 if ((err = operation_prep(handle)) != Z_OK) 2949 return (err); 2950 2951 cur = handle->zone_dh_cur; 2952 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2953 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 2954 continue; 2955 if ((fetchprop(cur, DTD_ATTR_NAME, savedname, 2956 sizeof (savedname)) == Z_OK) && 2957 (strcmp(savedname, tabptr->zone_rctl_name) == 0)) { 2958 tabptr->zone_rctl_valptr = NULL; 2959 for (val = cur->xmlChildrenNode; val != NULL; 2960 val = val->next) { 2961 valptr = (struct zone_rctlvaltab *)malloc( 2962 sizeof (struct zone_rctlvaltab)); 2963 if (valptr == NULL) 2964 return (Z_NOMEM); 2965 if ((fetchprop(val, DTD_ATTR_PRIV, 2966 valptr->zone_rctlval_priv, 2967 sizeof (valptr->zone_rctlval_priv)) != 2968 Z_OK)) 2969 break; 2970 if ((fetchprop(val, DTD_ATTR_LIMIT, 2971 valptr->zone_rctlval_limit, 2972 sizeof (valptr->zone_rctlval_limit)) != 2973 Z_OK)) 2974 break; 2975 if ((fetchprop(val, DTD_ATTR_ACTION, 2976 valptr->zone_rctlval_action, 2977 sizeof (valptr->zone_rctlval_action)) != 2978 Z_OK)) 2979 break; 2980 if (zonecfg_add_rctl_value(tabptr, valptr) != 2981 Z_OK) 2982 break; 2983 } 2984 return (Z_OK); 2985 } 2986 } 2987 return (Z_NO_RESOURCE_ID); 2988 } 2989 2990 static int 2991 zonecfg_add_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2992 { 2993 xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode; 2994 struct zone_rctlvaltab *valptr; 2995 int err; 2996 2997 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_RCTL, NULL); 2998 err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_rctl_name); 2999 if (err != Z_OK) 3000 return (err); 3001 for (valptr = tabptr->zone_rctl_valptr; valptr != NULL; 3002 valptr = valptr->zone_rctlval_next) { 3003 valnode = xmlNewTextChild(newnode, NULL, 3004 DTD_ELEM_RCTLVALUE, NULL); 3005 err = newprop(valnode, DTD_ATTR_PRIV, 3006 valptr->zone_rctlval_priv); 3007 if (err != Z_OK) 3008 return (err); 3009 err = newprop(valnode, DTD_ATTR_LIMIT, 3010 valptr->zone_rctlval_limit); 3011 if (err != Z_OK) 3012 return (err); 3013 err = newprop(valnode, DTD_ATTR_ACTION, 3014 valptr->zone_rctlval_action); 3015 if (err != Z_OK) 3016 return (err); 3017 } 3018 return (Z_OK); 3019 } 3020 3021 int 3022 zonecfg_add_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 3023 { 3024 int err; 3025 3026 if (tabptr == NULL || tabptr->zone_rctl_name == NULL) 3027 return (Z_INVAL); 3028 3029 if ((err = operation_prep(handle)) != Z_OK) 3030 return (err); 3031 3032 if ((err = zonecfg_add_rctl_core(handle, tabptr)) != Z_OK) 3033 return (err); 3034 3035 return (Z_OK); 3036 } 3037 3038 static int 3039 zonecfg_delete_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr) 3040 { 3041 xmlNodePtr cur = handle->zone_dh_cur; 3042 xmlChar *savedname; 3043 int name_result; 3044 3045 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 3046 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 3047 continue; 3048 3049 savedname = xmlGetProp(cur, DTD_ATTR_NAME); 3050 if (savedname == NULL) /* shouldn't happen */ 3051 continue; 3052 name_result = xmlStrcmp(savedname, 3053 (const xmlChar *) tabptr->zone_rctl_name); 3054 xmlFree(savedname); 3055 3056 if (name_result == 0) { 3057 xmlUnlinkNode(cur); 3058 xmlFreeNode(cur); 3059 return (Z_OK); 3060 } 3061 } 3062 return (Z_NO_RESOURCE_ID); 3063 } 3064 3065 int 3066 zonecfg_delete_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 3067 { 3068 int err; 3069 3070 if (tabptr == NULL || tabptr->zone_rctl_name == NULL) 3071 return (Z_INVAL); 3072 3073 if ((err = operation_prep(handle)) != Z_OK) 3074 return (err); 3075 3076 if ((err = zonecfg_delete_rctl_core(handle, tabptr)) != Z_OK) 3077 return (err); 3078 3079 return (Z_OK); 3080 } 3081 3082 int 3083 zonecfg_modify_rctl( 3084 zone_dochandle_t handle, 3085 struct zone_rctltab *oldtabptr, 3086 struct zone_rctltab *newtabptr) 3087 { 3088 int err; 3089 3090 if (oldtabptr == NULL || oldtabptr->zone_rctl_name == NULL || 3091 newtabptr == NULL || newtabptr->zone_rctl_name == NULL) 3092 return (Z_INVAL); 3093 3094 if ((err = operation_prep(handle)) != Z_OK) 3095 return (err); 3096 3097 if ((err = zonecfg_delete_rctl_core(handle, oldtabptr)) != Z_OK) 3098 return (err); 3099 3100 if ((err = zonecfg_add_rctl_core(handle, newtabptr)) != Z_OK) 3101 return (err); 3102 3103 return (Z_OK); 3104 } 3105 3106 int 3107 zonecfg_add_rctl_value( 3108 struct zone_rctltab *tabptr, 3109 struct zone_rctlvaltab *valtabptr) 3110 { 3111 struct zone_rctlvaltab *last, *old, *new; 3112 rctlblk_t *rctlblk = alloca(rctlblk_size()); 3113 3114 last = tabptr->zone_rctl_valptr; 3115 for (old = last; old != NULL; old = old->zone_rctlval_next) 3116 last = old; /* walk to the end of the list */ 3117 new = valtabptr; /* alloc'd by caller */ 3118 new->zone_rctlval_next = NULL; 3119 if (zonecfg_construct_rctlblk(valtabptr, rctlblk) != Z_OK) 3120 return (Z_INVAL); 3121 if (!zonecfg_valid_rctlblk(rctlblk)) 3122 return (Z_INVAL); 3123 if (last == NULL) 3124 tabptr->zone_rctl_valptr = new; 3125 else 3126 last->zone_rctlval_next = new; 3127 return (Z_OK); 3128 } 3129 3130 int 3131 zonecfg_remove_rctl_value( 3132 struct zone_rctltab *tabptr, 3133 struct zone_rctlvaltab *valtabptr) 3134 { 3135 struct zone_rctlvaltab *last, *this, *next; 3136 3137 last = tabptr->zone_rctl_valptr; 3138 for (this = last; this != NULL; this = this->zone_rctlval_next) { 3139 if (strcmp(this->zone_rctlval_priv, 3140 valtabptr->zone_rctlval_priv) == 0 && 3141 strcmp(this->zone_rctlval_limit, 3142 valtabptr->zone_rctlval_limit) == 0 && 3143 strcmp(this->zone_rctlval_action, 3144 valtabptr->zone_rctlval_action) == 0) { 3145 next = this->zone_rctlval_next; 3146 if (this == tabptr->zone_rctl_valptr) 3147 tabptr->zone_rctl_valptr = next; 3148 else 3149 last->zone_rctlval_next = next; 3150 free(this); 3151 return (Z_OK); 3152 } else 3153 last = this; 3154 } 3155 return (Z_NO_PROPERTY_ID); 3156 } 3157 3158 char * 3159 zonecfg_strerror(int errnum) 3160 { 3161 switch (errnum) { 3162 case Z_OK: 3163 return (dgettext(TEXT_DOMAIN, "OK")); 3164 case Z_EMPTY_DOCUMENT: 3165 return (dgettext(TEXT_DOMAIN, "Empty document")); 3166 case Z_WRONG_DOC_TYPE: 3167 return (dgettext(TEXT_DOMAIN, "Wrong document type")); 3168 case Z_BAD_PROPERTY: 3169 return (dgettext(TEXT_DOMAIN, "Bad document property")); 3170 case Z_TEMP_FILE: 3171 return (dgettext(TEXT_DOMAIN, 3172 "Problem creating temporary file")); 3173 case Z_SAVING_FILE: 3174 return (dgettext(TEXT_DOMAIN, "Problem saving file")); 3175 case Z_NO_ENTRY: 3176 return (dgettext(TEXT_DOMAIN, "No such entry")); 3177 case Z_BOGUS_ZONE_NAME: 3178 return (dgettext(TEXT_DOMAIN, "Bogus zone name")); 3179 case Z_REQD_RESOURCE_MISSING: 3180 return (dgettext(TEXT_DOMAIN, "Required resource missing")); 3181 case Z_REQD_PROPERTY_MISSING: 3182 return (dgettext(TEXT_DOMAIN, "Required property missing")); 3183 case Z_BAD_HANDLE: 3184 return (dgettext(TEXT_DOMAIN, "Bad handle")); 3185 case Z_NOMEM: 3186 return (dgettext(TEXT_DOMAIN, "Out of memory")); 3187 case Z_INVAL: 3188 return (dgettext(TEXT_DOMAIN, "Invalid argument")); 3189 case Z_ACCES: 3190 return (dgettext(TEXT_DOMAIN, "Permission denied")); 3191 case Z_TOO_BIG: 3192 return (dgettext(TEXT_DOMAIN, "Argument list too long")); 3193 case Z_MISC_FS: 3194 return (dgettext(TEXT_DOMAIN, 3195 "Miscellaneous file system error")); 3196 case Z_NO_ZONE: 3197 return (dgettext(TEXT_DOMAIN, "No such zone configured")); 3198 case Z_NO_RESOURCE_TYPE: 3199 return (dgettext(TEXT_DOMAIN, "No such resource type")); 3200 case Z_NO_RESOURCE_ID: 3201 return (dgettext(TEXT_DOMAIN, "No such resource with that id")); 3202 case Z_NO_PROPERTY_TYPE: 3203 return (dgettext(TEXT_DOMAIN, "No such property type")); 3204 case Z_NO_PROPERTY_ID: 3205 return (dgettext(TEXT_DOMAIN, "No such property with that id")); 3206 case Z_BAD_ZONE_STATE: 3207 return (dgettext(TEXT_DOMAIN, 3208 "Zone state is invalid for the requested operation")); 3209 case Z_INVALID_DOCUMENT: 3210 return (dgettext(TEXT_DOMAIN, "Invalid document")); 3211 case Z_NAME_IN_USE: 3212 return (dgettext(TEXT_DOMAIN, "Zone name already in use")); 3213 case Z_NO_SUCH_ID: 3214 return (dgettext(TEXT_DOMAIN, "No such zone ID")); 3215 case Z_UPDATING_INDEX: 3216 return (dgettext(TEXT_DOMAIN, "Problem updating index file")); 3217 case Z_LOCKING_FILE: 3218 return (dgettext(TEXT_DOMAIN, "Locking index file")); 3219 case Z_UNLOCKING_FILE: 3220 return (dgettext(TEXT_DOMAIN, "Unlocking index file")); 3221 case Z_INSUFFICIENT_SPEC: 3222 return (dgettext(TEXT_DOMAIN, "Insufficient specification")); 3223 case Z_RESOLVED_PATH: 3224 return (dgettext(TEXT_DOMAIN, "Resolved path mismatch")); 3225 case Z_IPV6_ADDR_PREFIX_LEN: 3226 return (dgettext(TEXT_DOMAIN, 3227 "IPv6 address missing required prefix length")); 3228 case Z_BOGUS_ADDRESS: 3229 return (dgettext(TEXT_DOMAIN, 3230 "Neither an IPv4 nor an IPv6 address nor a host name")); 3231 case Z_PRIV_PROHIBITED: 3232 return (dgettext(TEXT_DOMAIN, 3233 "Specified privilege is prohibited")); 3234 case Z_PRIV_REQUIRED: 3235 return (dgettext(TEXT_DOMAIN, 3236 "Required privilege is missing")); 3237 case Z_PRIV_UNKNOWN: 3238 return (dgettext(TEXT_DOMAIN, 3239 "Specified privilege is unknown")); 3240 case Z_BRAND_ERROR: 3241 return (dgettext(TEXT_DOMAIN, 3242 "Brand-specific error")); 3243 case Z_INCOMPATIBLE: 3244 return (dgettext(TEXT_DOMAIN, "Incompatible settings")); 3245 case Z_ALIAS_DISALLOW: 3246 return (dgettext(TEXT_DOMAIN, 3247 "An incompatible rctl already exists for this property")); 3248 case Z_CLEAR_DISALLOW: 3249 return (dgettext(TEXT_DOMAIN, 3250 "Clearing this property is not allowed")); 3251 case Z_POOL: 3252 return (dgettext(TEXT_DOMAIN, "libpool(3LIB) error")); 3253 case Z_POOLS_NOT_ACTIVE: 3254 return (dgettext(TEXT_DOMAIN, "Pools facility not active; " 3255 "zone will not be bound to pool")); 3256 case Z_POOL_ENABLE: 3257 return (dgettext(TEXT_DOMAIN, 3258 "Could not enable pools facility")); 3259 case Z_NO_POOL: 3260 return (dgettext(TEXT_DOMAIN, 3261 "Pool not found; using default pool")); 3262 case Z_POOL_CREATE: 3263 return (dgettext(TEXT_DOMAIN, 3264 "Could not create a temporary pool")); 3265 case Z_POOL_BIND: 3266 return (dgettext(TEXT_DOMAIN, "Could not bind zone to pool")); 3267 default: 3268 return (dgettext(TEXT_DOMAIN, "Unknown error")); 3269 } 3270 } 3271 3272 /* 3273 * Note that the zonecfg_setXent() and zonecfg_endXent() calls are all the 3274 * same, as they just turn around and call zonecfg_setent() / zonecfg_endent(). 3275 */ 3276 3277 static int 3278 zonecfg_setent(zone_dochandle_t handle) 3279 { 3280 xmlNodePtr cur; 3281 int err; 3282 3283 if (handle == NULL) 3284 return (Z_INVAL); 3285 3286 if ((err = operation_prep(handle)) != Z_OK) { 3287 handle->zone_dh_cur = NULL; 3288 return (err); 3289 } 3290 cur = handle->zone_dh_cur; 3291 cur = cur->xmlChildrenNode; 3292 handle->zone_dh_cur = cur; 3293 return (Z_OK); 3294 } 3295 3296 static int 3297 zonecfg_endent(zone_dochandle_t handle) 3298 { 3299 if (handle == NULL) 3300 return (Z_INVAL); 3301 3302 handle->zone_dh_cur = handle->zone_dh_top; 3303 return (Z_OK); 3304 } 3305 3306 /* 3307 * Do the work required to manipulate a process through libproc. 3308 * If grab_process() returns no errors (0), then release_process() 3309 * must eventually be called. 3310 * 3311 * Return values: 3312 * 0 Successful creation of agent thread 3313 * 1 Error grabbing 3314 * 2 Error creating agent 3315 */ 3316 static int 3317 grab_process(pr_info_handle_t *p) 3318 { 3319 int ret; 3320 3321 if ((p->pr = Pgrab(p->pid, 0, &ret)) != NULL) { 3322 3323 if (Psetflags(p->pr, PR_RLC) != 0) { 3324 Prelease(p->pr, 0); 3325 return (1); 3326 } 3327 if (Pcreate_agent(p->pr) == 0) { 3328 return (0); 3329 3330 } else { 3331 Prelease(p->pr, 0); 3332 return (2); 3333 } 3334 } else { 3335 return (1); 3336 } 3337 } 3338 3339 /* 3340 * Release the specified process. This destroys the agent 3341 * and releases the process. If the process is NULL, nothing 3342 * is done. This function should only be called if grab_process() 3343 * has previously been called and returned success. 3344 * 3345 * This function is Pgrab-safe. 3346 */ 3347 static void 3348 release_process(struct ps_prochandle *Pr) 3349 { 3350 if (Pr == NULL) 3351 return; 3352 3353 Pdestroy_agent(Pr); 3354 Prelease(Pr, 0); 3355 } 3356 3357 static boolean_t 3358 grab_zone_proc(char *zonename, pr_info_handle_t *p) 3359 { 3360 DIR *dirp; 3361 struct dirent *dentp; 3362 zoneid_t zoneid; 3363 int pid_self; 3364 psinfo_t psinfo; 3365 3366 if (zone_get_id(zonename, &zoneid) != 0) 3367 return (B_FALSE); 3368 3369 pid_self = getpid(); 3370 3371 if ((dirp = opendir("/proc")) == NULL) 3372 return (B_FALSE); 3373 3374 while (dentp = readdir(dirp)) { 3375 p->pid = atoi(dentp->d_name); 3376 3377 /* Skip self */ 3378 if (p->pid == pid_self) 3379 continue; 3380 3381 if (proc_get_psinfo(p->pid, &psinfo) != 0) 3382 continue; 3383 3384 if (psinfo.pr_zoneid != zoneid) 3385 continue; 3386 3387 /* attempt to grab process */ 3388 if (grab_process(p) != 0) 3389 continue; 3390 3391 if (pr_getzoneid(p->pr) != zoneid) { 3392 release_process(p->pr); 3393 continue; 3394 } 3395 3396 (void) closedir(dirp); 3397 return (B_TRUE); 3398 } 3399 3400 (void) closedir(dirp); 3401 return (B_FALSE); 3402 } 3403 3404 static boolean_t 3405 get_priv_rctl(struct ps_prochandle *pr, char *name, rctlblk_t *rblk) 3406 { 3407 if (pr_getrctl(pr, name, NULL, rblk, RCTL_FIRST)) 3408 return (B_FALSE); 3409 3410 if (rctlblk_get_privilege(rblk) == RCPRIV_PRIVILEGED) 3411 return (B_TRUE); 3412 3413 while (pr_getrctl(pr, name, rblk, rblk, RCTL_NEXT) == 0) { 3414 if (rctlblk_get_privilege(rblk) == RCPRIV_PRIVILEGED) 3415 return (B_TRUE); 3416 } 3417 3418 return (B_FALSE); 3419 } 3420 3421 /* 3422 * Apply the current rctl settings to the specified, running zone. 3423 */ 3424 int 3425 zonecfg_apply_rctls(char *zone_name, zone_dochandle_t handle) 3426 { 3427 int err; 3428 int res = Z_OK; 3429 rctlblk_t *rblk; 3430 pr_info_handle_t p; 3431 struct zone_rctltab rctl; 3432 3433 if ((err = zonecfg_setrctlent(handle)) != Z_OK) 3434 return (err); 3435 3436 if ((rblk = (rctlblk_t *)malloc(rctlblk_size())) == NULL) { 3437 (void) zonecfg_endrctlent(handle); 3438 return (Z_NOMEM); 3439 } 3440 3441 if (!grab_zone_proc(zone_name, &p)) { 3442 (void) zonecfg_endrctlent(handle); 3443 free(rblk); 3444 return (Z_SYSTEM); 3445 } 3446 3447 while (zonecfg_getrctlent(handle, &rctl) == Z_OK) { 3448 char *rname; 3449 struct zone_rctlvaltab *valptr; 3450 3451 rname = rctl.zone_rctl_name; 3452 3453 /* first delete all current privileged settings for this rctl */ 3454 while (get_priv_rctl(p.pr, rname, rblk)) { 3455 if (pr_setrctl(p.pr, rname, NULL, rblk, RCTL_DELETE) != 3456 0) { 3457 res = Z_SYSTEM; 3458 goto done; 3459 } 3460 } 3461 3462 /* now set each new value for the rctl */ 3463 for (valptr = rctl.zone_rctl_valptr; valptr != NULL; 3464 valptr = valptr->zone_rctlval_next) { 3465 if ((err = zonecfg_construct_rctlblk(valptr, rblk)) 3466 != Z_OK) { 3467 res = errno = err; 3468 goto done; 3469 } 3470 3471 if (pr_setrctl(p.pr, rname, NULL, rblk, RCTL_INSERT)) { 3472 res = Z_SYSTEM; 3473 goto done; 3474 } 3475 } 3476 } 3477 3478 done: 3479 release_process(p.pr); 3480 free(rblk); 3481 (void) zonecfg_endrctlent(handle); 3482 3483 return (res); 3484 } 3485 3486 static const xmlChar * 3487 nm_to_dtd(char *nm) 3488 { 3489 if (strcmp(nm, "device") == 0) 3490 return (DTD_ELEM_DEVICE); 3491 if (strcmp(nm, "fs") == 0) 3492 return (DTD_ELEM_FS); 3493 if (strcmp(nm, "inherit-pkg-dir") == 0) 3494 return (DTD_ELEM_IPD); 3495 if (strcmp(nm, "net") == 0) 3496 return (DTD_ELEM_NET); 3497 if (strcmp(nm, "attr") == 0) 3498 return (DTD_ELEM_ATTR); 3499 if (strcmp(nm, "rctl") == 0) 3500 return (DTD_ELEM_RCTL); 3501 if (strcmp(nm, "dataset") == 0) 3502 return (DTD_ELEM_DATASET); 3503 3504 return (NULL); 3505 } 3506 3507 int 3508 zonecfg_num_resources(zone_dochandle_t handle, char *rsrc) 3509 { 3510 int num = 0; 3511 const xmlChar *dtd; 3512 xmlNodePtr cur; 3513 3514 if ((dtd = nm_to_dtd(rsrc)) == NULL) 3515 return (num); 3516 3517 if (zonecfg_setent(handle) != Z_OK) 3518 return (num); 3519 3520 for (cur = handle->zone_dh_cur; cur != NULL; cur = cur->next) 3521 if (xmlStrcmp(cur->name, dtd) == 0) 3522 num++; 3523 3524 (void) zonecfg_endent(handle); 3525 3526 return (num); 3527 } 3528 3529 int 3530 zonecfg_del_all_resources(zone_dochandle_t handle, char *rsrc) 3531 { 3532 int err; 3533 const xmlChar *dtd; 3534 xmlNodePtr cur; 3535 3536 if ((dtd = nm_to_dtd(rsrc)) == NULL) 3537 return (Z_NO_RESOURCE_TYPE); 3538 3539 if ((err = zonecfg_setent(handle)) != Z_OK) 3540 return (err); 3541 3542 cur = handle->zone_dh_cur; 3543 while (cur != NULL) { 3544 xmlNodePtr tmp; 3545 3546 if (xmlStrcmp(cur->name, dtd)) { 3547 cur = cur->next; 3548 continue; 3549 } 3550 3551 tmp = cur->next; 3552 xmlUnlinkNode(cur); 3553 xmlFreeNode(cur); 3554 cur = tmp; 3555 } 3556 3557 (void) zonecfg_endent(handle); 3558 return (Z_OK); 3559 } 3560 3561 static boolean_t 3562 valid_uint(char *s, uint64_t *n) 3563 { 3564 char *endp; 3565 3566 /* strtoull accepts '-'?! so we want to flag that as an error */ 3567 if (strchr(s, '-') != NULL) 3568 return (B_FALSE); 3569 3570 errno = 0; 3571 *n = strtoull(s, &endp, 10); 3572 3573 if (errno != 0 || *endp != '\0') 3574 return (B_FALSE); 3575 return (B_TRUE); 3576 } 3577 3578 /* 3579 * Convert a string representing a number (possibly a fraction) into an integer. 3580 * The string can have a modifier (K, M, G or T). The modifiers are treated 3581 * as powers of two (not 10). 3582 */ 3583 int 3584 zonecfg_str_to_bytes(char *str, uint64_t *bytes) 3585 { 3586 long double val; 3587 char *unitp; 3588 uint64_t scale; 3589 3590 if ((val = strtold(str, &unitp)) < 0) 3591 return (-1); 3592 3593 /* remove any leading white space from units string */ 3594 while (isspace(*unitp) != 0) 3595 ++unitp; 3596 3597 /* if no units explicitly set, error */ 3598 if (unitp == NULL || *unitp == '\0') { 3599 scale = 1; 3600 } else { 3601 int i; 3602 char *units[] = {"K", "M", "G", "T", NULL}; 3603 3604 scale = 1024; 3605 3606 /* update scale based on units */ 3607 for (i = 0; units[i] != NULL; i++) { 3608 if (strcasecmp(unitp, units[i]) == 0) 3609 break; 3610 scale <<= 10; 3611 } 3612 3613 if (units[i] == NULL) 3614 return (-1); 3615 } 3616 3617 *bytes = (uint64_t)(val * scale); 3618 return (0); 3619 } 3620 3621 boolean_t 3622 zonecfg_valid_ncpus(char *lowstr, char *highstr) 3623 { 3624 uint64_t low, high; 3625 3626 if (!valid_uint(lowstr, &low) || !valid_uint(highstr, &high) || 3627 low < 1 || low > high) 3628 return (B_FALSE); 3629 3630 return (B_TRUE); 3631 } 3632 3633 boolean_t 3634 zonecfg_valid_importance(char *impstr) 3635 { 3636 uint64_t num; 3637 3638 if (!valid_uint(impstr, &num)) 3639 return (B_FALSE); 3640 3641 return (B_TRUE); 3642 } 3643 3644 boolean_t 3645 zonecfg_valid_alias_limit(char *name, char *limitstr, uint64_t *limit) 3646 { 3647 int i; 3648 3649 for (i = 0; aliases[i].shortname != NULL; i++) 3650 if (strcmp(name, aliases[i].shortname) == 0) 3651 break; 3652 3653 if (aliases[i].shortname == NULL) 3654 return (B_FALSE); 3655 3656 if (!valid_uint(limitstr, limit) || *limit < aliases[i].low_limit) 3657 return (B_FALSE); 3658 3659 return (B_TRUE); 3660 } 3661 3662 boolean_t 3663 zonecfg_valid_memlimit(char *memstr, uint64_t *mem_val) 3664 { 3665 if (zonecfg_str_to_bytes(memstr, mem_val) != 0) 3666 return (B_FALSE); 3667 3668 return (B_TRUE); 3669 } 3670 3671 static int 3672 zerr_pool(char *pool_err, int err_size, int res) 3673 { 3674 (void) strlcpy(pool_err, pool_strerror(pool_error()), err_size); 3675 return (res); 3676 } 3677 3678 static int 3679 create_tmp_pset(char *pool_err, int err_size, pool_conf_t *pconf, pool_t *pool, 3680 char *name, int min, int max) 3681 { 3682 pool_resource_t *res; 3683 pool_elem_t *elem; 3684 pool_value_t *val; 3685 3686 if ((res = pool_resource_create(pconf, "pset", name)) == NULL) 3687 return (zerr_pool(pool_err, err_size, Z_POOL)); 3688 3689 if (pool_associate(pconf, pool, res) != PO_SUCCESS) 3690 return (zerr_pool(pool_err, err_size, Z_POOL)); 3691 3692 if ((elem = pool_resource_to_elem(pconf, res)) == NULL) 3693 return (zerr_pool(pool_err, err_size, Z_POOL)); 3694 3695 if ((val = pool_value_alloc()) == NULL) 3696 return (zerr_pool(pool_err, err_size, Z_POOL)); 3697 3698 /* set the maximum number of cpus for the pset */ 3699 pool_value_set_uint64(val, (uint64_t)max); 3700 3701 if (pool_put_property(pconf, elem, "pset.max", val) != PO_SUCCESS) { 3702 pool_value_free(val); 3703 return (zerr_pool(pool_err, err_size, Z_POOL)); 3704 } 3705 3706 /* set the minimum number of cpus for the pset */ 3707 pool_value_set_uint64(val, (uint64_t)min); 3708 3709 if (pool_put_property(pconf, elem, "pset.min", val) != PO_SUCCESS) { 3710 pool_value_free(val); 3711 return (zerr_pool(pool_err, err_size, Z_POOL)); 3712 } 3713 3714 pool_value_free(val); 3715 3716 return (Z_OK); 3717 } 3718 3719 static int 3720 create_tmp_pool(char *pool_err, int err_size, pool_conf_t *pconf, char *name, 3721 struct zone_psettab *pset_tab) 3722 { 3723 pool_t *pool; 3724 int res = Z_OK; 3725 3726 /* create a temporary pool configuration */ 3727 if (pool_conf_open(pconf, NULL, PO_TEMP) != PO_SUCCESS) { 3728 res = zerr_pool(pool_err, err_size, Z_POOL); 3729 return (res); 3730 } 3731 3732 if ((pool = pool_create(pconf, name)) == NULL) { 3733 res = zerr_pool(pool_err, err_size, Z_POOL_CREATE); 3734 goto done; 3735 } 3736 3737 /* set pool importance */ 3738 if (pset_tab->zone_importance[0] != '\0') { 3739 pool_elem_t *elem; 3740 pool_value_t *val; 3741 3742 if ((elem = pool_to_elem(pconf, pool)) == NULL) { 3743 res = zerr_pool(pool_err, err_size, Z_POOL); 3744 goto done; 3745 } 3746 3747 if ((val = pool_value_alloc()) == NULL) { 3748 res = zerr_pool(pool_err, err_size, Z_POOL); 3749 goto done; 3750 } 3751 3752 pool_value_set_int64(val, 3753 (int64_t)atoi(pset_tab->zone_importance)); 3754 3755 if (pool_put_property(pconf, elem, "pool.importance", val) 3756 != PO_SUCCESS) { 3757 res = zerr_pool(pool_err, err_size, Z_POOL); 3758 pool_value_free(val); 3759 goto done; 3760 } 3761 3762 pool_value_free(val); 3763 } 3764 3765 if ((res = create_tmp_pset(pool_err, err_size, pconf, pool, name, 3766 atoi(pset_tab->zone_ncpu_min), 3767 atoi(pset_tab->zone_ncpu_max))) != Z_OK) 3768 goto done; 3769 3770 /* validation */ 3771 if (pool_conf_status(pconf) == POF_INVALID) { 3772 res = zerr_pool(pool_err, err_size, Z_POOL); 3773 goto done; 3774 } 3775 3776 /* 3777 * This validation is the one we expect to fail if the user specified 3778 * an invalid configuration (too many cpus) for this system. 3779 */ 3780 if (pool_conf_validate(pconf, POV_RUNTIME) != PO_SUCCESS) { 3781 res = zerr_pool(pool_err, err_size, Z_POOL_CREATE); 3782 goto done; 3783 } 3784 3785 /* 3786 * Commit the dynamic configuration but not the pool configuration 3787 * file. 3788 */ 3789 if (pool_conf_commit(pconf, 1) != PO_SUCCESS) 3790 res = zerr_pool(pool_err, err_size, Z_POOL); 3791 3792 done: 3793 (void) pool_conf_close(pconf); 3794 return (res); 3795 } 3796 3797 static int 3798 get_running_tmp_pset(pool_conf_t *pconf, pool_t *pool, pool_resource_t *pset, 3799 struct zone_psettab *pset_tab) 3800 { 3801 int nfound = 0; 3802 pool_elem_t *pe; 3803 pool_value_t *pv = pool_value_alloc(); 3804 uint64_t val_uint; 3805 3806 if (pool != NULL) { 3807 pe = pool_to_elem(pconf, pool); 3808 if (pool_get_property(pconf, pe, "pool.importance", pv) 3809 != POC_INVAL) { 3810 int64_t val_int; 3811 3812 (void) pool_value_get_int64(pv, &val_int); 3813 (void) snprintf(pset_tab->zone_importance, 3814 sizeof (pset_tab->zone_importance), "%d", val_int); 3815 nfound++; 3816 } 3817 } 3818 3819 if (pset != NULL) { 3820 pe = pool_resource_to_elem(pconf, pset); 3821 if (pool_get_property(pconf, pe, "pset.min", pv) != POC_INVAL) { 3822 (void) pool_value_get_uint64(pv, &val_uint); 3823 (void) snprintf(pset_tab->zone_ncpu_min, 3824 sizeof (pset_tab->zone_ncpu_min), "%u", val_uint); 3825 nfound++; 3826 } 3827 3828 if (pool_get_property(pconf, pe, "pset.max", pv) != POC_INVAL) { 3829 (void) pool_value_get_uint64(pv, &val_uint); 3830 (void) snprintf(pset_tab->zone_ncpu_max, 3831 sizeof (pset_tab->zone_ncpu_max), "%u", val_uint); 3832 nfound++; 3833 } 3834 } 3835 3836 pool_value_free(pv); 3837 3838 if (nfound == 3) 3839 return (PO_SUCCESS); 3840 3841 return (PO_FAIL); 3842 } 3843 3844 /* 3845 * Determine if a tmp pool is configured and if so, if the configuration is 3846 * still valid or if it has been changed since the tmp pool was created. 3847 * If the tmp pool configuration is no longer valid, delete the tmp pool. 3848 * 3849 * Set *valid=B_TRUE if there is an existing, valid tmp pool configuration. 3850 */ 3851 static int 3852 verify_del_tmp_pool(pool_conf_t *pconf, char *tmp_name, char *pool_err, 3853 int err_size, struct zone_psettab *pset_tab, boolean_t *exists) 3854 { 3855 int res = Z_OK; 3856 pool_t *pool; 3857 pool_resource_t *pset; 3858 struct zone_psettab pset_current; 3859 3860 *exists = B_FALSE; 3861 3862 if (pool_conf_open(pconf, pool_dynamic_location(), PO_RDWR) 3863 != PO_SUCCESS) { 3864 res = zerr_pool(pool_err, err_size, Z_POOL); 3865 return (res); 3866 } 3867 3868 pool = pool_get_pool(pconf, tmp_name); 3869 pset = pool_get_resource(pconf, "pset", tmp_name); 3870 3871 if (pool == NULL && pset == NULL) { 3872 /* no tmp pool configured */ 3873 goto done; 3874 } 3875 3876 /* 3877 * If an existing tmp pool for this zone is configured with the proper 3878 * settings, then the tmp pool is valid. 3879 */ 3880 if (get_running_tmp_pset(pconf, pool, pset, &pset_current) 3881 == PO_SUCCESS && 3882 strcmp(pset_tab->zone_ncpu_min, 3883 pset_current.zone_ncpu_min) == 0 && 3884 strcmp(pset_tab->zone_ncpu_max, 3885 pset_current.zone_ncpu_max) == 0 && 3886 strcmp(pset_tab->zone_importance, 3887 pset_current.zone_importance) == 0) { 3888 *exists = B_TRUE; 3889 3890 } else { 3891 /* 3892 * An out-of-date tmp pool configuration exists. Delete it 3893 * so that we can create the correct tmp pool config. 3894 */ 3895 if (pset != NULL && 3896 pool_resource_destroy(pconf, pset) != PO_SUCCESS) { 3897 res = zerr_pool(pool_err, err_size, Z_POOL); 3898 goto done; 3899 } 3900 3901 if (pool != NULL && 3902 pool_destroy(pconf, pool) != PO_SUCCESS) { 3903 res = zerr_pool(pool_err, err_size, Z_POOL); 3904 goto done; 3905 } 3906 3907 /* commit dynamic config */ 3908 if (pool_conf_commit(pconf, 0) != PO_SUCCESS) 3909 res = zerr_pool(pool_err, err_size, Z_POOL); 3910 } 3911 3912 done: 3913 (void) pool_conf_close(pconf); 3914 3915 return (res); 3916 } 3917 3918 /* 3919 * Destroy any existing tmp pool. 3920 */ 3921 int 3922 zonecfg_destroy_tmp_pool(char *zone_name, char *pool_err, int err_size) 3923 { 3924 int status; 3925 int res = Z_OK; 3926 pool_conf_t *pconf; 3927 pool_t *pool; 3928 pool_resource_t *pset; 3929 char tmp_name[MAX_TMP_POOL_NAME]; 3930 3931 /* if pools not enabled then nothing to do */ 3932 if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) 3933 return (Z_OK); 3934 3935 if ((pconf = pool_conf_alloc()) == NULL) 3936 return (zerr_pool(pool_err, err_size, Z_POOL)); 3937 3938 (void) snprintf(tmp_name, sizeof (tmp_name), TMP_POOL_NAME, zone_name); 3939 3940 if (pool_conf_open(pconf, pool_dynamic_location(), PO_RDWR) 3941 != PO_SUCCESS) { 3942 res = zerr_pool(pool_err, err_size, Z_POOL); 3943 pool_conf_free(pconf); 3944 return (res); 3945 } 3946 3947 pool = pool_get_pool(pconf, tmp_name); 3948 pset = pool_get_resource(pconf, "pset", tmp_name); 3949 3950 if (pool == NULL && pset == NULL) { 3951 /* nothing to destroy, we're done */ 3952 goto done; 3953 } 3954 3955 if (pset != NULL && pool_resource_destroy(pconf, pset) != PO_SUCCESS) { 3956 res = zerr_pool(pool_err, err_size, Z_POOL); 3957 goto done; 3958 } 3959 3960 if (pool != NULL && pool_destroy(pconf, pool) != PO_SUCCESS) { 3961 res = zerr_pool(pool_err, err_size, Z_POOL); 3962 goto done; 3963 } 3964 3965 /* commit dynamic config */ 3966 if (pool_conf_commit(pconf, 0) != PO_SUCCESS) 3967 res = zerr_pool(pool_err, err_size, Z_POOL); 3968 3969 done: 3970 (void) pool_conf_close(pconf); 3971 pool_conf_free(pconf); 3972 3973 return (res); 3974 } 3975 3976 /* 3977 * Attempt to bind to a tmp pool for this zone. If there is no tmp pool 3978 * configured, we just return Z_OK. 3979 * 3980 * We either attempt to create the tmp pool for this zone or rebind to an 3981 * existing tmp pool for this zone. 3982 * 3983 * Rebinding is used when a zone with a tmp pool reboots so that we don't have 3984 * to recreate the tmp pool. To do this we need to be sure we work correctly 3985 * for the following cases: 3986 * 3987 * - there is an existing, properly configured tmp pool. 3988 * - zonecfg added tmp pool after zone was booted, must now create. 3989 * - zonecfg updated tmp pool config after zone was booted, in this case 3990 * we destroy the old tmp pool and create a new one. 3991 */ 3992 int 3993 zonecfg_bind_tmp_pool(zone_dochandle_t handle, zoneid_t zoneid, char *pool_err, 3994 int err_size) 3995 { 3996 struct zone_psettab pset_tab; 3997 int err; 3998 int status; 3999 pool_conf_t *pconf; 4000 boolean_t exists; 4001 char zone_name[ZONENAME_MAX]; 4002 char tmp_name[MAX_TMP_POOL_NAME]; 4003 4004 (void) getzonenamebyid(zoneid, zone_name, sizeof (zone_name)); 4005 4006 err = zonecfg_lookup_pset(handle, &pset_tab); 4007 4008 /* if no temporary pool configured, we're done */ 4009 if (err == Z_NO_ENTRY) 4010 return (Z_OK); 4011 4012 /* 4013 * importance might not have a value but we need to validate it here, 4014 * so set the default. 4015 */ 4016 if (pset_tab.zone_importance[0] == '\0') 4017 (void) strlcpy(pset_tab.zone_importance, "1", 4018 sizeof (pset_tab.zone_importance)); 4019 4020 /* if pools not enabled, enable them now */ 4021 if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) { 4022 if (pool_set_status(POOL_ENABLED) != PO_SUCCESS) 4023 return (Z_POOL_ENABLE); 4024 } 4025 4026 if ((pconf = pool_conf_alloc()) == NULL) 4027 return (zerr_pool(pool_err, err_size, Z_POOL)); 4028 4029 (void) snprintf(tmp_name, sizeof (tmp_name), TMP_POOL_NAME, zone_name); 4030 4031 /* 4032 * Check if a valid tmp pool/pset already exists. If so, we just 4033 * reuse it. 4034 */ 4035 if ((err = verify_del_tmp_pool(pconf, tmp_name, pool_err, err_size, 4036 &pset_tab, &exists)) != Z_OK) { 4037 pool_conf_free(pconf); 4038 return (err); 4039 } 4040 4041 if (!exists) 4042 err = create_tmp_pool(pool_err, err_size, pconf, tmp_name, 4043 &pset_tab); 4044 4045 pool_conf_free(pconf); 4046 4047 if (err != Z_OK) 4048 return (err); 4049 4050 /* Bind the zone to the pool. */ 4051 if (pool_set_binding(tmp_name, P_ZONEID, zoneid) != PO_SUCCESS) 4052 return (zerr_pool(pool_err, err_size, Z_POOL_BIND)); 4053 4054 return (Z_OK); 4055 } 4056 4057 /* 4058 * Attempt to bind to a permanent pool for this zone. If there is no 4059 * permanent pool configured, we just return Z_OK. 4060 */ 4061 int 4062 zonecfg_bind_pool(zone_dochandle_t handle, zoneid_t zoneid, char *pool_err, 4063 int err_size) 4064 { 4065 pool_conf_t *poolconf; 4066 pool_t *pool; 4067 char poolname[MAXPATHLEN]; 4068 int status; 4069 int error; 4070 4071 /* 4072 * Find the pool mentioned in the zone configuration, and bind to it. 4073 */ 4074 error = zonecfg_get_pool(handle, poolname, sizeof (poolname)); 4075 if (error == Z_NO_ENTRY || (error == Z_OK && strlen(poolname) == 0)) { 4076 /* 4077 * The property is not set on the zone, so the pool 4078 * should be bound to the default pool. But that's 4079 * already done by the kernel, so we can just return. 4080 */ 4081 return (Z_OK); 4082 } 4083 if (error != Z_OK) { 4084 /* 4085 * Not an error, even though it shouldn't be happening. 4086 */ 4087 return (Z_OK); 4088 } 4089 /* 4090 * Don't do anything if pools aren't enabled. 4091 */ 4092 if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) 4093 return (Z_POOLS_NOT_ACTIVE); 4094 4095 /* 4096 * Try to provide a sane error message if the requested pool doesn't 4097 * exist. 4098 */ 4099 if ((poolconf = pool_conf_alloc()) == NULL) 4100 return (zerr_pool(pool_err, err_size, Z_POOL)); 4101 4102 if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) != 4103 PO_SUCCESS) { 4104 pool_conf_free(poolconf); 4105 return (zerr_pool(pool_err, err_size, Z_POOL)); 4106 } 4107 pool = pool_get_pool(poolconf, poolname); 4108 (void) pool_conf_close(poolconf); 4109 pool_conf_free(poolconf); 4110 if (pool == NULL) 4111 return (Z_NO_POOL); 4112 4113 /* 4114 * Bind the zone to the pool. 4115 */ 4116 if (pool_set_binding(poolname, P_ZONEID, zoneid) != PO_SUCCESS) { 4117 /* if bind fails, return poolname for the error msg */ 4118 (void) strlcpy(pool_err, poolname, err_size); 4119 return (Z_POOL_BIND); 4120 } 4121 4122 return (Z_OK); 4123 } 4124 4125 4126 static boolean_t 4127 svc_enabled(char *svc_name) 4128 { 4129 scf_simple_prop_t *prop; 4130 boolean_t found = B_FALSE; 4131 4132 prop = scf_simple_prop_get(NULL, svc_name, SCF_PG_GENERAL, 4133 SCF_PROPERTY_ENABLED); 4134 4135 if (scf_simple_prop_numvalues(prop) == 1 && 4136 *scf_simple_prop_next_boolean(prop) != 0) 4137 found = B_TRUE; 4138 4139 scf_simple_prop_free(prop); 4140 4141 return (found); 4142 } 4143 4144 /* 4145 * If the zone has capped-memory, make sure the rcap service is enabled. 4146 */ 4147 int 4148 zonecfg_enable_rcapd(char *err, int size) 4149 { 4150 if (!svc_enabled(RCAP_SERVICE) && 4151 smf_enable_instance(RCAP_SERVICE, 0) == -1) { 4152 (void) strlcpy(err, scf_strerror(scf_error()), size); 4153 return (Z_SYSTEM); 4154 } 4155 4156 return (Z_OK); 4157 } 4158 4159 /* 4160 * Return true if pset has cpu range specified and poold is not enabled. 4161 */ 4162 boolean_t 4163 zonecfg_warn_poold(zone_dochandle_t handle) 4164 { 4165 struct zone_psettab pset_tab; 4166 int min, max; 4167 int err; 4168 4169 err = zonecfg_lookup_pset(handle, &pset_tab); 4170 4171 /* if no temporary pool configured, we're done */ 4172 if (err == Z_NO_ENTRY) 4173 return (B_FALSE); 4174 4175 min = atoi(pset_tab.zone_ncpu_min); 4176 max = atoi(pset_tab.zone_ncpu_max); 4177 4178 /* range not specified, no need for poold */ 4179 if (min == max) 4180 return (B_FALSE); 4181 4182 /* we have a range, check if poold service is enabled */ 4183 if (svc_enabled(POOLD_SERVICE)) 4184 return (B_FALSE); 4185 4186 return (B_TRUE); 4187 } 4188 4189 static int 4190 get_pool_sched_class(char *poolname, char *class, int clsize) 4191 { 4192 int status; 4193 pool_conf_t *poolconf; 4194 pool_t *pool; 4195 pool_elem_t *pe; 4196 pool_value_t *pv = pool_value_alloc(); 4197 const char *sched_str; 4198 4199 if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) 4200 return (Z_NO_POOL); 4201 4202 if ((poolconf = pool_conf_alloc()) == NULL) 4203 return (Z_NO_POOL); 4204 4205 if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) != 4206 PO_SUCCESS) { 4207 pool_conf_free(poolconf); 4208 return (Z_NO_POOL); 4209 } 4210 4211 if ((pool = pool_get_pool(poolconf, poolname)) == NULL) { 4212 (void) pool_conf_close(poolconf); 4213 pool_conf_free(poolconf); 4214 return (Z_NO_POOL); 4215 } 4216 4217 pe = pool_to_elem(poolconf, pool); 4218 if (pool_get_property(poolconf, pe, "pool.scheduler", pv) 4219 != POC_INVAL) { 4220 (void) pool_value_get_string(pv, &sched_str); 4221 if (strlcpy(class, sched_str, clsize) >= clsize) 4222 return (Z_TOO_BIG); 4223 } 4224 4225 (void) pool_conf_close(poolconf); 4226 pool_conf_free(poolconf); 4227 return (Z_OK); 4228 } 4229 4230 /* 4231 * Get the default scheduling class for the zone. This will either be the 4232 * class set on the zone's pool or the system default scheduling class. 4233 */ 4234 int 4235 zonecfg_get_dflt_sched_class(zone_dochandle_t handle, char *class, int clsize) 4236 { 4237 char poolname[MAXPATHLEN]; 4238 4239 if (zonecfg_get_pool(handle, poolname, sizeof (poolname)) == Z_OK) { 4240 /* check if the zone's pool specified a sched class */ 4241 if (get_pool_sched_class(poolname, class, clsize) == Z_OK) 4242 return (Z_OK); 4243 } 4244 4245 if (priocntl(0, 0, PC_GETDFLCL, class, (uint64_t)clsize) == -1) 4246 return (Z_TOO_BIG); 4247 4248 return (Z_OK); 4249 } 4250 4251 int 4252 zonecfg_setfsent(zone_dochandle_t handle) 4253 { 4254 return (zonecfg_setent(handle)); 4255 } 4256 4257 int 4258 zonecfg_getfsent(zone_dochandle_t handle, struct zone_fstab *tabptr) 4259 { 4260 xmlNodePtr cur, options; 4261 char options_str[MAX_MNTOPT_STR]; 4262 int err; 4263 4264 if (handle == NULL) 4265 return (Z_INVAL); 4266 4267 if ((cur = handle->zone_dh_cur) == NULL) 4268 return (Z_NO_ENTRY); 4269 4270 for (; cur != NULL; cur = cur->next) 4271 if (!xmlStrcmp(cur->name, DTD_ELEM_FS)) 4272 break; 4273 if (cur == NULL) { 4274 handle->zone_dh_cur = handle->zone_dh_top; 4275 return (Z_NO_ENTRY); 4276 } 4277 4278 if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special, 4279 sizeof (tabptr->zone_fs_special))) != Z_OK) { 4280 handle->zone_dh_cur = handle->zone_dh_top; 4281 return (err); 4282 } 4283 4284 if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw, 4285 sizeof (tabptr->zone_fs_raw))) != Z_OK) { 4286 handle->zone_dh_cur = handle->zone_dh_top; 4287 return (err); 4288 } 4289 4290 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 4291 sizeof (tabptr->zone_fs_dir))) != Z_OK) { 4292 handle->zone_dh_cur = handle->zone_dh_top; 4293 return (err); 4294 } 4295 4296 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type, 4297 sizeof (tabptr->zone_fs_type))) != Z_OK) { 4298 handle->zone_dh_cur = handle->zone_dh_top; 4299 return (err); 4300 } 4301 4302 /* OK for options to be NULL */ 4303 tabptr->zone_fs_options = NULL; 4304 for (options = cur->xmlChildrenNode; options != NULL; 4305 options = options->next) { 4306 if (fetchprop(options, DTD_ATTR_NAME, options_str, 4307 sizeof (options_str)) != Z_OK) 4308 break; 4309 if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK) 4310 break; 4311 } 4312 4313 handle->zone_dh_cur = cur->next; 4314 return (Z_OK); 4315 } 4316 4317 int 4318 zonecfg_endfsent(zone_dochandle_t handle) 4319 { 4320 return (zonecfg_endent(handle)); 4321 } 4322 4323 int 4324 zonecfg_setipdent(zone_dochandle_t handle) 4325 { 4326 return (zonecfg_setent(handle)); 4327 } 4328 4329 int 4330 zonecfg_getipdent(zone_dochandle_t handle, struct zone_fstab *tabptr) 4331 { 4332 xmlNodePtr cur; 4333 int err; 4334 4335 if (handle == NULL) 4336 return (Z_INVAL); 4337 4338 if ((cur = handle->zone_dh_cur) == NULL) 4339 return (Z_NO_ENTRY); 4340 4341 for (; cur != NULL; cur = cur->next) 4342 if (!xmlStrcmp(cur->name, DTD_ELEM_IPD)) 4343 break; 4344 if (cur == NULL) { 4345 handle->zone_dh_cur = handle->zone_dh_top; 4346 return (Z_NO_ENTRY); 4347 } 4348 4349 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 4350 sizeof (tabptr->zone_fs_dir))) != Z_OK) { 4351 handle->zone_dh_cur = handle->zone_dh_top; 4352 return (err); 4353 } 4354 4355 handle->zone_dh_cur = cur->next; 4356 return (Z_OK); 4357 } 4358 4359 int 4360 zonecfg_endipdent(zone_dochandle_t handle) 4361 { 4362 return (zonecfg_endent(handle)); 4363 } 4364 4365 int 4366 zonecfg_setnwifent(zone_dochandle_t handle) 4367 { 4368 return (zonecfg_setent(handle)); 4369 } 4370 4371 int 4372 zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 4373 { 4374 xmlNodePtr cur; 4375 int err; 4376 4377 if (handle == NULL) 4378 return (Z_INVAL); 4379 4380 if ((cur = handle->zone_dh_cur) == NULL) 4381 return (Z_NO_ENTRY); 4382 4383 for (; cur != NULL; cur = cur->next) 4384 if (!xmlStrcmp(cur->name, DTD_ELEM_NET)) 4385 break; 4386 if (cur == NULL) { 4387 handle->zone_dh_cur = handle->zone_dh_top; 4388 return (Z_NO_ENTRY); 4389 } 4390 4391 if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address, 4392 sizeof (tabptr->zone_nwif_address))) != Z_OK) { 4393 handle->zone_dh_cur = handle->zone_dh_top; 4394 return (err); 4395 } 4396 4397 if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical, 4398 sizeof (tabptr->zone_nwif_physical))) != Z_OK) { 4399 handle->zone_dh_cur = handle->zone_dh_top; 4400 return (err); 4401 } 4402 4403 if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER, 4404 tabptr->zone_nwif_defrouter, 4405 sizeof (tabptr->zone_nwif_defrouter))) != Z_OK) { 4406 handle->zone_dh_cur = handle->zone_dh_top; 4407 return (err); 4408 } 4409 4410 handle->zone_dh_cur = cur->next; 4411 return (Z_OK); 4412 } 4413 4414 int 4415 zonecfg_endnwifent(zone_dochandle_t handle) 4416 { 4417 return (zonecfg_endent(handle)); 4418 } 4419 4420 int 4421 zonecfg_setdevent(zone_dochandle_t handle) 4422 { 4423 return (zonecfg_setent(handle)); 4424 } 4425 4426 int 4427 zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr) 4428 { 4429 xmlNodePtr cur; 4430 int err; 4431 4432 if (handle == NULL) 4433 return (Z_INVAL); 4434 4435 if ((cur = handle->zone_dh_cur) == NULL) 4436 return (Z_NO_ENTRY); 4437 4438 for (; cur != NULL; cur = cur->next) 4439 if (!xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) 4440 break; 4441 if (cur == NULL) { 4442 handle->zone_dh_cur = handle->zone_dh_top; 4443 return (Z_NO_ENTRY); 4444 } 4445 4446 if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match, 4447 sizeof (tabptr->zone_dev_match))) != Z_OK) { 4448 handle->zone_dh_cur = handle->zone_dh_top; 4449 return (err); 4450 } 4451 4452 handle->zone_dh_cur = cur->next; 4453 return (Z_OK); 4454 } 4455 4456 int 4457 zonecfg_enddevent(zone_dochandle_t handle) 4458 { 4459 return (zonecfg_endent(handle)); 4460 } 4461 4462 int 4463 zonecfg_setrctlent(zone_dochandle_t handle) 4464 { 4465 return (zonecfg_setent(handle)); 4466 } 4467 4468 int 4469 zonecfg_getrctlent(zone_dochandle_t handle, struct zone_rctltab *tabptr) 4470 { 4471 xmlNodePtr cur, val; 4472 struct zone_rctlvaltab *valptr; 4473 int err; 4474 4475 if (handle == NULL) 4476 return (Z_INVAL); 4477 4478 if ((cur = handle->zone_dh_cur) == NULL) 4479 return (Z_NO_ENTRY); 4480 4481 for (; cur != NULL; cur = cur->next) 4482 if (!xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 4483 break; 4484 if (cur == NULL) { 4485 handle->zone_dh_cur = handle->zone_dh_top; 4486 return (Z_NO_ENTRY); 4487 } 4488 4489 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_rctl_name, 4490 sizeof (tabptr->zone_rctl_name))) != Z_OK) { 4491 handle->zone_dh_cur = handle->zone_dh_top; 4492 return (err); 4493 } 4494 4495 tabptr->zone_rctl_valptr = NULL; 4496 for (val = cur->xmlChildrenNode; val != NULL; val = val->next) { 4497 valptr = (struct zone_rctlvaltab *)malloc( 4498 sizeof (struct zone_rctlvaltab)); 4499 if (valptr == NULL) 4500 return (Z_NOMEM); 4501 if (fetchprop(val, DTD_ATTR_PRIV, valptr->zone_rctlval_priv, 4502 sizeof (valptr->zone_rctlval_priv)) != Z_OK) 4503 break; 4504 if (fetchprop(val, DTD_ATTR_LIMIT, valptr->zone_rctlval_limit, 4505 sizeof (valptr->zone_rctlval_limit)) != Z_OK) 4506 break; 4507 if (fetchprop(val, DTD_ATTR_ACTION, valptr->zone_rctlval_action, 4508 sizeof (valptr->zone_rctlval_action)) != Z_OK) 4509 break; 4510 if (zonecfg_add_rctl_value(tabptr, valptr) != Z_OK) 4511 break; 4512 } 4513 4514 handle->zone_dh_cur = cur->next; 4515 return (Z_OK); 4516 } 4517 4518 int 4519 zonecfg_endrctlent(zone_dochandle_t handle) 4520 { 4521 return (zonecfg_endent(handle)); 4522 } 4523 4524 int 4525 zonecfg_setattrent(zone_dochandle_t handle) 4526 { 4527 return (zonecfg_setent(handle)); 4528 } 4529 4530 int 4531 zonecfg_getattrent(zone_dochandle_t handle, struct zone_attrtab *tabptr) 4532 { 4533 xmlNodePtr cur; 4534 int err; 4535 4536 if (handle == NULL) 4537 return (Z_INVAL); 4538 4539 if ((cur = handle->zone_dh_cur) == NULL) 4540 return (Z_NO_ENTRY); 4541 4542 for (; cur != NULL; cur = cur->next) 4543 if (!xmlStrcmp(cur->name, DTD_ELEM_ATTR)) 4544 break; 4545 if (cur == NULL) { 4546 handle->zone_dh_cur = handle->zone_dh_top; 4547 return (Z_NO_ENTRY); 4548 } 4549 4550 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name, 4551 sizeof (tabptr->zone_attr_name))) != Z_OK) { 4552 handle->zone_dh_cur = handle->zone_dh_top; 4553 return (err); 4554 } 4555 4556 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type, 4557 sizeof (tabptr->zone_attr_type))) != Z_OK) { 4558 handle->zone_dh_cur = handle->zone_dh_top; 4559 return (err); 4560 } 4561 4562 if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value, 4563 sizeof (tabptr->zone_attr_value))) != Z_OK) { 4564 handle->zone_dh_cur = handle->zone_dh_top; 4565 return (err); 4566 } 4567 4568 handle->zone_dh_cur = cur->next; 4569 return (Z_OK); 4570 } 4571 4572 int 4573 zonecfg_endattrent(zone_dochandle_t handle) 4574 { 4575 return (zonecfg_endent(handle)); 4576 } 4577 4578 /* 4579 * The privileges available on the system and described in privileges(5) 4580 * fall into four categories with respect to non-global zones: 4581 * 4582 * Default set of privileges considered safe for all non-global 4583 * zones. These privileges are "safe" in the sense that a 4584 * privileged process in the zone cannot affect processes in any 4585 * other zone on the system. 4586 * 4587 * Set of privileges not currently permitted within a non-global 4588 * zone. These privileges are considered by default, "unsafe," 4589 * and include ones which affect global resources (such as the 4590 * system clock or physical memory) or are overly broad and cover 4591 * more than one mechanism in the system. In other cases, there 4592 * has not been sufficient virtualization in the parts of the 4593 * system the privilege covers to allow its use within a 4594 * non-global zone. 4595 * 4596 * Set of privileges required in order to get a zone booted and 4597 * init(1M) started. These cannot be removed from the zone's 4598 * privilege set. 4599 * 4600 * All other privileges are optional and are potentially useful for 4601 * processes executing inside a non-global zone. 4602 * 4603 * When privileges are added to the system, a determination needs to be 4604 * made as to which category the privilege belongs to. Ideally, 4605 * privileges should be fine-grained enough and the mechanisms they cover 4606 * virtualized enough so that they can be made available to non-global 4607 * zones. 4608 */ 4609 4610 /* 4611 * Define some of the tokens that priv_str_to_set(3C) recognizes. Since 4612 * the privilege string separator can be any character, although it is 4613 * usually a comma character, define these here as well in the event that 4614 * they change or are augmented in the future. 4615 */ 4616 #define BASIC_TOKEN "basic" 4617 #define DEFAULT_TOKEN "default" 4618 #define ZONE_TOKEN "zone" 4619 #define TOKEN_PRIV_CHAR ',' 4620 #define TOKEN_PRIV_STR "," 4621 4622 typedef struct priv_node { 4623 struct priv_node *pn_next; /* Next privilege */ 4624 char *pn_priv; /* Privileges name */ 4625 } priv_node_t; 4626 4627 /* Privileges lists can differ across brands */ 4628 typedef struct priv_lists { 4629 /* Privileges considered safe for all non-global zones of a brand */ 4630 struct priv_node *pl_default; 4631 4632 /* Privileges not permitted for all non-global zones of a brand */ 4633 struct priv_node *pl_prohibited; 4634 4635 /* Privileges required for all non-global zones of a brand */ 4636 struct priv_node *pl_required; 4637 4638 /* 4639 * ip-type of the zone these privileges lists apply to. 4640 * It is used to pass ip-type to the callback function, 4641 * priv_lists_cb, which has no way of getting the ip-type. 4642 */ 4643 const char *pl_iptype; 4644 } priv_lists_t; 4645 4646 static int 4647 priv_lists_cb(void *data, priv_iter_t *priv_iter) 4648 { 4649 priv_lists_t *plp = (priv_lists_t *)data; 4650 priv_node_t *pnp; 4651 4652 /* Skip this privilege if ip-type does not match */ 4653 if ((strcmp(priv_iter->pi_iptype, "all") != 0) && 4654 (strcmp(priv_iter->pi_iptype, plp->pl_iptype) != 0)) 4655 return (0); 4656 4657 /* Allocate a new priv list node. */ 4658 if ((pnp = malloc(sizeof (*pnp))) == NULL) 4659 return (-1); 4660 if ((pnp->pn_priv = strdup(priv_iter->pi_name)) == NULL) { 4661 free(pnp); 4662 return (-1); 4663 } 4664 4665 /* Insert the new priv list node into the right list */ 4666 if (strcmp(priv_iter->pi_set, "default") == 0) { 4667 pnp->pn_next = plp->pl_default; 4668 plp->pl_default = pnp; 4669 } else if (strcmp(priv_iter->pi_set, "prohibited") == 0) { 4670 pnp->pn_next = plp->pl_prohibited; 4671 plp->pl_prohibited = pnp; 4672 } else if (strcmp(priv_iter->pi_set, "required") == 0) { 4673 pnp->pn_next = plp->pl_required; 4674 plp->pl_required = pnp; 4675 } else { 4676 free(pnp->pn_priv); 4677 free(pnp); 4678 return (-1); 4679 } 4680 return (0); 4681 } 4682 4683 static void 4684 priv_lists_destroy(priv_lists_t *plp) 4685 { 4686 priv_node_t *pnp; 4687 4688 assert(plp != NULL); 4689 4690 while ((pnp = plp->pl_default) != NULL) { 4691 plp->pl_default = pnp->pn_next; 4692 free(pnp->pn_priv); 4693 free(pnp); 4694 } 4695 while ((pnp = plp->pl_prohibited) != NULL) { 4696 plp->pl_prohibited = pnp->pn_next; 4697 free(pnp->pn_priv); 4698 free(pnp); 4699 } 4700 while ((pnp = plp->pl_required) != NULL) { 4701 plp->pl_required = pnp->pn_next; 4702 free(pnp->pn_priv); 4703 free(pnp); 4704 } 4705 free(plp); 4706 } 4707 4708 static int 4709 priv_lists_create(zone_dochandle_t handle, priv_lists_t **plpp, 4710 const char *curr_iptype) 4711 { 4712 priv_lists_t *plp; 4713 brand_handle_t bh; 4714 char brand[MAXNAMELEN]; 4715 4716 if (handle != NULL) { 4717 if (zonecfg_get_brand(handle, brand, sizeof (brand)) != 0) 4718 return (Z_BRAND_ERROR); 4719 } else { 4720 (void) strlcpy(brand, NATIVE_BRAND_NAME, MAXNAMELEN); 4721 } 4722 4723 if ((bh = brand_open(brand)) == NULL) 4724 return (Z_BRAND_ERROR); 4725 4726 if ((plp = calloc(1, sizeof (priv_lists_t))) == NULL) { 4727 brand_close(bh); 4728 return (Z_NOMEM); 4729 } 4730 4731 plp->pl_iptype = curr_iptype; 4732 4733 /* construct the privilege lists */ 4734 if (brand_config_iter_privilege(bh, priv_lists_cb, plp) != 0) { 4735 priv_lists_destroy(plp); 4736 brand_close(bh); 4737 return (Z_BRAND_ERROR); 4738 } 4739 4740 brand_close(bh); 4741 *plpp = plp; 4742 return (Z_OK); 4743 } 4744 4745 static int 4746 get_default_privset(priv_set_t *privs, priv_lists_t *plp) 4747 { 4748 priv_node_t *pnp; 4749 priv_set_t *basic; 4750 4751 basic = priv_str_to_set(BASIC_TOKEN, TOKEN_PRIV_STR, NULL); 4752 if (basic == NULL) 4753 return (errno == ENOMEM ? Z_NOMEM : Z_INVAL); 4754 4755 priv_union(basic, privs); 4756 priv_freeset(basic); 4757 4758 for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next) { 4759 if (priv_addset(privs, pnp->pn_priv) != 0) 4760 return (Z_INVAL); 4761 } 4762 4763 return (Z_OK); 4764 } 4765 4766 int 4767 zonecfg_default_privset(priv_set_t *privs, const char *curr_iptype) 4768 { 4769 priv_lists_t *plp; 4770 int ret; 4771 4772 if ((ret = priv_lists_create(NULL, &plp, curr_iptype)) != Z_OK) 4773 return (ret); 4774 ret = get_default_privset(privs, plp); 4775 priv_lists_destroy(plp); 4776 return (ret); 4777 } 4778 4779 void 4780 append_priv_token(char *priv, char *str, size_t strlen) 4781 { 4782 if (*str != '\0') 4783 (void) strlcat(str, TOKEN_PRIV_STR, strlen); 4784 (void) strlcat(str, priv, strlen); 4785 } 4786 4787 /* 4788 * Verify that the supplied string is a valid privilege limit set for a 4789 * non-global zone. This string must not only be acceptable to 4790 * priv_str_to_set(3C) which parses it, but it also must resolve to a 4791 * privilege set that includes certain required privileges and lacks 4792 * certain prohibited privileges. 4793 */ 4794 static int 4795 verify_privset(char *privbuf, priv_set_t *privs, char **privname, 4796 boolean_t add_default, priv_lists_t *plp) 4797 { 4798 priv_node_t *pnp; 4799 char *tmp, *cp, *lasts; 4800 size_t len; 4801 priv_set_t *mergeset; 4802 const char *token; 4803 4804 /* 4805 * The verification of the privilege string occurs in several 4806 * phases. In the first phase, the supplied string is scanned for 4807 * the ZONE_TOKEN token which is not support as part of the 4808 * "limitpriv" property. 4809 * 4810 * Duplicate the supplied privilege string since strtok_r(3C) 4811 * tokenizes its input by null-terminating the tokens. 4812 */ 4813 if ((tmp = strdup(privbuf)) == NULL) 4814 return (Z_NOMEM); 4815 for (cp = strtok_r(tmp, TOKEN_PRIV_STR, &lasts); cp != NULL; 4816 cp = strtok_r(NULL, TOKEN_PRIV_STR, &lasts)) { 4817 if (strcmp(cp, ZONE_TOKEN) == 0) { 4818 free(tmp); 4819 if ((*privname = strdup(ZONE_TOKEN)) == NULL) 4820 return (Z_NOMEM); 4821 else 4822 return (Z_PRIV_UNKNOWN); 4823 } 4824 } 4825 free(tmp); 4826 4827 if (add_default) { 4828 /* 4829 * If DEFAULT_TOKEN was specified, a string needs to be 4830 * built containing the privileges from the default, safe 4831 * set along with those of the "limitpriv" property. 4832 */ 4833 len = strlen(privbuf) + sizeof (BASIC_TOKEN) + 2; 4834 4835 for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next) 4836 len += strlen(pnp->pn_priv) + 1; 4837 tmp = alloca(len); 4838 *tmp = '\0'; 4839 4840 append_priv_token(BASIC_TOKEN, tmp, len); 4841 for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next) 4842 append_priv_token(pnp->pn_priv, tmp, len); 4843 (void) strlcat(tmp, TOKEN_PRIV_STR, len); 4844 (void) strlcat(tmp, privbuf, len); 4845 } else { 4846 tmp = privbuf; 4847 } 4848 4849 4850 /* 4851 * In the next phase, attempt to convert the merged privilege 4852 * string into a privilege set. In the case of an error, either 4853 * there was a memory allocation failure or there was an invalid 4854 * privilege token in the string. In either case, return an 4855 * appropriate error code but in the event of an invalid token, 4856 * allocate a string containing its name and return that back to 4857 * the caller. 4858 */ 4859 mergeset = priv_str_to_set(tmp, TOKEN_PRIV_STR, &token); 4860 if (mergeset == NULL) { 4861 if (token == NULL) 4862 return (Z_NOMEM); 4863 if ((cp = strchr(token, TOKEN_PRIV_CHAR)) != NULL) 4864 *cp = '\0'; 4865 if ((*privname = strdup(token)) == NULL) 4866 return (Z_NOMEM); 4867 else 4868 return (Z_PRIV_UNKNOWN); 4869 } 4870 4871 /* 4872 * Next, verify that none of the prohibited zone privileges are 4873 * present in the merged privilege set. 4874 */ 4875 for (pnp = plp->pl_prohibited; pnp != NULL; pnp = pnp->pn_next) { 4876 if (priv_ismember(mergeset, pnp->pn_priv)) { 4877 priv_freeset(mergeset); 4878 if ((*privname = strdup(pnp->pn_priv)) == NULL) 4879 return (Z_NOMEM); 4880 else 4881 return (Z_PRIV_PROHIBITED); 4882 } 4883 } 4884 4885 /* 4886 * Finally, verify that all of the required zone privileges are 4887 * present in the merged privilege set. 4888 */ 4889 for (pnp = plp->pl_required; pnp != NULL; pnp = pnp->pn_next) { 4890 if (!priv_ismember(mergeset, pnp->pn_priv)) { 4891 priv_freeset(mergeset); 4892 if ((*privname = strdup(pnp->pn_priv)) == NULL) 4893 return (Z_NOMEM); 4894 else 4895 return (Z_PRIV_REQUIRED); 4896 } 4897 } 4898 4899 priv_copyset(mergeset, privs); 4900 priv_freeset(mergeset); 4901 return (Z_OK); 4902 } 4903 4904 /* 4905 * Fill in the supplied privilege set with either the default, safe set of 4906 * privileges suitable for a non-global zone, or one based on the 4907 * "limitpriv" property in the zone's configuration. 4908 * 4909 * In the event of an invalid privilege specification in the 4910 * configuration, a string is allocated and returned containing the 4911 * "privilege" causing the issue. It is the caller's responsibility to 4912 * free this memory when it is done with it. 4913 */ 4914 int 4915 zonecfg_get_privset(zone_dochandle_t handle, priv_set_t *privs, 4916 char **privname) 4917 { 4918 priv_lists_t *plp; 4919 char *cp, *limitpriv = NULL; 4920 int err, limitlen; 4921 zone_iptype_t iptype; 4922 const char *curr_iptype; 4923 4924 /* 4925 * Attempt to lookup the "limitpriv" property. If it does not 4926 * exist or matches the string DEFAULT_TOKEN exactly, then the 4927 * default, safe privilege set is returned. 4928 */ 4929 if ((err = zonecfg_get_limitpriv(handle, &limitpriv)) != Z_OK) 4930 return (err); 4931 4932 if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK) 4933 return (err); 4934 4935 switch (iptype) { 4936 case ZS_SHARED: 4937 curr_iptype = "shared"; 4938 break; 4939 case ZS_EXCLUSIVE: 4940 curr_iptype = "exclusive"; 4941 break; 4942 } 4943 4944 if ((err = priv_lists_create(handle, &plp, curr_iptype)) != Z_OK) 4945 return (err); 4946 4947 limitlen = strlen(limitpriv); 4948 if (limitlen == 0 || strcmp(limitpriv, DEFAULT_TOKEN) == 0) { 4949 free(limitpriv); 4950 err = get_default_privset(privs, plp); 4951 priv_lists_destroy(plp); 4952 return (err); 4953 } 4954 4955 /* 4956 * Check if the string DEFAULT_TOKEN is the first token in a list 4957 * of privileges. 4958 */ 4959 cp = strchr(limitpriv, TOKEN_PRIV_CHAR); 4960 if (cp != NULL && 4961 strncmp(limitpriv, DEFAULT_TOKEN, cp - limitpriv) == 0) 4962 err = verify_privset(cp + 1, privs, privname, B_TRUE, plp); 4963 else 4964 err = verify_privset(limitpriv, privs, privname, B_FALSE, plp); 4965 4966 free(limitpriv); 4967 priv_lists_destroy(plp); 4968 return (err); 4969 } 4970 4971 int 4972 zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz) 4973 { 4974 zone_dochandle_t handle; 4975 boolean_t found = B_FALSE; 4976 struct zoneent *ze; 4977 FILE *cookie; 4978 int err; 4979 char *cp; 4980 4981 if (zone_name == NULL) 4982 return (Z_INVAL); 4983 4984 (void) strlcpy(zonepath, zonecfg_root, rp_sz); 4985 cp = zonepath + strlen(zonepath); 4986 while (cp > zonepath && cp[-1] == '/') 4987 *--cp = '\0'; 4988 4989 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) { 4990 if (zonepath[0] == '\0') 4991 (void) strlcpy(zonepath, "/", rp_sz); 4992 return (Z_OK); 4993 } 4994 4995 /* 4996 * First check the index file. Because older versions did not have 4997 * a copy of the zone path, allow for it to be zero length, in which 4998 * case we ignore this result and fall back to the XML files. 4999 */ 5000 cookie = setzoneent(); 5001 while ((ze = getzoneent_private(cookie)) != NULL) { 5002 if (strcmp(ze->zone_name, zone_name) == 0) { 5003 found = B_TRUE; 5004 if (ze->zone_path[0] != '\0') 5005 (void) strlcpy(cp, ze->zone_path, 5006 rp_sz - (cp - zonepath)); 5007 } 5008 free(ze); 5009 if (found) 5010 break; 5011 } 5012 endzoneent(cookie); 5013 if (found && *cp != '\0') 5014 return (Z_OK); 5015 5016 /* Fall back to the XML files. */ 5017 if ((handle = zonecfg_init_handle()) == NULL) 5018 return (Z_NOMEM); 5019 5020 /* 5021 * Check the snapshot first: if a zone is running, its zonepath 5022 * may have changed. 5023 */ 5024 if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) { 5025 if ((err = zonecfg_get_handle(zone_name, handle)) != Z_OK) { 5026 zonecfg_fini_handle(handle); 5027 return (err); 5028 } 5029 } 5030 err = zonecfg_get_zonepath(handle, zonepath, rp_sz); 5031 zonecfg_fini_handle(handle); 5032 return (err); 5033 } 5034 5035 int 5036 zone_get_rootpath(char *zone_name, char *rootpath, size_t rp_sz) 5037 { 5038 int err; 5039 5040 /* This function makes sense for non-global zones only. */ 5041 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) 5042 return (Z_BOGUS_ZONE_NAME); 5043 if ((err = zone_get_zonepath(zone_name, rootpath, rp_sz)) != Z_OK) 5044 return (err); 5045 if (strlcat(rootpath, "/root", rp_sz) >= rp_sz) 5046 return (Z_TOO_BIG); 5047 return (Z_OK); 5048 } 5049 5050 int 5051 zone_get_brand(char *zone_name, char *brandname, size_t rp_sz) 5052 { 5053 int err; 5054 zone_dochandle_t handle; 5055 char myzone[MAXNAMELEN]; 5056 int myzoneid = getzoneid(); 5057 5058 /* 5059 * If we are not in the global zone, then we don't have the zone 5060 * .xml files with the brand name available. Thus, we are going to 5061 * have to ask the kernel for the information. 5062 */ 5063 if (myzoneid != GLOBAL_ZONEID) { 5064 if (is_system_labeled()) { 5065 (void) strlcpy(brandname, NATIVE_BRAND_NAME, rp_sz); 5066 return (Z_OK); 5067 } 5068 if (zone_getattr(myzoneid, ZONE_ATTR_NAME, myzone, 5069 sizeof (myzone)) < 0) 5070 return (Z_NO_ZONE); 5071 if (strncmp(zone_name, myzone, MAXNAMELEN) != NULL) 5072 return (Z_NO_ZONE); 5073 err = zone_getattr(myzoneid, ZONE_ATTR_BRAND, brandname, rp_sz); 5074 if (err < 0) 5075 return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL); 5076 return (Z_OK); 5077 } 5078 5079 if (strcmp(zone_name, "global") == NULL) { 5080 (void) strlcpy(brandname, NATIVE_BRAND_NAME, rp_sz); 5081 return (Z_OK); 5082 } 5083 if ((handle = zonecfg_init_handle()) == NULL) 5084 return (Z_NOMEM); 5085 5086 err = zonecfg_get_handle((char *)zone_name, handle); 5087 if (err == Z_OK) 5088 err = zonecfg_get_brand(handle, brandname, rp_sz); 5089 5090 zonecfg_fini_handle(handle); 5091 return (err); 5092 } 5093 5094 /* 5095 * Return the appropriate root for the active /dev. 5096 * For normal zone, the path is $ZONEPATH/root; 5097 * for scratch zone, the dev path is $ZONEPATH/lu. 5098 */ 5099 int 5100 zone_get_devroot(char *zone_name, char *devroot, size_t rp_sz) 5101 { 5102 int err; 5103 char *suffix; 5104 zone_state_t state; 5105 5106 /* This function makes sense for non-global zones only. */ 5107 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) 5108 return (Z_BOGUS_ZONE_NAME); 5109 if ((err = zone_get_zonepath(zone_name, devroot, rp_sz)) != Z_OK) 5110 return (err); 5111 5112 if (zone_get_state(zone_name, &state) == Z_OK && 5113 state == ZONE_STATE_MOUNTED) 5114 suffix = "/lu"; 5115 else 5116 suffix = "/root"; 5117 if (strlcat(devroot, suffix, rp_sz) >= rp_sz) 5118 return (Z_TOO_BIG); 5119 return (Z_OK); 5120 } 5121 5122 static zone_state_t 5123 kernel_state_to_user_state(zoneid_t zoneid, zone_status_t kernel_state) 5124 { 5125 char zoneroot[MAXPATHLEN]; 5126 size_t zlen; 5127 5128 assert(kernel_state <= ZONE_MAX_STATE); 5129 switch (kernel_state) { 5130 case ZONE_IS_UNINITIALIZED: 5131 case ZONE_IS_INITIALIZED: 5132 /* The kernel will not return these two states */ 5133 return (ZONE_STATE_READY); 5134 case ZONE_IS_READY: 5135 /* 5136 * If the zone's root is mounted on $ZONEPATH/lu, then 5137 * it's a mounted scratch zone. 5138 */ 5139 if (zone_getattr(zoneid, ZONE_ATTR_ROOT, zoneroot, 5140 sizeof (zoneroot)) >= 0) { 5141 zlen = strlen(zoneroot); 5142 if (zlen > 3 && 5143 strcmp(zoneroot + zlen - 3, "/lu") == 0) 5144 return (ZONE_STATE_MOUNTED); 5145 } 5146 return (ZONE_STATE_READY); 5147 case ZONE_IS_BOOTING: 5148 case ZONE_IS_RUNNING: 5149 return (ZONE_STATE_RUNNING); 5150 case ZONE_IS_SHUTTING_DOWN: 5151 case ZONE_IS_EMPTY: 5152 return (ZONE_STATE_SHUTTING_DOWN); 5153 case ZONE_IS_DOWN: 5154 case ZONE_IS_DYING: 5155 case ZONE_IS_DEAD: 5156 default: 5157 return (ZONE_STATE_DOWN); 5158 } 5159 /* NOTREACHED */ 5160 } 5161 5162 int 5163 zone_get_state(char *zone_name, zone_state_t *state_num) 5164 { 5165 zone_status_t status; 5166 zoneid_t zone_id; 5167 struct zoneent *ze; 5168 boolean_t found = B_FALSE; 5169 FILE *cookie; 5170 char kernzone[ZONENAME_MAX]; 5171 FILE *fp; 5172 5173 if (zone_name == NULL) 5174 return (Z_INVAL); 5175 5176 /* 5177 * If we're looking at an alternate root, then we need to query the 5178 * kernel using the scratch zone name. 5179 */ 5180 zone_id = -1; 5181 if (*zonecfg_root != '\0' && !zonecfg_is_scratch(zone_name)) { 5182 if ((fp = zonecfg_open_scratch("", B_FALSE)) != NULL) { 5183 if (zonecfg_find_scratch(fp, zone_name, zonecfg_root, 5184 kernzone, sizeof (kernzone)) == 0) 5185 zone_id = getzoneidbyname(kernzone); 5186 zonecfg_close_scratch(fp); 5187 } 5188 } else { 5189 zone_id = getzoneidbyname(zone_name); 5190 } 5191 5192 /* check to see if zone is running */ 5193 if (zone_id != -1 && 5194 zone_getattr(zone_id, ZONE_ATTR_STATUS, &status, 5195 sizeof (status)) >= 0) { 5196 *state_num = kernel_state_to_user_state(zone_id, status); 5197 return (Z_OK); 5198 } 5199 5200 cookie = setzoneent(); 5201 while ((ze = getzoneent_private(cookie)) != NULL) { 5202 if (strcmp(ze->zone_name, zone_name) == 0) { 5203 found = B_TRUE; 5204 *state_num = ze->zone_state; 5205 } 5206 free(ze); 5207 if (found) 5208 break; 5209 } 5210 endzoneent(cookie); 5211 return ((found) ? Z_OK : Z_NO_ZONE); 5212 } 5213 5214 int 5215 zone_set_state(char *zone, zone_state_t state) 5216 { 5217 struct zoneent ze; 5218 5219 if (state != ZONE_STATE_CONFIGURED && state != ZONE_STATE_INSTALLED && 5220 state != ZONE_STATE_INCOMPLETE) 5221 return (Z_INVAL); 5222 5223 bzero(&ze, sizeof (ze)); 5224 (void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name)); 5225 ze.zone_state = state; 5226 (void) strlcpy(ze.zone_path, "", sizeof (ze.zone_path)); 5227 return (putzoneent(&ze, PZE_MODIFY)); 5228 } 5229 5230 /* 5231 * Get id (if any) for specified zone. There are four possible outcomes: 5232 * - If the string corresponds to the numeric id of an active (booted) 5233 * zone, sets *zip to the zone id and returns 0. 5234 * - If the string corresponds to the name of an active (booted) zone, 5235 * sets *zip to the zone id and returns 0. 5236 * - If the string is a name in the configuration but is not booted, 5237 * sets *zip to ZONE_ID_UNDEFINED and returns 0. 5238 * - Otherwise, leaves *zip unchanged and returns -1. 5239 * 5240 * This function acts as an auxiliary filter on the function of the same 5241 * name in libc; the linker binds to this version if libzonecfg exists, 5242 * and the libc version if it doesn't. Any changes to this version of 5243 * the function should probably be reflected in the libc version as well. 5244 */ 5245 int 5246 zone_get_id(const char *str, zoneid_t *zip) 5247 { 5248 zone_dochandle_t hdl; 5249 zoneid_t zoneid; 5250 char *cp; 5251 int err; 5252 5253 /* first try looking for active zone by id */ 5254 errno = 0; 5255 zoneid = (zoneid_t)strtol(str, &cp, 0); 5256 if (errno == 0 && cp != str && *cp == '\0' && 5257 getzonenamebyid(zoneid, NULL, 0) != -1) { 5258 *zip = zoneid; 5259 return (0); 5260 } 5261 5262 /* then look for active zone by name */ 5263 if ((zoneid = getzoneidbyname(str)) != -1) { 5264 *zip = zoneid; 5265 return (0); 5266 } 5267 5268 /* if in global zone, try looking up name in configuration database */ 5269 if (getzoneid() != GLOBAL_ZONEID || 5270 (hdl = zonecfg_init_handle()) == NULL) 5271 return (-1); 5272 5273 if (zonecfg_get_handle(str, hdl) == Z_OK) { 5274 /* zone exists but isn't active */ 5275 *zip = ZONE_ID_UNDEFINED; 5276 err = 0; 5277 } else { 5278 err = -1; 5279 } 5280 5281 zonecfg_fini_handle(hdl); 5282 return (err); 5283 } 5284 5285 char * 5286 zone_state_str(zone_state_t state_num) 5287 { 5288 switch (state_num) { 5289 case ZONE_STATE_CONFIGURED: 5290 return (ZONE_STATE_STR_CONFIGURED); 5291 case ZONE_STATE_INCOMPLETE: 5292 return (ZONE_STATE_STR_INCOMPLETE); 5293 case ZONE_STATE_INSTALLED: 5294 return (ZONE_STATE_STR_INSTALLED); 5295 case ZONE_STATE_READY: 5296 return (ZONE_STATE_STR_READY); 5297 case ZONE_STATE_MOUNTED: 5298 return (ZONE_STATE_STR_MOUNTED); 5299 case ZONE_STATE_RUNNING: 5300 return (ZONE_STATE_STR_RUNNING); 5301 case ZONE_STATE_SHUTTING_DOWN: 5302 return (ZONE_STATE_STR_SHUTTING_DOWN); 5303 case ZONE_STATE_DOWN: 5304 return (ZONE_STATE_STR_DOWN); 5305 default: 5306 return ("unknown"); 5307 } 5308 } 5309 5310 /* 5311 * Given a UUID value, find an associated zone name. This is intended to be 5312 * used by callers who set up some 'default' name (corresponding to the 5313 * expected name for the zone) in the zonename buffer, and thus the function 5314 * doesn't touch this buffer on failure. 5315 */ 5316 int 5317 zonecfg_get_name_by_uuid(const uuid_t uuidin, char *zonename, size_t namelen) 5318 { 5319 FILE *fp; 5320 struct zoneent *ze; 5321 uchar_t *uuid; 5322 5323 /* 5324 * A small amount of subterfuge via casts is necessary here because 5325 * libuuid doesn't use const correctly, but we don't want to export 5326 * this brokenness to our clients. 5327 */ 5328 uuid = (uchar_t *)uuidin; 5329 if (uuid_is_null(uuid)) 5330 return (Z_NO_ZONE); 5331 if ((fp = setzoneent()) == NULL) 5332 return (Z_NO_ZONE); 5333 while ((ze = getzoneent_private(fp)) != NULL) { 5334 if (uuid_compare(uuid, ze->zone_uuid) == 0) 5335 break; 5336 free(ze); 5337 } 5338 endzoneent(fp); 5339 if (ze != NULL) { 5340 (void) strlcpy(zonename, ze->zone_name, namelen); 5341 free(ze); 5342 return (Z_OK); 5343 } else { 5344 return (Z_NO_ZONE); 5345 } 5346 } 5347 5348 /* 5349 * Given a zone name, get its UUID. Returns a "NULL" UUID value if the zone 5350 * exists but the file doesn't have a value set yet. Returns an error if the 5351 * zone cannot be located. 5352 */ 5353 int 5354 zonecfg_get_uuid(const char *zonename, uuid_t uuid) 5355 { 5356 FILE *fp; 5357 struct zoneent *ze; 5358 5359 if ((fp = setzoneent()) == NULL) 5360 return (Z_NO_ZONE); 5361 while ((ze = getzoneent_private(fp)) != NULL) { 5362 if (strcmp(ze->zone_name, zonename) == 0) 5363 break; 5364 free(ze); 5365 } 5366 endzoneent(fp); 5367 if (ze != NULL) { 5368 uuid_copy(uuid, ze->zone_uuid); 5369 free(ze); 5370 return (Z_OK); 5371 } else { 5372 return (Z_NO_ZONE); 5373 } 5374 } 5375 5376 /* 5377 * File-system convenience functions. 5378 */ 5379 boolean_t 5380 zonecfg_valid_fs_type(const char *type) 5381 { 5382 /* 5383 * We already know which FS types don't work. 5384 */ 5385 if (strcmp(type, "proc") == 0 || 5386 strcmp(type, "mntfs") == 0 || 5387 strcmp(type, "autofs") == 0 || 5388 strncmp(type, "nfs", sizeof ("nfs") - 1) == 0 || 5389 strcmp(type, "cachefs") == 0) 5390 return (B_FALSE); 5391 /* 5392 * The caller may do more detailed verification to make sure other 5393 * aspects of this filesystem type make sense. 5394 */ 5395 return (B_TRUE); 5396 } 5397 5398 /* 5399 * Generally uninteresting rctl convenience functions. 5400 */ 5401 5402 int 5403 zonecfg_construct_rctlblk(const struct zone_rctlvaltab *rctlval, 5404 rctlblk_t *rctlblk) 5405 { 5406 unsigned long long ull; 5407 char *endp; 5408 rctl_priv_t priv; 5409 rctl_qty_t limit; 5410 uint_t action; 5411 5412 /* Get the privilege */ 5413 if (strcmp(rctlval->zone_rctlval_priv, "basic") == 0) { 5414 priv = RCPRIV_BASIC; 5415 } else if (strcmp(rctlval->zone_rctlval_priv, "privileged") == 0) { 5416 priv = RCPRIV_PRIVILEGED; 5417 } else { 5418 /* Invalid privilege */ 5419 return (Z_INVAL); 5420 } 5421 5422 /* deal with negative input; strtoull(3c) doesn't do what we want */ 5423 if (rctlval->zone_rctlval_limit[0] == '-') 5424 return (Z_INVAL); 5425 /* Get the limit */ 5426 errno = 0; 5427 ull = strtoull(rctlval->zone_rctlval_limit, &endp, 0); 5428 if (errno != 0 || *endp != '\0') { 5429 /* parse failed */ 5430 return (Z_INVAL); 5431 } 5432 limit = (rctl_qty_t)ull; 5433 5434 /* Get the action */ 5435 if (strcmp(rctlval->zone_rctlval_action, "none") == 0) { 5436 action = RCTL_LOCAL_NOACTION; 5437 } else if (strcmp(rctlval->zone_rctlval_action, "signal") == 0) { 5438 action = RCTL_LOCAL_SIGNAL; 5439 } else if (strcmp(rctlval->zone_rctlval_action, "deny") == 0) { 5440 action = RCTL_LOCAL_DENY; 5441 } else { 5442 /* Invalid Action */ 5443 return (Z_INVAL); 5444 } 5445 rctlblk_set_local_action(rctlblk, action, 0); 5446 rctlblk_set_privilege(rctlblk, priv); 5447 rctlblk_set_value(rctlblk, limit); 5448 return (Z_OK); 5449 } 5450 5451 static int 5452 rctl_check(const char *rctlname, void *arg) 5453 { 5454 const char *attrname = arg; 5455 5456 /* 5457 * Returning 1 here is our signal to zonecfg_is_rctl() that it is 5458 * indeed an rctl name recognized by the system. 5459 */ 5460 return (strcmp(rctlname, attrname) == 0 ? 1 : 0); 5461 } 5462 5463 boolean_t 5464 zonecfg_is_rctl(const char *name) 5465 { 5466 return (rctl_walk(rctl_check, (void *)name) == 1); 5467 } 5468 5469 boolean_t 5470 zonecfg_valid_rctlname(const char *name) 5471 { 5472 const char *c; 5473 5474 if (strncmp(name, "zone.", sizeof ("zone.") - 1) != 0) 5475 return (B_FALSE); 5476 if (strlen(name) == sizeof ("zone.") - 1) 5477 return (B_FALSE); 5478 for (c = name + sizeof ("zone.") - 1; *c != '\0'; c++) { 5479 if (!isalpha(*c) && *c != '-') 5480 return (B_FALSE); 5481 } 5482 return (B_TRUE); 5483 } 5484 5485 boolean_t 5486 zonecfg_valid_rctlblk(const rctlblk_t *rctlblk) 5487 { 5488 rctl_priv_t priv = rctlblk_get_privilege((rctlblk_t *)rctlblk); 5489 uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL); 5490 5491 if (priv != RCPRIV_PRIVILEGED) 5492 return (B_FALSE); 5493 if (action != RCTL_LOCAL_NOACTION && action != RCTL_LOCAL_DENY) 5494 return (B_FALSE); 5495 return (B_TRUE); 5496 } 5497 5498 boolean_t 5499 zonecfg_valid_rctl(const char *name, const rctlblk_t *rctlblk) 5500 { 5501 rctlblk_t *current, *next; 5502 rctl_qty_t limit = rctlblk_get_value((rctlblk_t *)rctlblk); 5503 uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL); 5504 uint_t global_flags; 5505 5506 if (!zonecfg_valid_rctlblk(rctlblk)) 5507 return (B_FALSE); 5508 if (!zonecfg_valid_rctlname(name)) 5509 return (B_FALSE); 5510 5511 current = alloca(rctlblk_size()); 5512 if (getrctl(name, NULL, current, RCTL_FIRST) != 0) 5513 return (B_TRUE); /* not an rctl on this system */ 5514 /* 5515 * Make sure the proposed value isn't greater than the current system 5516 * value. 5517 */ 5518 next = alloca(rctlblk_size()); 5519 while (rctlblk_get_privilege(current) != RCPRIV_SYSTEM) { 5520 rctlblk_t *tmp; 5521 5522 if (getrctl(name, current, next, RCTL_NEXT) != 0) 5523 return (B_FALSE); /* shouldn't happen */ 5524 tmp = current; 5525 current = next; 5526 next = tmp; 5527 } 5528 if (limit > rctlblk_get_value(current)) 5529 return (B_FALSE); 5530 5531 /* 5532 * Make sure the proposed action is allowed. 5533 */ 5534 global_flags = rctlblk_get_global_flags(current); 5535 if ((global_flags & RCTL_GLOBAL_DENY_NEVER) && 5536 action == RCTL_LOCAL_DENY) 5537 return (B_FALSE); 5538 if ((global_flags & RCTL_GLOBAL_DENY_ALWAYS) && 5539 action == RCTL_LOCAL_NOACTION) 5540 return (B_FALSE); 5541 5542 return (B_TRUE); 5543 } 5544 5545 /* 5546 * There is always a race condition between reading the initial copy of 5547 * a zones state and its state changing. We address this by providing 5548 * zonecfg_notify_critical_enter and zonecfg_noticy_critical_exit functions. 5549 * When zonecfg_critical_enter is called, sets the state field to LOCKED 5550 * and aquires biglock. Biglock protects against other threads executing 5551 * critical_enter and the state field protects against state changes during 5552 * the critical period. 5553 * 5554 * If any state changes occur, zn_cb will set the failed field of the znotify 5555 * structure. This will cause the critical_exit function to re-lock the 5556 * channel and return an error. Since evsnts may be delayed, the critical_exit 5557 * function "flushes" the queue by putting an event on the queue and waiting for 5558 * zn_cb to notify critical_exit that it received the ping event. 5559 */ 5560 static const char * 5561 string_get_tok(const char *in, char delim, int num) 5562 { 5563 int i = 0; 5564 5565 for (; i < num; in++) { 5566 if (*in == delim) 5567 i++; 5568 if (*in == 0) 5569 return (NULL); 5570 } 5571 return (in); 5572 } 5573 5574 static boolean_t 5575 is_ping(sysevent_t *ev) 5576 { 5577 if (strcmp(sysevent_get_subclass_name(ev), 5578 ZONE_EVENT_PING_SUBCLASS) == 0) { 5579 return (B_TRUE); 5580 } else { 5581 return (B_FALSE); 5582 } 5583 } 5584 5585 static boolean_t 5586 is_my_ping(sysevent_t *ev) 5587 { 5588 const char *sender; 5589 char mypid[sizeof (pid_t) * 3 + 1]; 5590 5591 (void) snprintf(mypid, sizeof (mypid), "%i", getpid()); 5592 sender = string_get_tok(sysevent_get_pub(ev), ':', 3); 5593 if (sender == NULL) 5594 return (B_FALSE); 5595 if (strcmp(sender, mypid) != 0) 5596 return (B_FALSE); 5597 return (B_TRUE); 5598 } 5599 5600 static int 5601 do_callback(struct znotify *zevtchan, sysevent_t *ev) 5602 { 5603 nvlist_t *l; 5604 int zid; 5605 char *zonename; 5606 char *newstate; 5607 char *oldstate; 5608 int ret; 5609 hrtime_t when; 5610 5611 if (strcmp(sysevent_get_subclass_name(ev), 5612 ZONE_EVENT_STATUS_SUBCLASS) == 0) { 5613 5614 if (sysevent_get_attr_list(ev, &l) != 0) { 5615 if (errno == ENOMEM) { 5616 zevtchan->zn_failure_count++; 5617 return (EAGAIN); 5618 } 5619 return (0); 5620 } 5621 ret = 0; 5622 5623 if ((nvlist_lookup_string(l, ZONE_CB_NAME, &zonename) == 0) && 5624 (nvlist_lookup_string(l, ZONE_CB_NEWSTATE, &newstate) 5625 == 0) && 5626 (nvlist_lookup_string(l, ZONE_CB_OLDSTATE, &oldstate) 5627 == 0) && 5628 (nvlist_lookup_uint64(l, ZONE_CB_TIMESTAMP, 5629 (uint64_t *)&when) == 0) && 5630 (nvlist_lookup_int32(l, ZONE_CB_ZONEID, &zid) == 0)) { 5631 ret = zevtchan->zn_callback(zonename, zid, newstate, 5632 oldstate, when, zevtchan->zn_private); 5633 } 5634 5635 zevtchan->zn_failure_count = 0; 5636 nvlist_free(l); 5637 return (ret); 5638 } else { 5639 /* 5640 * We have received an event in an unknown subclass. Ignore. 5641 */ 5642 zevtchan->zn_failure_count = 0; 5643 return (0); 5644 } 5645 } 5646 5647 static int 5648 zn_cb(sysevent_t *ev, void *p) 5649 { 5650 struct znotify *zevtchan = p; 5651 int error; 5652 5653 (void) pthread_mutex_lock(&(zevtchan->zn_mutex)); 5654 5655 if (is_ping(ev) && !is_my_ping(ev)) { 5656 (void) pthread_mutex_unlock((&zevtchan->zn_mutex)); 5657 return (0); 5658 } 5659 5660 if (zevtchan->zn_state == ZN_LOCKED) { 5661 assert(!is_ping(ev)); 5662 zevtchan->zn_failed = B_TRUE; 5663 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5664 return (0); 5665 } 5666 5667 if (zevtchan->zn_state == ZN_PING_INFLIGHT) { 5668 if (is_ping(ev)) { 5669 zevtchan->zn_state = ZN_PING_RECEIVED; 5670 (void) pthread_cond_signal(&(zevtchan->zn_cond)); 5671 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5672 return (0); 5673 } else { 5674 zevtchan->zn_failed = B_TRUE; 5675 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5676 return (0); 5677 } 5678 } 5679 5680 if (zevtchan->zn_state == ZN_UNLOCKED) { 5681 5682 error = do_callback(zevtchan, ev); 5683 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5684 /* 5685 * Every ENOMEM failure causes do_callback to increment 5686 * zn_failure_count and every success causes it to 5687 * set zn_failure_count to zero. If we got EAGAIN, 5688 * we will sleep for zn_failure_count seconds and return 5689 * EAGAIN to gpec to try again. 5690 * 5691 * After 55 seconds, or 10 try's we give up and drop the 5692 * event. 5693 */ 5694 if (error == EAGAIN) { 5695 if (zevtchan->zn_failure_count > ZONE_CB_RETRY_COUNT) { 5696 return (0); 5697 } 5698 (void) sleep(zevtchan->zn_failure_count); 5699 } 5700 return (error); 5701 } 5702 5703 if (zevtchan->zn_state == ZN_PING_RECEIVED) { 5704 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5705 return (0); 5706 } 5707 5708 abort(); 5709 return (0); 5710 } 5711 5712 void 5713 zonecfg_notify_critical_enter(void *h) 5714 { 5715 struct znotify *zevtchan = h; 5716 5717 (void) pthread_mutex_lock(&(zevtchan->zn_bigmutex)); 5718 zevtchan->zn_state = ZN_LOCKED; 5719 } 5720 5721 int 5722 zonecfg_notify_critical_exit(void * h) 5723 { 5724 5725 struct znotify *zevtchan = h; 5726 5727 if (zevtchan->zn_state == ZN_UNLOCKED) 5728 return (0); 5729 5730 (void) pthread_mutex_lock(&(zevtchan->zn_mutex)); 5731 zevtchan->zn_state = ZN_PING_INFLIGHT; 5732 5733 (void) sysevent_evc_publish(zevtchan->zn_eventchan, 5734 ZONE_EVENT_STATUS_CLASS, 5735 ZONE_EVENT_PING_SUBCLASS, ZONE_EVENT_PING_PUBLISHER, 5736 zevtchan->zn_subscriber_id, NULL, EVCH_SLEEP); 5737 5738 while (zevtchan->zn_state != ZN_PING_RECEIVED) { 5739 (void) pthread_cond_wait(&(zevtchan->zn_cond), 5740 &(zevtchan->zn_mutex)); 5741 } 5742 5743 if (zevtchan->zn_failed == B_TRUE) { 5744 zevtchan->zn_state = ZN_LOCKED; 5745 zevtchan->zn_failed = B_FALSE; 5746 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5747 return (1); 5748 } 5749 5750 zevtchan->zn_state = ZN_UNLOCKED; 5751 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5752 (void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex)); 5753 return (0); 5754 } 5755 5756 void 5757 zonecfg_notify_critical_abort(void *h) 5758 { 5759 struct znotify *zevtchan = h; 5760 5761 zevtchan->zn_state = ZN_UNLOCKED; 5762 zevtchan->zn_failed = B_FALSE; 5763 /* 5764 * Don't do anything about zn_lock. If it is held, it could only be 5765 * held by zn_cb and it will be unlocked soon. 5766 */ 5767 (void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex)); 5768 } 5769 5770 void * 5771 zonecfg_notify_bind(int(*func)(const char *zonename, zoneid_t zid, 5772 const char *newstate, const char *oldstate, hrtime_t when, void *p), 5773 void *p) 5774 { 5775 struct znotify *zevtchan; 5776 int i = 1; 5777 int r; 5778 5779 zevtchan = malloc(sizeof (struct znotify)); 5780 5781 if (zevtchan == NULL) 5782 return (NULL); 5783 5784 zevtchan->zn_private = p; 5785 zevtchan->zn_callback = func; 5786 zevtchan->zn_state = ZN_UNLOCKED; 5787 zevtchan->zn_failed = B_FALSE; 5788 5789 if (pthread_mutex_init(&(zevtchan->zn_mutex), NULL)) 5790 goto out3; 5791 if (pthread_cond_init(&(zevtchan->zn_cond), NULL)) { 5792 (void) pthread_mutex_destroy(&(zevtchan->zn_mutex)); 5793 goto out3; 5794 } 5795 if (pthread_mutex_init(&(zevtchan->zn_bigmutex), NULL)) { 5796 (void) pthread_mutex_destroy(&(zevtchan->zn_mutex)); 5797 (void) pthread_cond_destroy(&(zevtchan->zn_cond)); 5798 goto out3; 5799 } 5800 5801 if (sysevent_evc_bind(ZONE_EVENT_CHANNEL, &(zevtchan->zn_eventchan), 5802 0) != 0) 5803 goto out2; 5804 5805 do { 5806 /* 5807 * At 4 digits the subscriber ID gets too long and we have 5808 * no chance of successfully registering. 5809 */ 5810 if (i > 999) 5811 goto out1; 5812 5813 (void) sprintf(zevtchan->zn_subscriber_id, "zone_%li_%i", 5814 getpid() % 999999l, i); 5815 5816 r = sysevent_evc_subscribe(zevtchan->zn_eventchan, 5817 zevtchan->zn_subscriber_id, ZONE_EVENT_STATUS_CLASS, zn_cb, 5818 zevtchan, 0); 5819 5820 i++; 5821 5822 } while (r); 5823 5824 return (zevtchan); 5825 out1: 5826 sysevent_evc_unbind(zevtchan->zn_eventchan); 5827 out2: 5828 (void) pthread_mutex_destroy(&zevtchan->zn_mutex); 5829 (void) pthread_cond_destroy(&zevtchan->zn_cond); 5830 (void) pthread_mutex_destroy(&(zevtchan->zn_bigmutex)); 5831 out3: 5832 free(zevtchan); 5833 5834 return (NULL); 5835 } 5836 5837 void 5838 zonecfg_notify_unbind(void *handle) 5839 { 5840 5841 int ret; 5842 5843 sysevent_evc_unbind(((struct znotify *)handle)->zn_eventchan); 5844 /* 5845 * Check that all evc threads have gone away. This should be 5846 * enforced by sysevent_evc_unbind. 5847 */ 5848 ret = pthread_mutex_trylock(&((struct znotify *)handle)->zn_mutex); 5849 5850 if (ret) 5851 abort(); 5852 5853 (void) pthread_mutex_unlock(&((struct znotify *)handle)->zn_mutex); 5854 (void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_mutex); 5855 (void) pthread_cond_destroy(&((struct znotify *)handle)->zn_cond); 5856 (void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_bigmutex); 5857 5858 free(handle); 5859 } 5860 5861 static int 5862 zonecfg_add_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr) 5863 { 5864 xmlNodePtr newnode, cur = handle->zone_dh_cur; 5865 int err; 5866 5867 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DATASET, NULL); 5868 if ((err = newprop(newnode, DTD_ATTR_NAME, 5869 tabptr->zone_dataset_name)) != Z_OK) 5870 return (err); 5871 return (Z_OK); 5872 } 5873 5874 int 5875 zonecfg_add_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 5876 { 5877 int err; 5878 5879 if (tabptr == NULL) 5880 return (Z_INVAL); 5881 5882 if ((err = operation_prep(handle)) != Z_OK) 5883 return (err); 5884 5885 if ((err = zonecfg_add_ds_core(handle, tabptr)) != Z_OK) 5886 return (err); 5887 5888 return (Z_OK); 5889 } 5890 5891 static int 5892 zonecfg_delete_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr) 5893 { 5894 xmlNodePtr cur = handle->zone_dh_cur; 5895 5896 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 5897 if (xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 5898 continue; 5899 5900 if (match_prop(cur, DTD_ATTR_NAME, 5901 tabptr->zone_dataset_name)) { 5902 xmlUnlinkNode(cur); 5903 xmlFreeNode(cur); 5904 return (Z_OK); 5905 } 5906 } 5907 return (Z_NO_RESOURCE_ID); 5908 } 5909 5910 int 5911 zonecfg_delete_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 5912 { 5913 int err; 5914 5915 if (tabptr == NULL) 5916 return (Z_INVAL); 5917 5918 if ((err = operation_prep(handle)) != Z_OK) 5919 return (err); 5920 5921 if ((err = zonecfg_delete_ds_core(handle, tabptr)) != Z_OK) 5922 return (err); 5923 5924 return (Z_OK); 5925 } 5926 5927 int 5928 zonecfg_modify_ds( 5929 zone_dochandle_t handle, 5930 struct zone_dstab *oldtabptr, 5931 struct zone_dstab *newtabptr) 5932 { 5933 int err; 5934 5935 if (oldtabptr == NULL || newtabptr == NULL) 5936 return (Z_INVAL); 5937 5938 if ((err = operation_prep(handle)) != Z_OK) 5939 return (err); 5940 5941 if ((err = zonecfg_delete_ds_core(handle, oldtabptr)) != Z_OK) 5942 return (err); 5943 5944 if ((err = zonecfg_add_ds_core(handle, newtabptr)) != Z_OK) 5945 return (err); 5946 5947 return (Z_OK); 5948 } 5949 5950 int 5951 zonecfg_lookup_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 5952 { 5953 xmlNodePtr cur, firstmatch; 5954 int err; 5955 char dataset[MAXNAMELEN]; 5956 5957 if (tabptr == NULL) 5958 return (Z_INVAL); 5959 5960 if ((err = operation_prep(handle)) != Z_OK) 5961 return (err); 5962 5963 cur = handle->zone_dh_cur; 5964 firstmatch = NULL; 5965 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 5966 if (xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 5967 continue; 5968 if (strlen(tabptr->zone_dataset_name) > 0) { 5969 if ((fetchprop(cur, DTD_ATTR_NAME, dataset, 5970 sizeof (dataset)) == Z_OK) && 5971 (strcmp(tabptr->zone_dataset_name, 5972 dataset) == 0)) { 5973 if (firstmatch == NULL) 5974 firstmatch = cur; 5975 else 5976 return (Z_INSUFFICIENT_SPEC); 5977 } 5978 } 5979 } 5980 if (firstmatch == NULL) 5981 return (Z_NO_RESOURCE_ID); 5982 5983 cur = firstmatch; 5984 5985 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name, 5986 sizeof (tabptr->zone_dataset_name))) != Z_OK) 5987 return (err); 5988 5989 return (Z_OK); 5990 } 5991 5992 int 5993 zonecfg_setdsent(zone_dochandle_t handle) 5994 { 5995 return (zonecfg_setent(handle)); 5996 } 5997 5998 int 5999 zonecfg_getdsent(zone_dochandle_t handle, struct zone_dstab *tabptr) 6000 { 6001 xmlNodePtr cur; 6002 int err; 6003 6004 if (handle == NULL) 6005 return (Z_INVAL); 6006 6007 if ((cur = handle->zone_dh_cur) == NULL) 6008 return (Z_NO_ENTRY); 6009 6010 for (; cur != NULL; cur = cur->next) 6011 if (!xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 6012 break; 6013 if (cur == NULL) { 6014 handle->zone_dh_cur = handle->zone_dh_top; 6015 return (Z_NO_ENTRY); 6016 } 6017 6018 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name, 6019 sizeof (tabptr->zone_dataset_name))) != Z_OK) { 6020 handle->zone_dh_cur = handle->zone_dh_top; 6021 return (err); 6022 } 6023 6024 handle->zone_dh_cur = cur->next; 6025 return (Z_OK); 6026 } 6027 6028 int 6029 zonecfg_enddsent(zone_dochandle_t handle) 6030 { 6031 return (zonecfg_endent(handle)); 6032 } 6033 6034 /* 6035 * Support for aliased rctls; that is, rctls that have simplified names in 6036 * zonecfg. For example, max-lwps is an alias for a well defined zone.max-lwps 6037 * rctl. If there are multiple existing values for one of these rctls or if 6038 * there is a single value that does not match the well defined template (i.e. 6039 * it has a different action) then we cannot treat the rctl as having an alias 6040 * so we return Z_ALIAS_DISALLOW. That means that the rctl cannot be 6041 * managed in zonecfg via an alias and that the standard rctl syntax must be 6042 * used. 6043 * 6044 * The possible return values are: 6045 * Z_NO_PROPERTY_ID - invalid alias name 6046 * Z_ALIAS_DISALLOW - pre-existing, incompatible rctl definition 6047 * Z_NO_ENTRY - no rctl is configured for this alias 6048 * Z_OK - we got a valid rctl for the specified alias 6049 */ 6050 int 6051 zonecfg_get_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t *rval) 6052 { 6053 boolean_t found = B_FALSE; 6054 boolean_t found_val = B_FALSE; 6055 xmlNodePtr cur, val; 6056 char savedname[MAXNAMELEN]; 6057 struct zone_rctlvaltab rctl; 6058 int i; 6059 int err; 6060 6061 for (i = 0; aliases[i].shortname != NULL; i++) 6062 if (strcmp(name, aliases[i].shortname) == 0) 6063 break; 6064 6065 if (aliases[i].shortname == NULL) 6066 return (Z_NO_PROPERTY_ID); 6067 6068 if ((err = operation_prep(handle)) != Z_OK) 6069 return (err); 6070 6071 cur = handle->zone_dh_cur; 6072 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6073 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL) != 0) 6074 continue; 6075 if ((fetchprop(cur, DTD_ATTR_NAME, savedname, 6076 sizeof (savedname)) == Z_OK) && 6077 (strcmp(savedname, aliases[i].realname) == 0)) { 6078 6079 /* 6080 * If we already saw one of these, we can't have an 6081 * alias since we just found another. 6082 */ 6083 if (found) 6084 return (Z_ALIAS_DISALLOW); 6085 found = B_TRUE; 6086 6087 for (val = cur->xmlChildrenNode; val != NULL; 6088 val = val->next) { 6089 /* 6090 * If we already have one value, we can't have 6091 * an alias since we just found another. 6092 */ 6093 if (found_val) 6094 return (Z_ALIAS_DISALLOW); 6095 found_val = B_TRUE; 6096 6097 if ((fetchprop(val, DTD_ATTR_PRIV, 6098 rctl.zone_rctlval_priv, 6099 sizeof (rctl.zone_rctlval_priv)) != Z_OK)) 6100 break; 6101 if ((fetchprop(val, DTD_ATTR_LIMIT, 6102 rctl.zone_rctlval_limit, 6103 sizeof (rctl.zone_rctlval_limit)) != Z_OK)) 6104 break; 6105 if ((fetchprop(val, DTD_ATTR_ACTION, 6106 rctl.zone_rctlval_action, 6107 sizeof (rctl.zone_rctlval_action)) != Z_OK)) 6108 break; 6109 } 6110 6111 /* check priv and action match the expected vals */ 6112 if (strcmp(rctl.zone_rctlval_priv, 6113 aliases[i].priv) != 0 || 6114 strcmp(rctl.zone_rctlval_action, 6115 aliases[i].action) != 0) 6116 return (Z_ALIAS_DISALLOW); 6117 } 6118 } 6119 6120 if (found) { 6121 *rval = strtoull(rctl.zone_rctlval_limit, NULL, 10); 6122 return (Z_OK); 6123 } 6124 6125 return (Z_NO_ENTRY); 6126 } 6127 6128 int 6129 zonecfg_rm_aliased_rctl(zone_dochandle_t handle, char *name) 6130 { 6131 int i; 6132 uint64_t val; 6133 struct zone_rctltab rctltab; 6134 6135 /* 6136 * First check that we have a valid aliased rctl to remove. 6137 * This will catch an rctl entry with non-standard values or 6138 * multiple rctl values for this name. We need to ignore those 6139 * rctl entries. 6140 */ 6141 if (zonecfg_get_aliased_rctl(handle, name, &val) != Z_OK) 6142 return (Z_OK); 6143 6144 for (i = 0; aliases[i].shortname != NULL; i++) 6145 if (strcmp(name, aliases[i].shortname) == 0) 6146 break; 6147 6148 if (aliases[i].shortname == NULL) 6149 return (Z_NO_RESOURCE_ID); 6150 6151 (void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname, 6152 sizeof (rctltab.zone_rctl_name)); 6153 6154 return (zonecfg_delete_rctl(handle, &rctltab)); 6155 } 6156 6157 boolean_t 6158 zonecfg_aliased_rctl_ok(zone_dochandle_t handle, char *name) 6159 { 6160 uint64_t tmp_val; 6161 6162 switch (zonecfg_get_aliased_rctl(handle, name, &tmp_val)) { 6163 case Z_OK: 6164 /*FALLTHRU*/ 6165 case Z_NO_ENTRY: 6166 return (B_TRUE); 6167 default: 6168 return (B_FALSE); 6169 } 6170 } 6171 6172 int 6173 zonecfg_set_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t val) 6174 { 6175 int i; 6176 int err; 6177 struct zone_rctltab rctltab; 6178 struct zone_rctlvaltab *rctlvaltab; 6179 char buf[128]; 6180 6181 if (!zonecfg_aliased_rctl_ok(handle, name)) 6182 return (Z_ALIAS_DISALLOW); 6183 6184 for (i = 0; aliases[i].shortname != NULL; i++) 6185 if (strcmp(name, aliases[i].shortname) == 0) 6186 break; 6187 6188 if (aliases[i].shortname == NULL) 6189 return (Z_NO_RESOURCE_ID); 6190 6191 /* remove any pre-existing definition for this rctl */ 6192 (void) zonecfg_rm_aliased_rctl(handle, name); 6193 6194 (void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname, 6195 sizeof (rctltab.zone_rctl_name)); 6196 6197 rctltab.zone_rctl_valptr = NULL; 6198 6199 if ((rctlvaltab = calloc(1, sizeof (struct zone_rctlvaltab))) == NULL) 6200 return (Z_NOMEM); 6201 6202 (void) snprintf(buf, sizeof (buf), "%llu", (long long)val); 6203 6204 (void) strlcpy(rctlvaltab->zone_rctlval_priv, aliases[i].priv, 6205 sizeof (rctlvaltab->zone_rctlval_priv)); 6206 (void) strlcpy(rctlvaltab->zone_rctlval_limit, buf, 6207 sizeof (rctlvaltab->zone_rctlval_limit)); 6208 (void) strlcpy(rctlvaltab->zone_rctlval_action, aliases[i].action, 6209 sizeof (rctlvaltab->zone_rctlval_action)); 6210 6211 rctlvaltab->zone_rctlval_next = NULL; 6212 6213 if ((err = zonecfg_add_rctl_value(&rctltab, rctlvaltab)) != Z_OK) 6214 return (err); 6215 6216 return (zonecfg_add_rctl(handle, &rctltab)); 6217 } 6218 6219 static int 6220 delete_tmp_pool(zone_dochandle_t handle) 6221 { 6222 int err; 6223 xmlNodePtr cur = handle->zone_dh_cur; 6224 6225 if ((err = operation_prep(handle)) != Z_OK) 6226 return (err); 6227 6228 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6229 if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) { 6230 xmlUnlinkNode(cur); 6231 xmlFreeNode(cur); 6232 return (Z_OK); 6233 } 6234 } 6235 6236 return (Z_NO_RESOURCE_ID); 6237 } 6238 6239 static int 6240 modify_tmp_pool(zone_dochandle_t handle, char *pool_importance) 6241 { 6242 int err; 6243 xmlNodePtr cur = handle->zone_dh_cur; 6244 xmlNodePtr newnode; 6245 6246 err = delete_tmp_pool(handle); 6247 if (err != Z_OK && err != Z_NO_RESOURCE_ID) 6248 return (err); 6249 6250 if (*pool_importance != '\0') { 6251 if ((err = operation_prep(handle)) != Z_OK) 6252 return (err); 6253 6254 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_TMPPOOL, NULL); 6255 if ((err = newprop(newnode, DTD_ATTR_IMPORTANCE, 6256 pool_importance)) != Z_OK) 6257 return (err); 6258 } 6259 6260 return (Z_OK); 6261 } 6262 6263 static int 6264 add_pset_core(zone_dochandle_t handle, struct zone_psettab *tabptr) 6265 { 6266 xmlNodePtr newnode, cur = handle->zone_dh_cur; 6267 int err; 6268 6269 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PSET, NULL); 6270 if ((err = newprop(newnode, DTD_ATTR_NCPU_MIN, 6271 tabptr->zone_ncpu_min)) != Z_OK) 6272 return (err); 6273 if ((err = newprop(newnode, DTD_ATTR_NCPU_MAX, 6274 tabptr->zone_ncpu_max)) != Z_OK) 6275 return (err); 6276 6277 if ((err = modify_tmp_pool(handle, tabptr->zone_importance)) != Z_OK) 6278 return (err); 6279 6280 return (Z_OK); 6281 } 6282 6283 int 6284 zonecfg_add_pset(zone_dochandle_t handle, struct zone_psettab *tabptr) 6285 { 6286 int err; 6287 6288 if (tabptr == NULL) 6289 return (Z_INVAL); 6290 6291 if ((err = operation_prep(handle)) != Z_OK) 6292 return (err); 6293 6294 if ((err = add_pset_core(handle, tabptr)) != Z_OK) 6295 return (err); 6296 6297 return (Z_OK); 6298 } 6299 6300 int 6301 zonecfg_delete_pset(zone_dochandle_t handle) 6302 { 6303 int err; 6304 int res = Z_NO_RESOURCE_ID; 6305 xmlNodePtr cur = handle->zone_dh_cur; 6306 6307 if ((err = operation_prep(handle)) != Z_OK) 6308 return (err); 6309 6310 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6311 if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) { 6312 xmlUnlinkNode(cur); 6313 xmlFreeNode(cur); 6314 res = Z_OK; 6315 break; 6316 } 6317 } 6318 6319 /* 6320 * Once we have msets, we should check that a mset 6321 * do not exist before we delete the tmp_pool data. 6322 */ 6323 err = delete_tmp_pool(handle); 6324 if (err != Z_OK && err != Z_NO_RESOURCE_ID) 6325 return (err); 6326 6327 return (res); 6328 } 6329 6330 int 6331 zonecfg_modify_pset(zone_dochandle_t handle, struct zone_psettab *tabptr) 6332 { 6333 int err; 6334 6335 if (tabptr == NULL) 6336 return (Z_INVAL); 6337 6338 if ((err = zonecfg_delete_pset(handle)) != Z_OK) 6339 return (err); 6340 6341 if ((err = add_pset_core(handle, tabptr)) != Z_OK) 6342 return (err); 6343 6344 return (Z_OK); 6345 } 6346 6347 int 6348 zonecfg_lookup_pset(zone_dochandle_t handle, struct zone_psettab *tabptr) 6349 { 6350 xmlNodePtr cur; 6351 int err; 6352 int res = Z_NO_ENTRY; 6353 6354 if (tabptr == NULL) 6355 return (Z_INVAL); 6356 6357 if ((err = operation_prep(handle)) != Z_OK) 6358 return (err); 6359 6360 /* this is an optional component */ 6361 tabptr->zone_importance[0] = '\0'; 6362 6363 cur = handle->zone_dh_cur; 6364 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6365 if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) { 6366 if ((err = fetchprop(cur, DTD_ATTR_NCPU_MIN, 6367 tabptr->zone_ncpu_min, 6368 sizeof (tabptr->zone_ncpu_min))) != Z_OK) { 6369 handle->zone_dh_cur = handle->zone_dh_top; 6370 return (err); 6371 } 6372 6373 if ((err = fetchprop(cur, DTD_ATTR_NCPU_MAX, 6374 tabptr->zone_ncpu_max, 6375 sizeof (tabptr->zone_ncpu_max))) != Z_OK) { 6376 handle->zone_dh_cur = handle->zone_dh_top; 6377 return (err); 6378 } 6379 6380 res = Z_OK; 6381 6382 } else if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) { 6383 if ((err = fetchprop(cur, DTD_ATTR_IMPORTANCE, 6384 tabptr->zone_importance, 6385 sizeof (tabptr->zone_importance))) != Z_OK) { 6386 handle->zone_dh_cur = handle->zone_dh_top; 6387 return (err); 6388 } 6389 } 6390 } 6391 6392 return (res); 6393 } 6394 6395 int 6396 zonecfg_getpsetent(zone_dochandle_t handle, struct zone_psettab *tabptr) 6397 { 6398 int err; 6399 6400 if ((err = zonecfg_setent(handle)) != Z_OK) 6401 return (err); 6402 6403 err = zonecfg_lookup_pset(handle, tabptr); 6404 6405 (void) zonecfg_endent(handle); 6406 6407 return (err); 6408 } 6409 6410 static int 6411 add_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 6412 { 6413 xmlNodePtr newnode, cur = handle->zone_dh_cur; 6414 int err; 6415 6416 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_MCAP, NULL); 6417 if ((err = newprop(newnode, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap)) 6418 != Z_OK) 6419 return (err); 6420 6421 return (Z_OK); 6422 } 6423 6424 int 6425 zonecfg_delete_mcap(zone_dochandle_t handle) 6426 { 6427 int err; 6428 xmlNodePtr cur = handle->zone_dh_cur; 6429 6430 if ((err = operation_prep(handle)) != Z_OK) 6431 return (err); 6432 6433 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6434 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0) 6435 continue; 6436 6437 xmlUnlinkNode(cur); 6438 xmlFreeNode(cur); 6439 return (Z_OK); 6440 } 6441 return (Z_NO_RESOURCE_ID); 6442 } 6443 6444 int 6445 zonecfg_modify_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 6446 { 6447 int err; 6448 6449 if (tabptr == NULL) 6450 return (Z_INVAL); 6451 6452 err = zonecfg_delete_mcap(handle); 6453 /* it is ok if there is no mcap entry */ 6454 if (err != Z_OK && err != Z_NO_RESOURCE_ID) 6455 return (err); 6456 6457 if ((err = add_mcap(handle, tabptr)) != Z_OK) 6458 return (err); 6459 6460 return (Z_OK); 6461 } 6462 6463 int 6464 zonecfg_lookup_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 6465 { 6466 xmlNodePtr cur; 6467 int err; 6468 6469 if (tabptr == NULL) 6470 return (Z_INVAL); 6471 6472 if ((err = operation_prep(handle)) != Z_OK) 6473 return (err); 6474 6475 cur = handle->zone_dh_cur; 6476 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6477 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0) 6478 continue; 6479 if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP, 6480 tabptr->zone_physmem_cap, 6481 sizeof (tabptr->zone_physmem_cap))) != Z_OK) { 6482 handle->zone_dh_cur = handle->zone_dh_top; 6483 return (err); 6484 } 6485 6486 return (Z_OK); 6487 } 6488 6489 return (Z_NO_ENTRY); 6490 } 6491 6492 static int 6493 getmcapent_core(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 6494 { 6495 xmlNodePtr cur; 6496 int err; 6497 6498 if (handle == NULL) 6499 return (Z_INVAL); 6500 6501 if ((cur = handle->zone_dh_cur) == NULL) 6502 return (Z_NO_ENTRY); 6503 6504 for (; cur != NULL; cur = cur->next) 6505 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) == 0) 6506 break; 6507 if (cur == NULL) { 6508 handle->zone_dh_cur = handle->zone_dh_top; 6509 return (Z_NO_ENTRY); 6510 } 6511 6512 if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap, 6513 sizeof (tabptr->zone_physmem_cap))) != Z_OK) { 6514 handle->zone_dh_cur = handle->zone_dh_top; 6515 return (err); 6516 } 6517 6518 handle->zone_dh_cur = cur->next; 6519 return (Z_OK); 6520 } 6521 6522 int 6523 zonecfg_getmcapent(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 6524 { 6525 int err; 6526 6527 if ((err = zonecfg_setent(handle)) != Z_OK) 6528 return (err); 6529 6530 err = getmcapent_core(handle, tabptr); 6531 6532 (void) zonecfg_endent(handle); 6533 6534 return (err); 6535 } 6536 6537 /* 6538 * Get the full tree of pkg/patch metadata in a set of nested AVL trees. 6539 * pkgs_avl is an AVL tree of pkgs. Each pkg element contains a 6540 * zpe_patches_avl member which holds an AVL tree of patches for that pkg. 6541 * The patch elements have the same zpe_patches_avl member, each of which can 6542 * hold an AVL tree of patches that are obsoleted by the patch. 6543 * 6544 * The zone xml data contains DTD_ELEM_PACKAGE elements, followed by 6545 * DTD_ELEM_PATCH elements. The DTD_ELEM_PATCH patch element applies to the 6546 * DTD_ELEM_PACKAGE that precedes it. The DTD_ELEM_PATCH element may have 6547 * child DTD_ELEM_OBSOLETES nodes associated with it. The DTD_ELEM_PACKAGE 6548 * really should have had the DTD_ELEM_PATCH elements as children but it 6549 * was not defined that way initially so we are stuck with the DTD definition 6550 * now. However, we can safely assume the ordering for compatibility. 6551 */ 6552 int 6553 zonecfg_getpkgdata(zone_dochandle_t handle, uu_avl_pool_t *pkg_pool, 6554 uu_avl_t *pkgs_avl) 6555 { 6556 xmlNodePtr cur; 6557 int res; 6558 zone_pkg_entry_t *pkg; 6559 char name[MAXNAMELEN]; 6560 char version[ZONE_PKG_VERSMAX]; 6561 6562 if (handle == NULL) 6563 return (Z_INVAL); 6564 6565 if ((res = zonecfg_setent(handle)) != Z_OK) 6566 return (res); 6567 6568 if ((cur = handle->zone_dh_cur) == NULL) { 6569 res = Z_NO_ENTRY; 6570 goto done; 6571 } 6572 6573 for (; cur != NULL; cur = cur->next) { 6574 if (xmlStrcmp(cur->name, DTD_ELEM_PACKAGE) == 0) { 6575 uu_avl_index_t where; 6576 6577 if ((res = fetchprop(cur, DTD_ATTR_NAME, name, 6578 sizeof (name))) != Z_OK) 6579 goto done; 6580 6581 if ((res = fetchprop(cur, DTD_ATTR_VERSION, version, 6582 sizeof (version))) != Z_OK) 6583 goto done; 6584 6585 if ((pkg = (zone_pkg_entry_t *) 6586 malloc(sizeof (zone_pkg_entry_t))) == NULL) { 6587 res = Z_NOMEM; 6588 goto done; 6589 } 6590 6591 if ((pkg->zpe_name = strdup(name)) == NULL) { 6592 free(pkg); 6593 res = Z_NOMEM; 6594 goto done; 6595 } 6596 6597 if ((pkg->zpe_vers = strdup(version)) == NULL) { 6598 free(pkg->zpe_name); 6599 free(pkg); 6600 res = Z_NOMEM; 6601 goto done; 6602 } 6603 6604 pkg->zpe_patches_avl = NULL; 6605 6606 uu_avl_node_init(pkg, &pkg->zpe_entry, pkg_pool); 6607 if (uu_avl_find(pkgs_avl, pkg, NULL, &where) != NULL) { 6608 free(pkg->zpe_name); 6609 free(pkg->zpe_vers); 6610 free(pkg); 6611 } else { 6612 uu_avl_insert(pkgs_avl, pkg, where); 6613 } 6614 6615 } else if (xmlStrcmp(cur->name, DTD_ELEM_PATCH) == 0) { 6616 zone_pkg_entry_t *patch; 6617 uu_avl_index_t where; 6618 char *p; 6619 char *dashp = NULL; 6620 xmlNodePtr child; 6621 6622 if ((res = fetchprop(cur, DTD_ATTR_ID, name, 6623 sizeof (name))) != Z_OK) 6624 goto done; 6625 6626 if ((patch = (zone_pkg_entry_t *) 6627 malloc(sizeof (zone_pkg_entry_t))) == NULL) { 6628 res = Z_NOMEM; 6629 goto done; 6630 } 6631 6632 if ((p = strchr(name, '-')) != NULL) { 6633 dashp = p; 6634 *p++ = '\0'; 6635 } else { 6636 p = ""; 6637 } 6638 6639 if ((patch->zpe_name = strdup(name)) == NULL) { 6640 free(patch); 6641 res = Z_NOMEM; 6642 goto done; 6643 } 6644 6645 if ((patch->zpe_vers = strdup(p)) == NULL) { 6646 free(patch->zpe_name); 6647 free(patch); 6648 res = Z_NOMEM; 6649 goto done; 6650 } 6651 6652 if (dashp != NULL) 6653 *dashp = '-'; 6654 6655 patch->zpe_patches_avl = NULL; 6656 6657 if (pkg->zpe_patches_avl == NULL) { 6658 pkg->zpe_patches_avl = uu_avl_create(pkg_pool, 6659 NULL, UU_DEFAULT); 6660 if (pkg->zpe_patches_avl == NULL) { 6661 free(patch->zpe_name); 6662 free(patch->zpe_vers); 6663 free(patch); 6664 res = Z_NOMEM; 6665 goto done; 6666 } 6667 } 6668 6669 uu_avl_node_init(patch, &patch->zpe_entry, pkg_pool); 6670 if (uu_avl_find(pkg->zpe_patches_avl, patch, NULL, 6671 &where) != NULL) { 6672 free(patch->zpe_name); 6673 free(patch->zpe_vers); 6674 free(patch); 6675 } else { 6676 uu_avl_insert(pkg->zpe_patches_avl, patch, 6677 where); 6678 } 6679 6680 /* Add any patches this patch obsoletes. */ 6681 for (child = cur->xmlChildrenNode; child != NULL; 6682 child = child->next) { 6683 zone_pkg_entry_t *obs; 6684 6685 if (xmlStrcmp(child->name, DTD_ELEM_OBSOLETES) 6686 != 0) 6687 continue; 6688 6689 if ((res = fetchprop(child, DTD_ATTR_ID, 6690 name, sizeof (name))) != Z_OK) 6691 goto done; 6692 6693 if ((obs = (zone_pkg_entry_t *)malloc( 6694 sizeof (zone_pkg_entry_t))) == NULL) { 6695 res = Z_NOMEM; 6696 goto done; 6697 } 6698 6699 if ((obs->zpe_name = strdup(name)) == NULL) { 6700 free(obs); 6701 res = Z_NOMEM; 6702 goto done; 6703 } 6704 /* 6705 * The version doesn't matter for obsoleted 6706 * patches. 6707 */ 6708 obs->zpe_vers = NULL; 6709 obs->zpe_patches_avl = NULL; 6710 6711 /* 6712 * If this is the first obsolete patch, add an 6713 * AVL tree to the parent patch element. 6714 */ 6715 if (patch->zpe_patches_avl == NULL) { 6716 patch->zpe_patches_avl = 6717 uu_avl_create(pkg_pool, NULL, 6718 UU_DEFAULT); 6719 if (patch->zpe_patches_avl == NULL) { 6720 free(obs->zpe_name); 6721 free(obs); 6722 res = Z_NOMEM; 6723 goto done; 6724 } 6725 } 6726 6727 /* Insert obsolete patch into the AVL tree. */ 6728 uu_avl_node_init(obs, &obs->zpe_entry, 6729 pkg_pool); 6730 if (uu_avl_find(patch->zpe_patches_avl, obs, 6731 NULL, &where) != NULL) { 6732 free(obs->zpe_name); 6733 free(obs); 6734 } else { 6735 uu_avl_insert(patch->zpe_patches_avl, 6736 obs, where); 6737 } 6738 } 6739 } 6740 } 6741 6742 done: 6743 (void) zonecfg_endent(handle); 6744 return (res); 6745 } 6746 6747 int 6748 zonecfg_setdevperment(zone_dochandle_t handle) 6749 { 6750 return (zonecfg_setent(handle)); 6751 } 6752 6753 int 6754 zonecfg_getdevperment(zone_dochandle_t handle, struct zone_devpermtab *tabptr) 6755 { 6756 xmlNodePtr cur; 6757 int err; 6758 char buf[128]; 6759 6760 tabptr->zone_devperm_acl = NULL; 6761 6762 if (handle == NULL) 6763 return (Z_INVAL); 6764 6765 if ((cur = handle->zone_dh_cur) == NULL) 6766 return (Z_NO_ENTRY); 6767 6768 for (; cur != NULL; cur = cur->next) 6769 if (!xmlStrcmp(cur->name, DTD_ELEM_DEV_PERM)) 6770 break; 6771 if (cur == NULL) { 6772 handle->zone_dh_cur = handle->zone_dh_top; 6773 return (Z_NO_ENTRY); 6774 } 6775 6776 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_devperm_name, 6777 sizeof (tabptr->zone_devperm_name))) != Z_OK) { 6778 handle->zone_dh_cur = handle->zone_dh_top; 6779 return (err); 6780 } 6781 6782 if ((err = fetchprop(cur, DTD_ATTR_UID, buf, sizeof (buf))) != Z_OK) { 6783 handle->zone_dh_cur = handle->zone_dh_top; 6784 return (err); 6785 } 6786 tabptr->zone_devperm_uid = (uid_t)atol(buf); 6787 6788 if ((err = fetchprop(cur, DTD_ATTR_GID, buf, sizeof (buf))) != Z_OK) { 6789 handle->zone_dh_cur = handle->zone_dh_top; 6790 return (err); 6791 } 6792 tabptr->zone_devperm_gid = (gid_t)atol(buf); 6793 6794 if ((err = fetchprop(cur, DTD_ATTR_MODE, buf, sizeof (buf))) != Z_OK) { 6795 handle->zone_dh_cur = handle->zone_dh_top; 6796 return (err); 6797 } 6798 tabptr->zone_devperm_mode = (mode_t)strtol(buf, (char **)NULL, 8); 6799 6800 if ((err = fetch_alloc_prop(cur, DTD_ATTR_ACL, 6801 &(tabptr->zone_devperm_acl))) != Z_OK) { 6802 handle->zone_dh_cur = handle->zone_dh_top; 6803 return (err); 6804 } 6805 6806 handle->zone_dh_cur = cur->next; 6807 return (Z_OK); 6808 } 6809 6810 int 6811 zonecfg_enddevperment(zone_dochandle_t handle) 6812 { 6813 return (zonecfg_endent(handle)); 6814 } 6815 6816 /* 6817 * Maintain a space separated list of unique pkg names. PATH_MAX is used in 6818 * the pkg code as the maximum size for a pkg name. 6819 */ 6820 static int 6821 add_pkg_to_str(char **str, char *pkg) 6822 { 6823 int len, newlen; 6824 char tstr[PATH_MAX + 3]; 6825 char *tmp; 6826 6827 len = strlen(pkg); 6828 if (*str == NULL) { 6829 /* space for str + 2 spaces + NULL */ 6830 if ((*str = (char *)malloc(len + 3)) == NULL) 6831 return (Z_NOMEM); 6832 (void) snprintf(*str, len + 3, " %s ", pkg); 6833 return (Z_OK); 6834 } 6835 6836 (void) snprintf(tstr, sizeof (tstr), " %s ", pkg); 6837 if (strstr(*str, tstr) != NULL) 6838 return (Z_OK); 6839 6840 /* space for str + 1 space + NULL */ 6841 newlen = strlen(*str) + len + 2; 6842 if ((tmp = (char *)realloc(*str, newlen)) == NULL) 6843 return (Z_NOMEM); 6844 *str = tmp; 6845 (void) strlcat(*str, pkg, newlen); 6846 (void) strlcat(*str, " ", newlen); 6847 return (Z_OK); 6848 } 6849 6850 /* 6851 * Process a list of pkgs from an entry in the contents file, adding each pkg 6852 * name to the list of pkgs. 6853 * 6854 * It is possible for the pkg name to be preceeded by a special character 6855 * which indicates some bookkeeping information for pkging. Check if the 6856 * first char is not an Alpha char. If so, skip over it. 6857 */ 6858 static int 6859 add_pkg_list(char *lastp, char ***plist, int *pcnt, char **pkg_warn) 6860 { 6861 char *p; 6862 int pkg_cnt = *pcnt; 6863 char **pkgs = *plist; 6864 int res = Z_OK; 6865 6866 while ((p = strtok_r(NULL, " ", &lastp)) != NULL) { 6867 char **tmpp; 6868 int i; 6869 6870 /* skip over any special pkg bookkeeping char */ 6871 if (!isalpha(*p)) { 6872 p++; 6873 if ((res = add_pkg_to_str(pkg_warn, p)) != Z_OK) 6874 break; 6875 } 6876 6877 /* Check if the pkg is already in the list */ 6878 for (i = 0; i < pkg_cnt; i++) { 6879 if (strcmp(p, pkgs[i]) == 0) 6880 break; 6881 } 6882 6883 if (i < pkg_cnt) 6884 continue; 6885 6886 /* The pkg is not in the list; add it. */ 6887 if ((tmpp = (char **)realloc(pkgs, 6888 sizeof (char *) * (pkg_cnt + 1))) == NULL) { 6889 res = Z_NOMEM; 6890 break; 6891 } 6892 pkgs = tmpp; 6893 6894 if ((pkgs[pkg_cnt] = strdup(p)) == NULL) { 6895 res = Z_NOMEM; 6896 break; 6897 } 6898 pkg_cnt++; 6899 } 6900 6901 *plist = pkgs; 6902 *pcnt = pkg_cnt; 6903 6904 return (res); 6905 } 6906 6907 /* 6908 * Process an entry from the contents file (type "directory"). If the 6909 * directory path is in the list of ipds and is not under a lofs mount within 6910 * the ipd then add the associated list of pkgs to the pkg list. The input 6911 * parameter "entry" will be broken up by the parser within this function so 6912 * its value will be modified when this function exits. 6913 * 6914 * The entries we are looking for will look something like: 6915 * /usr d none 0755 root sys SUNWctpls SUNWidnl SUNWlibCf .... 6916 */ 6917 static int 6918 get_path_pkgs(char *entry, char **ipds, char **fss, char ***pkgs, int *pkg_cnt, 6919 char **pkg_warn) 6920 { 6921 char *f1; 6922 char *f2; 6923 char *lastp; 6924 int i; 6925 char *nlp; 6926 6927 if ((f1 = strtok_r(entry, " ", &lastp)) == NULL || 6928 (f2 = strtok_r(NULL, " ", &lastp)) == NULL || strcmp(f2, "d") != 0) 6929 return (Z_OK); 6930 6931 /* Check if this directory entry is in the list of ipds. */ 6932 for (i = 0; ipds[i] != NULL; i++) { 6933 char wildcard[MAXPATHLEN]; 6934 6935 /* 6936 * We want to match on the path and any other directory 6937 * entries under this path. When we use FNM_PATHNAME then 6938 * that means '/' will not be matched by a wildcard (*) so 6939 * we omit FNM_PATHNAME on the call with the wildcard matching. 6940 */ 6941 (void) snprintf(wildcard, sizeof (wildcard), "%s/*", ipds[i]); 6942 if (fnmatch(ipds[i], f1, FNM_PATHNAME) == 0 || 6943 fnmatch(wildcard, f1, 0) == 0) { 6944 /* It looks like we do want the pkgs for this path. */ 6945 break; 6946 } 6947 } 6948 6949 /* This entry did not match any of the ipds. */ 6950 if (ipds[i] == NULL) 6951 return (Z_OK); 6952 6953 /* 6954 * Check if there is a fs mounted under the ipd. If so, ignore this 6955 * entry. 6956 */ 6957 for (i = 0; fss[i] != NULL; i++) { 6958 char wildcard[MAXPATHLEN]; 6959 6960 (void) snprintf(wildcard, sizeof (wildcard), "%s/*", fss[i]); 6961 if (fnmatch(fss[i], f1, FNM_PATHNAME) == 0 || 6962 fnmatch(wildcard, f1, 0) == 0) { 6963 /* We should ignore this path. */ 6964 break; 6965 } 6966 } 6967 6968 /* If not null, then we matched an fs mount point so ignore entry. */ 6969 if (fss[i] != NULL) 6970 return (Z_OK); 6971 6972 /* 6973 * We do want the pkgs for this entry. First, skip over the next 4 6974 * fields in the entry so that we call add_pkg_list starting with the 6975 * pkg names. 6976 */ 6977 for (i = 0; i < 4 && strtok_r(NULL, " ", &lastp) != NULL; i++) 6978 ; 6979 /* If there are < 4 fields this entry is corrupt, just skip it. */ 6980 if (i < 4) 6981 return (Z_OK); 6982 6983 /* strip newline from the line */ 6984 nlp = (lastp + strlen(lastp) - 1); 6985 if (*nlp == '\n') 6986 *nlp = '\0'; 6987 6988 return (add_pkg_list(lastp, pkgs, pkg_cnt, pkg_warn)); 6989 } 6990 6991 /* 6992 * Read an entry from a pkginfo or contents file. Some of these lines can 6993 * either be arbitrarily long or be continued by a backslash at the end of 6994 * the line. This function coalesces lines that are longer than the read 6995 * buffer, and lines that are continued, into one buffer which is returned. 6996 * The caller must free this memory. NULL is returned when we hit EOF or 6997 * if we run out of memory (errno is set to ENOMEM). 6998 */ 6999 static char * 7000 read_pkg_data(FILE *fp) 7001 { 7002 char *start; 7003 char *inp; 7004 char *p; 7005 int char_cnt = 0; 7006 7007 errno = 0; 7008 if ((start = (char *)malloc(PKGINFO_RD_LEN)) == NULL) { 7009 errno = ENOMEM; 7010 return (NULL); 7011 } 7012 7013 inp = start; 7014 while ((p = fgets(inp, PKGINFO_RD_LEN, fp)) != NULL) { 7015 int len; 7016 7017 len = strlen(inp); 7018 if (inp[len - 1] == '\n' && 7019 (len == 1 || inp[len - 2] != '\\')) { 7020 char_cnt = len; 7021 break; 7022 } 7023 7024 if (inp[len - 2] == '\\') 7025 char_cnt += len - 2; 7026 else 7027 char_cnt += PKGINFO_RD_LEN - 1; 7028 7029 if ((p = realloc(start, char_cnt + PKGINFO_RD_LEN)) == NULL) { 7030 errno = ENOMEM; 7031 break; 7032 } 7033 7034 start = p; 7035 inp = start + char_cnt; 7036 } 7037 7038 if (errno == ENOMEM || (p == NULL && char_cnt == 0)) { 7039 free(start); 7040 start = NULL; 7041 } 7042 7043 return (start); 7044 } 7045 7046 static void 7047 free_ipd_pkgs(char **pkgs, int cnt) 7048 { 7049 int i; 7050 7051 for (i = 0; i < cnt; i++) 7052 free(pkgs[i]); 7053 free(pkgs); 7054 } 7055 7056 /* 7057 * Get a list of the inherited pkg dirs or fs entries configured for the 7058 * zone. The type parameter will be either ZONE_IPD or ZONE_FS. 7059 */ 7060 static int 7061 get_ipd_fs_list(zone_dochandle_t handle, enum zn_ipd_fs type, char ***list) 7062 { 7063 int res; 7064 struct zone_fstab fstab; 7065 int cnt = 0; 7066 char **entries = NULL; 7067 int i; 7068 int (*fp)(zone_dochandle_t, struct zone_fstab *); 7069 7070 if (type == ZONE_IPD) { 7071 fp = zonecfg_getipdent; 7072 res = zonecfg_setipdent(handle); 7073 } else { 7074 fp = zonecfg_getfsent; 7075 res = zonecfg_setfsent(handle); 7076 } 7077 7078 if (res != Z_OK) 7079 return (res); 7080 7081 while (fp(handle, &fstab) == Z_OK) { 7082 char **p; 7083 7084 if ((p = (char **)realloc(entries, 7085 sizeof (char *) * (cnt + 1))) == NULL) { 7086 res = Z_NOMEM; 7087 break; 7088 } 7089 entries = p; 7090 7091 if ((entries[cnt] = strdup(fstab.zone_fs_dir)) == NULL) { 7092 res = Z_NOMEM; 7093 break; 7094 } 7095 7096 cnt++; 7097 } 7098 7099 if (type == ZONE_IPD) 7100 (void) zonecfg_endipdent(handle); 7101 else 7102 (void) zonecfg_endfsent(handle); 7103 7104 /* Add a NULL terminating element. */ 7105 if (res == Z_OK) { 7106 char **p; 7107 7108 if ((p = (char **)realloc(entries, 7109 sizeof (char *) * (cnt + 1))) == NULL) { 7110 res = Z_NOMEM; 7111 } else { 7112 entries = p; 7113 entries[cnt] = NULL; 7114 } 7115 } 7116 7117 if (res != Z_OK) { 7118 if (entries != NULL) { 7119 for (i = 0; i < cnt; i++) 7120 free(entries[i]); 7121 free(entries); 7122 } 7123 return (res); 7124 } 7125 7126 *list = entries; 7127 return (Z_OK); 7128 } 7129 7130 /* 7131 * Get the list of inherited-pkg-dirs (ipd) for the zone and then get the 7132 * list of pkgs that deliver into those dirs. 7133 */ 7134 static int 7135 get_ipd_pkgs(zone_dochandle_t handle, char ***pkg_list, int *cnt) 7136 { 7137 int res; 7138 char **ipds; 7139 char **fss; 7140 int pkg_cnt = 0; 7141 char **pkgs = NULL; 7142 int i; 7143 7144 if ((res = get_ipd_fs_list(handle, ZONE_IPD, &ipds)) != Z_OK) 7145 return (res); 7146 7147 if ((res = get_ipd_fs_list(handle, ZONE_FS, &fss)) != Z_OK) { 7148 for (i = 0; ipds[i] != NULL; i++) 7149 free(ipds[i]); 7150 free(ipds); 7151 return (res); 7152 } 7153 7154 /* We only have to process the contents file if we have ipds. */ 7155 if (ipds != NULL) { 7156 FILE *fp; 7157 7158 if ((fp = fopen(CONTENTS_FILE, "r")) != NULL) { 7159 char *buf; 7160 char *pkg_warn = NULL; 7161 7162 while ((buf = read_pkg_data(fp)) != NULL) { 7163 res = get_path_pkgs(buf, ipds, fss, &pkgs, 7164 &pkg_cnt, &pkg_warn); 7165 free(buf); 7166 if (res != Z_OK) 7167 break; 7168 } 7169 7170 (void) fclose(fp); 7171 7172 if (pkg_warn != NULL) { 7173 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 7174 "WARNING: package operation in progress " 7175 "on the following packages:\n %s\n"), 7176 pkg_warn); 7177 free(pkg_warn); 7178 } 7179 } 7180 } 7181 7182 for (i = 0; ipds[i] != NULL; i++) 7183 free(ipds[i]); 7184 free(ipds); 7185 7186 for (i = 0; fss[i] != NULL; i++) 7187 free(fss[i]); 7188 free(fss); 7189 7190 if (res != Z_OK) { 7191 free_ipd_pkgs(pkgs, pkg_cnt); 7192 } else { 7193 *pkg_list = pkgs; 7194 *cnt = pkg_cnt; 7195 } 7196 7197 return (res); 7198 } 7199 7200 /* 7201 * Return true if pkg_name is in the list of pkgs that deliver into an 7202 * inherited pkg directory for the zone. 7203 */ 7204 static boolean_t 7205 dir_pkg(char *pkg_name, char **pkg_list, int cnt) 7206 { 7207 int i; 7208 7209 for (i = 0; i < cnt; i++) { 7210 if (strcmp(pkg_name, pkg_list[i]) == 0) 7211 return (B_TRUE); 7212 } 7213 7214 return (B_FALSE); 7215 } 7216 7217 /* 7218 * Keep track of obsoleted patches for this specific patch. We don't need to 7219 * keep track of the patch version since once a patch is obsoleted, all prior 7220 * versions are also obsolete and there won't be any new versions. 7221 */ 7222 static int 7223 add_obs_patch(patch_node_t *patch, char *num, uu_list_pool_t *patches_pool) 7224 { 7225 obs_patch_node_t *obs; 7226 7227 if (patch->obs_patches == NULL) { 7228 if ((patch->obs_patches = uu_list_create(patches_pool, NULL, 7229 0)) == NULL) 7230 return (Z_NOMEM); 7231 } 7232 7233 if ((obs = (obs_patch_node_t *)malloc(sizeof (obs_patch_node_t))) 7234 == NULL) 7235 return (Z_NOMEM); 7236 7237 if ((obs->patch_num = strdup(num)) == NULL) { 7238 free(obs); 7239 return (Z_NOMEM); 7240 } 7241 7242 uu_list_node_init(obs, &obs->link, patches_pool); 7243 (void) uu_list_insert_before(patch->obs_patches, NULL, obs); 7244 7245 return (Z_OK); 7246 } 7247 7248 /* 7249 * Keep track of obsoleted patches. We don't need to keep track of the patch 7250 * version since once a patch is obsoleted, all prior versions are also 7251 * obsolete and there won't be any new versions. 7252 */ 7253 static int 7254 save_obs_patch(char *num, uu_avl_pool_t *patches_pool, uu_avl_t *obs_patches) 7255 { 7256 patch_node_t *patch; 7257 uu_avl_index_t where; 7258 7259 if ((patch = (patch_node_t *)malloc(sizeof (patch_node_t))) == NULL) 7260 return (Z_NOMEM); 7261 7262 if ((patch->patch_num = strdup(num)) == NULL) { 7263 free(patch); 7264 return (Z_NOMEM); 7265 } 7266 7267 patch->patch_vers = NULL; 7268 patch->obs_patches = NULL; 7269 7270 uu_avl_node_init(patch, &patch->patch_node, patches_pool); 7271 7272 if (uu_avl_find(obs_patches, patch, NULL, &where) != NULL) { 7273 free(patch->patch_num); 7274 free(patch); 7275 return (Z_OK); 7276 } 7277 7278 uu_avl_insert(obs_patches, patch, where); 7279 return (Z_OK); 7280 } 7281 7282 /* 7283 * Keep a list of patches for a pkg. If we see a newer version of a patch, 7284 * we only keep track of the newer version. 7285 */ 7286 static void 7287 save_patch(patch_node_t *patch, uu_avl_t *patches_avl) 7288 { 7289 patch_node_t *existing; 7290 uu_avl_index_t where; 7291 7292 /* 7293 * Check if this is a newer version of a patch we already have. 7294 * If it is an older version of a patch we already have, ignore it. 7295 */ 7296 if ((existing = (patch_node_t *)uu_avl_find(patches_avl, patch, NULL, 7297 &where)) != NULL) { 7298 char *endptr; 7299 ulong_t pvers, evers; 7300 7301 pvers = strtoul(patch->patch_vers, &endptr, 10); 7302 evers = strtoul(existing->patch_vers, &endptr, 10); 7303 7304 if (pvers > evers) { 7305 free(existing->patch_vers); 7306 existing->patch_vers = patch->patch_vers; 7307 } else { 7308 free(patch->patch_vers); 7309 } 7310 free(patch->patch_num); 7311 free(patch); 7312 return; 7313 } 7314 7315 uu_avl_insert(patches_avl, patch, where); 7316 } 7317 7318 /* 7319 * Check if a patch is on the list of obsoleted patches. We don't need to 7320 * check the patch version since once a patch is obsoleted, all prior versions 7321 * are also obsolete and there won't be any new versions. 7322 */ 7323 static boolean_t 7324 obsolete_patch(patch_node_t *patch, uu_avl_t *obs_patches) 7325 { 7326 uu_avl_index_t where; 7327 7328 if (uu_avl_find(obs_patches, patch, NULL, &where) != NULL) 7329 return (B_TRUE); 7330 7331 return (B_FALSE); 7332 } 7333 7334 /* ARGSUSED */ 7335 static int 7336 patch_node_compare(const void *l_arg, const void *r_arg, void *private) 7337 { 7338 patch_node_t *l = (patch_node_t *)l_arg; 7339 patch_node_t *r = (patch_node_t *)r_arg; 7340 char *endptr; 7341 ulong_t lnum, rnum; 7342 7343 lnum = strtoul(l->patch_num, &endptr, 10); 7344 rnum = strtoul(r->patch_num, &endptr, 10); 7345 7346 if (lnum > rnum) 7347 return (1); 7348 if (lnum < rnum) 7349 return (-1); 7350 return (0); 7351 } 7352 7353 /* 7354 * Parse the patchinfo string for the patch. 7355 * 7356 * We are parsing entries of the form: 7357 * PATCH_INFO_121454-02=Installed: Wed Dec 7 07:13:51 PST 2005 From: mum \ 7358 * Obsoletes: 120777-03 121087-02 119108-07 Requires: 119575-02 \ 7359 * 119255-06 Incompatibles: 7360 * 7361 * A backed out patch will have "backed out\n" as the status. We should 7362 * skip these patches. We also ignore any entries that seem to be 7363 * corrupted. Obsolete patches are saved in the obs_patches parameter 7364 * AVL list. 7365 */ 7366 static int 7367 parse_info(char *patchinfo, uu_avl_pool_t *patches_pool, uu_avl_t *patches_avl, 7368 uu_avl_t *obs_patches, uu_list_pool_t *list_pool) 7369 { 7370 char *p; 7371 char *lastp; 7372 char *ep; 7373 char *pvers; 7374 boolean_t add_info = B_FALSE; 7375 patch_node_t *patch; 7376 7377 if (strlen(patchinfo) < (sizeof (PATCHINFO) - 1)) 7378 return (Z_OK); 7379 7380 /* Skip over "PATCH_INFO_" to get the patch id. */ 7381 p = patchinfo + sizeof (PATCHINFO) - 1; 7382 if ((ep = strchr(p, '=')) == NULL) 7383 return (Z_OK); 7384 7385 *ep++ = '\0'; 7386 7387 /* Ignore all but installed patches. */ 7388 if (strncmp(ep, "Installed:", 10) != 0) 7389 return (Z_OK); 7390 7391 /* remove newline */ 7392 lastp = (ep + strlen(ep) - 1); 7393 if (*lastp == '\n') 7394 *lastp = '\0'; 7395 7396 if ((patch = (patch_node_t *)malloc(sizeof (patch_node_t))) == NULL) 7397 return (Z_NOMEM); 7398 7399 if ((pvers = strchr(p, '-')) != NULL) 7400 *pvers++ = '\0'; 7401 else 7402 pvers = ""; 7403 7404 if ((patch->patch_num = strdup(p)) == NULL) { 7405 free(patch); 7406 return (Z_NOMEM); 7407 } 7408 if ((patch->patch_vers = strdup(pvers)) == NULL) { 7409 free(patch->patch_num); 7410 free(patch); 7411 return (Z_NOMEM); 7412 } 7413 patch->obs_patches = NULL; 7414 7415 uu_avl_node_init(patch, &patch->patch_node, patches_pool); 7416 save_patch(patch, patches_avl); 7417 7418 /* 7419 * Start with the first token. This will probably be "Installed:". 7420 * If we can't tokenize this entry, just return. 7421 */ 7422 if ((p = strtok_r(ep, " ", &lastp)) == NULL) 7423 return (Z_OK); 7424 7425 do { 7426 if (strcmp(p, "Installed:") == 0 || 7427 strcmp(p, "Requires:") == 0 || 7428 strcmp(p, "From:") == 0 || 7429 strcmp(p, "Incompatibles:") == 0) { 7430 add_info = B_FALSE; 7431 continue; 7432 } else if (strcmp(p, "Obsoletes:") == 0) { 7433 add_info = B_TRUE; 7434 continue; 7435 } 7436 7437 if (!add_info) 7438 continue; 7439 7440 if ((pvers = strchr(p, '-')) != NULL) 7441 *pvers = '\0'; 7442 7443 /* 7444 * We save all of the obsolete patches in one big list in the 7445 * obs_patches AVL tree so that we know not to output those as 7446 * part of the sw dependencies. However, we also need to save 7447 * the obsolete patch information for this sepcific patch so 7448 * so that we can do the cross manifest patch checking 7449 * correctly. 7450 */ 7451 if (save_obs_patch(p, patches_pool, obs_patches) != Z_OK) 7452 return (Z_NOMEM); 7453 if (add_obs_patch(patch, p, list_pool) != Z_OK) 7454 return (Z_NOMEM); 7455 } while ((p = strtok_r(NULL, " ", &lastp)) != NULL); 7456 7457 return (Z_OK); 7458 } 7459 7460 /* 7461 * AVL walker callback used to add patch to XML manifest. 7462 * 7463 * PATH_MAX is used in the pkg/patch code as the maximum size for the patch 7464 * number/version string. 7465 */ 7466 static int 7467 add_patch(void *e, void *p) 7468 { 7469 xmlNodePtr node; 7470 xmlNodePtr cur; 7471 char id[PATH_MAX]; 7472 patch_node_t *patch; 7473 patch_parms_t *args; 7474 7475 patch = e; 7476 args = p; 7477 7478 /* skip this patch if it has been obsoleted */ 7479 if (obsolete_patch(patch, args->obs_patches_avl)) 7480 return (UU_WALK_NEXT); 7481 7482 if (patch->patch_vers[0] == '\0') 7483 (void) snprintf(id, sizeof (id), "%s", patch->patch_num); 7484 else 7485 (void) snprintf(id, sizeof (id), "%s-%s", patch->patch_num, 7486 patch->patch_vers); 7487 7488 if ((args->res = operation_prep(args->handle)) != Z_OK) 7489 return (UU_WALK_DONE); 7490 7491 cur = args->handle->zone_dh_cur; 7492 node = xmlNewTextChild(cur, NULL, DTD_ELEM_PATCH, NULL); 7493 if ((args->res = newprop(node, DTD_ATTR_ID, id)) != Z_OK) 7494 return (UU_WALK_DONE); 7495 7496 if (patch->obs_patches != NULL) { 7497 obs_patch_node_t *op; 7498 xmlNodePtr node2; 7499 7500 for (op = uu_list_first(patch->obs_patches); op != NULL; 7501 op = uu_list_next(patch->obs_patches, op)) { 7502 (void) snprintf(id, sizeof (id), "%s", op->patch_num); 7503 node2 = xmlNewTextChild(node, NULL, DTD_ELEM_OBSOLETES, 7504 NULL); 7505 if ((args->res = newprop(node2, DTD_ATTR_ID, id)) 7506 != Z_OK) 7507 return (UU_WALK_DONE); 7508 } 7509 } 7510 7511 return (UU_WALK_NEXT); 7512 } 7513 7514 static void 7515 patch_avl_delete(uu_avl_t *patches_avl) 7516 { 7517 if (patches_avl != NULL) { 7518 patch_node_t *p; 7519 void *cookie = NULL; 7520 7521 while ((p = (patch_node_t *)uu_avl_teardown(patches_avl, 7522 &cookie)) != NULL) { 7523 free(p->patch_num); 7524 free(p->patch_vers); 7525 7526 if (p->obs_patches != NULL) { 7527 obs_patch_node_t *op; 7528 void *cookie2 = NULL; 7529 7530 while ((op = uu_list_teardown(p->obs_patches, 7531 &cookie2)) != NULL) { 7532 free(op->patch_num); 7533 free(op); 7534 } 7535 uu_list_destroy(p->obs_patches); 7536 } 7537 7538 free(p); 7539 } 7540 7541 uu_avl_destroy(patches_avl); 7542 } 7543 } 7544 7545 /* 7546 * Add the unique, highest version patches that are associated with this pkg 7547 * to the sw inventory on the handle. 7548 */ 7549 static int 7550 add_patches(zone_dochandle_t handle, struct zone_pkginfo *infop, 7551 uu_avl_pool_t *patches_pool, uu_avl_t *obs_patches, 7552 uu_list_pool_t *list_pool) 7553 { 7554 int i; 7555 int res; 7556 uu_avl_t *patches_avl; 7557 patch_parms_t args; 7558 7559 if ((patches_avl = uu_avl_create(patches_pool, NULL, UU_DEFAULT)) 7560 == NULL) 7561 return (Z_NOMEM); 7562 7563 for (i = 0; i < infop->zpi_patch_cnt; i++) { 7564 if ((res = parse_info(infop->zpi_patchinfo[i], patches_pool, 7565 patches_avl, obs_patches, list_pool)) != Z_OK) { 7566 patch_avl_delete(patches_avl); 7567 return (res); 7568 } 7569 } 7570 7571 args.obs_patches_avl = obs_patches; 7572 args.handle = handle; 7573 args.res = Z_OK; 7574 7575 (void) uu_avl_walk(patches_avl, add_patch, &args, 0); 7576 7577 patch_avl_delete(patches_avl); 7578 return (args.res); 7579 } 7580 7581 /* 7582 * Keep track of the pkgs we have already processed so that we can quickly 7583 * skip those pkgs while recursively doing dependents. 7584 */ 7585 static boolean_t 7586 pkg_in_manifest(uu_avl_t *saw_pkgs, char *pname, uu_avl_pool_t *pkgs_pool) 7587 { 7588 uu_avl_index_t where; 7589 7590 if (uu_avl_find(saw_pkgs, pname, NULL, &where) == NULL) { 7591 zone_pkg_entry_t *pkg; 7592 7593 /* 7594 * We need to add it. If we don't have memory we just skip 7595 * this pkg since this routine improves performance but the 7596 * algorithm is still correct without it. 7597 */ 7598 if ((pkg = (zone_pkg_entry_t *) 7599 malloc(sizeof (zone_pkg_entry_t))) == NULL) 7600 return (B_FALSE); 7601 7602 if ((pkg->zpe_name = strdup(pname)) == NULL) { 7603 free(pkg); 7604 return (B_FALSE); 7605 } 7606 7607 pkg->zpe_vers = NULL; 7608 pkg->zpe_patches_avl = NULL; 7609 7610 /* Insert pkg into the AVL tree. */ 7611 uu_avl_node_init(pkg, &pkg->zpe_entry, pkgs_pool); 7612 uu_avl_insert(saw_pkgs, pkg, where); 7613 return (B_FALSE); 7614 } 7615 7616 return (B_TRUE); 7617 } 7618 7619 /* 7620 * Add the pkg to the sw inventory on the handle. 7621 */ 7622 static int 7623 add_pkg(zone_dochandle_t handle, char *name, char *version) 7624 { 7625 xmlNodePtr newnode; 7626 xmlNodePtr cur; 7627 int err; 7628 7629 if ((err = operation_prep(handle)) != Z_OK) 7630 return (err); 7631 7632 cur = handle->zone_dh_cur; 7633 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PACKAGE, NULL); 7634 if ((err = newprop(newnode, DTD_ATTR_NAME, name)) != Z_OK) 7635 return (err); 7636 if ((err = newprop(newnode, DTD_ATTR_VERSION, version)) != Z_OK) 7637 return (err); 7638 return (Z_OK); 7639 } 7640 7641 static void 7642 free_pkginfo(struct zone_pkginfo *infop) 7643 { 7644 free(infop->zpi_version); 7645 if (infop->zpi_patch_cnt > 0) { 7646 int i; 7647 7648 for (i = 0; i < infop->zpi_patch_cnt; i++) 7649 free(infop->zpi_patchinfo[i]); 7650 free(infop->zpi_patchinfo); 7651 } 7652 } 7653 7654 /* 7655 * Read the pkginfo file and populate the structure with the data we need 7656 * from this pkg for a sw inventory. 7657 */ 7658 static int 7659 get_pkginfo(char *pkginfo, struct zone_pkginfo *infop) 7660 { 7661 FILE *fp; 7662 char *buf; 7663 int err = 0; 7664 7665 infop->zpi_all_zones = B_FALSE; 7666 infop->zpi_this_zone = B_FALSE; 7667 infop->zpi_version = NULL; 7668 infop->zpi_patch_cnt = 0; 7669 infop->zpi_patchinfo = NULL; 7670 7671 if ((fp = fopen(pkginfo, "r")) == NULL) 7672 return (errno); 7673 7674 while ((buf = read_pkg_data(fp)) != NULL) { 7675 if (strncmp(buf, VERSION, sizeof (VERSION) - 1) == 0) { 7676 int len; 7677 7678 if ((infop->zpi_version = 7679 strdup(buf + sizeof (VERSION) - 1)) == NULL) { 7680 err = ENOMEM; 7681 break; 7682 } 7683 7684 /* remove trailing newline */ 7685 len = strlen(infop->zpi_version); 7686 *(infop->zpi_version + len - 1) = 0; 7687 7688 } else if (strcmp(buf, SUNW_PKG_ALL_ZONES) == 0) { 7689 infop->zpi_all_zones = B_TRUE; 7690 7691 } else if (strcmp(buf, SUNW_PKG_THIS_ZONE) == 0) { 7692 infop->zpi_this_zone = B_TRUE; 7693 7694 } else if (strncmp(buf, PATCHINFO, sizeof (PATCHINFO) - 1) 7695 == 0) { 7696 char **p; 7697 7698 if ((p = (char **)realloc(infop->zpi_patchinfo, 7699 sizeof (char *) * (infop->zpi_patch_cnt + 1))) 7700 == NULL) { 7701 err = ENOMEM; 7702 break; 7703 } 7704 infop->zpi_patchinfo = p; 7705 7706 if ((infop->zpi_patchinfo[infop->zpi_patch_cnt] = 7707 strdup(buf)) == NULL) { 7708 err = ENOMEM; 7709 break; 7710 } 7711 infop->zpi_patch_cnt++; 7712 } 7713 7714 free(buf); 7715 } 7716 7717 free(buf); 7718 7719 if (errno == ENOMEM) { 7720 err = ENOMEM; 7721 /* Clean up anything we did manage to allocate. */ 7722 free_pkginfo(infop); 7723 } 7724 7725 (void) fclose(fp); 7726 7727 return (err); 7728 } 7729 7730 /* 7731 * Add any dependent pkgs to the list. The pkg depend file lists pkg 7732 * dependencies, one per line with an entry that looks like: 7733 * P SUNWcar Core Architecture, (Root) 7734 * See the depend(4) man page. 7735 */ 7736 static int 7737 add_dependents(zone_dochandle_t handle, char *pname, 7738 uu_avl_pool_t *patches_pool, uu_avl_t *obs_patches, 7739 uu_list_pool_t *list_pool, uu_avl_t *saw_pkgs, uu_avl_pool_t *pkgs_pool) 7740 { 7741 int res = Z_OK; 7742 FILE *fp; 7743 char depend[MAXPATHLEN]; 7744 char *buf; 7745 struct stat sbuf; 7746 7747 (void) snprintf(depend, sizeof (depend), "%s/%s/install/depend", 7748 PKG_PATH, pname); 7749 7750 if (stat(depend, &sbuf) == -1 || !S_ISREG(sbuf.st_mode)) 7751 return (Z_OK); 7752 7753 if ((fp = fopen(depend, "r")) == NULL) 7754 return (Z_OK); 7755 7756 while ((buf = read_pkg_data(fp)) != NULL) { 7757 char *deppkg; 7758 char *delims = " \t"; 7759 char pkginfo[MAXPATHLEN]; 7760 struct zone_pkginfo info; 7761 7762 if (*buf != 'P') { 7763 free(buf); 7764 continue; 7765 } 7766 7767 /* Skip past the leading 'P '. */ 7768 if ((deppkg = strtok(buf + 2, delims)) == NULL) { 7769 free(buf); 7770 continue; 7771 } 7772 7773 /* If the pkg is already in the manifest don't add it again. */ 7774 if (pkg_in_manifest(saw_pkgs, deppkg, pkgs_pool)) { 7775 free(buf); 7776 continue; 7777 } 7778 7779 (void) snprintf(pkginfo, sizeof (pkginfo), "%s/%s/pkginfo", 7780 PKG_PATH, deppkg); 7781 7782 if (stat(pkginfo, &sbuf) == -1 || !S_ISREG(sbuf.st_mode)) { 7783 free(buf); 7784 continue; 7785 } 7786 7787 if (get_pkginfo(pkginfo, &info) != 0) { 7788 res = Z_NOMEM; 7789 free(buf); 7790 break; 7791 } 7792 7793 if ((res = add_dependents(handle, deppkg, patches_pool, 7794 obs_patches, list_pool, saw_pkgs, pkgs_pool)) == Z_OK && 7795 (res = add_pkg(handle, deppkg, info.zpi_version)) == Z_OK) { 7796 if (info.zpi_patch_cnt > 0) 7797 res = add_patches(handle, &info, patches_pool, 7798 obs_patches, list_pool); 7799 } 7800 7801 free(buf); 7802 free_pkginfo(&info); 7803 7804 if (res != Z_OK) 7805 break; 7806 } 7807 7808 (void) fclose(fp); 7809 return (res); 7810 } 7811 7812 /* ARGSUSED */ 7813 static int 7814 pkg_entry_compare(const void *l_arg, const void *r_arg, void *private) 7815 { 7816 zone_pkg_entry_t *pkg = (zone_pkg_entry_t *)l_arg; 7817 char *name = (char *)r_arg; 7818 7819 return (strcmp(pkg->zpe_name, name)); 7820 } 7821 7822 static void 7823 pkg_avl_delete(uu_avl_t *pavl) 7824 { 7825 if (pavl != NULL) { 7826 zone_pkg_entry_t *p; 7827 void *cookie = NULL; 7828 7829 while ((p = uu_avl_teardown(pavl, &cookie)) != NULL) { 7830 free(p->zpe_name); 7831 free(p); 7832 } 7833 7834 uu_avl_destroy(pavl); 7835 } 7836 } 7837 7838 /* 7839 * Take a software inventory of the global zone. We need to get the set of 7840 * packages and patches that are on the global zone that the specified 7841 * non-global zone depends on. The packages we need in the inventory are: 7842 * 7843 * - skip the package if SUNW_PKG_THISZONE is 'true' 7844 * otherwise, 7845 * - add the package if 7846 * a) SUNW_PKG_ALLZONES is 'true', 7847 * or 7848 * b) any file delivered by the package is in a file system that is inherited 7849 * from the global zone. 7850 * If the zone does not inherit any file systems (whole root) 7851 * then (b) will be skipped. 7852 * 7853 * For each of the packages that is being added to the inventory, we will also 7854 * add its dependent packages to the inventory. 7855 * 7856 * For each of the packages that is being added to the inventory, we will also 7857 * add all of the associated, unique patches to the inventory. 7858 * 7859 * See the comment for zonecfg_getpkgdata() for compatability restrictions on 7860 * how we must save the XML representation of the software inventory. 7861 */ 7862 static int 7863 zonecfg_sw_inventory(zone_dochandle_t handle) 7864 { 7865 char pkginfo[MAXPATHLEN]; 7866 int res; 7867 struct dirent *dp; 7868 DIR *dirp; 7869 struct stat buf; 7870 struct zone_pkginfo info; 7871 int pkg_cnt = 0; 7872 char **pkgs = NULL; 7873 uu_avl_pool_t *pkgs_pool = NULL; 7874 uu_avl_pool_t *patches_pool = NULL; 7875 uu_list_pool_t *list_pool = NULL; 7876 uu_avl_t *saw_pkgs = NULL; 7877 uu_avl_t *obs_patches = NULL; 7878 7879 if ((pkgs_pool = uu_avl_pool_create("pkgs_pool", 7880 sizeof (zone_pkg_entry_t), offsetof(zone_pkg_entry_t, zpe_entry), 7881 pkg_entry_compare, UU_DEFAULT)) == NULL) { 7882 res = Z_NOMEM; 7883 goto done; 7884 } 7885 7886 if ((saw_pkgs = uu_avl_create(pkgs_pool, NULL, UU_DEFAULT)) == NULL) { 7887 res = Z_NOMEM; 7888 goto done; 7889 } 7890 7891 if ((patches_pool = uu_avl_pool_create("patches_pool", 7892 sizeof (patch_node_t), offsetof(patch_node_t, patch_node), 7893 patch_node_compare, UU_DEFAULT)) == NULL) { 7894 res = Z_NOMEM; 7895 goto done; 7896 } 7897 7898 if ((list_pool = uu_list_pool_create("list_pool", 7899 sizeof (obs_patch_node_t), offsetof(obs_patch_node_t, link), NULL, 7900 UU_DEFAULT)) == NULL) { 7901 res = Z_NOMEM; 7902 goto done; 7903 } 7904 7905 /* 7906 * The obs_patches AVL tree saves all of the obsolete patches so 7907 * that we know not to output those as part of the sw dependencies. 7908 */ 7909 if ((obs_patches = uu_avl_create(patches_pool, NULL, UU_DEFAULT)) 7910 == NULL) { 7911 res = Z_NOMEM; 7912 goto done; 7913 } 7914 7915 if ((res = get_ipd_pkgs(handle, &pkgs, &pkg_cnt)) != Z_OK) { 7916 res = Z_NOMEM; 7917 goto done; 7918 } 7919 7920 if ((dirp = opendir(PKG_PATH)) == NULL) { 7921 res = Z_NOMEM; 7922 goto done; 7923 } 7924 7925 while ((dp = readdir(dirp)) != (struct dirent *)0) { 7926 if (strcmp(dp->d_name, ".") == 0 || 7927 strcmp(dp->d_name, "..") == 0) 7928 continue; 7929 7930 (void) snprintf(pkginfo, sizeof (pkginfo), "%s/%s/pkginfo", 7931 PKG_PATH, dp->d_name); 7932 7933 if (stat(pkginfo, &buf) == -1 || !S_ISREG(buf.st_mode)) 7934 continue; 7935 7936 if (get_pkginfo(pkginfo, &info) != 0) { 7937 res = Z_NOMEM; 7938 break; 7939 } 7940 7941 if (!info.zpi_this_zone && 7942 (info.zpi_all_zones || 7943 dir_pkg(dp->d_name, pkgs, pkg_cnt)) && 7944 !pkg_in_manifest(saw_pkgs, dp->d_name, pkgs_pool)) { 7945 /* 7946 * Add dependents first so any patches will get 7947 * associated with the right pkg in the xml file. 7948 */ 7949 if ((res = add_dependents(handle, dp->d_name, 7950 patches_pool, obs_patches, list_pool, saw_pkgs, 7951 pkgs_pool)) == Z_OK && 7952 (res = add_pkg(handle, dp->d_name, 7953 info.zpi_version)) == Z_OK) { 7954 if (info.zpi_patch_cnt > 0) 7955 res = add_patches(handle, &info, 7956 patches_pool, obs_patches, 7957 list_pool); 7958 } 7959 } 7960 7961 free_pkginfo(&info); 7962 7963 if (res != Z_OK) 7964 break; 7965 } 7966 7967 (void) closedir(dirp); 7968 7969 done: 7970 pkg_avl_delete(saw_pkgs); 7971 patch_avl_delete(obs_patches); 7972 if (pkgs_pool != NULL) 7973 uu_avl_pool_destroy(pkgs_pool); 7974 if (patches_pool != NULL) 7975 uu_avl_pool_destroy(patches_pool); 7976 if (list_pool != NULL) 7977 uu_list_pool_destroy(list_pool); 7978 free_ipd_pkgs(pkgs, pkg_cnt); 7979 7980 if (res == Z_OK) 7981 handle->zone_dh_sw_inv = B_TRUE; 7982 7983 return (res); 7984 } 7985 7986 /* 7987 * zonecfg_devwalk call-back function used during detach to generate the 7988 * dev info in the manifest. 7989 */ 7990 static int 7991 get_detach_dev_entry(const char *name, uid_t uid, gid_t gid, mode_t mode, 7992 const char *acl, void *hdl) 7993 { 7994 zone_dochandle_t handle = (zone_dochandle_t)hdl; 7995 xmlNodePtr newnode; 7996 xmlNodePtr cur; 7997 int err; 7998 char buf[128]; 7999 8000 if ((err = operation_prep(handle)) != Z_OK) 8001 return (err); 8002 8003 cur = handle->zone_dh_cur; 8004 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEV_PERM, NULL); 8005 if ((err = newprop(newnode, DTD_ATTR_NAME, (char *)name)) != Z_OK) 8006 return (err); 8007 (void) snprintf(buf, sizeof (buf), "%lu", uid); 8008 if ((err = newprop(newnode, DTD_ATTR_UID, buf)) != Z_OK) 8009 return (err); 8010 (void) snprintf(buf, sizeof (buf), "%lu", gid); 8011 if ((err = newprop(newnode, DTD_ATTR_GID, buf)) != Z_OK) 8012 return (err); 8013 (void) snprintf(buf, sizeof (buf), "%o", mode); 8014 if ((err = newprop(newnode, DTD_ATTR_MODE, buf)) != Z_OK) 8015 return (err); 8016 if ((err = newprop(newnode, DTD_ATTR_ACL, (char *)acl)) != Z_OK) 8017 return (err); 8018 return (Z_OK); 8019 } 8020 8021 /* 8022 * Get the information required to support detaching a zone. This is 8023 * called on the source system when detaching (the detaching parameter should 8024 * be set to true) and on the destination system before attaching (the 8025 * detaching parameter should be false). 8026 * 8027 * For native Solaris zones, the detach/attach process involves validating 8028 * that the software on the global zone can support the zone when we attach. 8029 * To do this we take a software inventory of the global zone. We also 8030 * have to keep track of the device configuration so that we can properly 8031 * recreate it on the destination. 8032 */ 8033 int 8034 zonecfg_get_detach_info(zone_dochandle_t handle, boolean_t detaching) 8035 { 8036 int res; 8037 8038 if ((res = zonecfg_sw_inventory(handle)) != Z_OK) 8039 return (res); 8040 8041 if (detaching) 8042 res = zonecfg_devwalk(handle, get_detach_dev_entry, handle); 8043 8044 return (res); 8045 } 8046