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