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 myzoneid = getzoneid(); 4987 int ret; 4988 4989 /* 4990 * If we're running within a zone, then the default brand is the 4991 * current zone's brand. 4992 */ 4993 if (myzoneid != GLOBAL_ZONEID) { 4994 ret = zone_getattr(myzoneid, ZONE_ATTR_BRAND, brand, brandsize); 4995 if (ret < 0) 4996 return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL); 4997 return (Z_OK); 4998 } 4999 5000 if ((handle = zonecfg_init_handle()) == NULL) 5001 return (Z_NOMEM); 5002 if ((ret = zonecfg_get_handle("SUNWdefault", handle)) == Z_OK) { 5003 ret = i_zonecfg_get_brand(handle, brand, brandsize, B_TRUE); 5004 zonecfg_fini_handle(handle); 5005 return (ret); 5006 } 5007 return (ret); 5008 } 5009 5010 int 5011 zonecfg_default_privset(priv_set_t *privs, const char *curr_iptype) 5012 { 5013 priv_lists_t *plp; 5014 char buf[MAXNAMELEN]; 5015 int ret; 5016 5017 if ((ret = zonecfg_default_brand(buf, sizeof (buf))) != Z_OK) 5018 return (ret); 5019 if ((ret = priv_lists_create(NULL, buf, &plp, curr_iptype)) != Z_OK) 5020 return (ret); 5021 ret = get_default_privset(privs, plp); 5022 priv_lists_destroy(plp); 5023 return (ret); 5024 } 5025 5026 void 5027 append_priv_token(char *priv, char *str, size_t strlen) 5028 { 5029 if (*str != '\0') 5030 (void) strlcat(str, TOKEN_PRIV_STR, strlen); 5031 (void) strlcat(str, priv, strlen); 5032 } 5033 5034 /* 5035 * Verify that the supplied string is a valid privilege limit set for a 5036 * non-global zone. This string must not only be acceptable to 5037 * priv_str_to_set(3C) which parses it, but it also must resolve to a 5038 * privilege set that includes certain required privileges and lacks 5039 * certain prohibited privileges. 5040 */ 5041 static int 5042 verify_privset(char *privbuf, priv_set_t *privs, char **privname, 5043 boolean_t add_default, priv_lists_t *plp) 5044 { 5045 priv_node_t *pnp; 5046 char *tmp, *cp, *lasts; 5047 size_t len; 5048 priv_set_t *mergeset; 5049 const char *token; 5050 5051 /* 5052 * The verification of the privilege string occurs in several 5053 * phases. In the first phase, the supplied string is scanned for 5054 * the ZONE_TOKEN token which is not support as part of the 5055 * "limitpriv" property. 5056 * 5057 * Duplicate the supplied privilege string since strtok_r(3C) 5058 * tokenizes its input by null-terminating the tokens. 5059 */ 5060 if ((tmp = strdup(privbuf)) == NULL) 5061 return (Z_NOMEM); 5062 for (cp = strtok_r(tmp, TOKEN_PRIV_STR, &lasts); cp != NULL; 5063 cp = strtok_r(NULL, TOKEN_PRIV_STR, &lasts)) { 5064 if (strcmp(cp, ZONE_TOKEN) == 0) { 5065 free(tmp); 5066 if ((*privname = strdup(ZONE_TOKEN)) == NULL) 5067 return (Z_NOMEM); 5068 else 5069 return (Z_PRIV_UNKNOWN); 5070 } 5071 } 5072 free(tmp); 5073 5074 if (add_default) { 5075 /* 5076 * If DEFAULT_TOKEN was specified, a string needs to be 5077 * built containing the privileges from the default, safe 5078 * set along with those of the "limitpriv" property. 5079 */ 5080 len = strlen(privbuf) + sizeof (BASIC_TOKEN) + 2; 5081 5082 for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next) 5083 len += strlen(pnp->pn_priv) + 1; 5084 tmp = alloca(len); 5085 *tmp = '\0'; 5086 5087 append_priv_token(BASIC_TOKEN, tmp, len); 5088 for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next) 5089 append_priv_token(pnp->pn_priv, tmp, len); 5090 (void) strlcat(tmp, TOKEN_PRIV_STR, len); 5091 (void) strlcat(tmp, privbuf, len); 5092 } else { 5093 tmp = privbuf; 5094 } 5095 5096 5097 /* 5098 * In the next phase, attempt to convert the merged privilege 5099 * string into a privilege set. In the case of an error, either 5100 * there was a memory allocation failure or there was an invalid 5101 * privilege token in the string. In either case, return an 5102 * appropriate error code but in the event of an invalid token, 5103 * allocate a string containing its name and return that back to 5104 * the caller. 5105 */ 5106 mergeset = priv_str_to_set(tmp, TOKEN_PRIV_STR, &token); 5107 if (mergeset == NULL) { 5108 if (token == NULL) 5109 return (Z_NOMEM); 5110 if ((cp = strchr(token, TOKEN_PRIV_CHAR)) != NULL) 5111 *cp = '\0'; 5112 if ((*privname = strdup(token)) == NULL) 5113 return (Z_NOMEM); 5114 else 5115 return (Z_PRIV_UNKNOWN); 5116 } 5117 5118 /* 5119 * Next, verify that none of the prohibited zone privileges are 5120 * present in the merged privilege set. 5121 */ 5122 for (pnp = plp->pl_prohibited; pnp != NULL; pnp = pnp->pn_next) { 5123 if (priv_ismember(mergeset, pnp->pn_priv)) { 5124 priv_freeset(mergeset); 5125 if ((*privname = strdup(pnp->pn_priv)) == NULL) 5126 return (Z_NOMEM); 5127 else 5128 return (Z_PRIV_PROHIBITED); 5129 } 5130 } 5131 5132 /* 5133 * Finally, verify that all of the required zone privileges are 5134 * present in the merged privilege set. 5135 */ 5136 for (pnp = plp->pl_required; pnp != NULL; pnp = pnp->pn_next) { 5137 if (!priv_ismember(mergeset, pnp->pn_priv)) { 5138 priv_freeset(mergeset); 5139 if ((*privname = strdup(pnp->pn_priv)) == NULL) 5140 return (Z_NOMEM); 5141 else 5142 return (Z_PRIV_REQUIRED); 5143 } 5144 } 5145 5146 priv_copyset(mergeset, privs); 5147 priv_freeset(mergeset); 5148 return (Z_OK); 5149 } 5150 5151 /* 5152 * Fill in the supplied privilege set with either the default, safe set of 5153 * privileges suitable for a non-global zone, or one based on the 5154 * "limitpriv" property in the zone's configuration. 5155 * 5156 * In the event of an invalid privilege specification in the 5157 * configuration, a string is allocated and returned containing the 5158 * "privilege" causing the issue. It is the caller's responsibility to 5159 * free this memory when it is done with it. 5160 */ 5161 int 5162 zonecfg_get_privset(zone_dochandle_t handle, priv_set_t *privs, 5163 char **privname) 5164 { 5165 priv_lists_t *plp; 5166 char *cp, *limitpriv = NULL; 5167 int err, limitlen; 5168 zone_iptype_t iptype; 5169 const char *curr_iptype; 5170 5171 /* 5172 * Attempt to lookup the "limitpriv" property. If it does not 5173 * exist or matches the string DEFAULT_TOKEN exactly, then the 5174 * default, safe privilege set is returned. 5175 */ 5176 if ((err = zonecfg_get_limitpriv(handle, &limitpriv)) != Z_OK) 5177 return (err); 5178 5179 if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK) 5180 return (err); 5181 5182 switch (iptype) { 5183 case ZS_SHARED: 5184 curr_iptype = "shared"; 5185 break; 5186 case ZS_EXCLUSIVE: 5187 curr_iptype = "exclusive"; 5188 break; 5189 } 5190 5191 if ((err = priv_lists_create(handle, NULL, &plp, curr_iptype)) != Z_OK) 5192 return (err); 5193 5194 limitlen = strlen(limitpriv); 5195 if (limitlen == 0 || strcmp(limitpriv, DEFAULT_TOKEN) == 0) { 5196 free(limitpriv); 5197 err = get_default_privset(privs, plp); 5198 priv_lists_destroy(plp); 5199 return (err); 5200 } 5201 5202 /* 5203 * Check if the string DEFAULT_TOKEN is the first token in a list 5204 * of privileges. 5205 */ 5206 cp = strchr(limitpriv, TOKEN_PRIV_CHAR); 5207 if (cp != NULL && 5208 strncmp(limitpriv, DEFAULT_TOKEN, cp - limitpriv) == 0) 5209 err = verify_privset(cp + 1, privs, privname, B_TRUE, plp); 5210 else 5211 err = verify_privset(limitpriv, privs, privname, B_FALSE, plp); 5212 5213 free(limitpriv); 5214 priv_lists_destroy(plp); 5215 return (err); 5216 } 5217 5218 int 5219 zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz) 5220 { 5221 zone_dochandle_t handle; 5222 boolean_t found = B_FALSE; 5223 struct zoneent *ze; 5224 FILE *cookie; 5225 int err; 5226 char *cp; 5227 5228 if (zone_name == NULL) 5229 return (Z_INVAL); 5230 5231 (void) strlcpy(zonepath, zonecfg_root, rp_sz); 5232 cp = zonepath + strlen(zonepath); 5233 while (cp > zonepath && cp[-1] == '/') 5234 *--cp = '\0'; 5235 5236 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) { 5237 if (zonepath[0] == '\0') 5238 (void) strlcpy(zonepath, "/", rp_sz); 5239 return (Z_OK); 5240 } 5241 5242 /* 5243 * First check the index file. Because older versions did not have 5244 * a copy of the zone path, allow for it to be zero length, in which 5245 * case we ignore this result and fall back to the XML files. 5246 */ 5247 cookie = setzoneent(); 5248 while ((ze = getzoneent_private(cookie)) != NULL) { 5249 if (strcmp(ze->zone_name, zone_name) == 0) { 5250 found = B_TRUE; 5251 if (ze->zone_path[0] != '\0') 5252 (void) strlcpy(cp, ze->zone_path, 5253 rp_sz - (cp - zonepath)); 5254 } 5255 free(ze); 5256 if (found) 5257 break; 5258 } 5259 endzoneent(cookie); 5260 if (found && *cp != '\0') 5261 return (Z_OK); 5262 5263 /* Fall back to the XML files. */ 5264 if ((handle = zonecfg_init_handle()) == NULL) 5265 return (Z_NOMEM); 5266 5267 /* 5268 * Check the snapshot first: if a zone is running, its zonepath 5269 * may have changed. 5270 */ 5271 if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) { 5272 if ((err = zonecfg_get_handle(zone_name, handle)) != Z_OK) { 5273 zonecfg_fini_handle(handle); 5274 return (err); 5275 } 5276 } 5277 err = zonecfg_get_zonepath(handle, zonepath, rp_sz); 5278 zonecfg_fini_handle(handle); 5279 return (err); 5280 } 5281 5282 int 5283 zone_get_rootpath(char *zone_name, char *rootpath, size_t rp_sz) 5284 { 5285 int err; 5286 5287 /* This function makes sense for non-global zones only. */ 5288 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) 5289 return (Z_BOGUS_ZONE_NAME); 5290 if ((err = zone_get_zonepath(zone_name, rootpath, rp_sz)) != Z_OK) 5291 return (err); 5292 if (strlcat(rootpath, "/root", rp_sz) >= rp_sz) 5293 return (Z_TOO_BIG); 5294 return (Z_OK); 5295 } 5296 5297 int 5298 zone_get_brand(char *zone_name, char *brandname, size_t rp_sz) 5299 { 5300 int err; 5301 zone_dochandle_t handle; 5302 char myzone[MAXNAMELEN]; 5303 int myzoneid = getzoneid(); 5304 5305 /* 5306 * If we are not in the global zone, then we don't have the zone 5307 * .xml files with the brand name available. Thus, we are going to 5308 * have to ask the kernel for the information. 5309 */ 5310 if (myzoneid != GLOBAL_ZONEID) { 5311 if (is_system_labeled()) { 5312 (void) strlcpy(brandname, NATIVE_BRAND_NAME, rp_sz); 5313 return (Z_OK); 5314 } 5315 if (zone_getattr(myzoneid, ZONE_ATTR_NAME, myzone, 5316 sizeof (myzone)) < 0) 5317 return (Z_NO_ZONE); 5318 if (!zonecfg_is_scratch(myzone)) { 5319 if (strncmp(zone_name, myzone, MAXNAMELEN) != 0) 5320 return (Z_NO_ZONE); 5321 } 5322 err = zone_getattr(myzoneid, ZONE_ATTR_BRAND, brandname, rp_sz); 5323 if (err < 0) 5324 return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL); 5325 5326 return (Z_OK); 5327 } 5328 5329 if (strcmp(zone_name, "global") == 0) 5330 return (zonecfg_default_brand(brandname, rp_sz)); 5331 5332 if ((handle = zonecfg_init_handle()) == NULL) 5333 return (Z_NOMEM); 5334 5335 err = zonecfg_get_handle((char *)zone_name, handle); 5336 if (err == Z_OK) 5337 err = zonecfg_get_brand(handle, brandname, rp_sz); 5338 5339 zonecfg_fini_handle(handle); 5340 return (err); 5341 } 5342 5343 /* 5344 * Return the appropriate root for the active /dev. 5345 * For normal zone, the path is $ZONEPATH/root; 5346 * for scratch zone, the dev path is $ZONEPATH/lu. 5347 */ 5348 int 5349 zone_get_devroot(char *zone_name, char *devroot, size_t rp_sz) 5350 { 5351 int err; 5352 char *suffix; 5353 zone_state_t state; 5354 5355 /* This function makes sense for non-global zones only. */ 5356 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) 5357 return (Z_BOGUS_ZONE_NAME); 5358 if ((err = zone_get_zonepath(zone_name, devroot, rp_sz)) != Z_OK) 5359 return (err); 5360 5361 if (zone_get_state(zone_name, &state) == Z_OK && 5362 state == ZONE_STATE_MOUNTED) 5363 suffix = "/lu"; 5364 else 5365 suffix = "/root"; 5366 if (strlcat(devroot, suffix, rp_sz) >= rp_sz) 5367 return (Z_TOO_BIG); 5368 return (Z_OK); 5369 } 5370 5371 static zone_state_t 5372 kernel_state_to_user_state(zoneid_t zoneid, zone_status_t kernel_state) 5373 { 5374 char zoneroot[MAXPATHLEN]; 5375 size_t zlen; 5376 5377 assert(kernel_state <= ZONE_MAX_STATE); 5378 switch (kernel_state) { 5379 case ZONE_IS_UNINITIALIZED: 5380 case ZONE_IS_INITIALIZED: 5381 /* The kernel will not return these two states */ 5382 return (ZONE_STATE_READY); 5383 case ZONE_IS_READY: 5384 /* 5385 * If the zone's root is mounted on $ZONEPATH/lu, then 5386 * it's a mounted scratch zone. 5387 */ 5388 if (zone_getattr(zoneid, ZONE_ATTR_ROOT, zoneroot, 5389 sizeof (zoneroot)) >= 0) { 5390 zlen = strlen(zoneroot); 5391 if (zlen > 3 && 5392 strcmp(zoneroot + zlen - 3, "/lu") == 0) 5393 return (ZONE_STATE_MOUNTED); 5394 } 5395 return (ZONE_STATE_READY); 5396 case ZONE_IS_BOOTING: 5397 case ZONE_IS_RUNNING: 5398 return (ZONE_STATE_RUNNING); 5399 case ZONE_IS_SHUTTING_DOWN: 5400 case ZONE_IS_EMPTY: 5401 return (ZONE_STATE_SHUTTING_DOWN); 5402 case ZONE_IS_DOWN: 5403 case ZONE_IS_DYING: 5404 case ZONE_IS_DEAD: 5405 default: 5406 return (ZONE_STATE_DOWN); 5407 } 5408 /* NOTREACHED */ 5409 } 5410 5411 int 5412 zone_get_state(char *zone_name, zone_state_t *state_num) 5413 { 5414 zone_status_t status; 5415 zoneid_t zone_id; 5416 struct zoneent *ze; 5417 boolean_t found = B_FALSE; 5418 FILE *cookie; 5419 char kernzone[ZONENAME_MAX]; 5420 FILE *fp; 5421 5422 if (zone_name == NULL) 5423 return (Z_INVAL); 5424 5425 /* 5426 * If we're looking at an alternate root, then we need to query the 5427 * kernel using the scratch zone name. 5428 */ 5429 zone_id = -1; 5430 if (*zonecfg_root != '\0' && !zonecfg_is_scratch(zone_name)) { 5431 if ((fp = zonecfg_open_scratch("", B_FALSE)) != NULL) { 5432 if (zonecfg_find_scratch(fp, zone_name, zonecfg_root, 5433 kernzone, sizeof (kernzone)) == 0) 5434 zone_id = getzoneidbyname(kernzone); 5435 zonecfg_close_scratch(fp); 5436 } 5437 } else { 5438 zone_id = getzoneidbyname(zone_name); 5439 } 5440 5441 /* check to see if zone is running */ 5442 if (zone_id != -1 && 5443 zone_getattr(zone_id, ZONE_ATTR_STATUS, &status, 5444 sizeof (status)) >= 0) { 5445 *state_num = kernel_state_to_user_state(zone_id, status); 5446 return (Z_OK); 5447 } 5448 5449 cookie = setzoneent(); 5450 while ((ze = getzoneent_private(cookie)) != NULL) { 5451 if (strcmp(ze->zone_name, zone_name) == 0) { 5452 found = B_TRUE; 5453 *state_num = ze->zone_state; 5454 } 5455 free(ze); 5456 if (found) 5457 break; 5458 } 5459 endzoneent(cookie); 5460 return ((found) ? Z_OK : Z_NO_ZONE); 5461 } 5462 5463 int 5464 zone_set_state(char *zone, zone_state_t state) 5465 { 5466 struct zoneent ze; 5467 5468 if (state != ZONE_STATE_CONFIGURED && state != ZONE_STATE_INSTALLED && 5469 state != ZONE_STATE_INCOMPLETE) 5470 return (Z_INVAL); 5471 5472 bzero(&ze, sizeof (ze)); 5473 (void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name)); 5474 ze.zone_state = state; 5475 (void) strlcpy(ze.zone_path, "", sizeof (ze.zone_path)); 5476 return (putzoneent(&ze, PZE_MODIFY)); 5477 } 5478 5479 /* 5480 * Get id (if any) for specified zone. There are four possible outcomes: 5481 * - If the string corresponds to the numeric id of an active (booted) 5482 * zone, sets *zip to the zone id and returns 0. 5483 * - If the string corresponds to the name of an active (booted) zone, 5484 * sets *zip to the zone id and returns 0. 5485 * - If the string is a name in the configuration but is not booted, 5486 * sets *zip to ZONE_ID_UNDEFINED and returns 0. 5487 * - Otherwise, leaves *zip unchanged and returns -1. 5488 * 5489 * This function acts as an auxiliary filter on the function of the same 5490 * name in libc; the linker binds to this version if libzonecfg exists, 5491 * and the libc version if it doesn't. Any changes to this version of 5492 * the function should probably be reflected in the libc version as well. 5493 */ 5494 int 5495 zone_get_id(const char *str, zoneid_t *zip) 5496 { 5497 zone_dochandle_t hdl; 5498 zoneid_t zoneid; 5499 char *cp; 5500 int err; 5501 5502 /* first try looking for active zone by id */ 5503 errno = 0; 5504 zoneid = (zoneid_t)strtol(str, &cp, 0); 5505 if (errno == 0 && cp != str && *cp == '\0' && 5506 getzonenamebyid(zoneid, NULL, 0) != -1) { 5507 *zip = zoneid; 5508 return (0); 5509 } 5510 5511 /* then look for active zone by name */ 5512 if ((zoneid = getzoneidbyname(str)) != -1) { 5513 *zip = zoneid; 5514 return (0); 5515 } 5516 5517 /* if in global zone, try looking up name in configuration database */ 5518 if (getzoneid() != GLOBAL_ZONEID || 5519 (hdl = zonecfg_init_handle()) == NULL) 5520 return (-1); 5521 5522 if (zonecfg_get_handle(str, hdl) == Z_OK) { 5523 /* zone exists but isn't active */ 5524 *zip = ZONE_ID_UNDEFINED; 5525 err = 0; 5526 } else { 5527 err = -1; 5528 } 5529 5530 zonecfg_fini_handle(hdl); 5531 return (err); 5532 } 5533 5534 char * 5535 zone_state_str(zone_state_t state_num) 5536 { 5537 switch (state_num) { 5538 case ZONE_STATE_CONFIGURED: 5539 return (ZONE_STATE_STR_CONFIGURED); 5540 case ZONE_STATE_INCOMPLETE: 5541 return (ZONE_STATE_STR_INCOMPLETE); 5542 case ZONE_STATE_INSTALLED: 5543 return (ZONE_STATE_STR_INSTALLED); 5544 case ZONE_STATE_READY: 5545 return (ZONE_STATE_STR_READY); 5546 case ZONE_STATE_MOUNTED: 5547 return (ZONE_STATE_STR_MOUNTED); 5548 case ZONE_STATE_RUNNING: 5549 return (ZONE_STATE_STR_RUNNING); 5550 case ZONE_STATE_SHUTTING_DOWN: 5551 return (ZONE_STATE_STR_SHUTTING_DOWN); 5552 case ZONE_STATE_DOWN: 5553 return (ZONE_STATE_STR_DOWN); 5554 default: 5555 return ("unknown"); 5556 } 5557 } 5558 5559 /* 5560 * Given a UUID value, find an associated zone name. This is intended to be 5561 * used by callers who set up some 'default' name (corresponding to the 5562 * expected name for the zone) in the zonename buffer, and thus the function 5563 * doesn't touch this buffer on failure. 5564 */ 5565 int 5566 zonecfg_get_name_by_uuid(const uuid_t uuidin, char *zonename, size_t namelen) 5567 { 5568 FILE *fp; 5569 struct zoneent *ze; 5570 uchar_t *uuid; 5571 5572 /* 5573 * A small amount of subterfuge via casts is necessary here because 5574 * libuuid doesn't use const correctly, but we don't want to export 5575 * this brokenness to our clients. 5576 */ 5577 uuid = (uchar_t *)uuidin; 5578 if (uuid_is_null(uuid)) 5579 return (Z_NO_ZONE); 5580 if ((fp = setzoneent()) == NULL) 5581 return (Z_NO_ZONE); 5582 while ((ze = getzoneent_private(fp)) != NULL) { 5583 if (uuid_compare(uuid, ze->zone_uuid) == 0) 5584 break; 5585 free(ze); 5586 } 5587 endzoneent(fp); 5588 if (ze != NULL) { 5589 (void) strlcpy(zonename, ze->zone_name, namelen); 5590 free(ze); 5591 return (Z_OK); 5592 } else { 5593 return (Z_NO_ZONE); 5594 } 5595 } 5596 5597 /* 5598 * Given a zone name, get its UUID. Returns a "NULL" UUID value if the zone 5599 * exists but the file doesn't have a value set yet. Returns an error if the 5600 * zone cannot be located. 5601 */ 5602 int 5603 zonecfg_get_uuid(const char *zonename, uuid_t uuid) 5604 { 5605 FILE *fp; 5606 struct zoneent *ze; 5607 5608 if ((fp = setzoneent()) == NULL) 5609 return (Z_NO_ZONE); 5610 while ((ze = getzoneent_private(fp)) != NULL) { 5611 if (strcmp(ze->zone_name, zonename) == 0) 5612 break; 5613 free(ze); 5614 } 5615 endzoneent(fp); 5616 if (ze != NULL) { 5617 uuid_copy(uuid, ze->zone_uuid); 5618 free(ze); 5619 return (Z_OK); 5620 } else { 5621 return (Z_NO_ZONE); 5622 } 5623 } 5624 5625 /* 5626 * File-system convenience functions. 5627 */ 5628 boolean_t 5629 zonecfg_valid_fs_type(const char *type) 5630 { 5631 /* 5632 * We already know which FS types don't work. 5633 */ 5634 if (strcmp(type, "proc") == 0 || 5635 strcmp(type, "mntfs") == 0 || 5636 strcmp(type, "autofs") == 0 || 5637 strncmp(type, "nfs", sizeof ("nfs") - 1) == 0 || 5638 strcmp(type, "cachefs") == 0) 5639 return (B_FALSE); 5640 /* 5641 * The caller may do more detailed verification to make sure other 5642 * aspects of this filesystem type make sense. 5643 */ 5644 return (B_TRUE); 5645 } 5646 5647 /* 5648 * Generally uninteresting rctl convenience functions. 5649 */ 5650 5651 int 5652 zonecfg_construct_rctlblk(const struct zone_rctlvaltab *rctlval, 5653 rctlblk_t *rctlblk) 5654 { 5655 unsigned long long ull; 5656 char *endp; 5657 rctl_priv_t priv; 5658 rctl_qty_t limit; 5659 uint_t action; 5660 5661 /* Get the privilege */ 5662 if (strcmp(rctlval->zone_rctlval_priv, "basic") == 0) { 5663 priv = RCPRIV_BASIC; 5664 } else if (strcmp(rctlval->zone_rctlval_priv, "privileged") == 0) { 5665 priv = RCPRIV_PRIVILEGED; 5666 } else { 5667 /* Invalid privilege */ 5668 return (Z_INVAL); 5669 } 5670 5671 /* deal with negative input; strtoull(3c) doesn't do what we want */ 5672 if (rctlval->zone_rctlval_limit[0] == '-') 5673 return (Z_INVAL); 5674 /* Get the limit */ 5675 errno = 0; 5676 ull = strtoull(rctlval->zone_rctlval_limit, &endp, 0); 5677 if (errno != 0 || *endp != '\0') { 5678 /* parse failed */ 5679 return (Z_INVAL); 5680 } 5681 limit = (rctl_qty_t)ull; 5682 5683 /* Get the action */ 5684 if (strcmp(rctlval->zone_rctlval_action, "none") == 0) { 5685 action = RCTL_LOCAL_NOACTION; 5686 } else if (strcmp(rctlval->zone_rctlval_action, "signal") == 0) { 5687 action = RCTL_LOCAL_SIGNAL; 5688 } else if (strcmp(rctlval->zone_rctlval_action, "deny") == 0) { 5689 action = RCTL_LOCAL_DENY; 5690 } else { 5691 /* Invalid Action */ 5692 return (Z_INVAL); 5693 } 5694 rctlblk_set_local_action(rctlblk, action, 0); 5695 rctlblk_set_privilege(rctlblk, priv); 5696 rctlblk_set_value(rctlblk, limit); 5697 return (Z_OK); 5698 } 5699 5700 static int 5701 rctl_check(const char *rctlname, void *arg) 5702 { 5703 const char *attrname = arg; 5704 5705 /* 5706 * Returning 1 here is our signal to zonecfg_is_rctl() that it is 5707 * indeed an rctl name recognized by the system. 5708 */ 5709 return (strcmp(rctlname, attrname) == 0 ? 1 : 0); 5710 } 5711 5712 boolean_t 5713 zonecfg_is_rctl(const char *name) 5714 { 5715 return (rctl_walk(rctl_check, (void *)name) == 1); 5716 } 5717 5718 boolean_t 5719 zonecfg_valid_rctlname(const char *name) 5720 { 5721 const char *c; 5722 5723 if (strncmp(name, "zone.", sizeof ("zone.") - 1) != 0) 5724 return (B_FALSE); 5725 if (strlen(name) == sizeof ("zone.") - 1) 5726 return (B_FALSE); 5727 for (c = name + sizeof ("zone.") - 1; *c != '\0'; c++) { 5728 if (!isalpha(*c) && *c != '-') 5729 return (B_FALSE); 5730 } 5731 return (B_TRUE); 5732 } 5733 5734 boolean_t 5735 zonecfg_valid_rctlblk(const rctlblk_t *rctlblk) 5736 { 5737 rctl_priv_t priv = rctlblk_get_privilege((rctlblk_t *)rctlblk); 5738 uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL); 5739 5740 if (priv != RCPRIV_PRIVILEGED) 5741 return (B_FALSE); 5742 if (action != RCTL_LOCAL_NOACTION && action != RCTL_LOCAL_DENY) 5743 return (B_FALSE); 5744 return (B_TRUE); 5745 } 5746 5747 boolean_t 5748 zonecfg_valid_rctl(const char *name, const rctlblk_t *rctlblk) 5749 { 5750 rctlblk_t *current, *next; 5751 rctl_qty_t limit = rctlblk_get_value((rctlblk_t *)rctlblk); 5752 uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL); 5753 uint_t global_flags; 5754 5755 if (!zonecfg_valid_rctlblk(rctlblk)) 5756 return (B_FALSE); 5757 if (!zonecfg_valid_rctlname(name)) 5758 return (B_FALSE); 5759 5760 current = alloca(rctlblk_size()); 5761 if (getrctl(name, NULL, current, RCTL_FIRST) != 0) 5762 return (B_TRUE); /* not an rctl on this system */ 5763 /* 5764 * Make sure the proposed value isn't greater than the current system 5765 * value. 5766 */ 5767 next = alloca(rctlblk_size()); 5768 while (rctlblk_get_privilege(current) != RCPRIV_SYSTEM) { 5769 rctlblk_t *tmp; 5770 5771 if (getrctl(name, current, next, RCTL_NEXT) != 0) 5772 return (B_FALSE); /* shouldn't happen */ 5773 tmp = current; 5774 current = next; 5775 next = tmp; 5776 } 5777 if (limit > rctlblk_get_value(current)) 5778 return (B_FALSE); 5779 5780 /* 5781 * Make sure the proposed action is allowed. 5782 */ 5783 global_flags = rctlblk_get_global_flags(current); 5784 if ((global_flags & RCTL_GLOBAL_DENY_NEVER) && 5785 action == RCTL_LOCAL_DENY) 5786 return (B_FALSE); 5787 if ((global_flags & RCTL_GLOBAL_DENY_ALWAYS) && 5788 action == RCTL_LOCAL_NOACTION) 5789 return (B_FALSE); 5790 5791 return (B_TRUE); 5792 } 5793 5794 /* 5795 * There is always a race condition between reading the initial copy of 5796 * a zones state and its state changing. We address this by providing 5797 * zonecfg_notify_critical_enter and zonecfg_noticy_critical_exit functions. 5798 * When zonecfg_critical_enter is called, sets the state field to LOCKED 5799 * and aquires biglock. Biglock protects against other threads executing 5800 * critical_enter and the state field protects against state changes during 5801 * the critical period. 5802 * 5803 * If any state changes occur, zn_cb will set the failed field of the znotify 5804 * structure. This will cause the critical_exit function to re-lock the 5805 * channel and return an error. Since evsnts may be delayed, the critical_exit 5806 * function "flushes" the queue by putting an event on the queue and waiting for 5807 * zn_cb to notify critical_exit that it received the ping event. 5808 */ 5809 static const char * 5810 string_get_tok(const char *in, char delim, int num) 5811 { 5812 int i = 0; 5813 5814 for (; i < num; in++) { 5815 if (*in == delim) 5816 i++; 5817 if (*in == 0) 5818 return (NULL); 5819 } 5820 return (in); 5821 } 5822 5823 static boolean_t 5824 is_ping(sysevent_t *ev) 5825 { 5826 if (strcmp(sysevent_get_subclass_name(ev), 5827 ZONE_EVENT_PING_SUBCLASS) == 0) { 5828 return (B_TRUE); 5829 } else { 5830 return (B_FALSE); 5831 } 5832 } 5833 5834 static boolean_t 5835 is_my_ping(sysevent_t *ev) 5836 { 5837 const char *sender; 5838 char mypid[sizeof (pid_t) * 3 + 1]; 5839 5840 (void) snprintf(mypid, sizeof (mypid), "%i", getpid()); 5841 sender = string_get_tok(sysevent_get_pub(ev), ':', 3); 5842 if (sender == NULL) 5843 return (B_FALSE); 5844 if (strcmp(sender, mypid) != 0) 5845 return (B_FALSE); 5846 return (B_TRUE); 5847 } 5848 5849 static int 5850 do_callback(struct znotify *zevtchan, sysevent_t *ev) 5851 { 5852 nvlist_t *l; 5853 int zid; 5854 char *zonename; 5855 char *newstate; 5856 char *oldstate; 5857 int ret; 5858 hrtime_t when; 5859 5860 if (strcmp(sysevent_get_subclass_name(ev), 5861 ZONE_EVENT_STATUS_SUBCLASS) == 0) { 5862 5863 if (sysevent_get_attr_list(ev, &l) != 0) { 5864 if (errno == ENOMEM) { 5865 zevtchan->zn_failure_count++; 5866 return (EAGAIN); 5867 } 5868 return (0); 5869 } 5870 ret = 0; 5871 5872 if ((nvlist_lookup_string(l, ZONE_CB_NAME, &zonename) == 0) && 5873 (nvlist_lookup_string(l, ZONE_CB_NEWSTATE, &newstate) 5874 == 0) && 5875 (nvlist_lookup_string(l, ZONE_CB_OLDSTATE, &oldstate) 5876 == 0) && 5877 (nvlist_lookup_uint64(l, ZONE_CB_TIMESTAMP, 5878 (uint64_t *)&when) == 0) && 5879 (nvlist_lookup_int32(l, ZONE_CB_ZONEID, &zid) == 0)) { 5880 ret = zevtchan->zn_callback(zonename, zid, newstate, 5881 oldstate, when, zevtchan->zn_private); 5882 } 5883 5884 zevtchan->zn_failure_count = 0; 5885 nvlist_free(l); 5886 return (ret); 5887 } else { 5888 /* 5889 * We have received an event in an unknown subclass. Ignore. 5890 */ 5891 zevtchan->zn_failure_count = 0; 5892 return (0); 5893 } 5894 } 5895 5896 static int 5897 zn_cb(sysevent_t *ev, void *p) 5898 { 5899 struct znotify *zevtchan = p; 5900 int error; 5901 5902 (void) pthread_mutex_lock(&(zevtchan->zn_mutex)); 5903 5904 if (is_ping(ev) && !is_my_ping(ev)) { 5905 (void) pthread_mutex_unlock((&zevtchan->zn_mutex)); 5906 return (0); 5907 } 5908 5909 if (zevtchan->zn_state == ZN_LOCKED) { 5910 assert(!is_ping(ev)); 5911 zevtchan->zn_failed = B_TRUE; 5912 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5913 return (0); 5914 } 5915 5916 if (zevtchan->zn_state == ZN_PING_INFLIGHT) { 5917 if (is_ping(ev)) { 5918 zevtchan->zn_state = ZN_PING_RECEIVED; 5919 (void) pthread_cond_signal(&(zevtchan->zn_cond)); 5920 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5921 return (0); 5922 } else { 5923 zevtchan->zn_failed = B_TRUE; 5924 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5925 return (0); 5926 } 5927 } 5928 5929 if (zevtchan->zn_state == ZN_UNLOCKED) { 5930 5931 error = do_callback(zevtchan, ev); 5932 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5933 /* 5934 * Every ENOMEM failure causes do_callback to increment 5935 * zn_failure_count and every success causes it to 5936 * set zn_failure_count to zero. If we got EAGAIN, 5937 * we will sleep for zn_failure_count seconds and return 5938 * EAGAIN to gpec to try again. 5939 * 5940 * After 55 seconds, or 10 try's we give up and drop the 5941 * event. 5942 */ 5943 if (error == EAGAIN) { 5944 if (zevtchan->zn_failure_count > ZONE_CB_RETRY_COUNT) { 5945 return (0); 5946 } 5947 (void) sleep(zevtchan->zn_failure_count); 5948 } 5949 return (error); 5950 } 5951 5952 if (zevtchan->zn_state == ZN_PING_RECEIVED) { 5953 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5954 return (0); 5955 } 5956 5957 abort(); 5958 return (0); 5959 } 5960 5961 void 5962 zonecfg_notify_critical_enter(void *h) 5963 { 5964 struct znotify *zevtchan = h; 5965 5966 (void) pthread_mutex_lock(&(zevtchan->zn_bigmutex)); 5967 zevtchan->zn_state = ZN_LOCKED; 5968 } 5969 5970 int 5971 zonecfg_notify_critical_exit(void * h) 5972 { 5973 5974 struct znotify *zevtchan = h; 5975 5976 if (zevtchan->zn_state == ZN_UNLOCKED) 5977 return (0); 5978 5979 (void) pthread_mutex_lock(&(zevtchan->zn_mutex)); 5980 zevtchan->zn_state = ZN_PING_INFLIGHT; 5981 5982 (void) sysevent_evc_publish(zevtchan->zn_eventchan, 5983 ZONE_EVENT_STATUS_CLASS, 5984 ZONE_EVENT_PING_SUBCLASS, ZONE_EVENT_PING_PUBLISHER, 5985 zevtchan->zn_subscriber_id, NULL, EVCH_SLEEP); 5986 5987 while (zevtchan->zn_state != ZN_PING_RECEIVED) { 5988 (void) pthread_cond_wait(&(zevtchan->zn_cond), 5989 &(zevtchan->zn_mutex)); 5990 } 5991 5992 if (zevtchan->zn_failed == B_TRUE) { 5993 zevtchan->zn_state = ZN_LOCKED; 5994 zevtchan->zn_failed = B_FALSE; 5995 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5996 return (1); 5997 } 5998 5999 zevtchan->zn_state = ZN_UNLOCKED; 6000 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 6001 (void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex)); 6002 return (0); 6003 } 6004 6005 void 6006 zonecfg_notify_critical_abort(void *h) 6007 { 6008 struct znotify *zevtchan = h; 6009 6010 zevtchan->zn_state = ZN_UNLOCKED; 6011 zevtchan->zn_failed = B_FALSE; 6012 /* 6013 * Don't do anything about zn_lock. If it is held, it could only be 6014 * held by zn_cb and it will be unlocked soon. 6015 */ 6016 (void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex)); 6017 } 6018 6019 void * 6020 zonecfg_notify_bind(int(*func)(const char *zonename, zoneid_t zid, 6021 const char *newstate, const char *oldstate, hrtime_t when, void *p), 6022 void *p) 6023 { 6024 struct znotify *zevtchan; 6025 int i = 1; 6026 int r; 6027 6028 zevtchan = malloc(sizeof (struct znotify)); 6029 6030 if (zevtchan == NULL) 6031 return (NULL); 6032 6033 zevtchan->zn_private = p; 6034 zevtchan->zn_callback = func; 6035 zevtchan->zn_state = ZN_UNLOCKED; 6036 zevtchan->zn_failed = B_FALSE; 6037 6038 if (pthread_mutex_init(&(zevtchan->zn_mutex), NULL)) 6039 goto out3; 6040 if (pthread_cond_init(&(zevtchan->zn_cond), NULL)) { 6041 (void) pthread_mutex_destroy(&(zevtchan->zn_mutex)); 6042 goto out3; 6043 } 6044 if (pthread_mutex_init(&(zevtchan->zn_bigmutex), NULL)) { 6045 (void) pthread_mutex_destroy(&(zevtchan->zn_mutex)); 6046 (void) pthread_cond_destroy(&(zevtchan->zn_cond)); 6047 goto out3; 6048 } 6049 6050 if (sysevent_evc_bind(ZONE_EVENT_CHANNEL, &(zevtchan->zn_eventchan), 6051 0) != 0) 6052 goto out2; 6053 6054 do { 6055 /* 6056 * At 4 digits the subscriber ID gets too long and we have 6057 * no chance of successfully registering. 6058 */ 6059 if (i > 999) 6060 goto out1; 6061 6062 (void) sprintf(zevtchan->zn_subscriber_id, "zone_%li_%i", 6063 getpid() % 999999l, i); 6064 6065 r = sysevent_evc_subscribe(zevtchan->zn_eventchan, 6066 zevtchan->zn_subscriber_id, ZONE_EVENT_STATUS_CLASS, zn_cb, 6067 zevtchan, 0); 6068 6069 i++; 6070 6071 } while (r); 6072 6073 return (zevtchan); 6074 out1: 6075 (void) sysevent_evc_unbind(zevtchan->zn_eventchan); 6076 out2: 6077 (void) pthread_mutex_destroy(&zevtchan->zn_mutex); 6078 (void) pthread_cond_destroy(&zevtchan->zn_cond); 6079 (void) pthread_mutex_destroy(&(zevtchan->zn_bigmutex)); 6080 out3: 6081 free(zevtchan); 6082 6083 return (NULL); 6084 } 6085 6086 void 6087 zonecfg_notify_unbind(void *handle) 6088 { 6089 6090 int ret; 6091 6092 (void) sysevent_evc_unbind(((struct znotify *)handle)->zn_eventchan); 6093 /* 6094 * Check that all evc threads have gone away. This should be 6095 * enforced by sysevent_evc_unbind. 6096 */ 6097 ret = pthread_mutex_trylock(&((struct znotify *)handle)->zn_mutex); 6098 6099 if (ret) 6100 abort(); 6101 6102 (void) pthread_mutex_unlock(&((struct znotify *)handle)->zn_mutex); 6103 (void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_mutex); 6104 (void) pthread_cond_destroy(&((struct znotify *)handle)->zn_cond); 6105 (void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_bigmutex); 6106 6107 free(handle); 6108 } 6109 6110 static int 6111 zonecfg_add_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr) 6112 { 6113 xmlNodePtr newnode, cur = handle->zone_dh_cur; 6114 int err; 6115 6116 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DATASET, NULL); 6117 if ((err = newprop(newnode, DTD_ATTR_NAME, 6118 tabptr->zone_dataset_name)) != Z_OK) 6119 return (err); 6120 return (Z_OK); 6121 } 6122 6123 int 6124 zonecfg_add_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 6125 { 6126 int err; 6127 6128 if (tabptr == NULL) 6129 return (Z_INVAL); 6130 6131 if ((err = operation_prep(handle)) != Z_OK) 6132 return (err); 6133 6134 if ((err = zonecfg_add_ds_core(handle, tabptr)) != Z_OK) 6135 return (err); 6136 6137 return (Z_OK); 6138 } 6139 6140 static int 6141 zonecfg_delete_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr) 6142 { 6143 xmlNodePtr cur = handle->zone_dh_cur; 6144 6145 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6146 if (xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 6147 continue; 6148 6149 if (match_prop(cur, DTD_ATTR_NAME, 6150 tabptr->zone_dataset_name)) { 6151 xmlUnlinkNode(cur); 6152 xmlFreeNode(cur); 6153 return (Z_OK); 6154 } 6155 } 6156 return (Z_NO_RESOURCE_ID); 6157 } 6158 6159 int 6160 zonecfg_delete_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 6161 { 6162 int err; 6163 6164 if (tabptr == NULL) 6165 return (Z_INVAL); 6166 6167 if ((err = operation_prep(handle)) != Z_OK) 6168 return (err); 6169 6170 if ((err = zonecfg_delete_ds_core(handle, tabptr)) != Z_OK) 6171 return (err); 6172 6173 return (Z_OK); 6174 } 6175 6176 int 6177 zonecfg_modify_ds( 6178 zone_dochandle_t handle, 6179 struct zone_dstab *oldtabptr, 6180 struct zone_dstab *newtabptr) 6181 { 6182 int err; 6183 6184 if (oldtabptr == NULL || newtabptr == NULL) 6185 return (Z_INVAL); 6186 6187 if ((err = operation_prep(handle)) != Z_OK) 6188 return (err); 6189 6190 if ((err = zonecfg_delete_ds_core(handle, oldtabptr)) != Z_OK) 6191 return (err); 6192 6193 if ((err = zonecfg_add_ds_core(handle, newtabptr)) != Z_OK) 6194 return (err); 6195 6196 return (Z_OK); 6197 } 6198 6199 int 6200 zonecfg_lookup_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 6201 { 6202 xmlNodePtr cur, firstmatch; 6203 int err; 6204 char dataset[MAXNAMELEN]; 6205 6206 if (tabptr == NULL) 6207 return (Z_INVAL); 6208 6209 if ((err = operation_prep(handle)) != Z_OK) 6210 return (err); 6211 6212 cur = handle->zone_dh_cur; 6213 firstmatch = NULL; 6214 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6215 if (xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 6216 continue; 6217 if (strlen(tabptr->zone_dataset_name) > 0) { 6218 if ((fetchprop(cur, DTD_ATTR_NAME, dataset, 6219 sizeof (dataset)) == Z_OK) && 6220 (strcmp(tabptr->zone_dataset_name, 6221 dataset) == 0)) { 6222 if (firstmatch == NULL) 6223 firstmatch = cur; 6224 else 6225 return (Z_INSUFFICIENT_SPEC); 6226 } 6227 } 6228 } 6229 if (firstmatch == NULL) 6230 return (Z_NO_RESOURCE_ID); 6231 6232 cur = firstmatch; 6233 6234 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name, 6235 sizeof (tabptr->zone_dataset_name))) != Z_OK) 6236 return (err); 6237 6238 return (Z_OK); 6239 } 6240 6241 int 6242 zonecfg_setdsent(zone_dochandle_t handle) 6243 { 6244 return (zonecfg_setent(handle)); 6245 } 6246 6247 int 6248 zonecfg_getdsent(zone_dochandle_t handle, struct zone_dstab *tabptr) 6249 { 6250 xmlNodePtr cur; 6251 int err; 6252 6253 if (handle == NULL) 6254 return (Z_INVAL); 6255 6256 if ((cur = handle->zone_dh_cur) == NULL) 6257 return (Z_NO_ENTRY); 6258 6259 for (; cur != NULL; cur = cur->next) 6260 if (!xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 6261 break; 6262 if (cur == NULL) { 6263 handle->zone_dh_cur = handle->zone_dh_top; 6264 return (Z_NO_ENTRY); 6265 } 6266 6267 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name, 6268 sizeof (tabptr->zone_dataset_name))) != Z_OK) { 6269 handle->zone_dh_cur = handle->zone_dh_top; 6270 return (err); 6271 } 6272 6273 handle->zone_dh_cur = cur->next; 6274 return (Z_OK); 6275 } 6276 6277 int 6278 zonecfg_enddsent(zone_dochandle_t handle) 6279 { 6280 return (zonecfg_endent(handle)); 6281 } 6282 6283 /* 6284 * Support for aliased rctls; that is, rctls that have simplified names in 6285 * zonecfg. For example, max-lwps is an alias for a well defined zone.max-lwps 6286 * rctl. If there are multiple existing values for one of these rctls or if 6287 * there is a single value that does not match the well defined template (i.e. 6288 * it has a different action) then we cannot treat the rctl as having an alias 6289 * so we return Z_ALIAS_DISALLOW. That means that the rctl cannot be 6290 * managed in zonecfg via an alias and that the standard rctl syntax must be 6291 * used. 6292 * 6293 * The possible return values are: 6294 * Z_NO_PROPERTY_ID - invalid alias name 6295 * Z_ALIAS_DISALLOW - pre-existing, incompatible rctl definition 6296 * Z_NO_ENTRY - no rctl is configured for this alias 6297 * Z_OK - we got a valid rctl for the specified alias 6298 */ 6299 int 6300 zonecfg_get_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t *rval) 6301 { 6302 boolean_t found = B_FALSE; 6303 boolean_t found_val = B_FALSE; 6304 xmlNodePtr cur, val; 6305 char savedname[MAXNAMELEN]; 6306 struct zone_rctlvaltab rctl; 6307 int i; 6308 int err; 6309 6310 for (i = 0; aliases[i].shortname != NULL; i++) 6311 if (strcmp(name, aliases[i].shortname) == 0) 6312 break; 6313 6314 if (aliases[i].shortname == NULL) 6315 return (Z_NO_PROPERTY_ID); 6316 6317 if ((err = operation_prep(handle)) != Z_OK) 6318 return (err); 6319 6320 cur = handle->zone_dh_cur; 6321 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6322 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL) != 0) 6323 continue; 6324 if ((fetchprop(cur, DTD_ATTR_NAME, savedname, 6325 sizeof (savedname)) == Z_OK) && 6326 (strcmp(savedname, aliases[i].realname) == 0)) { 6327 6328 /* 6329 * If we already saw one of these, we can't have an 6330 * alias since we just found another. 6331 */ 6332 if (found) 6333 return (Z_ALIAS_DISALLOW); 6334 found = B_TRUE; 6335 6336 for (val = cur->xmlChildrenNode; val != NULL; 6337 val = val->next) { 6338 /* 6339 * If we already have one value, we can't have 6340 * an alias since we just found another. 6341 */ 6342 if (found_val) 6343 return (Z_ALIAS_DISALLOW); 6344 found_val = B_TRUE; 6345 6346 if ((fetchprop(val, DTD_ATTR_PRIV, 6347 rctl.zone_rctlval_priv, 6348 sizeof (rctl.zone_rctlval_priv)) != Z_OK)) 6349 break; 6350 if ((fetchprop(val, DTD_ATTR_LIMIT, 6351 rctl.zone_rctlval_limit, 6352 sizeof (rctl.zone_rctlval_limit)) != Z_OK)) 6353 break; 6354 if ((fetchprop(val, DTD_ATTR_ACTION, 6355 rctl.zone_rctlval_action, 6356 sizeof (rctl.zone_rctlval_action)) != Z_OK)) 6357 break; 6358 } 6359 6360 /* check priv and action match the expected vals */ 6361 if (strcmp(rctl.zone_rctlval_priv, 6362 aliases[i].priv) != 0 || 6363 strcmp(rctl.zone_rctlval_action, 6364 aliases[i].action) != 0) 6365 return (Z_ALIAS_DISALLOW); 6366 } 6367 } 6368 6369 if (found) { 6370 *rval = strtoull(rctl.zone_rctlval_limit, NULL, 10); 6371 return (Z_OK); 6372 } 6373 6374 return (Z_NO_ENTRY); 6375 } 6376 6377 int 6378 zonecfg_rm_aliased_rctl(zone_dochandle_t handle, char *name) 6379 { 6380 int i; 6381 uint64_t val; 6382 struct zone_rctltab rctltab; 6383 6384 /* 6385 * First check that we have a valid aliased rctl to remove. 6386 * This will catch an rctl entry with non-standard values or 6387 * multiple rctl values for this name. We need to ignore those 6388 * rctl entries. 6389 */ 6390 if (zonecfg_get_aliased_rctl(handle, name, &val) != Z_OK) 6391 return (Z_OK); 6392 6393 for (i = 0; aliases[i].shortname != NULL; i++) 6394 if (strcmp(name, aliases[i].shortname) == 0) 6395 break; 6396 6397 if (aliases[i].shortname == NULL) 6398 return (Z_NO_RESOURCE_ID); 6399 6400 (void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname, 6401 sizeof (rctltab.zone_rctl_name)); 6402 6403 return (zonecfg_delete_rctl(handle, &rctltab)); 6404 } 6405 6406 boolean_t 6407 zonecfg_aliased_rctl_ok(zone_dochandle_t handle, char *name) 6408 { 6409 uint64_t tmp_val; 6410 6411 switch (zonecfg_get_aliased_rctl(handle, name, &tmp_val)) { 6412 case Z_OK: 6413 /*FALLTHRU*/ 6414 case Z_NO_ENTRY: 6415 return (B_TRUE); 6416 default: 6417 return (B_FALSE); 6418 } 6419 } 6420 6421 int 6422 zonecfg_set_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t val) 6423 { 6424 int i; 6425 int err; 6426 struct zone_rctltab rctltab; 6427 struct zone_rctlvaltab *rctlvaltab; 6428 char buf[128]; 6429 6430 if (!zonecfg_aliased_rctl_ok(handle, name)) 6431 return (Z_ALIAS_DISALLOW); 6432 6433 for (i = 0; aliases[i].shortname != NULL; i++) 6434 if (strcmp(name, aliases[i].shortname) == 0) 6435 break; 6436 6437 if (aliases[i].shortname == NULL) 6438 return (Z_NO_RESOURCE_ID); 6439 6440 /* remove any pre-existing definition for this rctl */ 6441 (void) zonecfg_rm_aliased_rctl(handle, name); 6442 6443 (void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname, 6444 sizeof (rctltab.zone_rctl_name)); 6445 6446 rctltab.zone_rctl_valptr = NULL; 6447 6448 if ((rctlvaltab = calloc(1, sizeof (struct zone_rctlvaltab))) == NULL) 6449 return (Z_NOMEM); 6450 6451 (void) snprintf(buf, sizeof (buf), "%llu", (long long)val); 6452 6453 (void) strlcpy(rctlvaltab->zone_rctlval_priv, aliases[i].priv, 6454 sizeof (rctlvaltab->zone_rctlval_priv)); 6455 (void) strlcpy(rctlvaltab->zone_rctlval_limit, buf, 6456 sizeof (rctlvaltab->zone_rctlval_limit)); 6457 (void) strlcpy(rctlvaltab->zone_rctlval_action, aliases[i].action, 6458 sizeof (rctlvaltab->zone_rctlval_action)); 6459 6460 rctlvaltab->zone_rctlval_next = NULL; 6461 6462 if ((err = zonecfg_add_rctl_value(&rctltab, rctlvaltab)) != Z_OK) 6463 return (err); 6464 6465 return (zonecfg_add_rctl(handle, &rctltab)); 6466 } 6467 6468 static int 6469 delete_tmp_pool(zone_dochandle_t handle) 6470 { 6471 int err; 6472 xmlNodePtr cur = handle->zone_dh_cur; 6473 6474 if ((err = operation_prep(handle)) != Z_OK) 6475 return (err); 6476 6477 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6478 if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) { 6479 xmlUnlinkNode(cur); 6480 xmlFreeNode(cur); 6481 return (Z_OK); 6482 } 6483 } 6484 6485 return (Z_NO_RESOURCE_ID); 6486 } 6487 6488 static int 6489 modify_tmp_pool(zone_dochandle_t handle, char *pool_importance) 6490 { 6491 int err; 6492 xmlNodePtr cur = handle->zone_dh_cur; 6493 xmlNodePtr newnode; 6494 6495 err = delete_tmp_pool(handle); 6496 if (err != Z_OK && err != Z_NO_RESOURCE_ID) 6497 return (err); 6498 6499 if (*pool_importance != '\0') { 6500 if ((err = operation_prep(handle)) != Z_OK) 6501 return (err); 6502 6503 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_TMPPOOL, NULL); 6504 if ((err = newprop(newnode, DTD_ATTR_IMPORTANCE, 6505 pool_importance)) != Z_OK) 6506 return (err); 6507 } 6508 6509 return (Z_OK); 6510 } 6511 6512 static int 6513 add_pset_core(zone_dochandle_t handle, struct zone_psettab *tabptr) 6514 { 6515 xmlNodePtr newnode, cur = handle->zone_dh_cur; 6516 int err; 6517 6518 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PSET, NULL); 6519 if ((err = newprop(newnode, DTD_ATTR_NCPU_MIN, 6520 tabptr->zone_ncpu_min)) != Z_OK) 6521 return (err); 6522 if ((err = newprop(newnode, DTD_ATTR_NCPU_MAX, 6523 tabptr->zone_ncpu_max)) != Z_OK) 6524 return (err); 6525 6526 if ((err = modify_tmp_pool(handle, tabptr->zone_importance)) != Z_OK) 6527 return (err); 6528 6529 return (Z_OK); 6530 } 6531 6532 int 6533 zonecfg_add_pset(zone_dochandle_t handle, struct zone_psettab *tabptr) 6534 { 6535 int err; 6536 6537 if (tabptr == NULL) 6538 return (Z_INVAL); 6539 6540 if ((err = operation_prep(handle)) != Z_OK) 6541 return (err); 6542 6543 if ((err = add_pset_core(handle, tabptr)) != Z_OK) 6544 return (err); 6545 6546 return (Z_OK); 6547 } 6548 6549 int 6550 zonecfg_delete_pset(zone_dochandle_t handle) 6551 { 6552 int err; 6553 int res = Z_NO_RESOURCE_ID; 6554 xmlNodePtr cur = handle->zone_dh_cur; 6555 6556 if ((err = operation_prep(handle)) != Z_OK) 6557 return (err); 6558 6559 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6560 if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) { 6561 xmlUnlinkNode(cur); 6562 xmlFreeNode(cur); 6563 res = Z_OK; 6564 break; 6565 } 6566 } 6567 6568 /* 6569 * Once we have msets, we should check that a mset 6570 * do not exist before we delete the tmp_pool data. 6571 */ 6572 err = delete_tmp_pool(handle); 6573 if (err != Z_OK && err != Z_NO_RESOURCE_ID) 6574 return (err); 6575 6576 return (res); 6577 } 6578 6579 int 6580 zonecfg_modify_pset(zone_dochandle_t handle, struct zone_psettab *tabptr) 6581 { 6582 int err; 6583 6584 if (tabptr == NULL) 6585 return (Z_INVAL); 6586 6587 if ((err = zonecfg_delete_pset(handle)) != Z_OK) 6588 return (err); 6589 6590 if ((err = add_pset_core(handle, tabptr)) != Z_OK) 6591 return (err); 6592 6593 return (Z_OK); 6594 } 6595 6596 int 6597 zonecfg_lookup_pset(zone_dochandle_t handle, struct zone_psettab *tabptr) 6598 { 6599 xmlNodePtr cur; 6600 int err; 6601 int res = Z_NO_ENTRY; 6602 6603 if (tabptr == NULL) 6604 return (Z_INVAL); 6605 6606 if ((err = operation_prep(handle)) != Z_OK) 6607 return (err); 6608 6609 /* this is an optional component */ 6610 tabptr->zone_importance[0] = '\0'; 6611 6612 cur = handle->zone_dh_cur; 6613 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6614 if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) { 6615 if ((err = fetchprop(cur, DTD_ATTR_NCPU_MIN, 6616 tabptr->zone_ncpu_min, 6617 sizeof (tabptr->zone_ncpu_min))) != Z_OK) { 6618 handle->zone_dh_cur = handle->zone_dh_top; 6619 return (err); 6620 } 6621 6622 if ((err = fetchprop(cur, DTD_ATTR_NCPU_MAX, 6623 tabptr->zone_ncpu_max, 6624 sizeof (tabptr->zone_ncpu_max))) != Z_OK) { 6625 handle->zone_dh_cur = handle->zone_dh_top; 6626 return (err); 6627 } 6628 6629 res = Z_OK; 6630 6631 } else if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) { 6632 if ((err = fetchprop(cur, DTD_ATTR_IMPORTANCE, 6633 tabptr->zone_importance, 6634 sizeof (tabptr->zone_importance))) != Z_OK) { 6635 handle->zone_dh_cur = handle->zone_dh_top; 6636 return (err); 6637 } 6638 } 6639 } 6640 6641 return (res); 6642 } 6643 6644 int 6645 zonecfg_getpsetent(zone_dochandle_t handle, struct zone_psettab *tabptr) 6646 { 6647 int err; 6648 6649 if ((err = zonecfg_setent(handle)) != Z_OK) 6650 return (err); 6651 6652 err = zonecfg_lookup_pset(handle, tabptr); 6653 6654 (void) zonecfg_endent(handle); 6655 6656 return (err); 6657 } 6658 6659 static int 6660 add_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 6661 { 6662 xmlNodePtr newnode, cur = handle->zone_dh_cur; 6663 int err; 6664 6665 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_MCAP, NULL); 6666 if ((err = newprop(newnode, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap)) 6667 != Z_OK) 6668 return (err); 6669 6670 return (Z_OK); 6671 } 6672 6673 int 6674 zonecfg_delete_mcap(zone_dochandle_t handle) 6675 { 6676 int err; 6677 xmlNodePtr cur = handle->zone_dh_cur; 6678 6679 if ((err = operation_prep(handle)) != Z_OK) 6680 return (err); 6681 6682 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6683 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0) 6684 continue; 6685 6686 xmlUnlinkNode(cur); 6687 xmlFreeNode(cur); 6688 return (Z_OK); 6689 } 6690 return (Z_NO_RESOURCE_ID); 6691 } 6692 6693 int 6694 zonecfg_modify_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 6695 { 6696 int err; 6697 6698 if (tabptr == NULL) 6699 return (Z_INVAL); 6700 6701 err = zonecfg_delete_mcap(handle); 6702 /* it is ok if there is no mcap entry */ 6703 if (err != Z_OK && err != Z_NO_RESOURCE_ID) 6704 return (err); 6705 6706 if ((err = add_mcap(handle, tabptr)) != Z_OK) 6707 return (err); 6708 6709 return (Z_OK); 6710 } 6711 6712 int 6713 zonecfg_lookup_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 6714 { 6715 xmlNodePtr cur; 6716 int err; 6717 6718 if (tabptr == NULL) 6719 return (Z_INVAL); 6720 6721 if ((err = operation_prep(handle)) != Z_OK) 6722 return (err); 6723 6724 cur = handle->zone_dh_cur; 6725 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6726 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0) 6727 continue; 6728 if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP, 6729 tabptr->zone_physmem_cap, 6730 sizeof (tabptr->zone_physmem_cap))) != Z_OK) { 6731 handle->zone_dh_cur = handle->zone_dh_top; 6732 return (err); 6733 } 6734 6735 return (Z_OK); 6736 } 6737 6738 return (Z_NO_ENTRY); 6739 } 6740 6741 static int 6742 getmcapent_core(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 6743 { 6744 xmlNodePtr cur; 6745 int err; 6746 6747 if (handle == NULL) 6748 return (Z_INVAL); 6749 6750 if ((cur = handle->zone_dh_cur) == NULL) 6751 return (Z_NO_ENTRY); 6752 6753 for (; cur != NULL; cur = cur->next) 6754 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) == 0) 6755 break; 6756 if (cur == NULL) { 6757 handle->zone_dh_cur = handle->zone_dh_top; 6758 return (Z_NO_ENTRY); 6759 } 6760 6761 if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap, 6762 sizeof (tabptr->zone_physmem_cap))) != Z_OK) { 6763 handle->zone_dh_cur = handle->zone_dh_top; 6764 return (err); 6765 } 6766 6767 handle->zone_dh_cur = cur->next; 6768 return (Z_OK); 6769 } 6770 6771 int 6772 zonecfg_getmcapent(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 6773 { 6774 int err; 6775 6776 if ((err = zonecfg_setent(handle)) != Z_OK) 6777 return (err); 6778 6779 err = getmcapent_core(handle, tabptr); 6780 6781 (void) zonecfg_endent(handle); 6782 6783 return (err); 6784 } 6785 6786 /* 6787 * Get the full tree of pkg/patch metadata in a set of nested AVL trees. 6788 * pkgs_avl is an AVL tree of pkgs. Each pkg element contains a 6789 * zpe_patches_avl member which holds an AVL tree of patches for that pkg. 6790 * The patch elements have the same zpe_patches_avl member, each of which can 6791 * hold an AVL tree of patches that are obsoleted by the patch. 6792 * 6793 * The zone xml data contains DTD_ELEM_PACKAGE elements, followed by 6794 * DTD_ELEM_PATCH elements. The DTD_ELEM_PATCH patch element applies to the 6795 * DTD_ELEM_PACKAGE that precedes it. The DTD_ELEM_PATCH element may have 6796 * child DTD_ELEM_OBSOLETES nodes associated with it. The DTD_ELEM_PACKAGE 6797 * really should have had the DTD_ELEM_PATCH elements as children but it 6798 * was not defined that way initially so we are stuck with the DTD definition 6799 * now. However, we can safely assume the ordering for compatibility. 6800 */ 6801 int 6802 zonecfg_getpkgdata(zone_dochandle_t handle, uu_avl_pool_t *pkg_pool, 6803 uu_avl_t *pkgs_avl) 6804 { 6805 xmlNodePtr cur; 6806 int res; 6807 zone_pkg_entry_t *pkg; 6808 char name[MAXNAMELEN]; 6809 char version[ZONE_PKG_VERSMAX]; 6810 6811 if (handle == NULL) 6812 return (Z_INVAL); 6813 6814 if ((res = zonecfg_setent(handle)) != Z_OK) 6815 return (res); 6816 6817 if ((cur = handle->zone_dh_cur) == NULL) { 6818 res = Z_NO_ENTRY; 6819 goto done; 6820 } 6821 6822 for (; cur != NULL; cur = cur->next) { 6823 if (xmlStrcmp(cur->name, DTD_ELEM_PACKAGE) == 0) { 6824 uu_avl_index_t where; 6825 6826 if ((res = fetchprop(cur, DTD_ATTR_NAME, name, 6827 sizeof (name))) != Z_OK) 6828 goto done; 6829 6830 if ((res = fetchprop(cur, DTD_ATTR_VERSION, version, 6831 sizeof (version))) != Z_OK) 6832 goto done; 6833 6834 if ((pkg = (zone_pkg_entry_t *) 6835 malloc(sizeof (zone_pkg_entry_t))) == NULL) { 6836 res = Z_NOMEM; 6837 goto done; 6838 } 6839 6840 if ((pkg->zpe_name = strdup(name)) == NULL) { 6841 free(pkg); 6842 res = Z_NOMEM; 6843 goto done; 6844 } 6845 6846 if ((pkg->zpe_vers = strdup(version)) == NULL) { 6847 free(pkg->zpe_name); 6848 free(pkg); 6849 res = Z_NOMEM; 6850 goto done; 6851 } 6852 6853 pkg->zpe_patches_avl = NULL; 6854 6855 uu_avl_node_init(pkg, &pkg->zpe_entry, pkg_pool); 6856 if (uu_avl_find(pkgs_avl, pkg, NULL, &where) != NULL) { 6857 free(pkg->zpe_name); 6858 free(pkg->zpe_vers); 6859 free(pkg); 6860 } else { 6861 uu_avl_insert(pkgs_avl, pkg, where); 6862 } 6863 6864 } else if (xmlStrcmp(cur->name, DTD_ELEM_PATCH) == 0) { 6865 zone_pkg_entry_t *patch; 6866 uu_avl_index_t where; 6867 char *p; 6868 char *dashp = NULL; 6869 xmlNodePtr child; 6870 6871 if ((res = fetchprop(cur, DTD_ATTR_ID, name, 6872 sizeof (name))) != Z_OK) 6873 goto done; 6874 6875 if ((patch = (zone_pkg_entry_t *) 6876 malloc(sizeof (zone_pkg_entry_t))) == NULL) { 6877 res = Z_NOMEM; 6878 goto done; 6879 } 6880 6881 if ((p = strchr(name, '-')) != NULL) { 6882 dashp = p; 6883 *p++ = '\0'; 6884 } else { 6885 p = ""; 6886 } 6887 6888 if ((patch->zpe_name = strdup(name)) == NULL) { 6889 free(patch); 6890 res = Z_NOMEM; 6891 goto done; 6892 } 6893 6894 if ((patch->zpe_vers = strdup(p)) == NULL) { 6895 free(patch->zpe_name); 6896 free(patch); 6897 res = Z_NOMEM; 6898 goto done; 6899 } 6900 6901 if (dashp != NULL) 6902 *dashp = '-'; 6903 6904 patch->zpe_patches_avl = NULL; 6905 6906 if (pkg->zpe_patches_avl == NULL) { 6907 pkg->zpe_patches_avl = uu_avl_create(pkg_pool, 6908 NULL, UU_DEFAULT); 6909 if (pkg->zpe_patches_avl == NULL) { 6910 free(patch->zpe_name); 6911 free(patch->zpe_vers); 6912 free(patch); 6913 res = Z_NOMEM; 6914 goto done; 6915 } 6916 } 6917 6918 uu_avl_node_init(patch, &patch->zpe_entry, pkg_pool); 6919 if (uu_avl_find(pkg->zpe_patches_avl, patch, NULL, 6920 &where) != NULL) { 6921 free(patch->zpe_name); 6922 free(patch->zpe_vers); 6923 free(patch); 6924 } else { 6925 uu_avl_insert(pkg->zpe_patches_avl, patch, 6926 where); 6927 } 6928 6929 /* Add any patches this patch obsoletes. */ 6930 for (child = cur->xmlChildrenNode; child != NULL; 6931 child = child->next) { 6932 zone_pkg_entry_t *obs; 6933 6934 if (xmlStrcmp(child->name, DTD_ELEM_OBSOLETES) 6935 != 0) 6936 continue; 6937 6938 if ((res = fetchprop(child, DTD_ATTR_ID, 6939 name, sizeof (name))) != Z_OK) 6940 goto done; 6941 6942 if ((obs = (zone_pkg_entry_t *)malloc( 6943 sizeof (zone_pkg_entry_t))) == NULL) { 6944 res = Z_NOMEM; 6945 goto done; 6946 } 6947 6948 if ((obs->zpe_name = strdup(name)) == NULL) { 6949 free(obs); 6950 res = Z_NOMEM; 6951 goto done; 6952 } 6953 /* 6954 * The version doesn't matter for obsoleted 6955 * patches. 6956 */ 6957 obs->zpe_vers = NULL; 6958 obs->zpe_patches_avl = NULL; 6959 6960 /* 6961 * If this is the first obsolete patch, add an 6962 * AVL tree to the parent patch element. 6963 */ 6964 if (patch->zpe_patches_avl == NULL) { 6965 patch->zpe_patches_avl = 6966 uu_avl_create(pkg_pool, NULL, 6967 UU_DEFAULT); 6968 if (patch->zpe_patches_avl == NULL) { 6969 free(obs->zpe_name); 6970 free(obs); 6971 res = Z_NOMEM; 6972 goto done; 6973 } 6974 } 6975 6976 /* Insert obsolete patch into the AVL tree. */ 6977 uu_avl_node_init(obs, &obs->zpe_entry, 6978 pkg_pool); 6979 if (uu_avl_find(patch->zpe_patches_avl, obs, 6980 NULL, &where) != NULL) { 6981 free(obs->zpe_name); 6982 free(obs); 6983 } else { 6984 uu_avl_insert(patch->zpe_patches_avl, 6985 obs, where); 6986 } 6987 } 6988 } 6989 } 6990 6991 done: 6992 (void) zonecfg_endent(handle); 6993 return (res); 6994 } 6995 6996 int 6997 zonecfg_setdevperment(zone_dochandle_t handle) 6998 { 6999 return (zonecfg_setent(handle)); 7000 } 7001 7002 int 7003 zonecfg_getdevperment(zone_dochandle_t handle, struct zone_devpermtab *tabptr) 7004 { 7005 xmlNodePtr cur; 7006 int err; 7007 char buf[128]; 7008 7009 tabptr->zone_devperm_acl = NULL; 7010 7011 if (handle == NULL) 7012 return (Z_INVAL); 7013 7014 if ((cur = handle->zone_dh_cur) == NULL) 7015 return (Z_NO_ENTRY); 7016 7017 for (; cur != NULL; cur = cur->next) 7018 if (!xmlStrcmp(cur->name, DTD_ELEM_DEV_PERM)) 7019 break; 7020 if (cur == NULL) { 7021 handle->zone_dh_cur = handle->zone_dh_top; 7022 return (Z_NO_ENTRY); 7023 } 7024 7025 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_devperm_name, 7026 sizeof (tabptr->zone_devperm_name))) != Z_OK) { 7027 handle->zone_dh_cur = handle->zone_dh_top; 7028 return (err); 7029 } 7030 7031 if ((err = fetchprop(cur, DTD_ATTR_UID, buf, sizeof (buf))) != Z_OK) { 7032 handle->zone_dh_cur = handle->zone_dh_top; 7033 return (err); 7034 } 7035 tabptr->zone_devperm_uid = (uid_t)atol(buf); 7036 7037 if ((err = fetchprop(cur, DTD_ATTR_GID, buf, sizeof (buf))) != Z_OK) { 7038 handle->zone_dh_cur = handle->zone_dh_top; 7039 return (err); 7040 } 7041 tabptr->zone_devperm_gid = (gid_t)atol(buf); 7042 7043 if ((err = fetchprop(cur, DTD_ATTR_MODE, buf, sizeof (buf))) != Z_OK) { 7044 handle->zone_dh_cur = handle->zone_dh_top; 7045 return (err); 7046 } 7047 tabptr->zone_devperm_mode = (mode_t)strtol(buf, (char **)NULL, 8); 7048 7049 if ((err = fetch_alloc_prop(cur, DTD_ATTR_ACL, 7050 &(tabptr->zone_devperm_acl))) != Z_OK) { 7051 handle->zone_dh_cur = handle->zone_dh_top; 7052 return (err); 7053 } 7054 7055 handle->zone_dh_cur = cur->next; 7056 return (Z_OK); 7057 } 7058 7059 int 7060 zonecfg_enddevperment(zone_dochandle_t handle) 7061 { 7062 return (zonecfg_endent(handle)); 7063 } 7064 7065 /* PRINTFLIKE1 */ 7066 static void 7067 zerror(const char *zone_name, const char *fmt, ...) 7068 { 7069 va_list alist; 7070 7071 va_start(alist, fmt); 7072 (void) fprintf(stderr, "zone '%s': ", zone_name); 7073 (void) vfprintf(stderr, fmt, alist); 7074 (void) fprintf(stderr, "\n"); 7075 va_end(alist); 7076 } 7077 7078 static void 7079 zperror(const char *str) 7080 { 7081 (void) fprintf(stderr, "%s: %s\n", str, strerror(errno)); 7082 } 7083 7084 /* 7085 * The following three routines implement a simple locking mechanism to 7086 * ensure that only one instance of zoneadm at a time is able to manipulate 7087 * a given zone. The lock is built on top of an fcntl(2) lock of 7088 * [<altroot>]/var/run/zones/<zonename>.zoneadm.lock. If a zoneadm instance 7089 * can grab that lock, it is allowed to manipulate the zone. 7090 * 7091 * Since zoneadm may call external applications which in turn invoke 7092 * zoneadm again, we introduce the notion of "lock inheritance". Any 7093 * instance of zoneadm that has another instance in its ancestry is assumed 7094 * to be acting on behalf of the original zoneadm, and is thus allowed to 7095 * manipulate its zone. 7096 * 7097 * This inheritance is implemented via the _ZONEADM_LOCK_HELD environment 7098 * variable. When zoneadm is granted a lock on its zone, this environment 7099 * variable is set to 1. When it releases the lock, the variable is set to 7100 * 0. Since a child process inherits its parent's environment, checking 7101 * the state of this variable indicates whether or not any ancestor owns 7102 * the lock. 7103 */ 7104 void 7105 zonecfg_init_lock_file(const char *zone_name, char **lock_env) 7106 { 7107 *lock_env = getenv(LOCK_ENV_VAR); 7108 if (*lock_env == NULL) { 7109 if (putenv(zoneadm_lock_not_held) != 0) { 7110 zerror(zone_name, gettext("could not set env: %s"), 7111 strerror(errno)); 7112 exit(1); 7113 } 7114 } else { 7115 if (atoi(*lock_env) == 1) 7116 zone_lock_cnt = 1; 7117 } 7118 } 7119 7120 void 7121 zonecfg_release_lock_file(const char *zone_name, int lockfd) 7122 { 7123 /* 7124 * If we are cleaning up from a failed attempt to lock the zone for 7125 * the first time, we might have a zone_lock_cnt of 0. In that 7126 * error case, we don't want to do anything but close the lock 7127 * file. 7128 */ 7129 assert(zone_lock_cnt >= 0); 7130 if (zone_lock_cnt > 0) { 7131 assert(getenv(LOCK_ENV_VAR) != NULL); 7132 assert(atoi(getenv(LOCK_ENV_VAR)) == 1); 7133 if (--zone_lock_cnt > 0) { 7134 assert(lockfd == -1); 7135 return; 7136 } 7137 if (putenv(zoneadm_lock_not_held) != 0) { 7138 zerror(zone_name, gettext("could not set env: %s"), 7139 strerror(errno)); 7140 exit(1); 7141 } 7142 } 7143 assert(lockfd >= 0); 7144 (void) close(lockfd); 7145 } 7146 7147 int 7148 zonecfg_grab_lock_file(const char *zone_name, int *lockfd) 7149 { 7150 char pathbuf[PATH_MAX]; 7151 struct flock flock; 7152 7153 /* 7154 * If we already have the lock, we can skip this expensive song 7155 * and dance. 7156 */ 7157 assert(zone_lock_cnt >= 0); 7158 assert(getenv(LOCK_ENV_VAR) != NULL); 7159 if (zone_lock_cnt > 0) { 7160 assert(atoi(getenv(LOCK_ENV_VAR)) == 1); 7161 zone_lock_cnt++; 7162 *lockfd = -1; 7163 return (Z_OK); 7164 } 7165 assert(getenv(LOCK_ENV_VAR) != NULL); 7166 assert(atoi(getenv(LOCK_ENV_VAR)) == 0); 7167 7168 if (snprintf(pathbuf, sizeof (pathbuf), "%s%s", zonecfg_get_root(), 7169 ZONES_TMPDIR) >= sizeof (pathbuf)) { 7170 zerror(zone_name, gettext("alternate root path is too long")); 7171 return (-1); 7172 } 7173 if (mkdir(pathbuf, S_IRWXU) < 0 && errno != EEXIST) { 7174 zerror(zone_name, gettext("could not mkdir %s: %s"), pathbuf, 7175 strerror(errno)); 7176 return (-1); 7177 } 7178 (void) chmod(pathbuf, S_IRWXU); 7179 7180 /* 7181 * One of these lock files is created for each zone (when needed). 7182 * The lock files are not cleaned up (except on system reboot), 7183 * but since there is only one per zone, there is no resource 7184 * starvation issue. 7185 */ 7186 if (snprintf(pathbuf, sizeof (pathbuf), "%s%s/%s.zoneadm.lock", 7187 zonecfg_get_root(), ZONES_TMPDIR, zone_name) >= sizeof (pathbuf)) { 7188 zerror(zone_name, gettext("alternate root path is too long")); 7189 return (-1); 7190 } 7191 if ((*lockfd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { 7192 zerror(zone_name, gettext("could not open %s: %s"), pathbuf, 7193 strerror(errno)); 7194 return (-1); 7195 } 7196 /* 7197 * Lock the file to synchronize with other zoneadmds 7198 */ 7199 flock.l_type = F_WRLCK; 7200 flock.l_whence = SEEK_SET; 7201 flock.l_start = (off_t)0; 7202 flock.l_len = (off_t)0; 7203 if ((fcntl(*lockfd, F_SETLKW, &flock) < 0) || 7204 (putenv(zoneadm_lock_held) != 0)) { 7205 zerror(zone_name, gettext("unable to lock %s: %s"), pathbuf, 7206 strerror(errno)); 7207 zonecfg_release_lock_file(zone_name, *lockfd); 7208 return (-1); 7209 } 7210 zone_lock_cnt = 1; 7211 return (Z_OK); 7212 } 7213 7214 boolean_t 7215 zonecfg_lock_file_held(int *lockfd) 7216 { 7217 if (*lockfd >= 0 || zone_lock_cnt > 0) 7218 return (B_TRUE); 7219 return (B_FALSE); 7220 } 7221 7222 static boolean_t 7223 get_doorname(const char *zone_name, char *buffer) 7224 { 7225 return (snprintf(buffer, PATH_MAX, "%s" ZONE_DOOR_PATH, 7226 zonecfg_get_root(), zone_name) < PATH_MAX); 7227 } 7228 7229 /* 7230 * system daemons are not audited. For the global zone, this occurs 7231 * "naturally" since init is started with the default audit 7232 * characteristics. Since zoneadmd is a system daemon and it starts 7233 * init for a zone, it is necessary to clear out the audit 7234 * characteristics inherited from whomever started zoneadmd. This is 7235 * indicated by the audit id, which is set from the ruid parameter of 7236 * adt_set_user(), below. 7237 */ 7238 7239 static void 7240 prepare_audit_context(const char *zone_name) 7241 { 7242 adt_session_data_t *ah; 7243 char *failure = gettext("audit failure: %s"); 7244 7245 if (adt_start_session(&ah, NULL, 0)) { 7246 zerror(zone_name, failure, strerror(errno)); 7247 return; 7248 } 7249 if (adt_set_user(ah, ADT_NO_AUDIT, ADT_NO_AUDIT, 7250 ADT_NO_AUDIT, ADT_NO_AUDIT, NULL, ADT_NEW)) { 7251 zerror(zone_name, failure, strerror(errno)); 7252 (void) adt_end_session(ah); 7253 return; 7254 } 7255 if (adt_set_proc(ah)) 7256 zerror(zone_name, failure, strerror(errno)); 7257 7258 (void) adt_end_session(ah); 7259 } 7260 7261 static int 7262 start_zoneadmd(const char *zone_name, boolean_t lock) 7263 { 7264 char doorpath[PATH_MAX]; 7265 pid_t child_pid; 7266 int error = -1; 7267 int doorfd, lockfd; 7268 struct door_info info; 7269 7270 if (!get_doorname(zone_name, doorpath)) 7271 return (-1); 7272 7273 if (lock) 7274 if (zonecfg_grab_lock_file(zone_name, &lockfd) != Z_OK) 7275 return (-1); 7276 7277 /* 7278 * Now that we have the lock, re-confirm that the daemon is 7279 * *not* up and working fine. If it is still down, we have a green 7280 * light to start it. 7281 */ 7282 if ((doorfd = open(doorpath, O_RDONLY)) < 0) { 7283 if (errno != ENOENT) { 7284 zperror(doorpath); 7285 goto out; 7286 } 7287 } else { 7288 if (door_info(doorfd, &info) == 0 && 7289 ((info.di_attributes & DOOR_REVOKED) == 0)) { 7290 error = Z_OK; 7291 (void) close(doorfd); 7292 goto out; 7293 } 7294 (void) close(doorfd); 7295 } 7296 7297 if ((child_pid = fork()) == -1) { 7298 zperror(gettext("could not fork")); 7299 goto out; 7300 } 7301 7302 if (child_pid == 0) { 7303 const char *argv[6], **ap; 7304 7305 /* child process */ 7306 prepare_audit_context(zone_name); 7307 7308 ap = argv; 7309 *ap++ = "zoneadmd"; 7310 *ap++ = "-z"; 7311 *ap++ = zone_name; 7312 if (zonecfg_in_alt_root()) { 7313 *ap++ = "-R"; 7314 *ap++ = zonecfg_get_root(); 7315 } 7316 *ap = NULL; 7317 7318 (void) execv("/usr/lib/zones/zoneadmd", (char * const *)argv); 7319 /* 7320 * TRANSLATION_NOTE 7321 * zoneadmd is a literal that should not be translated. 7322 */ 7323 zperror(gettext("could not exec zoneadmd")); 7324 _exit(1); 7325 } else { 7326 /* parent process */ 7327 pid_t retval; 7328 int pstatus = 0; 7329 7330 do { 7331 retval = waitpid(child_pid, &pstatus, 0); 7332 } while (retval != child_pid); 7333 if (WIFSIGNALED(pstatus) || (WIFEXITED(pstatus) && 7334 WEXITSTATUS(pstatus) != 0)) { 7335 zerror(zone_name, gettext("could not start %s"), 7336 "zoneadmd"); 7337 goto out; 7338 } 7339 } 7340 error = Z_OK; 7341 out: 7342 if (lock) 7343 zonecfg_release_lock_file(zone_name, lockfd); 7344 return (error); 7345 } 7346 7347 int 7348 zonecfg_ping_zoneadmd(const char *zone_name) 7349 { 7350 char doorpath[PATH_MAX]; 7351 int doorfd; 7352 struct door_info info; 7353 7354 if (!get_doorname(zone_name, doorpath)) 7355 return (-1); 7356 7357 if ((doorfd = open(doorpath, O_RDONLY)) < 0) { 7358 return (-1); 7359 } 7360 if (door_info(doorfd, &info) == 0 && 7361 ((info.di_attributes & DOOR_REVOKED) == 0)) { 7362 (void) close(doorfd); 7363 return (Z_OK); 7364 } 7365 (void) close(doorfd); 7366 return (-1); 7367 } 7368 7369 int 7370 zonecfg_call_zoneadmd(const char *zone_name, zone_cmd_arg_t *arg, char *locale, 7371 boolean_t lock) 7372 { 7373 char doorpath[PATH_MAX]; 7374 int doorfd, result; 7375 door_arg_t darg; 7376 7377 zoneid_t zoneid; 7378 uint64_t uniqid = 0; 7379 7380 zone_cmd_rval_t *rvalp; 7381 size_t rlen; 7382 char *cp, *errbuf; 7383 7384 rlen = getpagesize(); 7385 if ((rvalp = malloc(rlen)) == NULL) { 7386 zerror(zone_name, gettext("failed to allocate %lu bytes: %s"), 7387 rlen, strerror(errno)); 7388 return (-1); 7389 } 7390 7391 if ((zoneid = getzoneidbyname(zone_name)) != ZONE_ID_UNDEFINED) { 7392 (void) zone_getattr(zoneid, ZONE_ATTR_UNIQID, &uniqid, 7393 sizeof (uniqid)); 7394 } 7395 arg->uniqid = uniqid; 7396 (void) strlcpy(arg->locale, locale, sizeof (arg->locale)); 7397 if (!get_doorname(zone_name, doorpath)) { 7398 zerror(zone_name, gettext("alternate root path is too long")); 7399 free(rvalp); 7400 return (-1); 7401 } 7402 7403 /* 7404 * Loop trying to start zoneadmd; if something goes seriously 7405 * wrong we break out and fail. 7406 */ 7407 for (;;) { 7408 if (start_zoneadmd(zone_name, lock) != Z_OK) 7409 break; 7410 7411 if ((doorfd = open(doorpath, O_RDONLY)) < 0) { 7412 zperror(gettext("failed to open zone door")); 7413 break; 7414 } 7415 7416 darg.data_ptr = (char *)arg; 7417 darg.data_size = sizeof (*arg); 7418 darg.desc_ptr = NULL; 7419 darg.desc_num = 0; 7420 darg.rbuf = (char *)rvalp; 7421 darg.rsize = rlen; 7422 if (door_call(doorfd, &darg) != 0) { 7423 (void) close(doorfd); 7424 /* 7425 * We'll get EBADF if the door has been revoked. 7426 */ 7427 if (errno != EBADF) { 7428 zperror(gettext("door_call failed")); 7429 break; 7430 } 7431 continue; /* take another lap */ 7432 } 7433 (void) close(doorfd); 7434 7435 if (darg.data_size == 0) { 7436 /* Door server is going away; kick it again. */ 7437 continue; 7438 } 7439 7440 errbuf = rvalp->errbuf; 7441 while (*errbuf != '\0') { 7442 /* 7443 * Remove any newlines since zerror() 7444 * will append one automatically. 7445 */ 7446 cp = strchr(errbuf, '\n'); 7447 if (cp != NULL) 7448 *cp = '\0'; 7449 zerror(zone_name, "%s", errbuf); 7450 if (cp == NULL) 7451 break; 7452 errbuf = cp + 1; 7453 } 7454 result = rvalp->rval == 0 ? 0 : -1; 7455 free(rvalp); 7456 return (result); 7457 } 7458 7459 free(rvalp); 7460 return (-1); 7461 } 7462