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 if ((err = newprop(newnode, DTD_ATTR_DEFROUTER, 2235 tabptr->zone_nwif_defrouter)) != Z_OK) 2236 return (err); 2237 return (Z_OK); 2238 } 2239 2240 int 2241 zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 2242 { 2243 int err; 2244 2245 if (tabptr == NULL) 2246 return (Z_INVAL); 2247 2248 if ((err = operation_prep(handle)) != Z_OK) 2249 return (err); 2250 2251 if ((err = zonecfg_add_nwif_core(handle, tabptr)) != Z_OK) 2252 return (err); 2253 2254 return (Z_OK); 2255 } 2256 2257 static int 2258 zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 2259 { 2260 xmlNodePtr cur = handle->zone_dh_cur; 2261 boolean_t addr_match, phys_match; 2262 2263 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2264 if (xmlStrcmp(cur->name, DTD_ELEM_NET)) 2265 continue; 2266 2267 addr_match = match_prop(cur, DTD_ATTR_ADDRESS, 2268 tabptr->zone_nwif_address); 2269 phys_match = match_prop(cur, DTD_ATTR_PHYSICAL, 2270 tabptr->zone_nwif_physical); 2271 2272 if (addr_match && phys_match) { 2273 xmlUnlinkNode(cur); 2274 xmlFreeNode(cur); 2275 return (Z_OK); 2276 } 2277 } 2278 return (Z_NO_RESOURCE_ID); 2279 } 2280 2281 int 2282 zonecfg_delete_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 2283 { 2284 int err; 2285 2286 if (tabptr == NULL) 2287 return (Z_INVAL); 2288 2289 if ((err = operation_prep(handle)) != Z_OK) 2290 return (err); 2291 2292 if ((err = zonecfg_delete_nwif_core(handle, tabptr)) != Z_OK) 2293 return (err); 2294 2295 return (Z_OK); 2296 } 2297 2298 int 2299 zonecfg_modify_nwif( 2300 zone_dochandle_t handle, 2301 struct zone_nwiftab *oldtabptr, 2302 struct zone_nwiftab *newtabptr) 2303 { 2304 int err; 2305 2306 if (oldtabptr == NULL || newtabptr == NULL) 2307 return (Z_INVAL); 2308 2309 if ((err = operation_prep(handle)) != Z_OK) 2310 return (err); 2311 2312 if ((err = zonecfg_delete_nwif_core(handle, oldtabptr)) != Z_OK) 2313 return (err); 2314 2315 if ((err = zonecfg_add_nwif_core(handle, newtabptr)) != Z_OK) 2316 return (err); 2317 2318 return (Z_OK); 2319 } 2320 2321 int 2322 zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) 2323 { 2324 xmlNodePtr cur, firstmatch; 2325 int err; 2326 char match[MAXPATHLEN]; 2327 2328 if (tabptr == NULL) 2329 return (Z_INVAL); 2330 2331 if ((err = operation_prep(handle)) != Z_OK) 2332 return (err); 2333 2334 cur = handle->zone_dh_cur; 2335 firstmatch = NULL; 2336 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2337 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) 2338 continue; 2339 if (strlen(tabptr->zone_dev_match) == 0) 2340 continue; 2341 2342 if ((fetchprop(cur, DTD_ATTR_MATCH, match, 2343 sizeof (match)) == Z_OK)) { 2344 if (strcmp(tabptr->zone_dev_match, 2345 match) == 0) { 2346 if (firstmatch == NULL) 2347 firstmatch = cur; 2348 else if (firstmatch != cur) 2349 return (Z_INSUFFICIENT_SPEC); 2350 } else { 2351 /* 2352 * If another property matched but this 2353 * one doesn't then reset firstmatch. 2354 */ 2355 if (firstmatch == cur) 2356 firstmatch = NULL; 2357 } 2358 } 2359 } 2360 if (firstmatch == NULL) 2361 return (Z_NO_RESOURCE_ID); 2362 2363 cur = firstmatch; 2364 2365 if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match, 2366 sizeof (tabptr->zone_dev_match))) != Z_OK) 2367 return (err); 2368 2369 return (Z_OK); 2370 } 2371 2372 static int 2373 zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr) 2374 { 2375 xmlNodePtr newnode, cur = handle->zone_dh_cur; 2376 int err; 2377 2378 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL); 2379 2380 if ((err = newprop(newnode, DTD_ATTR_MATCH, 2381 tabptr->zone_dev_match)) != Z_OK) 2382 return (err); 2383 2384 return (Z_OK); 2385 } 2386 2387 int 2388 zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) 2389 { 2390 int err; 2391 2392 if (tabptr == NULL) 2393 return (Z_INVAL); 2394 2395 if ((err = operation_prep(handle)) != Z_OK) 2396 return (err); 2397 2398 if ((err = zonecfg_add_dev_core(handle, tabptr)) != Z_OK) 2399 return (err); 2400 2401 return (Z_OK); 2402 } 2403 2404 static int 2405 zonecfg_delete_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr) 2406 { 2407 xmlNodePtr cur = handle->zone_dh_cur; 2408 int match_match; 2409 2410 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2411 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) 2412 continue; 2413 2414 match_match = match_prop(cur, DTD_ATTR_MATCH, 2415 tabptr->zone_dev_match); 2416 2417 if (match_match) { 2418 xmlUnlinkNode(cur); 2419 xmlFreeNode(cur); 2420 return (Z_OK); 2421 } 2422 } 2423 return (Z_NO_RESOURCE_ID); 2424 } 2425 2426 int 2427 zonecfg_delete_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) 2428 { 2429 int err; 2430 2431 if (tabptr == NULL) 2432 return (Z_INVAL); 2433 2434 if ((err = operation_prep(handle)) != Z_OK) 2435 return (err); 2436 2437 if ((err = zonecfg_delete_dev_core(handle, tabptr)) != Z_OK) 2438 return (err); 2439 2440 return (Z_OK); 2441 } 2442 2443 int 2444 zonecfg_modify_dev( 2445 zone_dochandle_t handle, 2446 struct zone_devtab *oldtabptr, 2447 struct zone_devtab *newtabptr) 2448 { 2449 int err; 2450 2451 if (oldtabptr == NULL || newtabptr == NULL) 2452 return (Z_INVAL); 2453 2454 if ((err = operation_prep(handle)) != Z_OK) 2455 return (err); 2456 2457 if ((err = zonecfg_delete_dev_core(handle, oldtabptr)) != Z_OK) 2458 return (err); 2459 2460 if ((err = zonecfg_add_dev_core(handle, newtabptr)) != Z_OK) 2461 return (err); 2462 2463 return (Z_OK); 2464 } 2465 2466 /* Lock to serialize all zonecfg_devwalks */ 2467 static pthread_mutex_t zonecfg_devwalk_lock = PTHREAD_MUTEX_INITIALIZER; 2468 /* 2469 * Global variables used to pass data from zonecfg_devwalk to the nftw 2470 * call-back (zonecfg_devwalk_cb). g_devwalk_data is really the void* 2471 * parameter and g_devwalk_cb is really the *cb parameter from zonecfg_devwalk. 2472 */ 2473 static void *g_devwalk_data; 2474 static int (*g_devwalk_cb)(const char *, uid_t, gid_t, mode_t, const char *, 2475 void *); 2476 static size_t g_devwalk_skip_prefix; 2477 2478 /* 2479 * This is the nftw call-back function used by zonecfg_devwalk. It is 2480 * responsible for calling the actual call-back that is passed in to 2481 * zonecfg_devwalk as the *cb argument. 2482 */ 2483 /* ARGSUSED2 */ 2484 static int 2485 zonecfg_devwalk_cb(const char *path, const struct stat *st, int f, 2486 struct FTW *ftw) 2487 { 2488 acl_t *acl; 2489 char *acl_txt = NULL; 2490 2491 /* skip all but character and block devices */ 2492 if (!S_ISBLK(st->st_mode) && !S_ISCHR(st->st_mode)) 2493 return (0); 2494 2495 if ((acl_get(path, ACL_NO_TRIVIAL, &acl) == 0) && 2496 acl != NULL) { 2497 acl_txt = acl_totext(acl, ACL_NORESOLVE); 2498 acl_free(acl); 2499 } 2500 2501 if (strlen(path) <= g_devwalk_skip_prefix) 2502 return (0); 2503 2504 g_devwalk_cb(path + g_devwalk_skip_prefix, st->st_uid, st->st_gid, 2505 st->st_mode & S_IAMB, acl_txt != NULL ? acl_txt : "", 2506 g_devwalk_data); 2507 free(acl_txt); 2508 return (0); 2509 } 2510 2511 /* 2512 * Walk the dev tree for the zone specified by hdl and call the call-back (cb) 2513 * function for each entry in the tree. The call-back will be passed the 2514 * name, uid, gid, mode, acl string and the void *data input parameter 2515 * for each dev entry. 2516 * 2517 * Data is passed to the zonecfg_devwalk_cb through the global variables 2518 * g_devwalk_data, *g_devwalk_cb, and g_devwalk_skip_prefix. The 2519 * zonecfg_devwalk_cb function will actually call *cb. 2520 */ 2521 int 2522 zonecfg_devwalk(zone_dochandle_t hdl, 2523 int (*cb)(const char *, uid_t, gid_t, mode_t, const char *, void *), 2524 void *data) 2525 { 2526 char path[MAXPATHLEN]; 2527 int ret; 2528 2529 if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK) 2530 return (ret); 2531 2532 if (strlcat(path, "/dev", sizeof (path)) >= sizeof (path)) 2533 return (Z_TOO_BIG); 2534 g_devwalk_skip_prefix = strlen(path) + 1; 2535 2536 /* 2537 * We have to serialize all zonecfg_devwalks in the same process 2538 * (which should be fine), since nftw() is so badly designed. 2539 */ 2540 (void) pthread_mutex_lock(&zonecfg_devwalk_lock); 2541 2542 g_devwalk_data = data; 2543 g_devwalk_cb = cb; 2544 (void) nftw(path, zonecfg_devwalk_cb, 0, FTW_PHYS); 2545 2546 (void) pthread_mutex_unlock(&zonecfg_devwalk_lock); 2547 return (Z_OK); 2548 } 2549 2550 /* 2551 * Update the owner, group, mode and acl on the specified dev (inpath) for 2552 * the zone (hdl). This function can be used to fix up the dev tree after 2553 * attaching a migrated zone. 2554 */ 2555 int 2556 zonecfg_devperms_apply(zone_dochandle_t hdl, const char *inpath, uid_t owner, 2557 gid_t group, mode_t mode, const char *acltxt) 2558 { 2559 int ret; 2560 char path[MAXPATHLEN]; 2561 struct stat st; 2562 acl_t *aclp; 2563 2564 if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK) 2565 return (ret); 2566 2567 if (strlcat(path, "/dev/", sizeof (path)) >= sizeof (path)) 2568 return (Z_TOO_BIG); 2569 if (strlcat(path, inpath, sizeof (path)) >= sizeof (path)) 2570 return (Z_TOO_BIG); 2571 2572 if (stat(path, &st) == -1) 2573 return (Z_INVAL); 2574 2575 /* make sure we're only touching device nodes */ 2576 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) 2577 return (Z_INVAL); 2578 2579 if (chown(path, owner, group) == -1) 2580 return (Z_SYSTEM); 2581 2582 if (chmod(path, mode) == -1) 2583 return (Z_SYSTEM); 2584 2585 if ((acltxt == NULL) || (strcmp(acltxt, "") == 0)) 2586 return (Z_OK); 2587 2588 if (acl_fromtext(acltxt, &aclp) != 0) 2589 return (Z_SYSTEM); 2590 2591 errno = 0; 2592 if (acl_set(path, aclp) == -1) { 2593 free(aclp); 2594 return (Z_SYSTEM); 2595 } 2596 2597 free(aclp); 2598 return (Z_OK); 2599 } 2600 2601 /* 2602 * This function finds everything mounted under a zone's rootpath. 2603 * This returns the number of mounts under rootpath, or -1 on error. 2604 * callback is called once per mount found with the first argument 2605 * pointing to the mount point. 2606 * 2607 * If the callback function returns non-zero zonecfg_find_mounts 2608 * aborts with an error. 2609 */ 2610 int 2611 zonecfg_find_mounts(char *rootpath, int (*callback)(const char *, void *), 2612 void *priv) { 2613 FILE *mnttab; 2614 struct mnttab m; 2615 size_t l; 2616 int zfsl; 2617 int rv = 0; 2618 char zfs_path[MAXPATHLEN]; 2619 2620 assert(rootpath != NULL); 2621 2622 if ((zfsl = snprintf(zfs_path, sizeof (zfs_path), "%s/.zfs/", rootpath)) 2623 >= sizeof (zfs_path)) 2624 return (-1); 2625 2626 l = strlen(rootpath); 2627 2628 mnttab = fopen("/etc/mnttab", "r"); 2629 2630 if (mnttab == NULL) 2631 return (-1); 2632 2633 if (ioctl(fileno(mnttab), MNTIOC_SHOWHIDDEN, NULL) < 0) { 2634 rv = -1; 2635 goto out; 2636 } 2637 2638 while (!getmntent(mnttab, &m)) { 2639 if ((strncmp(rootpath, m.mnt_mountp, l) == 0) && 2640 (m.mnt_mountp[l] == '/') && 2641 (strncmp(zfs_path, m.mnt_mountp, zfsl) != 0)) { 2642 rv++; 2643 if (callback == NULL) 2644 continue; 2645 if (callback(m.mnt_mountp, priv)) { 2646 rv = -1; 2647 goto out; 2648 2649 } 2650 } 2651 } 2652 2653 out: 2654 (void) fclose(mnttab); 2655 return (rv); 2656 } 2657 2658 int 2659 zonecfg_lookup_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2660 { 2661 xmlNodePtr cur, firstmatch; 2662 int err; 2663 char name[MAXNAMELEN], type[MAXNAMELEN], value[MAXNAMELEN]; 2664 2665 if (tabptr == NULL) 2666 return (Z_INVAL); 2667 2668 if ((err = operation_prep(handle)) != Z_OK) 2669 return (err); 2670 2671 cur = handle->zone_dh_cur; 2672 firstmatch = NULL; 2673 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2674 if (xmlStrcmp(cur->name, DTD_ELEM_ATTR)) 2675 continue; 2676 if (strlen(tabptr->zone_attr_name) > 0) { 2677 if ((fetchprop(cur, DTD_ATTR_NAME, name, 2678 sizeof (name)) == Z_OK) && 2679 (strcmp(tabptr->zone_attr_name, name) == 0)) { 2680 if (firstmatch == NULL) 2681 firstmatch = cur; 2682 else 2683 return (Z_INSUFFICIENT_SPEC); 2684 } 2685 } 2686 if (strlen(tabptr->zone_attr_type) > 0) { 2687 if ((fetchprop(cur, DTD_ATTR_TYPE, type, 2688 sizeof (type)) == Z_OK)) { 2689 if (strcmp(tabptr->zone_attr_type, type) == 0) { 2690 if (firstmatch == NULL) 2691 firstmatch = cur; 2692 else if (firstmatch != cur) 2693 return (Z_INSUFFICIENT_SPEC); 2694 } else { 2695 /* 2696 * If another property matched but this 2697 * one doesn't then reset firstmatch. 2698 */ 2699 if (firstmatch == cur) 2700 firstmatch = NULL; 2701 } 2702 } 2703 } 2704 if (strlen(tabptr->zone_attr_value) > 0) { 2705 if ((fetchprop(cur, DTD_ATTR_VALUE, value, 2706 sizeof (value)) == Z_OK)) { 2707 if (strcmp(tabptr->zone_attr_value, value) == 2708 0) { 2709 if (firstmatch == NULL) 2710 firstmatch = cur; 2711 else if (firstmatch != cur) 2712 return (Z_INSUFFICIENT_SPEC); 2713 } else { 2714 /* 2715 * If another property matched but this 2716 * one doesn't then reset firstmatch. 2717 */ 2718 if (firstmatch == cur) 2719 firstmatch = NULL; 2720 } 2721 } 2722 } 2723 } 2724 if (firstmatch == NULL) 2725 return (Z_NO_RESOURCE_ID); 2726 2727 cur = firstmatch; 2728 2729 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name, 2730 sizeof (tabptr->zone_attr_name))) != Z_OK) 2731 return (err); 2732 2733 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type, 2734 sizeof (tabptr->zone_attr_type))) != Z_OK) 2735 return (err); 2736 2737 if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value, 2738 sizeof (tabptr->zone_attr_value))) != Z_OK) 2739 return (err); 2740 2741 return (Z_OK); 2742 } 2743 2744 static int 2745 zonecfg_add_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2746 { 2747 xmlNodePtr newnode, cur = handle->zone_dh_cur; 2748 int err; 2749 2750 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ATTR, NULL); 2751 err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_attr_name); 2752 if (err != Z_OK) 2753 return (err); 2754 err = newprop(newnode, DTD_ATTR_TYPE, tabptr->zone_attr_type); 2755 if (err != Z_OK) 2756 return (err); 2757 err = newprop(newnode, DTD_ATTR_VALUE, tabptr->zone_attr_value); 2758 if (err != Z_OK) 2759 return (err); 2760 return (Z_OK); 2761 } 2762 2763 int 2764 zonecfg_add_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2765 { 2766 int err; 2767 2768 if (tabptr == NULL) 2769 return (Z_INVAL); 2770 2771 if ((err = operation_prep(handle)) != Z_OK) 2772 return (err); 2773 2774 if ((err = zonecfg_add_attr_core(handle, tabptr)) != Z_OK) 2775 return (err); 2776 2777 return (Z_OK); 2778 } 2779 2780 static int 2781 zonecfg_delete_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2782 { 2783 xmlNodePtr cur = handle->zone_dh_cur; 2784 int name_match, type_match, value_match; 2785 2786 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2787 if (xmlStrcmp(cur->name, DTD_ELEM_ATTR)) 2788 continue; 2789 2790 name_match = match_prop(cur, DTD_ATTR_NAME, 2791 tabptr->zone_attr_name); 2792 type_match = match_prop(cur, DTD_ATTR_TYPE, 2793 tabptr->zone_attr_type); 2794 value_match = match_prop(cur, DTD_ATTR_VALUE, 2795 tabptr->zone_attr_value); 2796 2797 if (name_match && type_match && value_match) { 2798 xmlUnlinkNode(cur); 2799 xmlFreeNode(cur); 2800 return (Z_OK); 2801 } 2802 } 2803 return (Z_NO_RESOURCE_ID); 2804 } 2805 2806 int 2807 zonecfg_delete_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2808 { 2809 int err; 2810 2811 if (tabptr == NULL) 2812 return (Z_INVAL); 2813 2814 if ((err = operation_prep(handle)) != Z_OK) 2815 return (err); 2816 2817 if ((err = zonecfg_delete_attr_core(handle, tabptr)) != Z_OK) 2818 return (err); 2819 2820 return (Z_OK); 2821 } 2822 2823 int 2824 zonecfg_modify_attr( 2825 zone_dochandle_t handle, 2826 struct zone_attrtab *oldtabptr, 2827 struct zone_attrtab *newtabptr) 2828 { 2829 int err; 2830 2831 if (oldtabptr == NULL || newtabptr == NULL) 2832 return (Z_INVAL); 2833 2834 if ((err = operation_prep(handle)) != Z_OK) 2835 return (err); 2836 2837 if ((err = zonecfg_delete_attr_core(handle, oldtabptr)) != Z_OK) 2838 return (err); 2839 2840 if ((err = zonecfg_add_attr_core(handle, newtabptr)) != Z_OK) 2841 return (err); 2842 2843 return (Z_OK); 2844 } 2845 2846 int 2847 zonecfg_get_attr_boolean(const struct zone_attrtab *attr, boolean_t *value) 2848 { 2849 if (attr == NULL) 2850 return (Z_INVAL); 2851 2852 if (strcmp(attr->zone_attr_type, DTD_ENTITY_BOOLEAN) != 0) 2853 return (Z_INVAL); 2854 2855 if (strcmp(attr->zone_attr_value, DTD_ENTITY_TRUE) == 0) { 2856 *value = B_TRUE; 2857 return (Z_OK); 2858 } 2859 if (strcmp(attr->zone_attr_value, DTD_ENTITY_FALSE) == 0) { 2860 *value = B_FALSE; 2861 return (Z_OK); 2862 } 2863 return (Z_INVAL); 2864 } 2865 2866 int 2867 zonecfg_get_attr_int(const struct zone_attrtab *attr, int64_t *value) 2868 { 2869 long long result; 2870 char *endptr; 2871 2872 if (attr == NULL) 2873 return (Z_INVAL); 2874 2875 if (strcmp(attr->zone_attr_type, DTD_ENTITY_INT) != 0) 2876 return (Z_INVAL); 2877 2878 errno = 0; 2879 result = strtoll(attr->zone_attr_value, &endptr, 10); 2880 if (errno != 0 || *endptr != '\0') 2881 return (Z_INVAL); 2882 *value = result; 2883 return (Z_OK); 2884 } 2885 2886 int 2887 zonecfg_get_attr_string(const struct zone_attrtab *attr, char *value, 2888 size_t val_sz) 2889 { 2890 if (attr == NULL) 2891 return (Z_INVAL); 2892 2893 if (strcmp(attr->zone_attr_type, DTD_ENTITY_STRING) != 0) 2894 return (Z_INVAL); 2895 2896 if (strlcpy(value, attr->zone_attr_value, val_sz) >= val_sz) 2897 return (Z_TOO_BIG); 2898 return (Z_OK); 2899 } 2900 2901 int 2902 zonecfg_get_attr_uint(const struct zone_attrtab *attr, uint64_t *value) 2903 { 2904 unsigned long long result; 2905 long long neg_result; 2906 char *endptr; 2907 2908 if (attr == NULL) 2909 return (Z_INVAL); 2910 2911 if (strcmp(attr->zone_attr_type, DTD_ENTITY_UINT) != 0) 2912 return (Z_INVAL); 2913 2914 errno = 0; 2915 result = strtoull(attr->zone_attr_value, &endptr, 10); 2916 if (errno != 0 || *endptr != '\0') 2917 return (Z_INVAL); 2918 errno = 0; 2919 neg_result = strtoll(attr->zone_attr_value, &endptr, 10); 2920 /* 2921 * Incredibly, strtoull("<negative number>", ...) will not fail but 2922 * return whatever (negative) number cast as a u_longlong_t, so we 2923 * need to look for this here. 2924 */ 2925 if (errno == 0 && neg_result < 0) 2926 return (Z_INVAL); 2927 *value = result; 2928 return (Z_OK); 2929 } 2930 2931 int 2932 zonecfg_lookup_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2933 { 2934 xmlNodePtr cur, val; 2935 char savedname[MAXNAMELEN]; 2936 struct zone_rctlvaltab *valptr; 2937 int err; 2938 2939 if (tabptr->zone_rctl_name == NULL || 2940 strlen(tabptr->zone_rctl_name) == 0) 2941 return (Z_INVAL); 2942 2943 if ((err = operation_prep(handle)) != Z_OK) 2944 return (err); 2945 2946 cur = handle->zone_dh_cur; 2947 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2948 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 2949 continue; 2950 if ((fetchprop(cur, DTD_ATTR_NAME, savedname, 2951 sizeof (savedname)) == Z_OK) && 2952 (strcmp(savedname, tabptr->zone_rctl_name) == 0)) { 2953 tabptr->zone_rctl_valptr = NULL; 2954 for (val = cur->xmlChildrenNode; val != NULL; 2955 val = val->next) { 2956 valptr = (struct zone_rctlvaltab *)malloc( 2957 sizeof (struct zone_rctlvaltab)); 2958 if (valptr == NULL) 2959 return (Z_NOMEM); 2960 if ((fetchprop(val, DTD_ATTR_PRIV, 2961 valptr->zone_rctlval_priv, 2962 sizeof (valptr->zone_rctlval_priv)) != 2963 Z_OK)) 2964 break; 2965 if ((fetchprop(val, DTD_ATTR_LIMIT, 2966 valptr->zone_rctlval_limit, 2967 sizeof (valptr->zone_rctlval_limit)) != 2968 Z_OK)) 2969 break; 2970 if ((fetchprop(val, DTD_ATTR_ACTION, 2971 valptr->zone_rctlval_action, 2972 sizeof (valptr->zone_rctlval_action)) != 2973 Z_OK)) 2974 break; 2975 if (zonecfg_add_rctl_value(tabptr, valptr) != 2976 Z_OK) 2977 break; 2978 } 2979 return (Z_OK); 2980 } 2981 } 2982 return (Z_NO_RESOURCE_ID); 2983 } 2984 2985 static int 2986 zonecfg_add_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2987 { 2988 xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode; 2989 struct zone_rctlvaltab *valptr; 2990 int err; 2991 2992 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_RCTL, NULL); 2993 err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_rctl_name); 2994 if (err != Z_OK) 2995 return (err); 2996 for (valptr = tabptr->zone_rctl_valptr; valptr != NULL; 2997 valptr = valptr->zone_rctlval_next) { 2998 valnode = xmlNewTextChild(newnode, NULL, 2999 DTD_ELEM_RCTLVALUE, NULL); 3000 err = newprop(valnode, DTD_ATTR_PRIV, 3001 valptr->zone_rctlval_priv); 3002 if (err != Z_OK) 3003 return (err); 3004 err = newprop(valnode, DTD_ATTR_LIMIT, 3005 valptr->zone_rctlval_limit); 3006 if (err != Z_OK) 3007 return (err); 3008 err = newprop(valnode, DTD_ATTR_ACTION, 3009 valptr->zone_rctlval_action); 3010 if (err != Z_OK) 3011 return (err); 3012 } 3013 return (Z_OK); 3014 } 3015 3016 int 3017 zonecfg_add_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 3018 { 3019 int err; 3020 3021 if (tabptr == NULL || tabptr->zone_rctl_name == NULL) 3022 return (Z_INVAL); 3023 3024 if ((err = operation_prep(handle)) != Z_OK) 3025 return (err); 3026 3027 if ((err = zonecfg_add_rctl_core(handle, tabptr)) != Z_OK) 3028 return (err); 3029 3030 return (Z_OK); 3031 } 3032 3033 static int 3034 zonecfg_delete_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr) 3035 { 3036 xmlNodePtr cur = handle->zone_dh_cur; 3037 xmlChar *savedname; 3038 int name_result; 3039 3040 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 3041 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 3042 continue; 3043 3044 savedname = xmlGetProp(cur, DTD_ATTR_NAME); 3045 if (savedname == NULL) /* shouldn't happen */ 3046 continue; 3047 name_result = xmlStrcmp(savedname, 3048 (const xmlChar *) tabptr->zone_rctl_name); 3049 xmlFree(savedname); 3050 3051 if (name_result == 0) { 3052 xmlUnlinkNode(cur); 3053 xmlFreeNode(cur); 3054 return (Z_OK); 3055 } 3056 } 3057 return (Z_NO_RESOURCE_ID); 3058 } 3059 3060 int 3061 zonecfg_delete_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 3062 { 3063 int err; 3064 3065 if (tabptr == NULL || tabptr->zone_rctl_name == NULL) 3066 return (Z_INVAL); 3067 3068 if ((err = operation_prep(handle)) != Z_OK) 3069 return (err); 3070 3071 if ((err = zonecfg_delete_rctl_core(handle, tabptr)) != Z_OK) 3072 return (err); 3073 3074 return (Z_OK); 3075 } 3076 3077 int 3078 zonecfg_modify_rctl( 3079 zone_dochandle_t handle, 3080 struct zone_rctltab *oldtabptr, 3081 struct zone_rctltab *newtabptr) 3082 { 3083 int err; 3084 3085 if (oldtabptr == NULL || oldtabptr->zone_rctl_name == NULL || 3086 newtabptr == NULL || newtabptr->zone_rctl_name == NULL) 3087 return (Z_INVAL); 3088 3089 if ((err = operation_prep(handle)) != Z_OK) 3090 return (err); 3091 3092 if ((err = zonecfg_delete_rctl_core(handle, oldtabptr)) != Z_OK) 3093 return (err); 3094 3095 if ((err = zonecfg_add_rctl_core(handle, newtabptr)) != Z_OK) 3096 return (err); 3097 3098 return (Z_OK); 3099 } 3100 3101 int 3102 zonecfg_add_rctl_value( 3103 struct zone_rctltab *tabptr, 3104 struct zone_rctlvaltab *valtabptr) 3105 { 3106 struct zone_rctlvaltab *last, *old, *new; 3107 rctlblk_t *rctlblk = alloca(rctlblk_size()); 3108 3109 last = tabptr->zone_rctl_valptr; 3110 for (old = last; old != NULL; old = old->zone_rctlval_next) 3111 last = old; /* walk to the end of the list */ 3112 new = valtabptr; /* alloc'd by caller */ 3113 new->zone_rctlval_next = NULL; 3114 if (zonecfg_construct_rctlblk(valtabptr, rctlblk) != Z_OK) 3115 return (Z_INVAL); 3116 if (!zonecfg_valid_rctlblk(rctlblk)) 3117 return (Z_INVAL); 3118 if (last == NULL) 3119 tabptr->zone_rctl_valptr = new; 3120 else 3121 last->zone_rctlval_next = new; 3122 return (Z_OK); 3123 } 3124 3125 int 3126 zonecfg_remove_rctl_value( 3127 struct zone_rctltab *tabptr, 3128 struct zone_rctlvaltab *valtabptr) 3129 { 3130 struct zone_rctlvaltab *last, *this, *next; 3131 3132 last = tabptr->zone_rctl_valptr; 3133 for (this = last; this != NULL; this = this->zone_rctlval_next) { 3134 if (strcmp(this->zone_rctlval_priv, 3135 valtabptr->zone_rctlval_priv) == 0 && 3136 strcmp(this->zone_rctlval_limit, 3137 valtabptr->zone_rctlval_limit) == 0 && 3138 strcmp(this->zone_rctlval_action, 3139 valtabptr->zone_rctlval_action) == 0) { 3140 next = this->zone_rctlval_next; 3141 if (this == tabptr->zone_rctl_valptr) 3142 tabptr->zone_rctl_valptr = next; 3143 else 3144 last->zone_rctlval_next = next; 3145 free(this); 3146 return (Z_OK); 3147 } else 3148 last = this; 3149 } 3150 return (Z_NO_PROPERTY_ID); 3151 } 3152 3153 char * 3154 zonecfg_strerror(int errnum) 3155 { 3156 switch (errnum) { 3157 case Z_OK: 3158 return (dgettext(TEXT_DOMAIN, "OK")); 3159 case Z_EMPTY_DOCUMENT: 3160 return (dgettext(TEXT_DOMAIN, "Empty document")); 3161 case Z_WRONG_DOC_TYPE: 3162 return (dgettext(TEXT_DOMAIN, "Wrong document type")); 3163 case Z_BAD_PROPERTY: 3164 return (dgettext(TEXT_DOMAIN, "Bad document property")); 3165 case Z_TEMP_FILE: 3166 return (dgettext(TEXT_DOMAIN, 3167 "Problem creating temporary file")); 3168 case Z_SAVING_FILE: 3169 return (dgettext(TEXT_DOMAIN, "Problem saving file")); 3170 case Z_NO_ENTRY: 3171 return (dgettext(TEXT_DOMAIN, "No such entry")); 3172 case Z_BOGUS_ZONE_NAME: 3173 return (dgettext(TEXT_DOMAIN, "Bogus zone name")); 3174 case Z_REQD_RESOURCE_MISSING: 3175 return (dgettext(TEXT_DOMAIN, "Required resource missing")); 3176 case Z_REQD_PROPERTY_MISSING: 3177 return (dgettext(TEXT_DOMAIN, "Required property missing")); 3178 case Z_BAD_HANDLE: 3179 return (dgettext(TEXT_DOMAIN, "Bad handle")); 3180 case Z_NOMEM: 3181 return (dgettext(TEXT_DOMAIN, "Out of memory")); 3182 case Z_INVAL: 3183 return (dgettext(TEXT_DOMAIN, "Invalid argument")); 3184 case Z_ACCES: 3185 return (dgettext(TEXT_DOMAIN, "Permission denied")); 3186 case Z_TOO_BIG: 3187 return (dgettext(TEXT_DOMAIN, "Argument list too long")); 3188 case Z_MISC_FS: 3189 return (dgettext(TEXT_DOMAIN, 3190 "Miscellaneous file system error")); 3191 case Z_NO_ZONE: 3192 return (dgettext(TEXT_DOMAIN, "No such zone configured")); 3193 case Z_NO_RESOURCE_TYPE: 3194 return (dgettext(TEXT_DOMAIN, "No such resource type")); 3195 case Z_NO_RESOURCE_ID: 3196 return (dgettext(TEXT_DOMAIN, "No such resource with that id")); 3197 case Z_NO_PROPERTY_TYPE: 3198 return (dgettext(TEXT_DOMAIN, "No such property type")); 3199 case Z_NO_PROPERTY_ID: 3200 return (dgettext(TEXT_DOMAIN, "No such property with that id")); 3201 case Z_BAD_ZONE_STATE: 3202 return (dgettext(TEXT_DOMAIN, 3203 "Zone state is invalid for the requested operation")); 3204 case Z_INVALID_DOCUMENT: 3205 return (dgettext(TEXT_DOMAIN, "Invalid document")); 3206 case Z_NAME_IN_USE: 3207 return (dgettext(TEXT_DOMAIN, "Zone name already in use")); 3208 case Z_NO_SUCH_ID: 3209 return (dgettext(TEXT_DOMAIN, "No such zone ID")); 3210 case Z_UPDATING_INDEX: 3211 return (dgettext(TEXT_DOMAIN, "Problem updating index file")); 3212 case Z_LOCKING_FILE: 3213 return (dgettext(TEXT_DOMAIN, "Locking index file")); 3214 case Z_UNLOCKING_FILE: 3215 return (dgettext(TEXT_DOMAIN, "Unlocking index file")); 3216 case Z_INSUFFICIENT_SPEC: 3217 return (dgettext(TEXT_DOMAIN, "Insufficient specification")); 3218 case Z_RESOLVED_PATH: 3219 return (dgettext(TEXT_DOMAIN, "Resolved path mismatch")); 3220 case Z_IPV6_ADDR_PREFIX_LEN: 3221 return (dgettext(TEXT_DOMAIN, 3222 "IPv6 address missing required prefix length")); 3223 case Z_BOGUS_ADDRESS: 3224 return (dgettext(TEXT_DOMAIN, 3225 "Neither an IPv4 nor an IPv6 address nor a host name")); 3226 case Z_PRIV_PROHIBITED: 3227 return (dgettext(TEXT_DOMAIN, 3228 "Specified privilege is prohibited")); 3229 case Z_PRIV_REQUIRED: 3230 return (dgettext(TEXT_DOMAIN, 3231 "Required privilege is missing")); 3232 case Z_PRIV_UNKNOWN: 3233 return (dgettext(TEXT_DOMAIN, 3234 "Specified privilege is unknown")); 3235 case Z_BRAND_ERROR: 3236 return (dgettext(TEXT_DOMAIN, 3237 "Brand-specific error")); 3238 case Z_INCOMPATIBLE: 3239 return (dgettext(TEXT_DOMAIN, "Incompatible settings")); 3240 case Z_ALIAS_DISALLOW: 3241 return (dgettext(TEXT_DOMAIN, 3242 "An incompatible rctl already exists for this property")); 3243 case Z_CLEAR_DISALLOW: 3244 return (dgettext(TEXT_DOMAIN, 3245 "Clearing this property is not allowed")); 3246 case Z_POOL: 3247 return (dgettext(TEXT_DOMAIN, "libpool(3LIB) error")); 3248 case Z_POOLS_NOT_ACTIVE: 3249 return (dgettext(TEXT_DOMAIN, "Pools facility not active; " 3250 "zone will not be bound to pool")); 3251 case Z_POOL_ENABLE: 3252 return (dgettext(TEXT_DOMAIN, 3253 "Could not enable pools facility")); 3254 case Z_NO_POOL: 3255 return (dgettext(TEXT_DOMAIN, 3256 "Pool not found; using default pool")); 3257 case Z_POOL_CREATE: 3258 return (dgettext(TEXT_DOMAIN, 3259 "Could not create a temporary pool")); 3260 case Z_POOL_BIND: 3261 return (dgettext(TEXT_DOMAIN, "Could not bind zone to pool")); 3262 default: 3263 return (dgettext(TEXT_DOMAIN, "Unknown error")); 3264 } 3265 } 3266 3267 /* 3268 * Note that the zonecfg_setXent() and zonecfg_endXent() calls are all the 3269 * same, as they just turn around and call zonecfg_setent() / zonecfg_endent(). 3270 */ 3271 3272 static int 3273 zonecfg_setent(zone_dochandle_t handle) 3274 { 3275 xmlNodePtr cur; 3276 int err; 3277 3278 if (handle == NULL) 3279 return (Z_INVAL); 3280 3281 if ((err = operation_prep(handle)) != Z_OK) { 3282 handle->zone_dh_cur = NULL; 3283 return (err); 3284 } 3285 cur = handle->zone_dh_cur; 3286 cur = cur->xmlChildrenNode; 3287 handle->zone_dh_cur = cur; 3288 return (Z_OK); 3289 } 3290 3291 static int 3292 zonecfg_endent(zone_dochandle_t handle) 3293 { 3294 if (handle == NULL) 3295 return (Z_INVAL); 3296 3297 handle->zone_dh_cur = handle->zone_dh_top; 3298 return (Z_OK); 3299 } 3300 3301 /* 3302 * Do the work required to manipulate a process through libproc. 3303 * If grab_process() returns no errors (0), then release_process() 3304 * must eventually be called. 3305 * 3306 * Return values: 3307 * 0 Successful creation of agent thread 3308 * 1 Error grabbing 3309 * 2 Error creating agent 3310 */ 3311 static int 3312 grab_process(pr_info_handle_t *p) 3313 { 3314 int ret; 3315 3316 if ((p->pr = Pgrab(p->pid, 0, &ret)) != NULL) { 3317 3318 if (Psetflags(p->pr, PR_RLC) != 0) { 3319 Prelease(p->pr, 0); 3320 return (1); 3321 } 3322 if (Pcreate_agent(p->pr) == 0) { 3323 return (0); 3324 3325 } else { 3326 Prelease(p->pr, 0); 3327 return (2); 3328 } 3329 } else { 3330 return (1); 3331 } 3332 } 3333 3334 /* 3335 * Release the specified process. This destroys the agent 3336 * and releases the process. If the process is NULL, nothing 3337 * is done. This function should only be called if grab_process() 3338 * has previously been called and returned success. 3339 * 3340 * This function is Pgrab-safe. 3341 */ 3342 static void 3343 release_process(struct ps_prochandle *Pr) 3344 { 3345 if (Pr == NULL) 3346 return; 3347 3348 Pdestroy_agent(Pr); 3349 Prelease(Pr, 0); 3350 } 3351 3352 static boolean_t 3353 grab_zone_proc(char *zonename, pr_info_handle_t *p) 3354 { 3355 DIR *dirp; 3356 struct dirent *dentp; 3357 zoneid_t zoneid; 3358 int pid_self; 3359 psinfo_t psinfo; 3360 3361 if (zone_get_id(zonename, &zoneid) != 0) 3362 return (B_FALSE); 3363 3364 pid_self = getpid(); 3365 3366 if ((dirp = opendir("/proc")) == NULL) 3367 return (B_FALSE); 3368 3369 while (dentp = readdir(dirp)) { 3370 p->pid = atoi(dentp->d_name); 3371 3372 /* Skip self */ 3373 if (p->pid == pid_self) 3374 continue; 3375 3376 if (proc_get_psinfo(p->pid, &psinfo) != 0) 3377 continue; 3378 3379 if (psinfo.pr_zoneid != zoneid) 3380 continue; 3381 3382 /* attempt to grab process */ 3383 if (grab_process(p) != 0) 3384 continue; 3385 3386 if (pr_getzoneid(p->pr) != zoneid) { 3387 release_process(p->pr); 3388 continue; 3389 } 3390 3391 (void) closedir(dirp); 3392 return (B_TRUE); 3393 } 3394 3395 (void) closedir(dirp); 3396 return (B_FALSE); 3397 } 3398 3399 static boolean_t 3400 get_priv_rctl(struct ps_prochandle *pr, char *name, rctlblk_t *rblk) 3401 { 3402 if (pr_getrctl(pr, name, NULL, rblk, RCTL_FIRST)) 3403 return (B_FALSE); 3404 3405 if (rctlblk_get_privilege(rblk) == RCPRIV_PRIVILEGED) 3406 return (B_TRUE); 3407 3408 while (pr_getrctl(pr, name, rblk, rblk, RCTL_NEXT) == 0) { 3409 if (rctlblk_get_privilege(rblk) == RCPRIV_PRIVILEGED) 3410 return (B_TRUE); 3411 } 3412 3413 return (B_FALSE); 3414 } 3415 3416 /* 3417 * Apply the current rctl settings to the specified, running zone. 3418 */ 3419 int 3420 zonecfg_apply_rctls(char *zone_name, zone_dochandle_t handle) 3421 { 3422 int err; 3423 int res = Z_OK; 3424 rctlblk_t *rblk; 3425 pr_info_handle_t p; 3426 struct zone_rctltab rctl; 3427 3428 if ((err = zonecfg_setrctlent(handle)) != Z_OK) 3429 return (err); 3430 3431 if ((rblk = (rctlblk_t *)malloc(rctlblk_size())) == NULL) { 3432 (void) zonecfg_endrctlent(handle); 3433 return (Z_NOMEM); 3434 } 3435 3436 if (!grab_zone_proc(zone_name, &p)) { 3437 (void) zonecfg_endrctlent(handle); 3438 free(rblk); 3439 return (Z_SYSTEM); 3440 } 3441 3442 while (zonecfg_getrctlent(handle, &rctl) == Z_OK) { 3443 char *rname; 3444 struct zone_rctlvaltab *valptr; 3445 3446 rname = rctl.zone_rctl_name; 3447 3448 /* first delete all current privileged settings for this rctl */ 3449 while (get_priv_rctl(p.pr, rname, rblk)) { 3450 if (pr_setrctl(p.pr, rname, NULL, rblk, RCTL_DELETE) != 3451 0) { 3452 res = Z_SYSTEM; 3453 goto done; 3454 } 3455 } 3456 3457 /* now set each new value for the rctl */ 3458 for (valptr = rctl.zone_rctl_valptr; valptr != NULL; 3459 valptr = valptr->zone_rctlval_next) { 3460 if ((err = zonecfg_construct_rctlblk(valptr, rblk)) 3461 != Z_OK) { 3462 res = errno = err; 3463 goto done; 3464 } 3465 3466 if (pr_setrctl(p.pr, rname, NULL, rblk, RCTL_INSERT)) { 3467 res = Z_SYSTEM; 3468 goto done; 3469 } 3470 } 3471 } 3472 3473 done: 3474 release_process(p.pr); 3475 free(rblk); 3476 (void) zonecfg_endrctlent(handle); 3477 3478 return (res); 3479 } 3480 3481 static const xmlChar * 3482 nm_to_dtd(char *nm) 3483 { 3484 if (strcmp(nm, "device") == 0) 3485 return (DTD_ELEM_DEVICE); 3486 if (strcmp(nm, "fs") == 0) 3487 return (DTD_ELEM_FS); 3488 if (strcmp(nm, "inherit-pkg-dir") == 0) 3489 return (DTD_ELEM_IPD); 3490 if (strcmp(nm, "net") == 0) 3491 return (DTD_ELEM_NET); 3492 if (strcmp(nm, "attr") == 0) 3493 return (DTD_ELEM_ATTR); 3494 if (strcmp(nm, "rctl") == 0) 3495 return (DTD_ELEM_RCTL); 3496 if (strcmp(nm, "dataset") == 0) 3497 return (DTD_ELEM_DATASET); 3498 3499 return (NULL); 3500 } 3501 3502 int 3503 zonecfg_num_resources(zone_dochandle_t handle, char *rsrc) 3504 { 3505 int num = 0; 3506 const xmlChar *dtd; 3507 xmlNodePtr cur; 3508 3509 if ((dtd = nm_to_dtd(rsrc)) == NULL) 3510 return (num); 3511 3512 if (zonecfg_setent(handle) != Z_OK) 3513 return (num); 3514 3515 for (cur = handle->zone_dh_cur; cur != NULL; cur = cur->next) 3516 if (xmlStrcmp(cur->name, dtd) == 0) 3517 num++; 3518 3519 (void) zonecfg_endent(handle); 3520 3521 return (num); 3522 } 3523 3524 int 3525 zonecfg_del_all_resources(zone_dochandle_t handle, char *rsrc) 3526 { 3527 int err; 3528 const xmlChar *dtd; 3529 xmlNodePtr cur; 3530 3531 if ((dtd = nm_to_dtd(rsrc)) == NULL) 3532 return (Z_NO_RESOURCE_TYPE); 3533 3534 if ((err = zonecfg_setent(handle)) != Z_OK) 3535 return (err); 3536 3537 cur = handle->zone_dh_cur; 3538 while (cur != NULL) { 3539 xmlNodePtr tmp; 3540 3541 if (xmlStrcmp(cur->name, dtd)) { 3542 cur = cur->next; 3543 continue; 3544 } 3545 3546 tmp = cur->next; 3547 xmlUnlinkNode(cur); 3548 xmlFreeNode(cur); 3549 cur = tmp; 3550 } 3551 3552 (void) zonecfg_endent(handle); 3553 return (Z_OK); 3554 } 3555 3556 static boolean_t 3557 valid_uint(char *s, uint64_t *n) 3558 { 3559 char *endp; 3560 3561 /* strtoull accepts '-'?! so we want to flag that as an error */ 3562 if (strchr(s, '-') != NULL) 3563 return (B_FALSE); 3564 3565 errno = 0; 3566 *n = strtoull(s, &endp, 10); 3567 3568 if (errno != 0 || *endp != '\0') 3569 return (B_FALSE); 3570 return (B_TRUE); 3571 } 3572 3573 /* 3574 * Convert a string representing a number (possibly a fraction) into an integer. 3575 * The string can have a modifier (K, M, G or T). The modifiers are treated 3576 * as powers of two (not 10). 3577 */ 3578 int 3579 zonecfg_str_to_bytes(char *str, uint64_t *bytes) 3580 { 3581 long double val; 3582 char *unitp; 3583 uint64_t scale; 3584 3585 if ((val = strtold(str, &unitp)) < 0) 3586 return (-1); 3587 3588 /* remove any leading white space from units string */ 3589 while (isspace(*unitp) != 0) 3590 ++unitp; 3591 3592 /* if no units explicitly set, error */ 3593 if (unitp == NULL || *unitp == '\0') { 3594 scale = 1; 3595 } else { 3596 int i; 3597 char *units[] = {"K", "M", "G", "T", NULL}; 3598 3599 scale = 1024; 3600 3601 /* update scale based on units */ 3602 for (i = 0; units[i] != NULL; i++) { 3603 if (strcasecmp(unitp, units[i]) == 0) 3604 break; 3605 scale <<= 10; 3606 } 3607 3608 if (units[i] == NULL) 3609 return (-1); 3610 } 3611 3612 *bytes = (uint64_t)(val * scale); 3613 return (0); 3614 } 3615 3616 boolean_t 3617 zonecfg_valid_ncpus(char *lowstr, char *highstr) 3618 { 3619 uint64_t low, high; 3620 3621 if (!valid_uint(lowstr, &low) || !valid_uint(highstr, &high) || 3622 low < 1 || low > high) 3623 return (B_FALSE); 3624 3625 return (B_TRUE); 3626 } 3627 3628 boolean_t 3629 zonecfg_valid_importance(char *impstr) 3630 { 3631 uint64_t num; 3632 3633 if (!valid_uint(impstr, &num)) 3634 return (B_FALSE); 3635 3636 return (B_TRUE); 3637 } 3638 3639 boolean_t 3640 zonecfg_valid_alias_limit(char *name, char *limitstr, uint64_t *limit) 3641 { 3642 int i; 3643 3644 for (i = 0; aliases[i].shortname != NULL; i++) 3645 if (strcmp(name, aliases[i].shortname) == 0) 3646 break; 3647 3648 if (aliases[i].shortname == NULL) 3649 return (B_FALSE); 3650 3651 if (!valid_uint(limitstr, limit) || *limit < aliases[i].low_limit) 3652 return (B_FALSE); 3653 3654 return (B_TRUE); 3655 } 3656 3657 boolean_t 3658 zonecfg_valid_memlimit(char *memstr, uint64_t *mem_val) 3659 { 3660 if (zonecfg_str_to_bytes(memstr, mem_val) != 0) 3661 return (B_FALSE); 3662 3663 return (B_TRUE); 3664 } 3665 3666 static int 3667 zerr_pool(char *pool_err, int err_size, int res) 3668 { 3669 (void) strlcpy(pool_err, pool_strerror(pool_error()), err_size); 3670 return (res); 3671 } 3672 3673 static int 3674 create_tmp_pset(char *pool_err, int err_size, pool_conf_t *pconf, pool_t *pool, 3675 char *name, int min, int max) 3676 { 3677 pool_resource_t *res; 3678 pool_elem_t *elem; 3679 pool_value_t *val; 3680 3681 if ((res = pool_resource_create(pconf, "pset", name)) == NULL) 3682 return (zerr_pool(pool_err, err_size, Z_POOL)); 3683 3684 if (pool_associate(pconf, pool, res) != PO_SUCCESS) 3685 return (zerr_pool(pool_err, err_size, Z_POOL)); 3686 3687 if ((elem = pool_resource_to_elem(pconf, res)) == NULL) 3688 return (zerr_pool(pool_err, err_size, Z_POOL)); 3689 3690 if ((val = pool_value_alloc()) == NULL) 3691 return (zerr_pool(pool_err, err_size, Z_POOL)); 3692 3693 /* set the maximum number of cpus for the pset */ 3694 pool_value_set_uint64(val, (uint64_t)max); 3695 3696 if (pool_put_property(pconf, elem, "pset.max", val) != PO_SUCCESS) { 3697 pool_value_free(val); 3698 return (zerr_pool(pool_err, err_size, Z_POOL)); 3699 } 3700 3701 /* set the minimum number of cpus for the pset */ 3702 pool_value_set_uint64(val, (uint64_t)min); 3703 3704 if (pool_put_property(pconf, elem, "pset.min", val) != PO_SUCCESS) { 3705 pool_value_free(val); 3706 return (zerr_pool(pool_err, err_size, Z_POOL)); 3707 } 3708 3709 pool_value_free(val); 3710 3711 return (Z_OK); 3712 } 3713 3714 static int 3715 create_tmp_pool(char *pool_err, int err_size, pool_conf_t *pconf, char *name, 3716 struct zone_psettab *pset_tab) 3717 { 3718 pool_t *pool; 3719 int res = Z_OK; 3720 3721 /* create a temporary pool configuration */ 3722 if (pool_conf_open(pconf, NULL, PO_TEMP) != PO_SUCCESS) { 3723 res = zerr_pool(pool_err, err_size, Z_POOL); 3724 return (res); 3725 } 3726 3727 if ((pool = pool_create(pconf, name)) == NULL) { 3728 res = zerr_pool(pool_err, err_size, Z_POOL_CREATE); 3729 goto done; 3730 } 3731 3732 /* set pool importance */ 3733 if (pset_tab->zone_importance[0] != '\0') { 3734 pool_elem_t *elem; 3735 pool_value_t *val; 3736 3737 if ((elem = pool_to_elem(pconf, pool)) == NULL) { 3738 res = zerr_pool(pool_err, err_size, Z_POOL); 3739 goto done; 3740 } 3741 3742 if ((val = pool_value_alloc()) == NULL) { 3743 res = zerr_pool(pool_err, err_size, Z_POOL); 3744 goto done; 3745 } 3746 3747 pool_value_set_int64(val, 3748 (int64_t)atoi(pset_tab->zone_importance)); 3749 3750 if (pool_put_property(pconf, elem, "pool.importance", val) 3751 != PO_SUCCESS) { 3752 res = zerr_pool(pool_err, err_size, Z_POOL); 3753 pool_value_free(val); 3754 goto done; 3755 } 3756 3757 pool_value_free(val); 3758 } 3759 3760 if ((res = create_tmp_pset(pool_err, err_size, pconf, pool, name, 3761 atoi(pset_tab->zone_ncpu_min), 3762 atoi(pset_tab->zone_ncpu_max))) != Z_OK) 3763 goto done; 3764 3765 /* validation */ 3766 if (pool_conf_status(pconf) == POF_INVALID) { 3767 res = zerr_pool(pool_err, err_size, Z_POOL); 3768 goto done; 3769 } 3770 3771 /* 3772 * This validation is the one we expect to fail if the user specified 3773 * an invalid configuration (too many cpus) for this system. 3774 */ 3775 if (pool_conf_validate(pconf, POV_RUNTIME) != PO_SUCCESS) { 3776 res = zerr_pool(pool_err, err_size, Z_POOL_CREATE); 3777 goto done; 3778 } 3779 3780 /* 3781 * Commit the dynamic configuration but not the pool configuration 3782 * file. 3783 */ 3784 if (pool_conf_commit(pconf, 1) != PO_SUCCESS) 3785 res = zerr_pool(pool_err, err_size, Z_POOL); 3786 3787 done: 3788 (void) pool_conf_close(pconf); 3789 return (res); 3790 } 3791 3792 static int 3793 get_running_tmp_pset(pool_conf_t *pconf, pool_t *pool, pool_resource_t *pset, 3794 struct zone_psettab *pset_tab) 3795 { 3796 int nfound = 0; 3797 pool_elem_t *pe; 3798 pool_value_t *pv = pool_value_alloc(); 3799 uint64_t val_uint; 3800 3801 if (pool != NULL) { 3802 pe = pool_to_elem(pconf, pool); 3803 if (pool_get_property(pconf, pe, "pool.importance", pv) 3804 != POC_INVAL) { 3805 int64_t val_int; 3806 3807 (void) pool_value_get_int64(pv, &val_int); 3808 (void) snprintf(pset_tab->zone_importance, 3809 sizeof (pset_tab->zone_importance), "%d", val_int); 3810 nfound++; 3811 } 3812 } 3813 3814 if (pset != NULL) { 3815 pe = pool_resource_to_elem(pconf, pset); 3816 if (pool_get_property(pconf, pe, "pset.min", pv) != POC_INVAL) { 3817 (void) pool_value_get_uint64(pv, &val_uint); 3818 (void) snprintf(pset_tab->zone_ncpu_min, 3819 sizeof (pset_tab->zone_ncpu_min), "%u", val_uint); 3820 nfound++; 3821 } 3822 3823 if (pool_get_property(pconf, pe, "pset.max", pv) != POC_INVAL) { 3824 (void) pool_value_get_uint64(pv, &val_uint); 3825 (void) snprintf(pset_tab->zone_ncpu_max, 3826 sizeof (pset_tab->zone_ncpu_max), "%u", val_uint); 3827 nfound++; 3828 } 3829 } 3830 3831 pool_value_free(pv); 3832 3833 if (nfound == 3) 3834 return (PO_SUCCESS); 3835 3836 return (PO_FAIL); 3837 } 3838 3839 /* 3840 * Determine if a tmp pool is configured and if so, if the configuration is 3841 * still valid or if it has been changed since the tmp pool was created. 3842 * If the tmp pool configuration is no longer valid, delete the tmp pool. 3843 * 3844 * Set *valid=B_TRUE if there is an existing, valid tmp pool configuration. 3845 */ 3846 static int 3847 verify_del_tmp_pool(pool_conf_t *pconf, char *tmp_name, char *pool_err, 3848 int err_size, struct zone_psettab *pset_tab, boolean_t *exists) 3849 { 3850 int res = Z_OK; 3851 pool_t *pool; 3852 pool_resource_t *pset; 3853 struct zone_psettab pset_current; 3854 3855 *exists = B_FALSE; 3856 3857 if (pool_conf_open(pconf, pool_dynamic_location(), PO_RDWR) 3858 != PO_SUCCESS) { 3859 res = zerr_pool(pool_err, err_size, Z_POOL); 3860 return (res); 3861 } 3862 3863 pool = pool_get_pool(pconf, tmp_name); 3864 pset = pool_get_resource(pconf, "pset", tmp_name); 3865 3866 if (pool == NULL && pset == NULL) { 3867 /* no tmp pool configured */ 3868 goto done; 3869 } 3870 3871 /* 3872 * If an existing tmp pool for this zone is configured with the proper 3873 * settings, then the tmp pool is valid. 3874 */ 3875 if (get_running_tmp_pset(pconf, pool, pset, &pset_current) 3876 == PO_SUCCESS && 3877 strcmp(pset_tab->zone_ncpu_min, 3878 pset_current.zone_ncpu_min) == 0 && 3879 strcmp(pset_tab->zone_ncpu_max, 3880 pset_current.zone_ncpu_max) == 0 && 3881 strcmp(pset_tab->zone_importance, 3882 pset_current.zone_importance) == 0) { 3883 *exists = B_TRUE; 3884 3885 } else { 3886 /* 3887 * An out-of-date tmp pool configuration exists. Delete it 3888 * so that we can create the correct tmp pool config. 3889 */ 3890 if (pset != NULL && 3891 pool_resource_destroy(pconf, pset) != PO_SUCCESS) { 3892 res = zerr_pool(pool_err, err_size, Z_POOL); 3893 goto done; 3894 } 3895 3896 if (pool != NULL && 3897 pool_destroy(pconf, pool) != PO_SUCCESS) { 3898 res = zerr_pool(pool_err, err_size, Z_POOL); 3899 goto done; 3900 } 3901 3902 /* commit dynamic config */ 3903 if (pool_conf_commit(pconf, 0) != PO_SUCCESS) 3904 res = zerr_pool(pool_err, err_size, Z_POOL); 3905 } 3906 3907 done: 3908 (void) pool_conf_close(pconf); 3909 3910 return (res); 3911 } 3912 3913 /* 3914 * Destroy any existing tmp pool. 3915 */ 3916 int 3917 zonecfg_destroy_tmp_pool(char *zone_name, char *pool_err, int err_size) 3918 { 3919 int status; 3920 int res = Z_OK; 3921 pool_conf_t *pconf; 3922 pool_t *pool; 3923 pool_resource_t *pset; 3924 char tmp_name[MAX_TMP_POOL_NAME]; 3925 3926 /* if pools not enabled then nothing to do */ 3927 if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) 3928 return (Z_OK); 3929 3930 if ((pconf = pool_conf_alloc()) == NULL) 3931 return (zerr_pool(pool_err, err_size, Z_POOL)); 3932 3933 (void) snprintf(tmp_name, sizeof (tmp_name), TMP_POOL_NAME, zone_name); 3934 3935 if (pool_conf_open(pconf, pool_dynamic_location(), PO_RDWR) 3936 != PO_SUCCESS) { 3937 res = zerr_pool(pool_err, err_size, Z_POOL); 3938 pool_conf_free(pconf); 3939 return (res); 3940 } 3941 3942 pool = pool_get_pool(pconf, tmp_name); 3943 pset = pool_get_resource(pconf, "pset", tmp_name); 3944 3945 if (pool == NULL && pset == NULL) { 3946 /* nothing to destroy, we're done */ 3947 goto done; 3948 } 3949 3950 if (pset != NULL && pool_resource_destroy(pconf, pset) != PO_SUCCESS) { 3951 res = zerr_pool(pool_err, err_size, Z_POOL); 3952 goto done; 3953 } 3954 3955 if (pool != NULL && pool_destroy(pconf, pool) != PO_SUCCESS) { 3956 res = zerr_pool(pool_err, err_size, Z_POOL); 3957 goto done; 3958 } 3959 3960 /* commit dynamic config */ 3961 if (pool_conf_commit(pconf, 0) != PO_SUCCESS) 3962 res = zerr_pool(pool_err, err_size, Z_POOL); 3963 3964 done: 3965 (void) pool_conf_close(pconf); 3966 pool_conf_free(pconf); 3967 3968 return (res); 3969 } 3970 3971 /* 3972 * Attempt to bind to a tmp pool for this zone. If there is no tmp pool 3973 * configured, we just return Z_OK. 3974 * 3975 * We either attempt to create the tmp pool for this zone or rebind to an 3976 * existing tmp pool for this zone. 3977 * 3978 * Rebinding is used when a zone with a tmp pool reboots so that we don't have 3979 * to recreate the tmp pool. To do this we need to be sure we work correctly 3980 * for the following cases: 3981 * 3982 * - there is an existing, properly configured tmp pool. 3983 * - zonecfg added tmp pool after zone was booted, must now create. 3984 * - zonecfg updated tmp pool config after zone was booted, in this case 3985 * we destroy the old tmp pool and create a new one. 3986 */ 3987 int 3988 zonecfg_bind_tmp_pool(zone_dochandle_t handle, zoneid_t zoneid, char *pool_err, 3989 int err_size) 3990 { 3991 struct zone_psettab pset_tab; 3992 int err; 3993 int status; 3994 pool_conf_t *pconf; 3995 boolean_t exists; 3996 char zone_name[ZONENAME_MAX]; 3997 char tmp_name[MAX_TMP_POOL_NAME]; 3998 3999 (void) getzonenamebyid(zoneid, zone_name, sizeof (zone_name)); 4000 4001 err = zonecfg_lookup_pset(handle, &pset_tab); 4002 4003 /* if no temporary pool configured, we're done */ 4004 if (err == Z_NO_ENTRY) 4005 return (Z_OK); 4006 4007 /* 4008 * importance might not have a value but we need to validate it here, 4009 * so set the default. 4010 */ 4011 if (pset_tab.zone_importance[0] == '\0') 4012 (void) strlcpy(pset_tab.zone_importance, "1", 4013 sizeof (pset_tab.zone_importance)); 4014 4015 /* if pools not enabled, enable them now */ 4016 if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) { 4017 if (pool_set_status(POOL_ENABLED) != PO_SUCCESS) 4018 return (Z_POOL_ENABLE); 4019 } 4020 4021 if ((pconf = pool_conf_alloc()) == NULL) 4022 return (zerr_pool(pool_err, err_size, Z_POOL)); 4023 4024 (void) snprintf(tmp_name, sizeof (tmp_name), TMP_POOL_NAME, zone_name); 4025 4026 /* 4027 * Check if a valid tmp pool/pset already exists. If so, we just 4028 * reuse it. 4029 */ 4030 if ((err = verify_del_tmp_pool(pconf, tmp_name, pool_err, err_size, 4031 &pset_tab, &exists)) != Z_OK) { 4032 pool_conf_free(pconf); 4033 return (err); 4034 } 4035 4036 if (!exists) 4037 err = create_tmp_pool(pool_err, err_size, pconf, tmp_name, 4038 &pset_tab); 4039 4040 pool_conf_free(pconf); 4041 4042 if (err != Z_OK) 4043 return (err); 4044 4045 /* Bind the zone to the pool. */ 4046 if (pool_set_binding(tmp_name, P_ZONEID, zoneid) != PO_SUCCESS) 4047 return (zerr_pool(pool_err, err_size, Z_POOL_BIND)); 4048 4049 return (Z_OK); 4050 } 4051 4052 /* 4053 * Attempt to bind to a permanent pool for this zone. If there is no 4054 * permanent pool configured, we just return Z_OK. 4055 */ 4056 int 4057 zonecfg_bind_pool(zone_dochandle_t handle, zoneid_t zoneid, char *pool_err, 4058 int err_size) 4059 { 4060 pool_conf_t *poolconf; 4061 pool_t *pool; 4062 char poolname[MAXPATHLEN]; 4063 int status; 4064 int error; 4065 4066 /* 4067 * Find the pool mentioned in the zone configuration, and bind to it. 4068 */ 4069 error = zonecfg_get_pool(handle, poolname, sizeof (poolname)); 4070 if (error == Z_NO_ENTRY || (error == Z_OK && strlen(poolname) == 0)) { 4071 /* 4072 * The property is not set on the zone, so the pool 4073 * should be bound to the default pool. But that's 4074 * already done by the kernel, so we can just return. 4075 */ 4076 return (Z_OK); 4077 } 4078 if (error != Z_OK) { 4079 /* 4080 * Not an error, even though it shouldn't be happening. 4081 */ 4082 return (Z_OK); 4083 } 4084 /* 4085 * Don't do anything if pools aren't enabled. 4086 */ 4087 if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) 4088 return (Z_POOLS_NOT_ACTIVE); 4089 4090 /* 4091 * Try to provide a sane error message if the requested pool doesn't 4092 * exist. 4093 */ 4094 if ((poolconf = pool_conf_alloc()) == NULL) 4095 return (zerr_pool(pool_err, err_size, Z_POOL)); 4096 4097 if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) != 4098 PO_SUCCESS) { 4099 pool_conf_free(poolconf); 4100 return (zerr_pool(pool_err, err_size, Z_POOL)); 4101 } 4102 pool = pool_get_pool(poolconf, poolname); 4103 (void) pool_conf_close(poolconf); 4104 pool_conf_free(poolconf); 4105 if (pool == NULL) 4106 return (Z_NO_POOL); 4107 4108 /* 4109 * Bind the zone to the pool. 4110 */ 4111 if (pool_set_binding(poolname, P_ZONEID, zoneid) != PO_SUCCESS) { 4112 /* if bind fails, return poolname for the error msg */ 4113 (void) strlcpy(pool_err, poolname, err_size); 4114 return (Z_POOL_BIND); 4115 } 4116 4117 return (Z_OK); 4118 } 4119 4120 4121 static boolean_t 4122 svc_enabled(char *svc_name) 4123 { 4124 scf_simple_prop_t *prop; 4125 boolean_t found = B_FALSE; 4126 4127 prop = scf_simple_prop_get(NULL, svc_name, SCF_PG_GENERAL, 4128 SCF_PROPERTY_ENABLED); 4129 4130 if (scf_simple_prop_numvalues(prop) == 1 && 4131 *scf_simple_prop_next_boolean(prop) != 0) 4132 found = B_TRUE; 4133 4134 scf_simple_prop_free(prop); 4135 4136 return (found); 4137 } 4138 4139 /* 4140 * If the zone has capped-memory, make sure the rcap service is enabled. 4141 */ 4142 int 4143 zonecfg_enable_rcapd(char *err, int size) 4144 { 4145 if (!svc_enabled(RCAP_SERVICE) && 4146 smf_enable_instance(RCAP_SERVICE, 0) == -1) { 4147 (void) strlcpy(err, scf_strerror(scf_error()), size); 4148 return (Z_SYSTEM); 4149 } 4150 4151 return (Z_OK); 4152 } 4153 4154 /* 4155 * Return true if pset has cpu range specified and poold is not enabled. 4156 */ 4157 boolean_t 4158 zonecfg_warn_poold(zone_dochandle_t handle) 4159 { 4160 struct zone_psettab pset_tab; 4161 int min, max; 4162 int err; 4163 4164 err = zonecfg_lookup_pset(handle, &pset_tab); 4165 4166 /* if no temporary pool configured, we're done */ 4167 if (err == Z_NO_ENTRY) 4168 return (B_FALSE); 4169 4170 min = atoi(pset_tab.zone_ncpu_min); 4171 max = atoi(pset_tab.zone_ncpu_max); 4172 4173 /* range not specified, no need for poold */ 4174 if (min == max) 4175 return (B_FALSE); 4176 4177 /* we have a range, check if poold service is enabled */ 4178 if (svc_enabled(POOLD_SERVICE)) 4179 return (B_FALSE); 4180 4181 return (B_TRUE); 4182 } 4183 4184 static int 4185 get_pool_sched_class(char *poolname, char *class, int clsize) 4186 { 4187 int status; 4188 pool_conf_t *poolconf; 4189 pool_t *pool; 4190 pool_elem_t *pe; 4191 pool_value_t *pv = pool_value_alloc(); 4192 const char *sched_str; 4193 4194 if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) 4195 return (Z_NO_POOL); 4196 4197 if ((poolconf = pool_conf_alloc()) == NULL) 4198 return (Z_NO_POOL); 4199 4200 if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) != 4201 PO_SUCCESS) { 4202 pool_conf_free(poolconf); 4203 return (Z_NO_POOL); 4204 } 4205 4206 if ((pool = pool_get_pool(poolconf, poolname)) == NULL) { 4207 (void) pool_conf_close(poolconf); 4208 pool_conf_free(poolconf); 4209 return (Z_NO_POOL); 4210 } 4211 4212 pe = pool_to_elem(poolconf, pool); 4213 if (pool_get_property(poolconf, pe, "pool.scheduler", pv) 4214 != POC_INVAL) { 4215 (void) pool_value_get_string(pv, &sched_str); 4216 if (strlcpy(class, sched_str, clsize) >= clsize) 4217 return (Z_TOO_BIG); 4218 } 4219 4220 (void) pool_conf_close(poolconf); 4221 pool_conf_free(poolconf); 4222 return (Z_OK); 4223 } 4224 4225 /* 4226 * Get the default scheduling class for the zone. This will either be the 4227 * class set on the zone's pool or the system default scheduling class. 4228 */ 4229 int 4230 zonecfg_get_dflt_sched_class(zone_dochandle_t handle, char *class, int clsize) 4231 { 4232 char poolname[MAXPATHLEN]; 4233 4234 if (zonecfg_get_pool(handle, poolname, sizeof (poolname)) == Z_OK) { 4235 /* check if the zone's pool specified a sched class */ 4236 if (get_pool_sched_class(poolname, class, clsize) == Z_OK) 4237 return (Z_OK); 4238 } 4239 4240 if (priocntl(0, 0, PC_GETDFLCL, class, (uint64_t)clsize) == -1) 4241 return (Z_TOO_BIG); 4242 4243 return (Z_OK); 4244 } 4245 4246 int 4247 zonecfg_setfsent(zone_dochandle_t handle) 4248 { 4249 return (zonecfg_setent(handle)); 4250 } 4251 4252 int 4253 zonecfg_getfsent(zone_dochandle_t handle, struct zone_fstab *tabptr) 4254 { 4255 xmlNodePtr cur, options; 4256 char options_str[MAX_MNTOPT_STR]; 4257 int err; 4258 4259 if (handle == NULL) 4260 return (Z_INVAL); 4261 4262 if ((cur = handle->zone_dh_cur) == NULL) 4263 return (Z_NO_ENTRY); 4264 4265 for (; cur != NULL; cur = cur->next) 4266 if (!xmlStrcmp(cur->name, DTD_ELEM_FS)) 4267 break; 4268 if (cur == NULL) { 4269 handle->zone_dh_cur = handle->zone_dh_top; 4270 return (Z_NO_ENTRY); 4271 } 4272 4273 if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special, 4274 sizeof (tabptr->zone_fs_special))) != Z_OK) { 4275 handle->zone_dh_cur = handle->zone_dh_top; 4276 return (err); 4277 } 4278 4279 if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw, 4280 sizeof (tabptr->zone_fs_raw))) != Z_OK) { 4281 handle->zone_dh_cur = handle->zone_dh_top; 4282 return (err); 4283 } 4284 4285 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 4286 sizeof (tabptr->zone_fs_dir))) != Z_OK) { 4287 handle->zone_dh_cur = handle->zone_dh_top; 4288 return (err); 4289 } 4290 4291 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type, 4292 sizeof (tabptr->zone_fs_type))) != Z_OK) { 4293 handle->zone_dh_cur = handle->zone_dh_top; 4294 return (err); 4295 } 4296 4297 /* OK for options to be NULL */ 4298 tabptr->zone_fs_options = NULL; 4299 for (options = cur->xmlChildrenNode; options != NULL; 4300 options = options->next) { 4301 if (fetchprop(options, DTD_ATTR_NAME, options_str, 4302 sizeof (options_str)) != Z_OK) 4303 break; 4304 if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK) 4305 break; 4306 } 4307 4308 handle->zone_dh_cur = cur->next; 4309 return (Z_OK); 4310 } 4311 4312 int 4313 zonecfg_endfsent(zone_dochandle_t handle) 4314 { 4315 return (zonecfg_endent(handle)); 4316 } 4317 4318 int 4319 zonecfg_setipdent(zone_dochandle_t handle) 4320 { 4321 return (zonecfg_setent(handle)); 4322 } 4323 4324 int 4325 zonecfg_getipdent(zone_dochandle_t handle, struct zone_fstab *tabptr) 4326 { 4327 xmlNodePtr cur; 4328 int err; 4329 4330 if (handle == NULL) 4331 return (Z_INVAL); 4332 4333 if ((cur = handle->zone_dh_cur) == NULL) 4334 return (Z_NO_ENTRY); 4335 4336 for (; cur != NULL; cur = cur->next) 4337 if (!xmlStrcmp(cur->name, DTD_ELEM_IPD)) 4338 break; 4339 if (cur == NULL) { 4340 handle->zone_dh_cur = handle->zone_dh_top; 4341 return (Z_NO_ENTRY); 4342 } 4343 4344 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 4345 sizeof (tabptr->zone_fs_dir))) != Z_OK) { 4346 handle->zone_dh_cur = handle->zone_dh_top; 4347 return (err); 4348 } 4349 4350 handle->zone_dh_cur = cur->next; 4351 return (Z_OK); 4352 } 4353 4354 int 4355 zonecfg_endipdent(zone_dochandle_t handle) 4356 { 4357 return (zonecfg_endent(handle)); 4358 } 4359 4360 int 4361 zonecfg_setnwifent(zone_dochandle_t handle) 4362 { 4363 return (zonecfg_setent(handle)); 4364 } 4365 4366 int 4367 zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 4368 { 4369 xmlNodePtr cur; 4370 int err; 4371 4372 if (handle == NULL) 4373 return (Z_INVAL); 4374 4375 if ((cur = handle->zone_dh_cur) == NULL) 4376 return (Z_NO_ENTRY); 4377 4378 for (; cur != NULL; cur = cur->next) 4379 if (!xmlStrcmp(cur->name, DTD_ELEM_NET)) 4380 break; 4381 if (cur == NULL) { 4382 handle->zone_dh_cur = handle->zone_dh_top; 4383 return (Z_NO_ENTRY); 4384 } 4385 4386 if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address, 4387 sizeof (tabptr->zone_nwif_address))) != Z_OK) { 4388 handle->zone_dh_cur = handle->zone_dh_top; 4389 return (err); 4390 } 4391 4392 if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical, 4393 sizeof (tabptr->zone_nwif_physical))) != Z_OK) { 4394 handle->zone_dh_cur = handle->zone_dh_top; 4395 return (err); 4396 } 4397 4398 if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER, 4399 tabptr->zone_nwif_defrouter, 4400 sizeof (tabptr->zone_nwif_defrouter))) != Z_OK) { 4401 handle->zone_dh_cur = handle->zone_dh_top; 4402 return (err); 4403 } 4404 4405 handle->zone_dh_cur = cur->next; 4406 return (Z_OK); 4407 } 4408 4409 int 4410 zonecfg_endnwifent(zone_dochandle_t handle) 4411 { 4412 return (zonecfg_endent(handle)); 4413 } 4414 4415 int 4416 zonecfg_setdevent(zone_dochandle_t handle) 4417 { 4418 return (zonecfg_setent(handle)); 4419 } 4420 4421 int 4422 zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr) 4423 { 4424 xmlNodePtr cur; 4425 int err; 4426 4427 if (handle == NULL) 4428 return (Z_INVAL); 4429 4430 if ((cur = handle->zone_dh_cur) == NULL) 4431 return (Z_NO_ENTRY); 4432 4433 for (; cur != NULL; cur = cur->next) 4434 if (!xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) 4435 break; 4436 if (cur == NULL) { 4437 handle->zone_dh_cur = handle->zone_dh_top; 4438 return (Z_NO_ENTRY); 4439 } 4440 4441 if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match, 4442 sizeof (tabptr->zone_dev_match))) != Z_OK) { 4443 handle->zone_dh_cur = handle->zone_dh_top; 4444 return (err); 4445 } 4446 4447 handle->zone_dh_cur = cur->next; 4448 return (Z_OK); 4449 } 4450 4451 int 4452 zonecfg_enddevent(zone_dochandle_t handle) 4453 { 4454 return (zonecfg_endent(handle)); 4455 } 4456 4457 int 4458 zonecfg_setrctlent(zone_dochandle_t handle) 4459 { 4460 return (zonecfg_setent(handle)); 4461 } 4462 4463 int 4464 zonecfg_getrctlent(zone_dochandle_t handle, struct zone_rctltab *tabptr) 4465 { 4466 xmlNodePtr cur, val; 4467 struct zone_rctlvaltab *valptr; 4468 int err; 4469 4470 if (handle == NULL) 4471 return (Z_INVAL); 4472 4473 if ((cur = handle->zone_dh_cur) == NULL) 4474 return (Z_NO_ENTRY); 4475 4476 for (; cur != NULL; cur = cur->next) 4477 if (!xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 4478 break; 4479 if (cur == NULL) { 4480 handle->zone_dh_cur = handle->zone_dh_top; 4481 return (Z_NO_ENTRY); 4482 } 4483 4484 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_rctl_name, 4485 sizeof (tabptr->zone_rctl_name))) != Z_OK) { 4486 handle->zone_dh_cur = handle->zone_dh_top; 4487 return (err); 4488 } 4489 4490 tabptr->zone_rctl_valptr = NULL; 4491 for (val = cur->xmlChildrenNode; val != NULL; val = val->next) { 4492 valptr = (struct zone_rctlvaltab *)malloc( 4493 sizeof (struct zone_rctlvaltab)); 4494 if (valptr == NULL) 4495 return (Z_NOMEM); 4496 if (fetchprop(val, DTD_ATTR_PRIV, valptr->zone_rctlval_priv, 4497 sizeof (valptr->zone_rctlval_priv)) != Z_OK) 4498 break; 4499 if (fetchprop(val, DTD_ATTR_LIMIT, valptr->zone_rctlval_limit, 4500 sizeof (valptr->zone_rctlval_limit)) != Z_OK) 4501 break; 4502 if (fetchprop(val, DTD_ATTR_ACTION, valptr->zone_rctlval_action, 4503 sizeof (valptr->zone_rctlval_action)) != Z_OK) 4504 break; 4505 if (zonecfg_add_rctl_value(tabptr, valptr) != Z_OK) 4506 break; 4507 } 4508 4509 handle->zone_dh_cur = cur->next; 4510 return (Z_OK); 4511 } 4512 4513 int 4514 zonecfg_endrctlent(zone_dochandle_t handle) 4515 { 4516 return (zonecfg_endent(handle)); 4517 } 4518 4519 int 4520 zonecfg_setattrent(zone_dochandle_t handle) 4521 { 4522 return (zonecfg_setent(handle)); 4523 } 4524 4525 int 4526 zonecfg_getattrent(zone_dochandle_t handle, struct zone_attrtab *tabptr) 4527 { 4528 xmlNodePtr cur; 4529 int err; 4530 4531 if (handle == NULL) 4532 return (Z_INVAL); 4533 4534 if ((cur = handle->zone_dh_cur) == NULL) 4535 return (Z_NO_ENTRY); 4536 4537 for (; cur != NULL; cur = cur->next) 4538 if (!xmlStrcmp(cur->name, DTD_ELEM_ATTR)) 4539 break; 4540 if (cur == NULL) { 4541 handle->zone_dh_cur = handle->zone_dh_top; 4542 return (Z_NO_ENTRY); 4543 } 4544 4545 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name, 4546 sizeof (tabptr->zone_attr_name))) != Z_OK) { 4547 handle->zone_dh_cur = handle->zone_dh_top; 4548 return (err); 4549 } 4550 4551 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type, 4552 sizeof (tabptr->zone_attr_type))) != Z_OK) { 4553 handle->zone_dh_cur = handle->zone_dh_top; 4554 return (err); 4555 } 4556 4557 if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value, 4558 sizeof (tabptr->zone_attr_value))) != Z_OK) { 4559 handle->zone_dh_cur = handle->zone_dh_top; 4560 return (err); 4561 } 4562 4563 handle->zone_dh_cur = cur->next; 4564 return (Z_OK); 4565 } 4566 4567 int 4568 zonecfg_endattrent(zone_dochandle_t handle) 4569 { 4570 return (zonecfg_endent(handle)); 4571 } 4572 4573 /* 4574 * The privileges available on the system and described in privileges(5) 4575 * fall into four categories with respect to non-global zones: 4576 * 4577 * Default set of privileges considered safe for all non-global 4578 * zones. These privileges are "safe" in the sense that a 4579 * privileged process in the zone cannot affect processes in any 4580 * other zone on the system. 4581 * 4582 * Set of privileges not currently permitted within a non-global 4583 * zone. These privileges are considered by default, "unsafe," 4584 * and include ones which affect global resources (such as the 4585 * system clock or physical memory) or are overly broad and cover 4586 * more than one mechanism in the system. In other cases, there 4587 * has not been sufficient virtualization in the parts of the 4588 * system the privilege covers to allow its use within a 4589 * non-global zone. 4590 * 4591 * Set of privileges required in order to get a zone booted and 4592 * init(1M) started. These cannot be removed from the zone's 4593 * privilege set. 4594 * 4595 * All other privileges are optional and are potentially useful for 4596 * processes executing inside a non-global zone. 4597 * 4598 * When privileges are added to the system, a determination needs to be 4599 * made as to which category the privilege belongs to. Ideally, 4600 * privileges should be fine-grained enough and the mechanisms they cover 4601 * virtualized enough so that they can be made available to non-global 4602 * zones. 4603 */ 4604 4605 /* 4606 * Define some of the tokens that priv_str_to_set(3C) recognizes. Since 4607 * the privilege string separator can be any character, although it is 4608 * usually a comma character, define these here as well in the event that 4609 * they change or are augmented in the future. 4610 */ 4611 #define BASIC_TOKEN "basic" 4612 #define DEFAULT_TOKEN "default" 4613 #define ZONE_TOKEN "zone" 4614 #define TOKEN_PRIV_CHAR ',' 4615 #define TOKEN_PRIV_STR "," 4616 4617 typedef struct priv_node { 4618 struct priv_node *pn_next; /* Next privilege */ 4619 char *pn_priv; /* Privileges name */ 4620 } priv_node_t; 4621 4622 /* Privileges lists can differ across brands */ 4623 typedef struct priv_lists { 4624 /* Privileges considered safe for all non-global zones of a brand */ 4625 struct priv_node *pl_default; 4626 4627 /* Privileges not permitted for all non-global zones of a brand */ 4628 struct priv_node *pl_prohibited; 4629 4630 /* Privileges required for all non-global zones of a brand */ 4631 struct priv_node *pl_required; 4632 4633 /* 4634 * ip-type of the zone these privileges lists apply to. 4635 * It is used to pass ip-type to the callback function, 4636 * priv_lists_cb, which has no way of getting the ip-type. 4637 */ 4638 const char *pl_iptype; 4639 } priv_lists_t; 4640 4641 static int 4642 priv_lists_cb(void *data, priv_iter_t *priv_iter) 4643 { 4644 priv_lists_t *plp = (priv_lists_t *)data; 4645 priv_node_t *pnp; 4646 4647 /* Skip this privilege if ip-type does not match */ 4648 if ((strcmp(priv_iter->pi_iptype, "all") != 0) && 4649 (strcmp(priv_iter->pi_iptype, plp->pl_iptype) != 0)) 4650 return (0); 4651 4652 /* Allocate a new priv list node. */ 4653 if ((pnp = malloc(sizeof (*pnp))) == NULL) 4654 return (-1); 4655 if ((pnp->pn_priv = strdup(priv_iter->pi_name)) == NULL) { 4656 free(pnp); 4657 return (-1); 4658 } 4659 4660 /* Insert the new priv list node into the right list */ 4661 if (strcmp(priv_iter->pi_set, "default") == 0) { 4662 pnp->pn_next = plp->pl_default; 4663 plp->pl_default = pnp; 4664 } else if (strcmp(priv_iter->pi_set, "prohibited") == 0) { 4665 pnp->pn_next = plp->pl_prohibited; 4666 plp->pl_prohibited = pnp; 4667 } else if (strcmp(priv_iter->pi_set, "required") == 0) { 4668 pnp->pn_next = plp->pl_required; 4669 plp->pl_required = pnp; 4670 } else { 4671 free(pnp->pn_priv); 4672 free(pnp); 4673 return (-1); 4674 } 4675 return (0); 4676 } 4677 4678 static void 4679 priv_lists_destroy(priv_lists_t *plp) 4680 { 4681 priv_node_t *pnp; 4682 4683 assert(plp != NULL); 4684 4685 while ((pnp = plp->pl_default) != NULL) { 4686 plp->pl_default = pnp->pn_next; 4687 free(pnp->pn_priv); 4688 free(pnp); 4689 } 4690 while ((pnp = plp->pl_prohibited) != NULL) { 4691 plp->pl_prohibited = pnp->pn_next; 4692 free(pnp->pn_priv); 4693 free(pnp); 4694 } 4695 while ((pnp = plp->pl_required) != NULL) { 4696 plp->pl_required = pnp->pn_next; 4697 free(pnp->pn_priv); 4698 free(pnp); 4699 } 4700 free(plp); 4701 } 4702 4703 static int 4704 priv_lists_create(zone_dochandle_t handle, priv_lists_t **plpp, 4705 const char *curr_iptype) 4706 { 4707 priv_lists_t *plp; 4708 brand_handle_t bh; 4709 char brand[MAXNAMELEN]; 4710 4711 if (handle != NULL) { 4712 if (zonecfg_get_brand(handle, brand, sizeof (brand)) != 0) 4713 return (Z_BRAND_ERROR); 4714 } else { 4715 (void) strlcpy(brand, NATIVE_BRAND_NAME, MAXNAMELEN); 4716 } 4717 4718 if ((bh = brand_open(brand)) == NULL) 4719 return (Z_BRAND_ERROR); 4720 4721 if ((plp = calloc(1, sizeof (priv_lists_t))) == NULL) { 4722 brand_close(bh); 4723 return (Z_NOMEM); 4724 } 4725 4726 plp->pl_iptype = curr_iptype; 4727 4728 /* construct the privilege lists */ 4729 if (brand_config_iter_privilege(bh, priv_lists_cb, plp) != 0) { 4730 priv_lists_destroy(plp); 4731 brand_close(bh); 4732 return (Z_BRAND_ERROR); 4733 } 4734 4735 brand_close(bh); 4736 *plpp = plp; 4737 return (Z_OK); 4738 } 4739 4740 static int 4741 get_default_privset(priv_set_t *privs, priv_lists_t *plp) 4742 { 4743 priv_node_t *pnp; 4744 priv_set_t *basic; 4745 4746 basic = priv_str_to_set(BASIC_TOKEN, TOKEN_PRIV_STR, NULL); 4747 if (basic == NULL) 4748 return (errno == ENOMEM ? Z_NOMEM : Z_INVAL); 4749 4750 priv_union(basic, privs); 4751 priv_freeset(basic); 4752 4753 for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next) { 4754 if (priv_addset(privs, pnp->pn_priv) != 0) 4755 return (Z_INVAL); 4756 } 4757 4758 return (Z_OK); 4759 } 4760 4761 int 4762 zonecfg_default_privset(priv_set_t *privs, const char *curr_iptype) 4763 { 4764 priv_lists_t *plp; 4765 int ret; 4766 4767 if ((ret = priv_lists_create(NULL, &plp, curr_iptype)) != Z_OK) 4768 return (ret); 4769 ret = get_default_privset(privs, plp); 4770 priv_lists_destroy(plp); 4771 return (ret); 4772 } 4773 4774 void 4775 append_priv_token(char *priv, char *str, size_t strlen) 4776 { 4777 if (*str != '\0') 4778 (void) strlcat(str, TOKEN_PRIV_STR, strlen); 4779 (void) strlcat(str, priv, strlen); 4780 } 4781 4782 /* 4783 * Verify that the supplied string is a valid privilege limit set for a 4784 * non-global zone. This string must not only be acceptable to 4785 * priv_str_to_set(3C) which parses it, but it also must resolve to a 4786 * privilege set that includes certain required privileges and lacks 4787 * certain prohibited privileges. 4788 */ 4789 static int 4790 verify_privset(char *privbuf, priv_set_t *privs, char **privname, 4791 boolean_t add_default, priv_lists_t *plp) 4792 { 4793 priv_node_t *pnp; 4794 char *tmp, *cp, *lasts; 4795 size_t len; 4796 priv_set_t *mergeset; 4797 const char *token; 4798 4799 /* 4800 * The verification of the privilege string occurs in several 4801 * phases. In the first phase, the supplied string is scanned for 4802 * the ZONE_TOKEN token which is not support as part of the 4803 * "limitpriv" property. 4804 * 4805 * Duplicate the supplied privilege string since strtok_r(3C) 4806 * tokenizes its input by null-terminating the tokens. 4807 */ 4808 if ((tmp = strdup(privbuf)) == NULL) 4809 return (Z_NOMEM); 4810 for (cp = strtok_r(tmp, TOKEN_PRIV_STR, &lasts); cp != NULL; 4811 cp = strtok_r(NULL, TOKEN_PRIV_STR, &lasts)) { 4812 if (strcmp(cp, ZONE_TOKEN) == 0) { 4813 free(tmp); 4814 if ((*privname = strdup(ZONE_TOKEN)) == NULL) 4815 return (Z_NOMEM); 4816 else 4817 return (Z_PRIV_UNKNOWN); 4818 } 4819 } 4820 free(tmp); 4821 4822 if (add_default) { 4823 /* 4824 * If DEFAULT_TOKEN was specified, a string needs to be 4825 * built containing the privileges from the default, safe 4826 * set along with those of the "limitpriv" property. 4827 */ 4828 len = strlen(privbuf) + sizeof (BASIC_TOKEN) + 2; 4829 4830 for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next) 4831 len += strlen(pnp->pn_priv) + 1; 4832 tmp = alloca(len); 4833 *tmp = '\0'; 4834 4835 append_priv_token(BASIC_TOKEN, tmp, len); 4836 for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next) 4837 append_priv_token(pnp->pn_priv, tmp, len); 4838 (void) strlcat(tmp, TOKEN_PRIV_STR, len); 4839 (void) strlcat(tmp, privbuf, len); 4840 } else { 4841 tmp = privbuf; 4842 } 4843 4844 4845 /* 4846 * In the next phase, attempt to convert the merged privilege 4847 * string into a privilege set. In the case of an error, either 4848 * there was a memory allocation failure or there was an invalid 4849 * privilege token in the string. In either case, return an 4850 * appropriate error code but in the event of an invalid token, 4851 * allocate a string containing its name and return that back to 4852 * the caller. 4853 */ 4854 mergeset = priv_str_to_set(tmp, TOKEN_PRIV_STR, &token); 4855 if (mergeset == NULL) { 4856 if (token == NULL) 4857 return (Z_NOMEM); 4858 if ((cp = strchr(token, TOKEN_PRIV_CHAR)) != NULL) 4859 *cp = '\0'; 4860 if ((*privname = strdup(token)) == NULL) 4861 return (Z_NOMEM); 4862 else 4863 return (Z_PRIV_UNKNOWN); 4864 } 4865 4866 /* 4867 * Next, verify that none of the prohibited zone privileges are 4868 * present in the merged privilege set. 4869 */ 4870 for (pnp = plp->pl_prohibited; pnp != NULL; pnp = pnp->pn_next) { 4871 if (priv_ismember(mergeset, pnp->pn_priv)) { 4872 priv_freeset(mergeset); 4873 if ((*privname = strdup(pnp->pn_priv)) == NULL) 4874 return (Z_NOMEM); 4875 else 4876 return (Z_PRIV_PROHIBITED); 4877 } 4878 } 4879 4880 /* 4881 * Finally, verify that all of the required zone privileges are 4882 * present in the merged privilege set. 4883 */ 4884 for (pnp = plp->pl_required; pnp != NULL; pnp = pnp->pn_next) { 4885 if (!priv_ismember(mergeset, pnp->pn_priv)) { 4886 priv_freeset(mergeset); 4887 if ((*privname = strdup(pnp->pn_priv)) == NULL) 4888 return (Z_NOMEM); 4889 else 4890 return (Z_PRIV_REQUIRED); 4891 } 4892 } 4893 4894 priv_copyset(mergeset, privs); 4895 priv_freeset(mergeset); 4896 return (Z_OK); 4897 } 4898 4899 /* 4900 * Fill in the supplied privilege set with either the default, safe set of 4901 * privileges suitable for a non-global zone, or one based on the 4902 * "limitpriv" property in the zone's configuration. 4903 * 4904 * In the event of an invalid privilege specification in the 4905 * configuration, a string is allocated and returned containing the 4906 * "privilege" causing the issue. It is the caller's responsibility to 4907 * free this memory when it is done with it. 4908 */ 4909 int 4910 zonecfg_get_privset(zone_dochandle_t handle, priv_set_t *privs, 4911 char **privname) 4912 { 4913 priv_lists_t *plp; 4914 char *cp, *limitpriv = NULL; 4915 int err, limitlen; 4916 zone_iptype_t iptype; 4917 const char *curr_iptype; 4918 4919 /* 4920 * Attempt to lookup the "limitpriv" property. If it does not 4921 * exist or matches the string DEFAULT_TOKEN exactly, then the 4922 * default, safe privilege set is returned. 4923 */ 4924 if ((err = zonecfg_get_limitpriv(handle, &limitpriv)) != Z_OK) 4925 return (err); 4926 4927 if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK) 4928 return (err); 4929 4930 switch (iptype) { 4931 case ZS_SHARED: 4932 curr_iptype = "shared"; 4933 break; 4934 case ZS_EXCLUSIVE: 4935 curr_iptype = "exclusive"; 4936 break; 4937 } 4938 4939 if ((err = priv_lists_create(handle, &plp, curr_iptype)) != Z_OK) 4940 return (err); 4941 4942 limitlen = strlen(limitpriv); 4943 if (limitlen == 0 || strcmp(limitpriv, DEFAULT_TOKEN) == 0) { 4944 free(limitpriv); 4945 err = get_default_privset(privs, plp); 4946 priv_lists_destroy(plp); 4947 return (err); 4948 } 4949 4950 /* 4951 * Check if the string DEFAULT_TOKEN is the first token in a list 4952 * of privileges. 4953 */ 4954 cp = strchr(limitpriv, TOKEN_PRIV_CHAR); 4955 if (cp != NULL && 4956 strncmp(limitpriv, DEFAULT_TOKEN, cp - limitpriv) == 0) 4957 err = verify_privset(cp + 1, privs, privname, B_TRUE, plp); 4958 else 4959 err = verify_privset(limitpriv, privs, privname, B_FALSE, plp); 4960 4961 free(limitpriv); 4962 priv_lists_destroy(plp); 4963 return (err); 4964 } 4965 4966 int 4967 zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz) 4968 { 4969 zone_dochandle_t handle; 4970 boolean_t found = B_FALSE; 4971 struct zoneent *ze; 4972 FILE *cookie; 4973 int err; 4974 char *cp; 4975 4976 if (zone_name == NULL) 4977 return (Z_INVAL); 4978 4979 (void) strlcpy(zonepath, zonecfg_root, rp_sz); 4980 cp = zonepath + strlen(zonepath); 4981 while (cp > zonepath && cp[-1] == '/') 4982 *--cp = '\0'; 4983 4984 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) { 4985 if (zonepath[0] == '\0') 4986 (void) strlcpy(zonepath, "/", rp_sz); 4987 return (Z_OK); 4988 } 4989 4990 /* 4991 * First check the index file. Because older versions did not have 4992 * a copy of the zone path, allow for it to be zero length, in which 4993 * case we ignore this result and fall back to the XML files. 4994 */ 4995 cookie = setzoneent(); 4996 while ((ze = getzoneent_private(cookie)) != NULL) { 4997 if (strcmp(ze->zone_name, zone_name) == 0) { 4998 found = B_TRUE; 4999 if (ze->zone_path[0] != '\0') 5000 (void) strlcpy(cp, ze->zone_path, 5001 rp_sz - (cp - zonepath)); 5002 } 5003 free(ze); 5004 if (found) 5005 break; 5006 } 5007 endzoneent(cookie); 5008 if (found && *cp != '\0') 5009 return (Z_OK); 5010 5011 /* Fall back to the XML files. */ 5012 if ((handle = zonecfg_init_handle()) == NULL) 5013 return (Z_NOMEM); 5014 5015 /* 5016 * Check the snapshot first: if a zone is running, its zonepath 5017 * may have changed. 5018 */ 5019 if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) { 5020 if ((err = zonecfg_get_handle(zone_name, handle)) != Z_OK) { 5021 zonecfg_fini_handle(handle); 5022 return (err); 5023 } 5024 } 5025 err = zonecfg_get_zonepath(handle, zonepath, rp_sz); 5026 zonecfg_fini_handle(handle); 5027 return (err); 5028 } 5029 5030 int 5031 zone_get_rootpath(char *zone_name, char *rootpath, size_t rp_sz) 5032 { 5033 int err; 5034 5035 /* This function makes sense for non-global zones only. */ 5036 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) 5037 return (Z_BOGUS_ZONE_NAME); 5038 if ((err = zone_get_zonepath(zone_name, rootpath, rp_sz)) != Z_OK) 5039 return (err); 5040 if (strlcat(rootpath, "/root", rp_sz) >= rp_sz) 5041 return (Z_TOO_BIG); 5042 return (Z_OK); 5043 } 5044 5045 int 5046 zone_get_brand(char *zone_name, char *brandname, size_t rp_sz) 5047 { 5048 int err; 5049 zone_dochandle_t handle; 5050 char myzone[MAXNAMELEN]; 5051 int myzoneid = getzoneid(); 5052 5053 /* 5054 * If we are not in the global zone, then we don't have the zone 5055 * .xml files with the brand name available. Thus, we are going to 5056 * have to ask the kernel for the information. 5057 */ 5058 if (myzoneid != GLOBAL_ZONEID) { 5059 if (is_system_labeled()) { 5060 (void) strlcpy(brandname, NATIVE_BRAND_NAME, rp_sz); 5061 return (Z_OK); 5062 } 5063 if (zone_getattr(myzoneid, ZONE_ATTR_NAME, myzone, 5064 sizeof (myzone)) < 0) 5065 return (Z_NO_ZONE); 5066 if (strncmp(zone_name, myzone, MAXNAMELEN) != NULL) 5067 return (Z_NO_ZONE); 5068 err = zone_getattr(myzoneid, ZONE_ATTR_BRAND, brandname, rp_sz); 5069 if (err < 0) 5070 return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL); 5071 return (Z_OK); 5072 } 5073 5074 if (strcmp(zone_name, "global") == NULL) { 5075 (void) strlcpy(brandname, NATIVE_BRAND_NAME, rp_sz); 5076 return (Z_OK); 5077 } 5078 if ((handle = zonecfg_init_handle()) == NULL) 5079 return (Z_NOMEM); 5080 5081 err = zonecfg_get_handle((char *)zone_name, handle); 5082 if (err == Z_OK) 5083 err = zonecfg_get_brand(handle, brandname, rp_sz); 5084 5085 zonecfg_fini_handle(handle); 5086 return (err); 5087 } 5088 5089 /* 5090 * Return the appropriate root for the active /dev. 5091 * For normal zone, the path is $ZONEPATH/root; 5092 * for scratch zone, the dev path is $ZONEPATH/lu. 5093 */ 5094 int 5095 zone_get_devroot(char *zone_name, char *devroot, size_t rp_sz) 5096 { 5097 int err; 5098 char *suffix; 5099 zone_state_t state; 5100 5101 /* This function makes sense for non-global zones only. */ 5102 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) 5103 return (Z_BOGUS_ZONE_NAME); 5104 if ((err = zone_get_zonepath(zone_name, devroot, rp_sz)) != Z_OK) 5105 return (err); 5106 5107 if (zone_get_state(zone_name, &state) == Z_OK && 5108 state == ZONE_STATE_MOUNTED) 5109 suffix = "/lu"; 5110 else 5111 suffix = "/root"; 5112 if (strlcat(devroot, suffix, rp_sz) >= rp_sz) 5113 return (Z_TOO_BIG); 5114 return (Z_OK); 5115 } 5116 5117 static zone_state_t 5118 kernel_state_to_user_state(zoneid_t zoneid, zone_status_t kernel_state) 5119 { 5120 char zoneroot[MAXPATHLEN]; 5121 size_t zlen; 5122 5123 assert(kernel_state <= ZONE_MAX_STATE); 5124 switch (kernel_state) { 5125 case ZONE_IS_UNINITIALIZED: 5126 case ZONE_IS_INITIALIZED: 5127 /* The kernel will not return these two states */ 5128 return (ZONE_STATE_READY); 5129 case ZONE_IS_READY: 5130 /* 5131 * If the zone's root is mounted on $ZONEPATH/lu, then 5132 * it's a mounted scratch zone. 5133 */ 5134 if (zone_getattr(zoneid, ZONE_ATTR_ROOT, zoneroot, 5135 sizeof (zoneroot)) >= 0) { 5136 zlen = strlen(zoneroot); 5137 if (zlen > 3 && 5138 strcmp(zoneroot + zlen - 3, "/lu") == 0) 5139 return (ZONE_STATE_MOUNTED); 5140 } 5141 return (ZONE_STATE_READY); 5142 case ZONE_IS_BOOTING: 5143 case ZONE_IS_RUNNING: 5144 return (ZONE_STATE_RUNNING); 5145 case ZONE_IS_SHUTTING_DOWN: 5146 case ZONE_IS_EMPTY: 5147 return (ZONE_STATE_SHUTTING_DOWN); 5148 case ZONE_IS_DOWN: 5149 case ZONE_IS_DYING: 5150 case ZONE_IS_DEAD: 5151 default: 5152 return (ZONE_STATE_DOWN); 5153 } 5154 /* NOTREACHED */ 5155 } 5156 5157 int 5158 zone_get_state(char *zone_name, zone_state_t *state_num) 5159 { 5160 zone_status_t status; 5161 zoneid_t zone_id; 5162 struct zoneent *ze; 5163 boolean_t found = B_FALSE; 5164 FILE *cookie; 5165 char kernzone[ZONENAME_MAX]; 5166 FILE *fp; 5167 5168 if (zone_name == NULL) 5169 return (Z_INVAL); 5170 5171 /* 5172 * If we're looking at an alternate root, then we need to query the 5173 * kernel using the scratch zone name. 5174 */ 5175 zone_id = -1; 5176 if (*zonecfg_root != '\0' && !zonecfg_is_scratch(zone_name)) { 5177 if ((fp = zonecfg_open_scratch("", B_FALSE)) != NULL) { 5178 if (zonecfg_find_scratch(fp, zone_name, zonecfg_root, 5179 kernzone, sizeof (kernzone)) == 0) 5180 zone_id = getzoneidbyname(kernzone); 5181 zonecfg_close_scratch(fp); 5182 } 5183 } else { 5184 zone_id = getzoneidbyname(zone_name); 5185 } 5186 5187 /* check to see if zone is running */ 5188 if (zone_id != -1 && 5189 zone_getattr(zone_id, ZONE_ATTR_STATUS, &status, 5190 sizeof (status)) >= 0) { 5191 *state_num = kernel_state_to_user_state(zone_id, status); 5192 return (Z_OK); 5193 } 5194 5195 cookie = setzoneent(); 5196 while ((ze = getzoneent_private(cookie)) != NULL) { 5197 if (strcmp(ze->zone_name, zone_name) == 0) { 5198 found = B_TRUE; 5199 *state_num = ze->zone_state; 5200 } 5201 free(ze); 5202 if (found) 5203 break; 5204 } 5205 endzoneent(cookie); 5206 return ((found) ? Z_OK : Z_NO_ZONE); 5207 } 5208 5209 int 5210 zone_set_state(char *zone, zone_state_t state) 5211 { 5212 struct zoneent ze; 5213 5214 if (state != ZONE_STATE_CONFIGURED && state != ZONE_STATE_INSTALLED && 5215 state != ZONE_STATE_INCOMPLETE) 5216 return (Z_INVAL); 5217 5218 bzero(&ze, sizeof (ze)); 5219 (void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name)); 5220 ze.zone_state = state; 5221 (void) strlcpy(ze.zone_path, "", sizeof (ze.zone_path)); 5222 return (putzoneent(&ze, PZE_MODIFY)); 5223 } 5224 5225 /* 5226 * Get id (if any) for specified zone. There are four possible outcomes: 5227 * - If the string corresponds to the numeric id of an active (booted) 5228 * zone, sets *zip to the zone id and returns 0. 5229 * - If the string corresponds to the name of an active (booted) zone, 5230 * sets *zip to the zone id and returns 0. 5231 * - If the string is a name in the configuration but is not booted, 5232 * sets *zip to ZONE_ID_UNDEFINED and returns 0. 5233 * - Otherwise, leaves *zip unchanged and returns -1. 5234 * 5235 * This function acts as an auxiliary filter on the function of the same 5236 * name in libc; the linker binds to this version if libzonecfg exists, 5237 * and the libc version if it doesn't. Any changes to this version of 5238 * the function should probably be reflected in the libc version as well. 5239 */ 5240 int 5241 zone_get_id(const char *str, zoneid_t *zip) 5242 { 5243 zone_dochandle_t hdl; 5244 zoneid_t zoneid; 5245 char *cp; 5246 int err; 5247 5248 /* first try looking for active zone by id */ 5249 errno = 0; 5250 zoneid = (zoneid_t)strtol(str, &cp, 0); 5251 if (errno == 0 && cp != str && *cp == '\0' && 5252 getzonenamebyid(zoneid, NULL, 0) != -1) { 5253 *zip = zoneid; 5254 return (0); 5255 } 5256 5257 /* then look for active zone by name */ 5258 if ((zoneid = getzoneidbyname(str)) != -1) { 5259 *zip = zoneid; 5260 return (0); 5261 } 5262 5263 /* if in global zone, try looking up name in configuration database */ 5264 if (getzoneid() != GLOBAL_ZONEID || 5265 (hdl = zonecfg_init_handle()) == NULL) 5266 return (-1); 5267 5268 if (zonecfg_get_handle(str, hdl) == Z_OK) { 5269 /* zone exists but isn't active */ 5270 *zip = ZONE_ID_UNDEFINED; 5271 err = 0; 5272 } else { 5273 err = -1; 5274 } 5275 5276 zonecfg_fini_handle(hdl); 5277 return (err); 5278 } 5279 5280 char * 5281 zone_state_str(zone_state_t state_num) 5282 { 5283 switch (state_num) { 5284 case ZONE_STATE_CONFIGURED: 5285 return (ZONE_STATE_STR_CONFIGURED); 5286 case ZONE_STATE_INCOMPLETE: 5287 return (ZONE_STATE_STR_INCOMPLETE); 5288 case ZONE_STATE_INSTALLED: 5289 return (ZONE_STATE_STR_INSTALLED); 5290 case ZONE_STATE_READY: 5291 return (ZONE_STATE_STR_READY); 5292 case ZONE_STATE_MOUNTED: 5293 return (ZONE_STATE_STR_MOUNTED); 5294 case ZONE_STATE_RUNNING: 5295 return (ZONE_STATE_STR_RUNNING); 5296 case ZONE_STATE_SHUTTING_DOWN: 5297 return (ZONE_STATE_STR_SHUTTING_DOWN); 5298 case ZONE_STATE_DOWN: 5299 return (ZONE_STATE_STR_DOWN); 5300 default: 5301 return ("unknown"); 5302 } 5303 } 5304 5305 /* 5306 * Given a UUID value, find an associated zone name. This is intended to be 5307 * used by callers who set up some 'default' name (corresponding to the 5308 * expected name for the zone) in the zonename buffer, and thus the function 5309 * doesn't touch this buffer on failure. 5310 */ 5311 int 5312 zonecfg_get_name_by_uuid(const uuid_t uuidin, char *zonename, size_t namelen) 5313 { 5314 FILE *fp; 5315 struct zoneent *ze; 5316 uchar_t *uuid; 5317 5318 /* 5319 * A small amount of subterfuge via casts is necessary here because 5320 * libuuid doesn't use const correctly, but we don't want to export 5321 * this brokenness to our clients. 5322 */ 5323 uuid = (uchar_t *)uuidin; 5324 if (uuid_is_null(uuid)) 5325 return (Z_NO_ZONE); 5326 if ((fp = setzoneent()) == NULL) 5327 return (Z_NO_ZONE); 5328 while ((ze = getzoneent_private(fp)) != NULL) { 5329 if (uuid_compare(uuid, ze->zone_uuid) == 0) 5330 break; 5331 free(ze); 5332 } 5333 endzoneent(fp); 5334 if (ze != NULL) { 5335 (void) strlcpy(zonename, ze->zone_name, namelen); 5336 free(ze); 5337 return (Z_OK); 5338 } else { 5339 return (Z_NO_ZONE); 5340 } 5341 } 5342 5343 /* 5344 * Given a zone name, get its UUID. Returns a "NULL" UUID value if the zone 5345 * exists but the file doesn't have a value set yet. Returns an error if the 5346 * zone cannot be located. 5347 */ 5348 int 5349 zonecfg_get_uuid(const char *zonename, uuid_t uuid) 5350 { 5351 FILE *fp; 5352 struct zoneent *ze; 5353 5354 if ((fp = setzoneent()) == NULL) 5355 return (Z_NO_ZONE); 5356 while ((ze = getzoneent_private(fp)) != NULL) { 5357 if (strcmp(ze->zone_name, zonename) == 0) 5358 break; 5359 free(ze); 5360 } 5361 endzoneent(fp); 5362 if (ze != NULL) { 5363 uuid_copy(uuid, ze->zone_uuid); 5364 free(ze); 5365 return (Z_OK); 5366 } else { 5367 return (Z_NO_ZONE); 5368 } 5369 } 5370 5371 /* 5372 * File-system convenience functions. 5373 */ 5374 boolean_t 5375 zonecfg_valid_fs_type(const char *type) 5376 { 5377 /* 5378 * We already know which FS types don't work. 5379 */ 5380 if (strcmp(type, "proc") == 0 || 5381 strcmp(type, "mntfs") == 0 || 5382 strcmp(type, "autofs") == 0 || 5383 strncmp(type, "nfs", sizeof ("nfs") - 1) == 0 || 5384 strcmp(type, "cachefs") == 0) 5385 return (B_FALSE); 5386 /* 5387 * The caller may do more detailed verification to make sure other 5388 * aspects of this filesystem type make sense. 5389 */ 5390 return (B_TRUE); 5391 } 5392 5393 /* 5394 * Generally uninteresting rctl convenience functions. 5395 */ 5396 5397 int 5398 zonecfg_construct_rctlblk(const struct zone_rctlvaltab *rctlval, 5399 rctlblk_t *rctlblk) 5400 { 5401 unsigned long long ull; 5402 char *endp; 5403 rctl_priv_t priv; 5404 rctl_qty_t limit; 5405 uint_t action; 5406 5407 /* Get the privilege */ 5408 if (strcmp(rctlval->zone_rctlval_priv, "basic") == 0) { 5409 priv = RCPRIV_BASIC; 5410 } else if (strcmp(rctlval->zone_rctlval_priv, "privileged") == 0) { 5411 priv = RCPRIV_PRIVILEGED; 5412 } else { 5413 /* Invalid privilege */ 5414 return (Z_INVAL); 5415 } 5416 5417 /* deal with negative input; strtoull(3c) doesn't do what we want */ 5418 if (rctlval->zone_rctlval_limit[0] == '-') 5419 return (Z_INVAL); 5420 /* Get the limit */ 5421 errno = 0; 5422 ull = strtoull(rctlval->zone_rctlval_limit, &endp, 0); 5423 if (errno != 0 || *endp != '\0') { 5424 /* parse failed */ 5425 return (Z_INVAL); 5426 } 5427 limit = (rctl_qty_t)ull; 5428 5429 /* Get the action */ 5430 if (strcmp(rctlval->zone_rctlval_action, "none") == 0) { 5431 action = RCTL_LOCAL_NOACTION; 5432 } else if (strcmp(rctlval->zone_rctlval_action, "signal") == 0) { 5433 action = RCTL_LOCAL_SIGNAL; 5434 } else if (strcmp(rctlval->zone_rctlval_action, "deny") == 0) { 5435 action = RCTL_LOCAL_DENY; 5436 } else { 5437 /* Invalid Action */ 5438 return (Z_INVAL); 5439 } 5440 rctlblk_set_local_action(rctlblk, action, 0); 5441 rctlblk_set_privilege(rctlblk, priv); 5442 rctlblk_set_value(rctlblk, limit); 5443 return (Z_OK); 5444 } 5445 5446 static int 5447 rctl_check(const char *rctlname, void *arg) 5448 { 5449 const char *attrname = arg; 5450 5451 /* 5452 * Returning 1 here is our signal to zonecfg_is_rctl() that it is 5453 * indeed an rctl name recognized by the system. 5454 */ 5455 return (strcmp(rctlname, attrname) == 0 ? 1 : 0); 5456 } 5457 5458 boolean_t 5459 zonecfg_is_rctl(const char *name) 5460 { 5461 return (rctl_walk(rctl_check, (void *)name) == 1); 5462 } 5463 5464 boolean_t 5465 zonecfg_valid_rctlname(const char *name) 5466 { 5467 const char *c; 5468 5469 if (strncmp(name, "zone.", sizeof ("zone.") - 1) != 0) 5470 return (B_FALSE); 5471 if (strlen(name) == sizeof ("zone.") - 1) 5472 return (B_FALSE); 5473 for (c = name + sizeof ("zone.") - 1; *c != '\0'; c++) { 5474 if (!isalpha(*c) && *c != '-') 5475 return (B_FALSE); 5476 } 5477 return (B_TRUE); 5478 } 5479 5480 boolean_t 5481 zonecfg_valid_rctlblk(const rctlblk_t *rctlblk) 5482 { 5483 rctl_priv_t priv = rctlblk_get_privilege((rctlblk_t *)rctlblk); 5484 uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL); 5485 5486 if (priv != RCPRIV_PRIVILEGED) 5487 return (B_FALSE); 5488 if (action != RCTL_LOCAL_NOACTION && action != RCTL_LOCAL_DENY) 5489 return (B_FALSE); 5490 return (B_TRUE); 5491 } 5492 5493 boolean_t 5494 zonecfg_valid_rctl(const char *name, const rctlblk_t *rctlblk) 5495 { 5496 rctlblk_t *current, *next; 5497 rctl_qty_t limit = rctlblk_get_value((rctlblk_t *)rctlblk); 5498 uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL); 5499 uint_t global_flags; 5500 5501 if (!zonecfg_valid_rctlblk(rctlblk)) 5502 return (B_FALSE); 5503 if (!zonecfg_valid_rctlname(name)) 5504 return (B_FALSE); 5505 5506 current = alloca(rctlblk_size()); 5507 if (getrctl(name, NULL, current, RCTL_FIRST) != 0) 5508 return (B_TRUE); /* not an rctl on this system */ 5509 /* 5510 * Make sure the proposed value isn't greater than the current system 5511 * value. 5512 */ 5513 next = alloca(rctlblk_size()); 5514 while (rctlblk_get_privilege(current) != RCPRIV_SYSTEM) { 5515 rctlblk_t *tmp; 5516 5517 if (getrctl(name, current, next, RCTL_NEXT) != 0) 5518 return (B_FALSE); /* shouldn't happen */ 5519 tmp = current; 5520 current = next; 5521 next = tmp; 5522 } 5523 if (limit > rctlblk_get_value(current)) 5524 return (B_FALSE); 5525 5526 /* 5527 * Make sure the proposed action is allowed. 5528 */ 5529 global_flags = rctlblk_get_global_flags(current); 5530 if ((global_flags & RCTL_GLOBAL_DENY_NEVER) && 5531 action == RCTL_LOCAL_DENY) 5532 return (B_FALSE); 5533 if ((global_flags & RCTL_GLOBAL_DENY_ALWAYS) && 5534 action == RCTL_LOCAL_NOACTION) 5535 return (B_FALSE); 5536 5537 return (B_TRUE); 5538 } 5539 5540 /* 5541 * There is always a race condition between reading the initial copy of 5542 * a zones state and its state changing. We address this by providing 5543 * zonecfg_notify_critical_enter and zonecfg_noticy_critical_exit functions. 5544 * When zonecfg_critical_enter is called, sets the state field to LOCKED 5545 * and aquires biglock. Biglock protects against other threads executing 5546 * critical_enter and the state field protects against state changes during 5547 * the critical period. 5548 * 5549 * If any state changes occur, zn_cb will set the failed field of the znotify 5550 * structure. This will cause the critical_exit function to re-lock the 5551 * channel and return an error. Since evsnts may be delayed, the critical_exit 5552 * function "flushes" the queue by putting an event on the queue and waiting for 5553 * zn_cb to notify critical_exit that it received the ping event. 5554 */ 5555 static const char * 5556 string_get_tok(const char *in, char delim, int num) 5557 { 5558 int i = 0; 5559 5560 for (; i < num; in++) { 5561 if (*in == delim) 5562 i++; 5563 if (*in == 0) 5564 return (NULL); 5565 } 5566 return (in); 5567 } 5568 5569 static boolean_t 5570 is_ping(sysevent_t *ev) 5571 { 5572 if (strcmp(sysevent_get_subclass_name(ev), 5573 ZONE_EVENT_PING_SUBCLASS) == 0) { 5574 return (B_TRUE); 5575 } else { 5576 return (B_FALSE); 5577 } 5578 } 5579 5580 static boolean_t 5581 is_my_ping(sysevent_t *ev) 5582 { 5583 const char *sender; 5584 char mypid[sizeof (pid_t) * 3 + 1]; 5585 5586 (void) snprintf(mypid, sizeof (mypid), "%i", getpid()); 5587 sender = string_get_tok(sysevent_get_pub(ev), ':', 3); 5588 if (sender == NULL) 5589 return (B_FALSE); 5590 if (strcmp(sender, mypid) != 0) 5591 return (B_FALSE); 5592 return (B_TRUE); 5593 } 5594 5595 static int 5596 do_callback(struct znotify *zevtchan, sysevent_t *ev) 5597 { 5598 nvlist_t *l; 5599 int zid; 5600 char *zonename; 5601 char *newstate; 5602 char *oldstate; 5603 int ret; 5604 hrtime_t when; 5605 5606 if (strcmp(sysevent_get_subclass_name(ev), 5607 ZONE_EVENT_STATUS_SUBCLASS) == 0) { 5608 5609 if (sysevent_get_attr_list(ev, &l) != 0) { 5610 if (errno == ENOMEM) { 5611 zevtchan->zn_failure_count++; 5612 return (EAGAIN); 5613 } 5614 return (0); 5615 } 5616 ret = 0; 5617 5618 if ((nvlist_lookup_string(l, ZONE_CB_NAME, &zonename) == 0) && 5619 (nvlist_lookup_string(l, ZONE_CB_NEWSTATE, &newstate) 5620 == 0) && 5621 (nvlist_lookup_string(l, ZONE_CB_OLDSTATE, &oldstate) 5622 == 0) && 5623 (nvlist_lookup_uint64(l, ZONE_CB_TIMESTAMP, 5624 (uint64_t *)&when) == 0) && 5625 (nvlist_lookup_int32(l, ZONE_CB_ZONEID, &zid) == 0)) { 5626 ret = zevtchan->zn_callback(zonename, zid, newstate, 5627 oldstate, when, zevtchan->zn_private); 5628 } 5629 5630 zevtchan->zn_failure_count = 0; 5631 nvlist_free(l); 5632 return (ret); 5633 } else { 5634 /* 5635 * We have received an event in an unknown subclass. Ignore. 5636 */ 5637 zevtchan->zn_failure_count = 0; 5638 return (0); 5639 } 5640 } 5641 5642 static int 5643 zn_cb(sysevent_t *ev, void *p) 5644 { 5645 struct znotify *zevtchan = p; 5646 int error; 5647 5648 (void) pthread_mutex_lock(&(zevtchan->zn_mutex)); 5649 5650 if (is_ping(ev) && !is_my_ping(ev)) { 5651 (void) pthread_mutex_unlock((&zevtchan->zn_mutex)); 5652 return (0); 5653 } 5654 5655 if (zevtchan->zn_state == ZN_LOCKED) { 5656 assert(!is_ping(ev)); 5657 zevtchan->zn_failed = B_TRUE; 5658 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5659 return (0); 5660 } 5661 5662 if (zevtchan->zn_state == ZN_PING_INFLIGHT) { 5663 if (is_ping(ev)) { 5664 zevtchan->zn_state = ZN_PING_RECEIVED; 5665 (void) pthread_cond_signal(&(zevtchan->zn_cond)); 5666 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5667 return (0); 5668 } else { 5669 zevtchan->zn_failed = B_TRUE; 5670 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5671 return (0); 5672 } 5673 } 5674 5675 if (zevtchan->zn_state == ZN_UNLOCKED) { 5676 5677 error = do_callback(zevtchan, ev); 5678 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5679 /* 5680 * Every ENOMEM failure causes do_callback to increment 5681 * zn_failure_count and every success causes it to 5682 * set zn_failure_count to zero. If we got EAGAIN, 5683 * we will sleep for zn_failure_count seconds and return 5684 * EAGAIN to gpec to try again. 5685 * 5686 * After 55 seconds, or 10 try's we give up and drop the 5687 * event. 5688 */ 5689 if (error == EAGAIN) { 5690 if (zevtchan->zn_failure_count > ZONE_CB_RETRY_COUNT) { 5691 return (0); 5692 } 5693 (void) sleep(zevtchan->zn_failure_count); 5694 } 5695 return (error); 5696 } 5697 5698 if (zevtchan->zn_state == ZN_PING_RECEIVED) { 5699 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5700 return (0); 5701 } 5702 5703 abort(); 5704 return (0); 5705 } 5706 5707 void 5708 zonecfg_notify_critical_enter(void *h) 5709 { 5710 struct znotify *zevtchan = h; 5711 5712 (void) pthread_mutex_lock(&(zevtchan->zn_bigmutex)); 5713 zevtchan->zn_state = ZN_LOCKED; 5714 } 5715 5716 int 5717 zonecfg_notify_critical_exit(void * h) 5718 { 5719 5720 struct znotify *zevtchan = h; 5721 5722 if (zevtchan->zn_state == ZN_UNLOCKED) 5723 return (0); 5724 5725 (void) pthread_mutex_lock(&(zevtchan->zn_mutex)); 5726 zevtchan->zn_state = ZN_PING_INFLIGHT; 5727 5728 (void) sysevent_evc_publish(zevtchan->zn_eventchan, 5729 ZONE_EVENT_STATUS_CLASS, 5730 ZONE_EVENT_PING_SUBCLASS, ZONE_EVENT_PING_PUBLISHER, 5731 zevtchan->zn_subscriber_id, NULL, EVCH_SLEEP); 5732 5733 while (zevtchan->zn_state != ZN_PING_RECEIVED) { 5734 (void) pthread_cond_wait(&(zevtchan->zn_cond), 5735 &(zevtchan->zn_mutex)); 5736 } 5737 5738 if (zevtchan->zn_failed == B_TRUE) { 5739 zevtchan->zn_state = ZN_LOCKED; 5740 zevtchan->zn_failed = B_FALSE; 5741 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5742 return (1); 5743 } 5744 5745 zevtchan->zn_state = ZN_UNLOCKED; 5746 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5747 (void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex)); 5748 return (0); 5749 } 5750 5751 void 5752 zonecfg_notify_critical_abort(void *h) 5753 { 5754 struct znotify *zevtchan = h; 5755 5756 zevtchan->zn_state = ZN_UNLOCKED; 5757 zevtchan->zn_failed = B_FALSE; 5758 /* 5759 * Don't do anything about zn_lock. If it is held, it could only be 5760 * held by zn_cb and it will be unlocked soon. 5761 */ 5762 (void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex)); 5763 } 5764 5765 void * 5766 zonecfg_notify_bind(int(*func)(const char *zonename, zoneid_t zid, 5767 const char *newstate, const char *oldstate, hrtime_t when, void *p), 5768 void *p) 5769 { 5770 struct znotify *zevtchan; 5771 int i = 1; 5772 int r; 5773 5774 zevtchan = malloc(sizeof (struct znotify)); 5775 5776 if (zevtchan == NULL) 5777 return (NULL); 5778 5779 zevtchan->zn_private = p; 5780 zevtchan->zn_callback = func; 5781 zevtchan->zn_state = ZN_UNLOCKED; 5782 zevtchan->zn_failed = B_FALSE; 5783 5784 if (pthread_mutex_init(&(zevtchan->zn_mutex), NULL)) 5785 goto out3; 5786 if (pthread_cond_init(&(zevtchan->zn_cond), NULL)) { 5787 (void) pthread_mutex_destroy(&(zevtchan->zn_mutex)); 5788 goto out3; 5789 } 5790 if (pthread_mutex_init(&(zevtchan->zn_bigmutex), NULL)) { 5791 (void) pthread_mutex_destroy(&(zevtchan->zn_mutex)); 5792 (void) pthread_cond_destroy(&(zevtchan->zn_cond)); 5793 goto out3; 5794 } 5795 5796 if (sysevent_evc_bind(ZONE_EVENT_CHANNEL, &(zevtchan->zn_eventchan), 5797 0) != 0) 5798 goto out2; 5799 5800 do { 5801 /* 5802 * At 4 digits the subscriber ID gets too long and we have 5803 * no chance of successfully registering. 5804 */ 5805 if (i > 999) 5806 goto out1; 5807 5808 (void) sprintf(zevtchan->zn_subscriber_id, "zone_%li_%i", 5809 getpid() % 999999l, i); 5810 5811 r = sysevent_evc_subscribe(zevtchan->zn_eventchan, 5812 zevtchan->zn_subscriber_id, ZONE_EVENT_STATUS_CLASS, zn_cb, 5813 zevtchan, 0); 5814 5815 i++; 5816 5817 } while (r); 5818 5819 return (zevtchan); 5820 out1: 5821 sysevent_evc_unbind(zevtchan->zn_eventchan); 5822 out2: 5823 (void) pthread_mutex_destroy(&zevtchan->zn_mutex); 5824 (void) pthread_cond_destroy(&zevtchan->zn_cond); 5825 (void) pthread_mutex_destroy(&(zevtchan->zn_bigmutex)); 5826 out3: 5827 free(zevtchan); 5828 5829 return (NULL); 5830 } 5831 5832 void 5833 zonecfg_notify_unbind(void *handle) 5834 { 5835 5836 int ret; 5837 5838 sysevent_evc_unbind(((struct znotify *)handle)->zn_eventchan); 5839 /* 5840 * Check that all evc threads have gone away. This should be 5841 * enforced by sysevent_evc_unbind. 5842 */ 5843 ret = pthread_mutex_trylock(&((struct znotify *)handle)->zn_mutex); 5844 5845 if (ret) 5846 abort(); 5847 5848 (void) pthread_mutex_unlock(&((struct znotify *)handle)->zn_mutex); 5849 (void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_mutex); 5850 (void) pthread_cond_destroy(&((struct znotify *)handle)->zn_cond); 5851 (void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_bigmutex); 5852 5853 free(handle); 5854 } 5855 5856 static int 5857 zonecfg_add_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr) 5858 { 5859 xmlNodePtr newnode, cur = handle->zone_dh_cur; 5860 int err; 5861 5862 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DATASET, NULL); 5863 if ((err = newprop(newnode, DTD_ATTR_NAME, 5864 tabptr->zone_dataset_name)) != Z_OK) 5865 return (err); 5866 return (Z_OK); 5867 } 5868 5869 int 5870 zonecfg_add_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 5871 { 5872 int err; 5873 5874 if (tabptr == NULL) 5875 return (Z_INVAL); 5876 5877 if ((err = operation_prep(handle)) != Z_OK) 5878 return (err); 5879 5880 if ((err = zonecfg_add_ds_core(handle, tabptr)) != Z_OK) 5881 return (err); 5882 5883 return (Z_OK); 5884 } 5885 5886 static int 5887 zonecfg_delete_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr) 5888 { 5889 xmlNodePtr cur = handle->zone_dh_cur; 5890 5891 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 5892 if (xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 5893 continue; 5894 5895 if (match_prop(cur, DTD_ATTR_NAME, 5896 tabptr->zone_dataset_name)) { 5897 xmlUnlinkNode(cur); 5898 xmlFreeNode(cur); 5899 return (Z_OK); 5900 } 5901 } 5902 return (Z_NO_RESOURCE_ID); 5903 } 5904 5905 int 5906 zonecfg_delete_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 5907 { 5908 int err; 5909 5910 if (tabptr == NULL) 5911 return (Z_INVAL); 5912 5913 if ((err = operation_prep(handle)) != Z_OK) 5914 return (err); 5915 5916 if ((err = zonecfg_delete_ds_core(handle, tabptr)) != Z_OK) 5917 return (err); 5918 5919 return (Z_OK); 5920 } 5921 5922 int 5923 zonecfg_modify_ds( 5924 zone_dochandle_t handle, 5925 struct zone_dstab *oldtabptr, 5926 struct zone_dstab *newtabptr) 5927 { 5928 int err; 5929 5930 if (oldtabptr == NULL || newtabptr == NULL) 5931 return (Z_INVAL); 5932 5933 if ((err = operation_prep(handle)) != Z_OK) 5934 return (err); 5935 5936 if ((err = zonecfg_delete_ds_core(handle, oldtabptr)) != Z_OK) 5937 return (err); 5938 5939 if ((err = zonecfg_add_ds_core(handle, newtabptr)) != Z_OK) 5940 return (err); 5941 5942 return (Z_OK); 5943 } 5944 5945 int 5946 zonecfg_lookup_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 5947 { 5948 xmlNodePtr cur, firstmatch; 5949 int err; 5950 char dataset[MAXNAMELEN]; 5951 5952 if (tabptr == NULL) 5953 return (Z_INVAL); 5954 5955 if ((err = operation_prep(handle)) != Z_OK) 5956 return (err); 5957 5958 cur = handle->zone_dh_cur; 5959 firstmatch = NULL; 5960 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 5961 if (xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 5962 continue; 5963 if (strlen(tabptr->zone_dataset_name) > 0) { 5964 if ((fetchprop(cur, DTD_ATTR_NAME, dataset, 5965 sizeof (dataset)) == Z_OK) && 5966 (strcmp(tabptr->zone_dataset_name, 5967 dataset) == 0)) { 5968 if (firstmatch == NULL) 5969 firstmatch = cur; 5970 else 5971 return (Z_INSUFFICIENT_SPEC); 5972 } 5973 } 5974 } 5975 if (firstmatch == NULL) 5976 return (Z_NO_RESOURCE_ID); 5977 5978 cur = firstmatch; 5979 5980 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name, 5981 sizeof (tabptr->zone_dataset_name))) != Z_OK) 5982 return (err); 5983 5984 return (Z_OK); 5985 } 5986 5987 int 5988 zonecfg_setdsent(zone_dochandle_t handle) 5989 { 5990 return (zonecfg_setent(handle)); 5991 } 5992 5993 int 5994 zonecfg_getdsent(zone_dochandle_t handle, struct zone_dstab *tabptr) 5995 { 5996 xmlNodePtr cur; 5997 int err; 5998 5999 if (handle == NULL) 6000 return (Z_INVAL); 6001 6002 if ((cur = handle->zone_dh_cur) == NULL) 6003 return (Z_NO_ENTRY); 6004 6005 for (; cur != NULL; cur = cur->next) 6006 if (!xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 6007 break; 6008 if (cur == NULL) { 6009 handle->zone_dh_cur = handle->zone_dh_top; 6010 return (Z_NO_ENTRY); 6011 } 6012 6013 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name, 6014 sizeof (tabptr->zone_dataset_name))) != Z_OK) { 6015 handle->zone_dh_cur = handle->zone_dh_top; 6016 return (err); 6017 } 6018 6019 handle->zone_dh_cur = cur->next; 6020 return (Z_OK); 6021 } 6022 6023 int 6024 zonecfg_enddsent(zone_dochandle_t handle) 6025 { 6026 return (zonecfg_endent(handle)); 6027 } 6028 6029 /* 6030 * Support for aliased rctls; that is, rctls that have simplified names in 6031 * zonecfg. For example, max-lwps is an alias for a well defined zone.max-lwps 6032 * rctl. If there are multiple existing values for one of these rctls or if 6033 * there is a single value that does not match the well defined template (i.e. 6034 * it has a different action) then we cannot treat the rctl as having an alias 6035 * so we return Z_ALIAS_DISALLOW. That means that the rctl cannot be 6036 * managed in zonecfg via an alias and that the standard rctl syntax must be 6037 * used. 6038 * 6039 * The possible return values are: 6040 * Z_NO_PROPERTY_ID - invalid alias name 6041 * Z_ALIAS_DISALLOW - pre-existing, incompatible rctl definition 6042 * Z_NO_ENTRY - no rctl is configured for this alias 6043 * Z_OK - we got a valid rctl for the specified alias 6044 */ 6045 int 6046 zonecfg_get_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t *rval) 6047 { 6048 boolean_t found = B_FALSE; 6049 boolean_t found_val = B_FALSE; 6050 xmlNodePtr cur, val; 6051 char savedname[MAXNAMELEN]; 6052 struct zone_rctlvaltab rctl; 6053 int i; 6054 int err; 6055 6056 for (i = 0; aliases[i].shortname != NULL; i++) 6057 if (strcmp(name, aliases[i].shortname) == 0) 6058 break; 6059 6060 if (aliases[i].shortname == NULL) 6061 return (Z_NO_PROPERTY_ID); 6062 6063 if ((err = operation_prep(handle)) != Z_OK) 6064 return (err); 6065 6066 cur = handle->zone_dh_cur; 6067 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6068 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL) != 0) 6069 continue; 6070 if ((fetchprop(cur, DTD_ATTR_NAME, savedname, 6071 sizeof (savedname)) == Z_OK) && 6072 (strcmp(savedname, aliases[i].realname) == 0)) { 6073 6074 /* 6075 * If we already saw one of these, we can't have an 6076 * alias since we just found another. 6077 */ 6078 if (found) 6079 return (Z_ALIAS_DISALLOW); 6080 found = B_TRUE; 6081 6082 for (val = cur->xmlChildrenNode; val != NULL; 6083 val = val->next) { 6084 /* 6085 * If we already have one value, we can't have 6086 * an alias since we just found another. 6087 */ 6088 if (found_val) 6089 return (Z_ALIAS_DISALLOW); 6090 found_val = B_TRUE; 6091 6092 if ((fetchprop(val, DTD_ATTR_PRIV, 6093 rctl.zone_rctlval_priv, 6094 sizeof (rctl.zone_rctlval_priv)) != Z_OK)) 6095 break; 6096 if ((fetchprop(val, DTD_ATTR_LIMIT, 6097 rctl.zone_rctlval_limit, 6098 sizeof (rctl.zone_rctlval_limit)) != Z_OK)) 6099 break; 6100 if ((fetchprop(val, DTD_ATTR_ACTION, 6101 rctl.zone_rctlval_action, 6102 sizeof (rctl.zone_rctlval_action)) != Z_OK)) 6103 break; 6104 } 6105 6106 /* check priv and action match the expected vals */ 6107 if (strcmp(rctl.zone_rctlval_priv, 6108 aliases[i].priv) != 0 || 6109 strcmp(rctl.zone_rctlval_action, 6110 aliases[i].action) != 0) 6111 return (Z_ALIAS_DISALLOW); 6112 } 6113 } 6114 6115 if (found) { 6116 *rval = strtoull(rctl.zone_rctlval_limit, NULL, 10); 6117 return (Z_OK); 6118 } 6119 6120 return (Z_NO_ENTRY); 6121 } 6122 6123 int 6124 zonecfg_rm_aliased_rctl(zone_dochandle_t handle, char *name) 6125 { 6126 int i; 6127 uint64_t val; 6128 struct zone_rctltab rctltab; 6129 6130 /* 6131 * First check that we have a valid aliased rctl to remove. 6132 * This will catch an rctl entry with non-standard values or 6133 * multiple rctl values for this name. We need to ignore those 6134 * rctl entries. 6135 */ 6136 if (zonecfg_get_aliased_rctl(handle, name, &val) != Z_OK) 6137 return (Z_OK); 6138 6139 for (i = 0; aliases[i].shortname != NULL; i++) 6140 if (strcmp(name, aliases[i].shortname) == 0) 6141 break; 6142 6143 if (aliases[i].shortname == NULL) 6144 return (Z_NO_RESOURCE_ID); 6145 6146 (void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname, 6147 sizeof (rctltab.zone_rctl_name)); 6148 6149 return (zonecfg_delete_rctl(handle, &rctltab)); 6150 } 6151 6152 boolean_t 6153 zonecfg_aliased_rctl_ok(zone_dochandle_t handle, char *name) 6154 { 6155 uint64_t tmp_val; 6156 6157 switch (zonecfg_get_aliased_rctl(handle, name, &tmp_val)) { 6158 case Z_OK: 6159 /*FALLTHRU*/ 6160 case Z_NO_ENTRY: 6161 return (B_TRUE); 6162 default: 6163 return (B_FALSE); 6164 } 6165 } 6166 6167 int 6168 zonecfg_set_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t val) 6169 { 6170 int i; 6171 int err; 6172 struct zone_rctltab rctltab; 6173 struct zone_rctlvaltab *rctlvaltab; 6174 char buf[128]; 6175 6176 if (!zonecfg_aliased_rctl_ok(handle, name)) 6177 return (Z_ALIAS_DISALLOW); 6178 6179 for (i = 0; aliases[i].shortname != NULL; i++) 6180 if (strcmp(name, aliases[i].shortname) == 0) 6181 break; 6182 6183 if (aliases[i].shortname == NULL) 6184 return (Z_NO_RESOURCE_ID); 6185 6186 /* remove any pre-existing definition for this rctl */ 6187 (void) zonecfg_rm_aliased_rctl(handle, name); 6188 6189 (void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname, 6190 sizeof (rctltab.zone_rctl_name)); 6191 6192 rctltab.zone_rctl_valptr = NULL; 6193 6194 if ((rctlvaltab = calloc(1, sizeof (struct zone_rctlvaltab))) == NULL) 6195 return (Z_NOMEM); 6196 6197 (void) snprintf(buf, sizeof (buf), "%llu", (long long)val); 6198 6199 (void) strlcpy(rctlvaltab->zone_rctlval_priv, aliases[i].priv, 6200 sizeof (rctlvaltab->zone_rctlval_priv)); 6201 (void) strlcpy(rctlvaltab->zone_rctlval_limit, buf, 6202 sizeof (rctlvaltab->zone_rctlval_limit)); 6203 (void) strlcpy(rctlvaltab->zone_rctlval_action, aliases[i].action, 6204 sizeof (rctlvaltab->zone_rctlval_action)); 6205 6206 rctlvaltab->zone_rctlval_next = NULL; 6207 6208 if ((err = zonecfg_add_rctl_value(&rctltab, rctlvaltab)) != Z_OK) 6209 return (err); 6210 6211 return (zonecfg_add_rctl(handle, &rctltab)); 6212 } 6213 6214 static int 6215 delete_tmp_pool(zone_dochandle_t handle) 6216 { 6217 int err; 6218 xmlNodePtr cur = handle->zone_dh_cur; 6219 6220 if ((err = operation_prep(handle)) != Z_OK) 6221 return (err); 6222 6223 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6224 if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) { 6225 xmlUnlinkNode(cur); 6226 xmlFreeNode(cur); 6227 return (Z_OK); 6228 } 6229 } 6230 6231 return (Z_NO_RESOURCE_ID); 6232 } 6233 6234 static int 6235 modify_tmp_pool(zone_dochandle_t handle, char *pool_importance) 6236 { 6237 int err; 6238 xmlNodePtr cur = handle->zone_dh_cur; 6239 xmlNodePtr newnode; 6240 6241 err = delete_tmp_pool(handle); 6242 if (err != Z_OK && err != Z_NO_RESOURCE_ID) 6243 return (err); 6244 6245 if (*pool_importance != '\0') { 6246 if ((err = operation_prep(handle)) != Z_OK) 6247 return (err); 6248 6249 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_TMPPOOL, NULL); 6250 if ((err = newprop(newnode, DTD_ATTR_IMPORTANCE, 6251 pool_importance)) != Z_OK) 6252 return (err); 6253 } 6254 6255 return (Z_OK); 6256 } 6257 6258 static int 6259 add_pset_core(zone_dochandle_t handle, struct zone_psettab *tabptr) 6260 { 6261 xmlNodePtr newnode, cur = handle->zone_dh_cur; 6262 int err; 6263 6264 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PSET, NULL); 6265 if ((err = newprop(newnode, DTD_ATTR_NCPU_MIN, 6266 tabptr->zone_ncpu_min)) != Z_OK) 6267 return (err); 6268 if ((err = newprop(newnode, DTD_ATTR_NCPU_MAX, 6269 tabptr->zone_ncpu_max)) != Z_OK) 6270 return (err); 6271 6272 if ((err = modify_tmp_pool(handle, tabptr->zone_importance)) != Z_OK) 6273 return (err); 6274 6275 return (Z_OK); 6276 } 6277 6278 int 6279 zonecfg_add_pset(zone_dochandle_t handle, struct zone_psettab *tabptr) 6280 { 6281 int err; 6282 6283 if (tabptr == NULL) 6284 return (Z_INVAL); 6285 6286 if ((err = operation_prep(handle)) != Z_OK) 6287 return (err); 6288 6289 if ((err = add_pset_core(handle, tabptr)) != Z_OK) 6290 return (err); 6291 6292 return (Z_OK); 6293 } 6294 6295 int 6296 zonecfg_delete_pset(zone_dochandle_t handle) 6297 { 6298 int err; 6299 int res = Z_NO_RESOURCE_ID; 6300 xmlNodePtr cur = handle->zone_dh_cur; 6301 6302 if ((err = operation_prep(handle)) != Z_OK) 6303 return (err); 6304 6305 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6306 if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) { 6307 xmlUnlinkNode(cur); 6308 xmlFreeNode(cur); 6309 res = Z_OK; 6310 break; 6311 } 6312 } 6313 6314 /* 6315 * Once we have msets, we should check that a mset 6316 * do not exist before we delete the tmp_pool data. 6317 */ 6318 err = delete_tmp_pool(handle); 6319 if (err != Z_OK && err != Z_NO_RESOURCE_ID) 6320 return (err); 6321 6322 return (res); 6323 } 6324 6325 int 6326 zonecfg_modify_pset(zone_dochandle_t handle, struct zone_psettab *tabptr) 6327 { 6328 int err; 6329 6330 if (tabptr == NULL) 6331 return (Z_INVAL); 6332 6333 if ((err = zonecfg_delete_pset(handle)) != Z_OK) 6334 return (err); 6335 6336 if ((err = add_pset_core(handle, tabptr)) != Z_OK) 6337 return (err); 6338 6339 return (Z_OK); 6340 } 6341 6342 int 6343 zonecfg_lookup_pset(zone_dochandle_t handle, struct zone_psettab *tabptr) 6344 { 6345 xmlNodePtr cur; 6346 int err; 6347 int res = Z_NO_ENTRY; 6348 6349 if (tabptr == NULL) 6350 return (Z_INVAL); 6351 6352 if ((err = operation_prep(handle)) != Z_OK) 6353 return (err); 6354 6355 /* this is an optional component */ 6356 tabptr->zone_importance[0] = '\0'; 6357 6358 cur = handle->zone_dh_cur; 6359 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6360 if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) { 6361 if ((err = fetchprop(cur, DTD_ATTR_NCPU_MIN, 6362 tabptr->zone_ncpu_min, 6363 sizeof (tabptr->zone_ncpu_min))) != Z_OK) { 6364 handle->zone_dh_cur = handle->zone_dh_top; 6365 return (err); 6366 } 6367 6368 if ((err = fetchprop(cur, DTD_ATTR_NCPU_MAX, 6369 tabptr->zone_ncpu_max, 6370 sizeof (tabptr->zone_ncpu_max))) != Z_OK) { 6371 handle->zone_dh_cur = handle->zone_dh_top; 6372 return (err); 6373 } 6374 6375 res = Z_OK; 6376 6377 } else if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) { 6378 if ((err = fetchprop(cur, DTD_ATTR_IMPORTANCE, 6379 tabptr->zone_importance, 6380 sizeof (tabptr->zone_importance))) != Z_OK) { 6381 handle->zone_dh_cur = handle->zone_dh_top; 6382 return (err); 6383 } 6384 } 6385 } 6386 6387 return (res); 6388 } 6389 6390 int 6391 zonecfg_getpsetent(zone_dochandle_t handle, struct zone_psettab *tabptr) 6392 { 6393 int err; 6394 6395 if ((err = zonecfg_setent(handle)) != Z_OK) 6396 return (err); 6397 6398 err = zonecfg_lookup_pset(handle, tabptr); 6399 6400 (void) zonecfg_endent(handle); 6401 6402 return (err); 6403 } 6404 6405 static int 6406 add_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 6407 { 6408 xmlNodePtr newnode, cur = handle->zone_dh_cur; 6409 int err; 6410 6411 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_MCAP, NULL); 6412 if ((err = newprop(newnode, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap)) 6413 != Z_OK) 6414 return (err); 6415 6416 return (Z_OK); 6417 } 6418 6419 int 6420 zonecfg_delete_mcap(zone_dochandle_t handle) 6421 { 6422 int err; 6423 xmlNodePtr cur = handle->zone_dh_cur; 6424 6425 if ((err = operation_prep(handle)) != Z_OK) 6426 return (err); 6427 6428 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6429 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0) 6430 continue; 6431 6432 xmlUnlinkNode(cur); 6433 xmlFreeNode(cur); 6434 return (Z_OK); 6435 } 6436 return (Z_NO_RESOURCE_ID); 6437 } 6438 6439 int 6440 zonecfg_modify_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 6441 { 6442 int err; 6443 6444 if (tabptr == NULL) 6445 return (Z_INVAL); 6446 6447 err = zonecfg_delete_mcap(handle); 6448 /* it is ok if there is no mcap entry */ 6449 if (err != Z_OK && err != Z_NO_RESOURCE_ID) 6450 return (err); 6451 6452 if ((err = add_mcap(handle, tabptr)) != Z_OK) 6453 return (err); 6454 6455 return (Z_OK); 6456 } 6457 6458 int 6459 zonecfg_lookup_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 6460 { 6461 xmlNodePtr cur; 6462 int err; 6463 6464 if (tabptr == NULL) 6465 return (Z_INVAL); 6466 6467 if ((err = operation_prep(handle)) != Z_OK) 6468 return (err); 6469 6470 cur = handle->zone_dh_cur; 6471 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6472 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0) 6473 continue; 6474 if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP, 6475 tabptr->zone_physmem_cap, 6476 sizeof (tabptr->zone_physmem_cap))) != Z_OK) { 6477 handle->zone_dh_cur = handle->zone_dh_top; 6478 return (err); 6479 } 6480 6481 return (Z_OK); 6482 } 6483 6484 return (Z_NO_ENTRY); 6485 } 6486 6487 static int 6488 getmcapent_core(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 6489 { 6490 xmlNodePtr cur; 6491 int err; 6492 6493 if (handle == NULL) 6494 return (Z_INVAL); 6495 6496 if ((cur = handle->zone_dh_cur) == NULL) 6497 return (Z_NO_ENTRY); 6498 6499 for (; cur != NULL; cur = cur->next) 6500 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) == 0) 6501 break; 6502 if (cur == NULL) { 6503 handle->zone_dh_cur = handle->zone_dh_top; 6504 return (Z_NO_ENTRY); 6505 } 6506 6507 if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap, 6508 sizeof (tabptr->zone_physmem_cap))) != Z_OK) { 6509 handle->zone_dh_cur = handle->zone_dh_top; 6510 return (err); 6511 } 6512 6513 handle->zone_dh_cur = cur->next; 6514 return (Z_OK); 6515 } 6516 6517 int 6518 zonecfg_getmcapent(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 6519 { 6520 int err; 6521 6522 if ((err = zonecfg_setent(handle)) != Z_OK) 6523 return (err); 6524 6525 err = getmcapent_core(handle, tabptr); 6526 6527 (void) zonecfg_endent(handle); 6528 6529 return (err); 6530 } 6531 6532 /* 6533 * Get the full tree of pkg/patch metadata in a set of nested AVL trees. 6534 * pkgs_avl is an AVL tree of pkgs. Each pkg element contains a 6535 * zpe_patches_avl member which holds an AVL tree of patches for that pkg. 6536 * The patch elements have the same zpe_patches_avl member, each of which can 6537 * hold an AVL tree of patches that are obsoleted by the patch. 6538 * 6539 * The zone xml data contains DTD_ELEM_PACKAGE elements, followed by 6540 * DTD_ELEM_PATCH elements. The DTD_ELEM_PATCH patch element applies to the 6541 * DTD_ELEM_PACKAGE that precedes it. The DTD_ELEM_PATCH element may have 6542 * child DTD_ELEM_OBSOLETES nodes associated with it. The DTD_ELEM_PACKAGE 6543 * really should have had the DTD_ELEM_PATCH elements as children but it 6544 * was not defined that way initially so we are stuck with the DTD definition 6545 * now. However, we can safely assume the ordering for compatibility. 6546 */ 6547 int 6548 zonecfg_getpkgdata(zone_dochandle_t handle, uu_avl_pool_t *pkg_pool, 6549 uu_avl_t *pkgs_avl) 6550 { 6551 xmlNodePtr cur; 6552 int res; 6553 zone_pkg_entry_t *pkg; 6554 char name[MAXNAMELEN]; 6555 char version[ZONE_PKG_VERSMAX]; 6556 6557 if (handle == NULL) 6558 return (Z_INVAL); 6559 6560 if ((res = zonecfg_setent(handle)) != Z_OK) 6561 return (res); 6562 6563 if ((cur = handle->zone_dh_cur) == NULL) { 6564 res = Z_NO_ENTRY; 6565 goto done; 6566 } 6567 6568 for (; cur != NULL; cur = cur->next) { 6569 if (xmlStrcmp(cur->name, DTD_ELEM_PACKAGE) == 0) { 6570 uu_avl_index_t where; 6571 6572 if ((res = fetchprop(cur, DTD_ATTR_NAME, name, 6573 sizeof (name))) != Z_OK) 6574 goto done; 6575 6576 if ((res = fetchprop(cur, DTD_ATTR_VERSION, version, 6577 sizeof (version))) != Z_OK) 6578 goto done; 6579 6580 if ((pkg = (zone_pkg_entry_t *) 6581 malloc(sizeof (zone_pkg_entry_t))) == NULL) { 6582 res = Z_NOMEM; 6583 goto done; 6584 } 6585 6586 if ((pkg->zpe_name = strdup(name)) == NULL) { 6587 free(pkg); 6588 res = Z_NOMEM; 6589 goto done; 6590 } 6591 6592 if ((pkg->zpe_vers = strdup(version)) == NULL) { 6593 free(pkg->zpe_name); 6594 free(pkg); 6595 res = Z_NOMEM; 6596 goto done; 6597 } 6598 6599 pkg->zpe_patches_avl = NULL; 6600 6601 uu_avl_node_init(pkg, &pkg->zpe_entry, pkg_pool); 6602 if (uu_avl_find(pkgs_avl, pkg, NULL, &where) != NULL) { 6603 free(pkg->zpe_name); 6604 free(pkg->zpe_vers); 6605 free(pkg); 6606 } else { 6607 uu_avl_insert(pkgs_avl, pkg, where); 6608 } 6609 6610 } else if (xmlStrcmp(cur->name, DTD_ELEM_PATCH) == 0) { 6611 zone_pkg_entry_t *patch; 6612 uu_avl_index_t where; 6613 char *p; 6614 char *dashp = NULL; 6615 xmlNodePtr child; 6616 6617 if ((res = fetchprop(cur, DTD_ATTR_ID, name, 6618 sizeof (name))) != Z_OK) 6619 goto done; 6620 6621 if ((patch = (zone_pkg_entry_t *) 6622 malloc(sizeof (zone_pkg_entry_t))) == NULL) { 6623 res = Z_NOMEM; 6624 goto done; 6625 } 6626 6627 if ((p = strchr(name, '-')) != NULL) { 6628 dashp = p; 6629 *p++ = '\0'; 6630 } else { 6631 p = ""; 6632 } 6633 6634 if ((patch->zpe_name = strdup(name)) == NULL) { 6635 free(patch); 6636 res = Z_NOMEM; 6637 goto done; 6638 } 6639 6640 if ((patch->zpe_vers = strdup(p)) == NULL) { 6641 free(patch->zpe_name); 6642 free(patch); 6643 res = Z_NOMEM; 6644 goto done; 6645 } 6646 6647 if (dashp != NULL) 6648 *dashp = '-'; 6649 6650 patch->zpe_patches_avl = NULL; 6651 6652 if (pkg->zpe_patches_avl == NULL) { 6653 pkg->zpe_patches_avl = uu_avl_create(pkg_pool, 6654 NULL, UU_DEFAULT); 6655 if (pkg->zpe_patches_avl == NULL) { 6656 free(patch->zpe_name); 6657 free(patch->zpe_vers); 6658 free(patch); 6659 res = Z_NOMEM; 6660 goto done; 6661 } 6662 } 6663 6664 uu_avl_node_init(patch, &patch->zpe_entry, pkg_pool); 6665 if (uu_avl_find(pkg->zpe_patches_avl, patch, NULL, 6666 &where) != NULL) { 6667 free(patch->zpe_name); 6668 free(patch->zpe_vers); 6669 free(patch); 6670 } else { 6671 uu_avl_insert(pkg->zpe_patches_avl, patch, 6672 where); 6673 } 6674 6675 /* Add any patches this patch obsoletes. */ 6676 for (child = cur->xmlChildrenNode; child != NULL; 6677 child = child->next) { 6678 zone_pkg_entry_t *obs; 6679 6680 if (xmlStrcmp(child->name, DTD_ELEM_OBSOLETES) 6681 != 0) 6682 continue; 6683 6684 if ((res = fetchprop(child, DTD_ATTR_ID, 6685 name, sizeof (name))) != Z_OK) 6686 goto done; 6687 6688 if ((obs = (zone_pkg_entry_t *)malloc( 6689 sizeof (zone_pkg_entry_t))) == NULL) { 6690 res = Z_NOMEM; 6691 goto done; 6692 } 6693 6694 if ((obs->zpe_name = strdup(name)) == NULL) { 6695 free(obs); 6696 res = Z_NOMEM; 6697 goto done; 6698 } 6699 /* 6700 * The version doesn't matter for obsoleted 6701 * patches. 6702 */ 6703 obs->zpe_vers = NULL; 6704 obs->zpe_patches_avl = NULL; 6705 6706 /* 6707 * If this is the first obsolete patch, add an 6708 * AVL tree to the parent patch element. 6709 */ 6710 if (patch->zpe_patches_avl == NULL) { 6711 patch->zpe_patches_avl = 6712 uu_avl_create(pkg_pool, NULL, 6713 UU_DEFAULT); 6714 if (patch->zpe_patches_avl == NULL) { 6715 free(obs->zpe_name); 6716 free(obs); 6717 res = Z_NOMEM; 6718 goto done; 6719 } 6720 } 6721 6722 /* Insert obsolete patch into the AVL tree. */ 6723 uu_avl_node_init(obs, &obs->zpe_entry, 6724 pkg_pool); 6725 if (uu_avl_find(patch->zpe_patches_avl, obs, 6726 NULL, &where) != NULL) { 6727 free(obs->zpe_name); 6728 free(obs); 6729 } else { 6730 uu_avl_insert(patch->zpe_patches_avl, 6731 obs, where); 6732 } 6733 } 6734 } 6735 } 6736 6737 done: 6738 (void) zonecfg_endent(handle); 6739 return (res); 6740 } 6741 6742 int 6743 zonecfg_setdevperment(zone_dochandle_t handle) 6744 { 6745 return (zonecfg_setent(handle)); 6746 } 6747 6748 int 6749 zonecfg_getdevperment(zone_dochandle_t handle, struct zone_devpermtab *tabptr) 6750 { 6751 xmlNodePtr cur; 6752 int err; 6753 char buf[128]; 6754 6755 tabptr->zone_devperm_acl = NULL; 6756 6757 if (handle == NULL) 6758 return (Z_INVAL); 6759 6760 if ((cur = handle->zone_dh_cur) == NULL) 6761 return (Z_NO_ENTRY); 6762 6763 for (; cur != NULL; cur = cur->next) 6764 if (!xmlStrcmp(cur->name, DTD_ELEM_DEV_PERM)) 6765 break; 6766 if (cur == NULL) { 6767 handle->zone_dh_cur = handle->zone_dh_top; 6768 return (Z_NO_ENTRY); 6769 } 6770 6771 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_devperm_name, 6772 sizeof (tabptr->zone_devperm_name))) != Z_OK) { 6773 handle->zone_dh_cur = handle->zone_dh_top; 6774 return (err); 6775 } 6776 6777 if ((err = fetchprop(cur, DTD_ATTR_UID, buf, sizeof (buf))) != Z_OK) { 6778 handle->zone_dh_cur = handle->zone_dh_top; 6779 return (err); 6780 } 6781 tabptr->zone_devperm_uid = (uid_t)atol(buf); 6782 6783 if ((err = fetchprop(cur, DTD_ATTR_GID, buf, sizeof (buf))) != Z_OK) { 6784 handle->zone_dh_cur = handle->zone_dh_top; 6785 return (err); 6786 } 6787 tabptr->zone_devperm_gid = (gid_t)atol(buf); 6788 6789 if ((err = fetchprop(cur, DTD_ATTR_MODE, buf, sizeof (buf))) != Z_OK) { 6790 handle->zone_dh_cur = handle->zone_dh_top; 6791 return (err); 6792 } 6793 tabptr->zone_devperm_mode = (mode_t)strtol(buf, (char **)NULL, 8); 6794 6795 if ((err = fetch_alloc_prop(cur, DTD_ATTR_ACL, 6796 &(tabptr->zone_devperm_acl))) != Z_OK) { 6797 handle->zone_dh_cur = handle->zone_dh_top; 6798 return (err); 6799 } 6800 6801 handle->zone_dh_cur = cur->next; 6802 return (Z_OK); 6803 } 6804 6805 int 6806 zonecfg_enddevperment(zone_dochandle_t handle) 6807 { 6808 return (zonecfg_endent(handle)); 6809 } 6810 6811 /* 6812 * Maintain a space separated list of unique pkg names. PATH_MAX is used in 6813 * the pkg code as the maximum size for a pkg name. 6814 */ 6815 static int 6816 add_pkg_to_str(char **str, char *pkg) 6817 { 6818 int len, newlen; 6819 char tstr[PATH_MAX + 3]; 6820 char *tmp; 6821 6822 len = strlen(pkg); 6823 if (*str == NULL) { 6824 /* space for str + 2 spaces + NULL */ 6825 if ((*str = (char *)malloc(len + 3)) == NULL) 6826 return (Z_NOMEM); 6827 (void) snprintf(*str, len + 3, " %s ", pkg); 6828 return (Z_OK); 6829 } 6830 6831 (void) snprintf(tstr, sizeof (tstr), " %s ", pkg); 6832 if (strstr(*str, tstr) != NULL) 6833 return (Z_OK); 6834 6835 /* space for str + 1 space + NULL */ 6836 newlen = strlen(*str) + len + 2; 6837 if ((tmp = (char *)realloc(*str, newlen)) == NULL) 6838 return (Z_NOMEM); 6839 *str = tmp; 6840 (void) strlcat(*str, pkg, newlen); 6841 (void) strlcat(*str, " ", newlen); 6842 return (Z_OK); 6843 } 6844 6845 /* 6846 * Process a list of pkgs from an entry in the contents file, adding each pkg 6847 * name to the list of pkgs. 6848 * 6849 * It is possible for the pkg name to be preceeded by a special character 6850 * which indicates some bookkeeping information for pkging. Check if the 6851 * first char is not an Alpha char. If so, skip over it. 6852 */ 6853 static int 6854 add_pkg_list(char *lastp, char ***plist, int *pcnt, char **pkg_warn) 6855 { 6856 char *p; 6857 int pkg_cnt = *pcnt; 6858 char **pkgs = *plist; 6859 int res = Z_OK; 6860 6861 while ((p = strtok_r(NULL, " ", &lastp)) != NULL) { 6862 char **tmpp; 6863 int i; 6864 6865 /* skip over any special pkg bookkeeping char */ 6866 if (!isalpha(*p)) { 6867 p++; 6868 if ((res = add_pkg_to_str(pkg_warn, p)) != Z_OK) 6869 break; 6870 } 6871 6872 /* Check if the pkg is already in the list */ 6873 for (i = 0; i < pkg_cnt; i++) { 6874 if (strcmp(p, pkgs[i]) == 0) 6875 break; 6876 } 6877 6878 if (i < pkg_cnt) 6879 continue; 6880 6881 /* The pkg is not in the list; add it. */ 6882 if ((tmpp = (char **)realloc(pkgs, 6883 sizeof (char *) * (pkg_cnt + 1))) == NULL) { 6884 res = Z_NOMEM; 6885 break; 6886 } 6887 pkgs = tmpp; 6888 6889 if ((pkgs[pkg_cnt] = strdup(p)) == NULL) { 6890 res = Z_NOMEM; 6891 break; 6892 } 6893 pkg_cnt++; 6894 } 6895 6896 *plist = pkgs; 6897 *pcnt = pkg_cnt; 6898 6899 return (res); 6900 } 6901 6902 /* 6903 * Process an entry from the contents file (type "directory"). If the 6904 * directory path is in the list of ipds and is not under a lofs mount within 6905 * the ipd then add the associated list of pkgs to the pkg list. The input 6906 * parameter "entry" will be broken up by the parser within this function so 6907 * its value will be modified when this function exits. 6908 * 6909 * The entries we are looking for will look something like: 6910 * /usr d none 0755 root sys SUNWctpls SUNWidnl SUNWlibCf .... 6911 */ 6912 static int 6913 get_path_pkgs(char *entry, char **ipds, char **fss, char ***pkgs, int *pkg_cnt, 6914 char **pkg_warn) 6915 { 6916 char *f1; 6917 char *f2; 6918 char *lastp; 6919 int i; 6920 char *nlp; 6921 6922 if ((f1 = strtok_r(entry, " ", &lastp)) == NULL || 6923 (f2 = strtok_r(NULL, " ", &lastp)) == NULL || strcmp(f2, "d") != 0) 6924 return (Z_OK); 6925 6926 /* Check if this directory entry is in the list of ipds. */ 6927 for (i = 0; ipds[i] != NULL; i++) { 6928 char wildcard[MAXPATHLEN]; 6929 6930 /* 6931 * We want to match on the path and any other directory 6932 * entries under this path. When we use FNM_PATHNAME then 6933 * that means '/' will not be matched by a wildcard (*) so 6934 * we omit FNM_PATHNAME on the call with the wildcard matching. 6935 */ 6936 (void) snprintf(wildcard, sizeof (wildcard), "%s/*", ipds[i]); 6937 if (fnmatch(ipds[i], f1, FNM_PATHNAME) == 0 || 6938 fnmatch(wildcard, f1, 0) == 0) { 6939 /* It looks like we do want the pkgs for this path. */ 6940 break; 6941 } 6942 } 6943 6944 /* This entry did not match any of the ipds. */ 6945 if (ipds[i] == NULL) 6946 return (Z_OK); 6947 6948 /* 6949 * Check if there is a fs mounted under the ipd. If so, ignore this 6950 * entry. 6951 */ 6952 for (i = 0; fss[i] != NULL; i++) { 6953 char wildcard[MAXPATHLEN]; 6954 6955 (void) snprintf(wildcard, sizeof (wildcard), "%s/*", fss[i]); 6956 if (fnmatch(fss[i], f1, FNM_PATHNAME) == 0 || 6957 fnmatch(wildcard, f1, 0) == 0) { 6958 /* We should ignore this path. */ 6959 break; 6960 } 6961 } 6962 6963 /* If not null, then we matched an fs mount point so ignore entry. */ 6964 if (fss[i] != NULL) 6965 return (Z_OK); 6966 6967 /* 6968 * We do want the pkgs for this entry. First, skip over the next 4 6969 * fields in the entry so that we call add_pkg_list starting with the 6970 * pkg names. 6971 */ 6972 for (i = 0; i < 4 && strtok_r(NULL, " ", &lastp) != NULL; i++) 6973 ; 6974 /* If there are < 4 fields this entry is corrupt, just skip it. */ 6975 if (i < 4) 6976 return (Z_OK); 6977 6978 /* strip newline from the line */ 6979 nlp = (lastp + strlen(lastp) - 1); 6980 if (*nlp == '\n') 6981 *nlp = '\0'; 6982 6983 return (add_pkg_list(lastp, pkgs, pkg_cnt, pkg_warn)); 6984 } 6985 6986 /* 6987 * Read an entry from a pkginfo or contents file. Some of these lines can 6988 * either be arbitrarily long or be continued by a backslash at the end of 6989 * the line. This function coalesces lines that are longer than the read 6990 * buffer, and lines that are continued, into one buffer which is returned. 6991 * The caller must free this memory. NULL is returned when we hit EOF or 6992 * if we run out of memory (errno is set to ENOMEM). 6993 */ 6994 static char * 6995 read_pkg_data(FILE *fp) 6996 { 6997 char *start; 6998 char *inp; 6999 char *p; 7000 int char_cnt = 0; 7001 7002 errno = 0; 7003 if ((start = (char *)malloc(PKGINFO_RD_LEN)) == NULL) { 7004 errno = ENOMEM; 7005 return (NULL); 7006 } 7007 7008 inp = start; 7009 while ((p = fgets(inp, PKGINFO_RD_LEN, fp)) != NULL) { 7010 int len; 7011 7012 len = strlen(inp); 7013 if (inp[len - 1] == '\n' && 7014 (len == 1 || inp[len - 2] != '\\')) { 7015 char_cnt = len; 7016 break; 7017 } 7018 7019 if (inp[len - 2] == '\\') 7020 char_cnt += len - 2; 7021 else 7022 char_cnt += PKGINFO_RD_LEN - 1; 7023 7024 if ((p = realloc(start, char_cnt + PKGINFO_RD_LEN)) == NULL) { 7025 errno = ENOMEM; 7026 break; 7027 } 7028 7029 start = p; 7030 inp = start + char_cnt; 7031 } 7032 7033 if (errno == ENOMEM || (p == NULL && char_cnt == 0)) { 7034 free(start); 7035 start = NULL; 7036 } 7037 7038 return (start); 7039 } 7040 7041 static void 7042 free_ipd_pkgs(char **pkgs, int cnt) 7043 { 7044 int i; 7045 7046 for (i = 0; i < cnt; i++) 7047 free(pkgs[i]); 7048 free(pkgs); 7049 } 7050 7051 /* 7052 * Get a list of the inherited pkg dirs or fs entries configured for the 7053 * zone. The type parameter will be either ZONE_IPD or ZONE_FS. 7054 */ 7055 static int 7056 get_ipd_fs_list(zone_dochandle_t handle, enum zn_ipd_fs type, char ***list) 7057 { 7058 int res; 7059 struct zone_fstab fstab; 7060 int cnt = 0; 7061 char **entries = NULL; 7062 int i; 7063 int (*fp)(zone_dochandle_t, struct zone_fstab *); 7064 7065 if (type == ZONE_IPD) { 7066 fp = zonecfg_getipdent; 7067 res = zonecfg_setipdent(handle); 7068 } else { 7069 fp = zonecfg_getfsent; 7070 res = zonecfg_setfsent(handle); 7071 } 7072 7073 if (res != Z_OK) 7074 return (res); 7075 7076 while (fp(handle, &fstab) == Z_OK) { 7077 char **p; 7078 7079 if ((p = (char **)realloc(entries, 7080 sizeof (char *) * (cnt + 1))) == NULL) { 7081 res = Z_NOMEM; 7082 break; 7083 } 7084 entries = p; 7085 7086 if ((entries[cnt] = strdup(fstab.zone_fs_dir)) == NULL) { 7087 res = Z_NOMEM; 7088 break; 7089 } 7090 7091 cnt++; 7092 } 7093 7094 if (type == ZONE_IPD) 7095 (void) zonecfg_endipdent(handle); 7096 else 7097 (void) zonecfg_endfsent(handle); 7098 7099 /* Add a NULL terminating element. */ 7100 if (res == Z_OK) { 7101 char **p; 7102 7103 if ((p = (char **)realloc(entries, 7104 sizeof (char *) * (cnt + 1))) == NULL) { 7105 res = Z_NOMEM; 7106 } else { 7107 entries = p; 7108 entries[cnt] = NULL; 7109 } 7110 } 7111 7112 if (res != Z_OK) { 7113 if (entries != NULL) { 7114 for (i = 0; i < cnt; i++) 7115 free(entries[i]); 7116 free(entries); 7117 } 7118 return (res); 7119 } 7120 7121 *list = entries; 7122 return (Z_OK); 7123 } 7124 7125 /* 7126 * Get the list of inherited-pkg-dirs (ipd) for the zone and then get the 7127 * list of pkgs that deliver into those dirs. 7128 */ 7129 static int 7130 get_ipd_pkgs(zone_dochandle_t handle, char ***pkg_list, int *cnt) 7131 { 7132 int res; 7133 char **ipds; 7134 char **fss; 7135 int pkg_cnt = 0; 7136 char **pkgs = NULL; 7137 int i; 7138 7139 if ((res = get_ipd_fs_list(handle, ZONE_IPD, &ipds)) != Z_OK) 7140 return (res); 7141 7142 if ((res = get_ipd_fs_list(handle, ZONE_FS, &fss)) != Z_OK) { 7143 for (i = 0; ipds[i] != NULL; i++) 7144 free(ipds[i]); 7145 free(ipds); 7146 return (res); 7147 } 7148 7149 /* We only have to process the contents file if we have ipds. */ 7150 if (ipds != NULL) { 7151 FILE *fp; 7152 7153 if ((fp = fopen(CONTENTS_FILE, "r")) != NULL) { 7154 char *buf; 7155 char *pkg_warn = NULL; 7156 7157 while ((buf = read_pkg_data(fp)) != NULL) { 7158 res = get_path_pkgs(buf, ipds, fss, &pkgs, 7159 &pkg_cnt, &pkg_warn); 7160 free(buf); 7161 if (res != Z_OK) 7162 break; 7163 } 7164 7165 (void) fclose(fp); 7166 7167 if (pkg_warn != NULL) { 7168 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 7169 "WARNING: package operation in progress " 7170 "on the following packages:\n %s\n"), 7171 pkg_warn); 7172 free(pkg_warn); 7173 } 7174 } 7175 } 7176 7177 for (i = 0; ipds[i] != NULL; i++) 7178 free(ipds[i]); 7179 free(ipds); 7180 7181 for (i = 0; fss[i] != NULL; i++) 7182 free(fss[i]); 7183 free(fss); 7184 7185 if (res != Z_OK) { 7186 free_ipd_pkgs(pkgs, pkg_cnt); 7187 } else { 7188 *pkg_list = pkgs; 7189 *cnt = pkg_cnt; 7190 } 7191 7192 return (res); 7193 } 7194 7195 /* 7196 * Return true if pkg_name is in the list of pkgs that deliver into an 7197 * inherited pkg directory for the zone. 7198 */ 7199 static boolean_t 7200 dir_pkg(char *pkg_name, char **pkg_list, int cnt) 7201 { 7202 int i; 7203 7204 for (i = 0; i < cnt; i++) { 7205 if (strcmp(pkg_name, pkg_list[i]) == 0) 7206 return (B_TRUE); 7207 } 7208 7209 return (B_FALSE); 7210 } 7211 7212 /* 7213 * Keep track of obsoleted patches for this specific patch. We don't need to 7214 * keep track of the patch version since once a patch is obsoleted, all prior 7215 * versions are also obsolete and there won't be any new versions. 7216 */ 7217 static int 7218 add_obs_patch(patch_node_t *patch, char *num, uu_list_pool_t *patches_pool) 7219 { 7220 obs_patch_node_t *obs; 7221 7222 if (patch->obs_patches == NULL) { 7223 if ((patch->obs_patches = uu_list_create(patches_pool, NULL, 7224 0)) == NULL) 7225 return (Z_NOMEM); 7226 } 7227 7228 if ((obs = (obs_patch_node_t *)malloc(sizeof (obs_patch_node_t))) 7229 == NULL) 7230 return (Z_NOMEM); 7231 7232 if ((obs->patch_num = strdup(num)) == NULL) { 7233 free(obs); 7234 return (Z_NOMEM); 7235 } 7236 7237 uu_list_node_init(obs, &obs->link, patches_pool); 7238 (void) uu_list_insert_before(patch->obs_patches, NULL, obs); 7239 7240 return (Z_OK); 7241 } 7242 7243 /* 7244 * Keep track of obsoleted patches. We don't need to keep track of the patch 7245 * version since once a patch is obsoleted, all prior versions are also 7246 * obsolete and there won't be any new versions. 7247 */ 7248 static int 7249 save_obs_patch(char *num, uu_avl_pool_t *patches_pool, uu_avl_t *obs_patches) 7250 { 7251 patch_node_t *patch; 7252 uu_avl_index_t where; 7253 7254 if ((patch = (patch_node_t *)malloc(sizeof (patch_node_t))) == NULL) 7255 return (Z_NOMEM); 7256 7257 if ((patch->patch_num = strdup(num)) == NULL) { 7258 free(patch); 7259 return (Z_NOMEM); 7260 } 7261 7262 patch->patch_vers = NULL; 7263 patch->obs_patches = NULL; 7264 7265 uu_avl_node_init(patch, &patch->patch_node, patches_pool); 7266 7267 if (uu_avl_find(obs_patches, patch, NULL, &where) != NULL) { 7268 free(patch->patch_num); 7269 free(patch); 7270 return (Z_OK); 7271 } 7272 7273 uu_avl_insert(obs_patches, patch, where); 7274 return (Z_OK); 7275 } 7276 7277 /* 7278 * Keep a list of patches for a pkg. If we see a newer version of a patch, 7279 * we only keep track of the newer version. 7280 */ 7281 static void 7282 save_patch(patch_node_t *patch, uu_avl_t *patches_avl) 7283 { 7284 patch_node_t *existing; 7285 uu_avl_index_t where; 7286 7287 /* Check if this is a newer version of a patch we already have. */ 7288 if ((existing = (patch_node_t *)uu_avl_find(patches_avl, patch, NULL, 7289 &where)) != NULL) { 7290 char *endptr; 7291 ulong_t pvers, evers; 7292 7293 pvers = strtoul(patch->patch_vers, &endptr, 10); 7294 evers = strtoul(existing->patch_vers, &endptr, 10); 7295 7296 if (pvers > evers) { 7297 free(existing->patch_vers); 7298 existing->patch_vers = patch->patch_vers; 7299 free(patch->patch_num); 7300 free(patch); 7301 return; 7302 } 7303 } 7304 7305 uu_avl_insert(patches_avl, patch, where); 7306 } 7307 7308 /* 7309 * Check if a patch is on the list of obsoleted patches. We don't need to 7310 * check the patch version since once a patch is obsoleted, all prior versions 7311 * are also obsolete and there won't be any new versions. 7312 */ 7313 static boolean_t 7314 obsolete_patch(patch_node_t *patch, uu_avl_t *obs_patches) 7315 { 7316 uu_avl_index_t where; 7317 7318 if (uu_avl_find(obs_patches, patch, NULL, &where) != NULL) 7319 return (B_TRUE); 7320 7321 return (B_FALSE); 7322 } 7323 7324 /* ARGSUSED */ 7325 static int 7326 patch_node_compare(const void *l_arg, const void *r_arg, void *private) 7327 { 7328 patch_node_t *l = (patch_node_t *)l_arg; 7329 patch_node_t *r = (patch_node_t *)r_arg; 7330 char *endptr; 7331 ulong_t lnum, rnum; 7332 7333 lnum = strtoul(l->patch_num, &endptr, 10); 7334 rnum = strtoul(r->patch_num, &endptr, 10); 7335 7336 if (lnum > rnum) 7337 return (1); 7338 if (lnum < rnum) 7339 return (-1); 7340 return (0); 7341 } 7342 7343 /* 7344 * Parse the patchinfo string for the patch. 7345 * 7346 * We are parsing entries of the form: 7347 * PATCH_INFO_121454-02=Installed: Wed Dec 7 07:13:51 PST 2005 From: mum \ 7348 * Obsoletes: 120777-03 121087-02 119108-07 Requires: 119575-02 \ 7349 * 119255-06 Incompatibles: 7350 * 7351 * A backed out patch will have "backed out\n" as the status. We should 7352 * skip these patches. We also ignore any entries that seem to be 7353 * corrupted. Obsolete patches are saved in the obs_patches parameter 7354 * AVL list. 7355 */ 7356 static int 7357 parse_info(char *patchinfo, uu_avl_pool_t *patches_pool, uu_avl_t *patches_avl, 7358 uu_avl_t *obs_patches, uu_list_pool_t *list_pool) 7359 { 7360 char *p; 7361 char *lastp; 7362 char *ep; 7363 char *pvers; 7364 boolean_t add_info = B_FALSE; 7365 patch_node_t *patch; 7366 7367 if (strlen(patchinfo) < (sizeof (PATCHINFO) - 1)) 7368 return (Z_OK); 7369 7370 /* Skip over "PATCH_INFO_" to get the patch id. */ 7371 p = patchinfo + sizeof (PATCHINFO) - 1; 7372 if ((ep = strchr(p, '=')) == NULL) 7373 return (Z_OK); 7374 7375 *ep++ = '\0'; 7376 7377 /* Ignore all but installed patches. */ 7378 if (strncmp(ep, "Installed:", 10) != 0) 7379 return (Z_OK); 7380 7381 /* remove newline */ 7382 lastp = (ep + strlen(ep) - 1); 7383 if (*lastp == '\n') 7384 *lastp = '\0'; 7385 7386 if ((patch = (patch_node_t *)malloc(sizeof (patch_node_t))) == NULL) 7387 return (Z_NOMEM); 7388 7389 if ((pvers = strchr(p, '-')) != NULL) 7390 *pvers++ = '\0'; 7391 else 7392 pvers = ""; 7393 7394 if ((patch->patch_num = strdup(p)) == NULL) { 7395 free(patch); 7396 return (Z_NOMEM); 7397 } 7398 if ((patch->patch_vers = strdup(pvers)) == NULL) { 7399 free(patch->patch_num); 7400 free(patch); 7401 return (Z_NOMEM); 7402 } 7403 patch->obs_patches = NULL; 7404 7405 uu_avl_node_init(patch, &patch->patch_node, patches_pool); 7406 save_patch(patch, patches_avl); 7407 7408 /* 7409 * Start with the first token. This will probably be "Installed:". 7410 * If we can't tokenize this entry, just return. 7411 */ 7412 if ((p = strtok_r(ep, " ", &lastp)) == NULL) 7413 return (Z_OK); 7414 7415 do { 7416 if (strcmp(p, "Installed:") == 0 || 7417 strcmp(p, "Requires:") == 0 || 7418 strcmp(p, "From:") == 0 || 7419 strcmp(p, "Incompatibles:") == 0) { 7420 add_info = B_FALSE; 7421 continue; 7422 } else if (strcmp(p, "Obsoletes:") == 0) { 7423 add_info = B_TRUE; 7424 continue; 7425 } 7426 7427 if (!add_info) 7428 continue; 7429 7430 if ((pvers = strchr(p, '-')) != NULL) 7431 *pvers = '\0'; 7432 7433 /* 7434 * We save all of the obsolete patches in one big list in the 7435 * obs_patches AVL tree so that we know not to output those as 7436 * part of the sw dependencies. However, we also need to save 7437 * the obsolete patch information for this sepcific patch so 7438 * so that we can do the cross manifest patch checking 7439 * correctly. 7440 */ 7441 if (save_obs_patch(p, patches_pool, obs_patches) != Z_OK) 7442 return (Z_NOMEM); 7443 if (add_obs_patch(patch, p, list_pool) != Z_OK) 7444 return (Z_NOMEM); 7445 } while ((p = strtok_r(NULL, " ", &lastp)) != NULL); 7446 7447 return (Z_OK); 7448 } 7449 7450 /* 7451 * AVL walker callback used to add patch to XML manifest. 7452 * 7453 * PATH_MAX is used in the pkg/patch code as the maximum size for the patch 7454 * number/version string. 7455 */ 7456 static int 7457 add_patch(void *e, void *p) 7458 { 7459 xmlNodePtr node; 7460 xmlNodePtr cur; 7461 char id[PATH_MAX]; 7462 patch_node_t *patch; 7463 patch_parms_t *args; 7464 7465 patch = e; 7466 args = p; 7467 7468 /* skip this patch if it has been obsoleted */ 7469 if (obsolete_patch(patch, args->obs_patches_avl)) 7470 return (UU_WALK_NEXT); 7471 7472 if (patch->patch_vers[0] == '\0') 7473 (void) snprintf(id, sizeof (id), "%s", patch->patch_num); 7474 else 7475 (void) snprintf(id, sizeof (id), "%s-%s", patch->patch_num, 7476 patch->patch_vers); 7477 7478 if ((args->res = operation_prep(args->handle)) != Z_OK) 7479 return (UU_WALK_DONE); 7480 7481 cur = args->handle->zone_dh_cur; 7482 node = xmlNewTextChild(cur, NULL, DTD_ELEM_PATCH, NULL); 7483 if ((args->res = newprop(node, DTD_ATTR_ID, id)) != Z_OK) 7484 return (UU_WALK_DONE); 7485 7486 if (patch->obs_patches != NULL) { 7487 obs_patch_node_t *op; 7488 xmlNodePtr node2; 7489 7490 for (op = uu_list_first(patch->obs_patches); op != NULL; 7491 op = uu_list_next(patch->obs_patches, op)) { 7492 (void) snprintf(id, sizeof (id), "%s", op->patch_num); 7493 node2 = xmlNewTextChild(node, NULL, DTD_ELEM_OBSOLETES, 7494 NULL); 7495 if ((args->res = newprop(node2, DTD_ATTR_ID, id)) 7496 != Z_OK) 7497 return (UU_WALK_DONE); 7498 } 7499 } 7500 7501 return (UU_WALK_NEXT); 7502 } 7503 7504 static void 7505 patch_avl_delete(uu_avl_t *patches_avl) 7506 { 7507 if (patches_avl != NULL) { 7508 patch_node_t *p; 7509 void *cookie = NULL; 7510 7511 while ((p = (patch_node_t *)uu_avl_teardown(patches_avl, 7512 &cookie)) != NULL) { 7513 free(p->patch_num); 7514 free(p->patch_vers); 7515 7516 if (p->obs_patches != NULL) { 7517 obs_patch_node_t *op; 7518 void *cookie2 = NULL; 7519 7520 while ((op = uu_list_teardown(p->obs_patches, 7521 &cookie2)) != NULL) { 7522 free(op->patch_num); 7523 free(op); 7524 } 7525 uu_list_destroy(p->obs_patches); 7526 } 7527 7528 free(p); 7529 } 7530 7531 uu_avl_destroy(patches_avl); 7532 } 7533 } 7534 7535 /* 7536 * Add the unique, highest version patches that are associated with this pkg 7537 * to the sw inventory on the handle. 7538 */ 7539 static int 7540 add_patches(zone_dochandle_t handle, struct zone_pkginfo *infop, 7541 uu_avl_pool_t *patches_pool, uu_avl_t *obs_patches, 7542 uu_list_pool_t *list_pool) 7543 { 7544 int i; 7545 int res; 7546 uu_avl_t *patches_avl; 7547 patch_parms_t args; 7548 7549 if ((patches_avl = uu_avl_create(patches_pool, NULL, UU_DEFAULT)) 7550 == NULL) 7551 return (Z_NOMEM); 7552 7553 for (i = 0; i < infop->zpi_patch_cnt; i++) { 7554 if ((res = parse_info(infop->zpi_patchinfo[i], patches_pool, 7555 patches_avl, obs_patches, list_pool)) != Z_OK) { 7556 patch_avl_delete(patches_avl); 7557 return (res); 7558 } 7559 } 7560 7561 args.obs_patches_avl = obs_patches; 7562 args.handle = handle; 7563 args.res = Z_OK; 7564 7565 (void) uu_avl_walk(patches_avl, add_patch, &args, 0); 7566 7567 patch_avl_delete(patches_avl); 7568 return (args.res); 7569 } 7570 7571 /* 7572 * Keep track of the pkgs we have already processed so that we can quickly 7573 * skip those pkgs while recursively doing dependents. 7574 */ 7575 static boolean_t 7576 pkg_in_manifest(uu_avl_t *saw_pkgs, char *pname, uu_avl_pool_t *pkgs_pool) 7577 { 7578 uu_avl_index_t where; 7579 7580 if (uu_avl_find(saw_pkgs, pname, NULL, &where) == NULL) { 7581 zone_pkg_entry_t *pkg; 7582 7583 /* 7584 * We need to add it. If we don't have memory we just skip 7585 * this pkg since this routine improves performance but the 7586 * algorithm is still correct without it. 7587 */ 7588 if ((pkg = (zone_pkg_entry_t *) 7589 malloc(sizeof (zone_pkg_entry_t))) == NULL) 7590 return (B_FALSE); 7591 7592 if ((pkg->zpe_name = strdup(pname)) == NULL) { 7593 free(pkg); 7594 return (B_FALSE); 7595 } 7596 7597 pkg->zpe_vers = NULL; 7598 pkg->zpe_patches_avl = NULL; 7599 7600 /* Insert pkg into the AVL tree. */ 7601 uu_avl_node_init(pkg, &pkg->zpe_entry, pkgs_pool); 7602 uu_avl_insert(saw_pkgs, pkg, where); 7603 return (B_FALSE); 7604 } 7605 7606 return (B_TRUE); 7607 } 7608 7609 /* 7610 * Add the pkg to the sw inventory on the handle. 7611 */ 7612 static int 7613 add_pkg(zone_dochandle_t handle, char *name, char *version) 7614 { 7615 xmlNodePtr newnode; 7616 xmlNodePtr cur; 7617 int err; 7618 7619 if ((err = operation_prep(handle)) != Z_OK) 7620 return (err); 7621 7622 cur = handle->zone_dh_cur; 7623 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PACKAGE, NULL); 7624 if ((err = newprop(newnode, DTD_ATTR_NAME, name)) != Z_OK) 7625 return (err); 7626 if ((err = newprop(newnode, DTD_ATTR_VERSION, version)) != Z_OK) 7627 return (err); 7628 return (Z_OK); 7629 } 7630 7631 static void 7632 free_pkginfo(struct zone_pkginfo *infop) 7633 { 7634 free(infop->zpi_version); 7635 if (infop->zpi_patch_cnt > 0) { 7636 int i; 7637 7638 for (i = 0; i < infop->zpi_patch_cnt; i++) 7639 free(infop->zpi_patchinfo[i]); 7640 free(infop->zpi_patchinfo); 7641 } 7642 } 7643 7644 /* 7645 * Read the pkginfo file and populate the structure with the data we need 7646 * from this pkg for a sw inventory. 7647 */ 7648 static int 7649 get_pkginfo(char *pkginfo, struct zone_pkginfo *infop) 7650 { 7651 FILE *fp; 7652 char *buf; 7653 int err = 0; 7654 7655 infop->zpi_all_zones = B_FALSE; 7656 infop->zpi_this_zone = B_FALSE; 7657 infop->zpi_version = NULL; 7658 infop->zpi_patch_cnt = 0; 7659 infop->zpi_patchinfo = NULL; 7660 7661 if ((fp = fopen(pkginfo, "r")) == NULL) 7662 return (errno); 7663 7664 while ((buf = read_pkg_data(fp)) != NULL) { 7665 if (strncmp(buf, VERSION, sizeof (VERSION) - 1) == 0) { 7666 int len; 7667 7668 if ((infop->zpi_version = 7669 strdup(buf + sizeof (VERSION) - 1)) == NULL) { 7670 err = ENOMEM; 7671 break; 7672 } 7673 7674 /* remove trailing newline */ 7675 len = strlen(infop->zpi_version); 7676 *(infop->zpi_version + len - 1) = 0; 7677 7678 } else if (strcmp(buf, SUNW_PKG_ALL_ZONES) == 0) { 7679 infop->zpi_all_zones = B_TRUE; 7680 7681 } else if (strcmp(buf, SUNW_PKG_THIS_ZONE) == 0) { 7682 infop->zpi_this_zone = B_TRUE; 7683 7684 } else if (strncmp(buf, PATCHINFO, sizeof (PATCHINFO) - 1) 7685 == 0) { 7686 char **p; 7687 7688 if ((p = (char **)realloc(infop->zpi_patchinfo, 7689 sizeof (char *) * (infop->zpi_patch_cnt + 1))) 7690 == NULL) { 7691 err = ENOMEM; 7692 break; 7693 } 7694 infop->zpi_patchinfo = p; 7695 7696 if ((infop->zpi_patchinfo[infop->zpi_patch_cnt] = 7697 strdup(buf)) == NULL) { 7698 err = ENOMEM; 7699 break; 7700 } 7701 infop->zpi_patch_cnt++; 7702 } 7703 7704 free(buf); 7705 } 7706 7707 free(buf); 7708 7709 if (errno == ENOMEM) { 7710 err = ENOMEM; 7711 /* Clean up anything we did manage to allocate. */ 7712 free_pkginfo(infop); 7713 } 7714 7715 (void) fclose(fp); 7716 7717 return (err); 7718 } 7719 7720 /* 7721 * Add any dependent pkgs to the list. The pkg depend file lists pkg 7722 * dependencies, one per line with an entry that looks like: 7723 * P SUNWcar Core Architecture, (Root) 7724 * See the depend(4) man page. 7725 */ 7726 static int 7727 add_dependents(zone_dochandle_t handle, char *pname, 7728 uu_avl_pool_t *patches_pool, uu_avl_t *obs_patches, 7729 uu_list_pool_t *list_pool, uu_avl_t *saw_pkgs, uu_avl_pool_t *pkgs_pool) 7730 { 7731 int res = Z_OK; 7732 FILE *fp; 7733 char depend[MAXPATHLEN]; 7734 char *buf; 7735 struct stat sbuf; 7736 7737 (void) snprintf(depend, sizeof (depend), "%s/%s/install/depend", 7738 PKG_PATH, pname); 7739 7740 if (stat(depend, &sbuf) == -1 || !S_ISREG(sbuf.st_mode)) 7741 return (Z_OK); 7742 7743 if ((fp = fopen(depend, "r")) == NULL) 7744 return (Z_OK); 7745 7746 while ((buf = read_pkg_data(fp)) != NULL) { 7747 char *deppkg; 7748 char *delims = " \t"; 7749 char pkginfo[MAXPATHLEN]; 7750 struct zone_pkginfo info; 7751 7752 if (*buf != 'P') { 7753 free(buf); 7754 continue; 7755 } 7756 7757 /* Skip past the leading 'P '. */ 7758 if ((deppkg = strtok(buf + 2, delims)) == NULL) { 7759 free(buf); 7760 continue; 7761 } 7762 7763 /* If the pkg is already in the manifest don't add it again. */ 7764 if (pkg_in_manifest(saw_pkgs, deppkg, pkgs_pool)) { 7765 free(buf); 7766 continue; 7767 } 7768 7769 (void) snprintf(pkginfo, sizeof (pkginfo), "%s/%s/pkginfo", 7770 PKG_PATH, deppkg); 7771 7772 if (stat(pkginfo, &sbuf) == -1 || !S_ISREG(sbuf.st_mode)) { 7773 free(buf); 7774 continue; 7775 } 7776 7777 if (get_pkginfo(pkginfo, &info) != 0) { 7778 res = Z_NOMEM; 7779 free(buf); 7780 break; 7781 } 7782 7783 if ((res = add_dependents(handle, deppkg, patches_pool, 7784 obs_patches, list_pool, saw_pkgs, pkgs_pool)) == Z_OK && 7785 (res = add_pkg(handle, deppkg, info.zpi_version)) == Z_OK) { 7786 if (info.zpi_patch_cnt > 0) 7787 res = add_patches(handle, &info, patches_pool, 7788 obs_patches, list_pool); 7789 } 7790 7791 free(buf); 7792 free_pkginfo(&info); 7793 7794 if (res != Z_OK) 7795 break; 7796 } 7797 7798 (void) fclose(fp); 7799 return (res); 7800 } 7801 7802 /* ARGSUSED */ 7803 static int 7804 pkg_entry_compare(const void *l_arg, const void *r_arg, void *private) 7805 { 7806 zone_pkg_entry_t *pkg = (zone_pkg_entry_t *)l_arg; 7807 char *name = (char *)r_arg; 7808 7809 return (strcmp(pkg->zpe_name, name)); 7810 } 7811 7812 static void 7813 pkg_avl_delete(uu_avl_t *pavl) 7814 { 7815 if (pavl != NULL) { 7816 zone_pkg_entry_t *p; 7817 void *cookie = NULL; 7818 7819 while ((p = uu_avl_teardown(pavl, &cookie)) != NULL) { 7820 free(p->zpe_name); 7821 free(p); 7822 } 7823 7824 uu_avl_destroy(pavl); 7825 } 7826 } 7827 7828 /* 7829 * Take a software inventory of the global zone. We need to get the set of 7830 * packages and patches that are on the global zone that the specified 7831 * non-global zone depends on. The packages we need in the inventory are: 7832 * 7833 * - skip the package if SUNW_PKG_THISZONE is 'true' 7834 * otherwise, 7835 * - add the package if 7836 * a) SUNW_PKG_ALLZONES is 'true', 7837 * or 7838 * b) any file delivered by the package is in a file system that is inherited 7839 * from the global zone. 7840 * If the zone does not inherit any file systems (whole root) 7841 * then (b) will be skipped. 7842 * 7843 * For each of the packages that is being added to the inventory, we will also 7844 * add its dependent packages to the inventory. 7845 * 7846 * For each of the packages that is being added to the inventory, we will also 7847 * add all of the associated, unique patches to the inventory. 7848 * 7849 * See the comment for zonecfg_getpkgdata() for compatability restrictions on 7850 * how we must save the XML representation of the software inventory. 7851 */ 7852 static int 7853 zonecfg_sw_inventory(zone_dochandle_t handle) 7854 { 7855 char pkginfo[MAXPATHLEN]; 7856 int res; 7857 struct dirent *dp; 7858 DIR *dirp; 7859 struct stat buf; 7860 struct zone_pkginfo info; 7861 int pkg_cnt = 0; 7862 char **pkgs = NULL; 7863 uu_avl_pool_t *pkgs_pool = NULL; 7864 uu_avl_pool_t *patches_pool = NULL; 7865 uu_list_pool_t *list_pool = NULL; 7866 uu_avl_t *saw_pkgs = NULL; 7867 uu_avl_t *obs_patches = NULL; 7868 7869 if ((pkgs_pool = uu_avl_pool_create("pkgs_pool", 7870 sizeof (zone_pkg_entry_t), offsetof(zone_pkg_entry_t, zpe_entry), 7871 pkg_entry_compare, UU_DEFAULT)) == NULL) { 7872 res = Z_NOMEM; 7873 goto done; 7874 } 7875 7876 if ((saw_pkgs = uu_avl_create(pkgs_pool, NULL, UU_DEFAULT)) == NULL) { 7877 res = Z_NOMEM; 7878 goto done; 7879 } 7880 7881 if ((patches_pool = uu_avl_pool_create("patches_pool", 7882 sizeof (patch_node_t), offsetof(patch_node_t, patch_node), 7883 patch_node_compare, UU_DEFAULT)) == NULL) { 7884 res = Z_NOMEM; 7885 goto done; 7886 } 7887 7888 if ((list_pool = uu_list_pool_create("list_pool", 7889 sizeof (obs_patch_node_t), offsetof(obs_patch_node_t, link), NULL, 7890 UU_DEFAULT)) == NULL) { 7891 res = Z_NOMEM; 7892 goto done; 7893 } 7894 7895 /* 7896 * The obs_patches AVL tree saves all of the obsolete patches so 7897 * that we know not to output those as part of the sw dependencies. 7898 */ 7899 if ((obs_patches = uu_avl_create(patches_pool, NULL, UU_DEFAULT)) 7900 == NULL) { 7901 res = Z_NOMEM; 7902 goto done; 7903 } 7904 7905 if ((res = get_ipd_pkgs(handle, &pkgs, &pkg_cnt)) != Z_OK) { 7906 res = Z_NOMEM; 7907 goto done; 7908 } 7909 7910 if ((dirp = opendir(PKG_PATH)) == NULL) { 7911 res = Z_NOMEM; 7912 goto done; 7913 } 7914 7915 while ((dp = readdir(dirp)) != (struct dirent *)0) { 7916 if (strcmp(dp->d_name, ".") == 0 || 7917 strcmp(dp->d_name, "..") == 0) 7918 continue; 7919 7920 (void) snprintf(pkginfo, sizeof (pkginfo), "%s/%s/pkginfo", 7921 PKG_PATH, dp->d_name); 7922 7923 if (stat(pkginfo, &buf) == -1 || !S_ISREG(buf.st_mode)) 7924 continue; 7925 7926 if (get_pkginfo(pkginfo, &info) != 0) { 7927 res = Z_NOMEM; 7928 break; 7929 } 7930 7931 if (!info.zpi_this_zone && 7932 (info.zpi_all_zones || 7933 dir_pkg(dp->d_name, pkgs, pkg_cnt)) && 7934 !pkg_in_manifest(saw_pkgs, dp->d_name, pkgs_pool)) { 7935 /* 7936 * Add dependents first so any patches will get 7937 * associated with the right pkg in the xml file. 7938 */ 7939 if ((res = add_dependents(handle, dp->d_name, 7940 patches_pool, obs_patches, list_pool, saw_pkgs, 7941 pkgs_pool)) == Z_OK && 7942 (res = add_pkg(handle, dp->d_name, 7943 info.zpi_version)) == Z_OK) { 7944 if (info.zpi_patch_cnt > 0) 7945 res = add_patches(handle, &info, 7946 patches_pool, obs_patches, 7947 list_pool); 7948 } 7949 } 7950 7951 free_pkginfo(&info); 7952 7953 if (res != Z_OK) 7954 break; 7955 } 7956 7957 (void) closedir(dirp); 7958 7959 done: 7960 pkg_avl_delete(saw_pkgs); 7961 patch_avl_delete(obs_patches); 7962 if (pkgs_pool != NULL) 7963 uu_avl_pool_destroy(pkgs_pool); 7964 if (patches_pool != NULL) 7965 uu_avl_pool_destroy(patches_pool); 7966 if (list_pool != NULL) 7967 uu_list_pool_destroy(list_pool); 7968 free_ipd_pkgs(pkgs, pkg_cnt); 7969 7970 if (res == Z_OK) 7971 handle->zone_dh_sw_inv = B_TRUE; 7972 7973 return (res); 7974 } 7975 7976 /* 7977 * zonecfg_devwalk call-back function used during detach to generate the 7978 * dev info in the manifest. 7979 */ 7980 static int 7981 get_detach_dev_entry(const char *name, uid_t uid, gid_t gid, mode_t mode, 7982 const char *acl, void *hdl) 7983 { 7984 zone_dochandle_t handle = (zone_dochandle_t)hdl; 7985 xmlNodePtr newnode; 7986 xmlNodePtr cur; 7987 int err; 7988 char buf[128]; 7989 7990 if ((err = operation_prep(handle)) != Z_OK) 7991 return (err); 7992 7993 cur = handle->zone_dh_cur; 7994 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEV_PERM, NULL); 7995 if ((err = newprop(newnode, DTD_ATTR_NAME, (char *)name)) != Z_OK) 7996 return (err); 7997 (void) snprintf(buf, sizeof (buf), "%lu", uid); 7998 if ((err = newprop(newnode, DTD_ATTR_UID, buf)) != Z_OK) 7999 return (err); 8000 (void) snprintf(buf, sizeof (buf), "%lu", gid); 8001 if ((err = newprop(newnode, DTD_ATTR_GID, buf)) != Z_OK) 8002 return (err); 8003 (void) snprintf(buf, sizeof (buf), "%o", mode); 8004 if ((err = newprop(newnode, DTD_ATTR_MODE, buf)) != Z_OK) 8005 return (err); 8006 if ((err = newprop(newnode, DTD_ATTR_ACL, (char *)acl)) != Z_OK) 8007 return (err); 8008 return (Z_OK); 8009 } 8010 8011 /* 8012 * Get the information required to support detaching a zone. This is 8013 * called on the source system when detaching (the detaching parameter should 8014 * be set to true) and on the destination system before attaching (the 8015 * detaching parameter should be false). 8016 * 8017 * For native Solaris zones, the detach/attach process involves validating 8018 * that the software on the global zone can support the zone when we attach. 8019 * To do this we take a software inventory of the global zone. We also 8020 * have to keep track of the device configuration so that we can properly 8021 * recreate it on the destination. 8022 */ 8023 int 8024 zonecfg_get_detach_info(zone_dochandle_t handle, boolean_t detaching) 8025 { 8026 int res; 8027 8028 if ((res = zonecfg_sw_inventory(handle)) != Z_OK) 8029 return (res); 8030 8031 if (detaching) 8032 res = zonecfg_devwalk(handle, get_detach_dev_entry, handle); 8033 8034 return (res); 8035 } 8036