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