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