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