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