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 (zone_getattr(myzoneid, ZONE_ATTR_NAME, myzone, 5024 sizeof (myzone)) < 0) 5025 return (Z_NO_ZONE); 5026 if (strncmp(zone_name, myzone, MAXNAMELEN) != NULL) 5027 return (Z_NO_ZONE); 5028 err = zone_getattr(myzoneid, ZONE_ATTR_BRAND, brandname, rp_sz); 5029 if (err < 0) 5030 return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL); 5031 return (Z_OK); 5032 } 5033 5034 if (strcmp(zone_name, "global") == NULL) { 5035 (void) strlcpy(brandname, NATIVE_BRAND_NAME, rp_sz); 5036 return (0); 5037 } 5038 if ((handle = zonecfg_init_handle()) == NULL) 5039 return (Z_NOMEM); 5040 5041 err = zonecfg_get_handle((char *)zone_name, handle); 5042 if (err == Z_OK) 5043 err = zonecfg_get_brand(handle, brandname, rp_sz); 5044 5045 zonecfg_fini_handle(handle); 5046 return (err); 5047 } 5048 5049 /* 5050 * Return the appropriate root for the active /dev. 5051 * For normal zone, the path is $ZONEPATH/root; 5052 * for scratch zone, the dev path is $ZONEPATH/lu. 5053 */ 5054 int 5055 zone_get_devroot(char *zone_name, char *devroot, size_t rp_sz) 5056 { 5057 int err; 5058 char *suffix; 5059 zone_state_t state; 5060 5061 /* This function makes sense for non-global zones only. */ 5062 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) 5063 return (Z_BOGUS_ZONE_NAME); 5064 if ((err = zone_get_zonepath(zone_name, devroot, rp_sz)) != Z_OK) 5065 return (err); 5066 5067 if (zone_get_state(zone_name, &state) == Z_OK && 5068 state == ZONE_STATE_MOUNTED) 5069 suffix = "/lu"; 5070 else 5071 suffix = "/root"; 5072 if (strlcat(devroot, suffix, rp_sz) >= rp_sz) 5073 return (Z_TOO_BIG); 5074 return (Z_OK); 5075 } 5076 5077 static zone_state_t 5078 kernel_state_to_user_state(zoneid_t zoneid, zone_status_t kernel_state) 5079 { 5080 char zoneroot[MAXPATHLEN]; 5081 size_t zlen; 5082 5083 assert(kernel_state <= ZONE_MAX_STATE); 5084 switch (kernel_state) { 5085 case ZONE_IS_UNINITIALIZED: 5086 return (ZONE_STATE_READY); 5087 case ZONE_IS_READY: 5088 /* 5089 * If the zone's root is mounted on $ZONEPATH/lu, then 5090 * it's a mounted scratch zone. 5091 */ 5092 if (zone_getattr(zoneid, ZONE_ATTR_ROOT, zoneroot, 5093 sizeof (zoneroot)) >= 0) { 5094 zlen = strlen(zoneroot); 5095 if (zlen > 3 && 5096 strcmp(zoneroot + zlen - 3, "/lu") == 0) 5097 return (ZONE_STATE_MOUNTED); 5098 } 5099 return (ZONE_STATE_READY); 5100 case ZONE_IS_BOOTING: 5101 case ZONE_IS_RUNNING: 5102 return (ZONE_STATE_RUNNING); 5103 case ZONE_IS_SHUTTING_DOWN: 5104 case ZONE_IS_EMPTY: 5105 return (ZONE_STATE_SHUTTING_DOWN); 5106 case ZONE_IS_DOWN: 5107 case ZONE_IS_DYING: 5108 case ZONE_IS_DEAD: 5109 default: 5110 return (ZONE_STATE_DOWN); 5111 } 5112 /* NOTREACHED */ 5113 } 5114 5115 int 5116 zone_get_state(char *zone_name, zone_state_t *state_num) 5117 { 5118 zone_status_t status; 5119 zoneid_t zone_id; 5120 struct zoneent *ze; 5121 boolean_t found = B_FALSE; 5122 FILE *cookie; 5123 char kernzone[ZONENAME_MAX]; 5124 FILE *fp; 5125 5126 if (zone_name == NULL) 5127 return (Z_INVAL); 5128 5129 /* 5130 * If we're looking at an alternate root, then we need to query the 5131 * kernel using the scratch zone name. 5132 */ 5133 zone_id = -1; 5134 if (*zonecfg_root != '\0' && !zonecfg_is_scratch(zone_name)) { 5135 if ((fp = zonecfg_open_scratch("", B_FALSE)) != NULL) { 5136 if (zonecfg_find_scratch(fp, zone_name, zonecfg_root, 5137 kernzone, sizeof (kernzone)) == 0) 5138 zone_id = getzoneidbyname(kernzone); 5139 zonecfg_close_scratch(fp); 5140 } 5141 } else { 5142 zone_id = getzoneidbyname(zone_name); 5143 } 5144 5145 /* check to see if zone is running */ 5146 if (zone_id != -1 && 5147 zone_getattr(zone_id, ZONE_ATTR_STATUS, &status, 5148 sizeof (status)) >= 0) { 5149 *state_num = kernel_state_to_user_state(zone_id, status); 5150 return (Z_OK); 5151 } 5152 5153 cookie = setzoneent(); 5154 while ((ze = getzoneent_private(cookie)) != NULL) { 5155 if (strcmp(ze->zone_name, zone_name) == 0) { 5156 found = B_TRUE; 5157 *state_num = ze->zone_state; 5158 } 5159 free(ze); 5160 if (found) 5161 break; 5162 } 5163 endzoneent(cookie); 5164 return ((found) ? Z_OK : Z_NO_ZONE); 5165 } 5166 5167 int 5168 zone_set_state(char *zone, zone_state_t state) 5169 { 5170 struct zoneent ze; 5171 5172 if (state != ZONE_STATE_CONFIGURED && state != ZONE_STATE_INSTALLED && 5173 state != ZONE_STATE_INCOMPLETE) 5174 return (Z_INVAL); 5175 5176 bzero(&ze, sizeof (ze)); 5177 (void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name)); 5178 ze.zone_state = state; 5179 (void) strlcpy(ze.zone_path, "", sizeof (ze.zone_path)); 5180 return (putzoneent(&ze, PZE_MODIFY)); 5181 } 5182 5183 /* 5184 * Get id (if any) for specified zone. There are four possible outcomes: 5185 * - If the string corresponds to the numeric id of an active (booted) 5186 * zone, sets *zip to the zone id and returns 0. 5187 * - If the string corresponds to the name of an active (booted) zone, 5188 * sets *zip to the zone id and returns 0. 5189 * - If the string is a name in the configuration but is not booted, 5190 * sets *zip to ZONE_ID_UNDEFINED and returns 0. 5191 * - Otherwise, leaves *zip unchanged and returns -1. 5192 * 5193 * This function acts as an auxiliary filter on the function of the same 5194 * name in libc; the linker binds to this version if libzonecfg exists, 5195 * and the libc version if it doesn't. Any changes to this version of 5196 * the function should probably be reflected in the libc version as well. 5197 */ 5198 int 5199 zone_get_id(const char *str, zoneid_t *zip) 5200 { 5201 zone_dochandle_t hdl; 5202 zoneid_t zoneid; 5203 char *cp; 5204 int err; 5205 5206 /* first try looking for active zone by id */ 5207 errno = 0; 5208 zoneid = (zoneid_t)strtol(str, &cp, 0); 5209 if (errno == 0 && cp != str && *cp == '\0' && 5210 getzonenamebyid(zoneid, NULL, 0) != -1) { 5211 *zip = zoneid; 5212 return (0); 5213 } 5214 5215 /* then look for active zone by name */ 5216 if ((zoneid = getzoneidbyname(str)) != -1) { 5217 *zip = zoneid; 5218 return (0); 5219 } 5220 5221 /* if in global zone, try looking up name in configuration database */ 5222 if (getzoneid() != GLOBAL_ZONEID || 5223 (hdl = zonecfg_init_handle()) == NULL) 5224 return (-1); 5225 5226 if (zonecfg_get_handle(str, hdl) == Z_OK) { 5227 /* zone exists but isn't active */ 5228 *zip = ZONE_ID_UNDEFINED; 5229 err = 0; 5230 } else { 5231 err = -1; 5232 } 5233 5234 zonecfg_fini_handle(hdl); 5235 return (err); 5236 } 5237 5238 char * 5239 zone_state_str(zone_state_t state_num) 5240 { 5241 switch (state_num) { 5242 case ZONE_STATE_CONFIGURED: 5243 return (ZONE_STATE_STR_CONFIGURED); 5244 case ZONE_STATE_INCOMPLETE: 5245 return (ZONE_STATE_STR_INCOMPLETE); 5246 case ZONE_STATE_INSTALLED: 5247 return (ZONE_STATE_STR_INSTALLED); 5248 case ZONE_STATE_READY: 5249 return (ZONE_STATE_STR_READY); 5250 case ZONE_STATE_MOUNTED: 5251 return (ZONE_STATE_STR_MOUNTED); 5252 case ZONE_STATE_RUNNING: 5253 return (ZONE_STATE_STR_RUNNING); 5254 case ZONE_STATE_SHUTTING_DOWN: 5255 return (ZONE_STATE_STR_SHUTTING_DOWN); 5256 case ZONE_STATE_DOWN: 5257 return (ZONE_STATE_STR_DOWN); 5258 default: 5259 return ("unknown"); 5260 } 5261 } 5262 5263 /* 5264 * Given a UUID value, find an associated zone name. This is intended to be 5265 * used by callers who set up some 'default' name (corresponding to the 5266 * expected name for the zone) in the zonename buffer, and thus the function 5267 * doesn't touch this buffer on failure. 5268 */ 5269 int 5270 zonecfg_get_name_by_uuid(const uuid_t uuidin, char *zonename, size_t namelen) 5271 { 5272 FILE *fp; 5273 struct zoneent *ze; 5274 uchar_t *uuid; 5275 5276 /* 5277 * A small amount of subterfuge via casts is necessary here because 5278 * libuuid doesn't use const correctly, but we don't want to export 5279 * this brokenness to our clients. 5280 */ 5281 uuid = (uchar_t *)uuidin; 5282 if (uuid_is_null(uuid)) 5283 return (Z_NO_ZONE); 5284 if ((fp = setzoneent()) == NULL) 5285 return (Z_NO_ZONE); 5286 while ((ze = getzoneent_private(fp)) != NULL) { 5287 if (uuid_compare(uuid, ze->zone_uuid) == 0) 5288 break; 5289 free(ze); 5290 } 5291 endzoneent(fp); 5292 if (ze != NULL) { 5293 (void) strlcpy(zonename, ze->zone_name, namelen); 5294 free(ze); 5295 return (Z_OK); 5296 } else { 5297 return (Z_NO_ZONE); 5298 } 5299 } 5300 5301 /* 5302 * Given a zone name, get its UUID. Returns a "NULL" UUID value if the zone 5303 * exists but the file doesn't have a value set yet. Returns an error if the 5304 * zone cannot be located. 5305 */ 5306 int 5307 zonecfg_get_uuid(const char *zonename, uuid_t uuid) 5308 { 5309 FILE *fp; 5310 struct zoneent *ze; 5311 5312 if ((fp = setzoneent()) == NULL) 5313 return (Z_NO_ZONE); 5314 while ((ze = getzoneent_private(fp)) != NULL) { 5315 if (strcmp(ze->zone_name, zonename) == 0) 5316 break; 5317 free(ze); 5318 } 5319 endzoneent(fp); 5320 if (ze != NULL) { 5321 uuid_copy(uuid, ze->zone_uuid); 5322 free(ze); 5323 return (Z_OK); 5324 } else { 5325 return (Z_NO_ZONE); 5326 } 5327 } 5328 5329 /* 5330 * File-system convenience functions. 5331 */ 5332 boolean_t 5333 zonecfg_valid_fs_type(const char *type) 5334 { 5335 /* 5336 * We already know which FS types don't work. 5337 */ 5338 if (strcmp(type, "proc") == 0 || 5339 strcmp(type, "mntfs") == 0 || 5340 strcmp(type, "autofs") == 0 || 5341 strncmp(type, "nfs", sizeof ("nfs") - 1) == 0 || 5342 strcmp(type, "cachefs") == 0) 5343 return (B_FALSE); 5344 /* 5345 * The caller may do more detailed verification to make sure other 5346 * aspects of this filesystem type make sense. 5347 */ 5348 return (B_TRUE); 5349 } 5350 5351 /* 5352 * Generally uninteresting rctl convenience functions. 5353 */ 5354 5355 int 5356 zonecfg_construct_rctlblk(const struct zone_rctlvaltab *rctlval, 5357 rctlblk_t *rctlblk) 5358 { 5359 unsigned long long ull; 5360 char *endp; 5361 rctl_priv_t priv; 5362 rctl_qty_t limit; 5363 uint_t action; 5364 5365 /* Get the privilege */ 5366 if (strcmp(rctlval->zone_rctlval_priv, "basic") == 0) { 5367 priv = RCPRIV_BASIC; 5368 } else if (strcmp(rctlval->zone_rctlval_priv, "privileged") == 0) { 5369 priv = RCPRIV_PRIVILEGED; 5370 } else { 5371 /* Invalid privilege */ 5372 return (Z_INVAL); 5373 } 5374 5375 /* deal with negative input; strtoull(3c) doesn't do what we want */ 5376 if (rctlval->zone_rctlval_limit[0] == '-') 5377 return (Z_INVAL); 5378 /* Get the limit */ 5379 errno = 0; 5380 ull = strtoull(rctlval->zone_rctlval_limit, &endp, 0); 5381 if (errno != 0 || *endp != '\0') { 5382 /* parse failed */ 5383 return (Z_INVAL); 5384 } 5385 limit = (rctl_qty_t)ull; 5386 5387 /* Get the action */ 5388 if (strcmp(rctlval->zone_rctlval_action, "none") == 0) { 5389 action = RCTL_LOCAL_NOACTION; 5390 } else if (strcmp(rctlval->zone_rctlval_action, "signal") == 0) { 5391 action = RCTL_LOCAL_SIGNAL; 5392 } else if (strcmp(rctlval->zone_rctlval_action, "deny") == 0) { 5393 action = RCTL_LOCAL_DENY; 5394 } else { 5395 /* Invalid Action */ 5396 return (Z_INVAL); 5397 } 5398 rctlblk_set_local_action(rctlblk, action, 0); 5399 rctlblk_set_privilege(rctlblk, priv); 5400 rctlblk_set_value(rctlblk, limit); 5401 return (Z_OK); 5402 } 5403 5404 static int 5405 rctl_check(const char *rctlname, void *arg) 5406 { 5407 const char *attrname = arg; 5408 5409 /* 5410 * Returning 1 here is our signal to zonecfg_is_rctl() that it is 5411 * indeed an rctl name recognized by the system. 5412 */ 5413 return (strcmp(rctlname, attrname) == 0 ? 1 : 0); 5414 } 5415 5416 boolean_t 5417 zonecfg_is_rctl(const char *name) 5418 { 5419 return (rctl_walk(rctl_check, (void *)name) == 1); 5420 } 5421 5422 boolean_t 5423 zonecfg_valid_rctlname(const char *name) 5424 { 5425 const char *c; 5426 5427 if (strncmp(name, "zone.", sizeof ("zone.") - 1) != 0) 5428 return (B_FALSE); 5429 if (strlen(name) == sizeof ("zone.") - 1) 5430 return (B_FALSE); 5431 for (c = name + sizeof ("zone.") - 1; *c != '\0'; c++) { 5432 if (!isalpha(*c) && *c != '-') 5433 return (B_FALSE); 5434 } 5435 return (B_TRUE); 5436 } 5437 5438 boolean_t 5439 zonecfg_valid_rctlblk(const rctlblk_t *rctlblk) 5440 { 5441 rctl_priv_t priv = rctlblk_get_privilege((rctlblk_t *)rctlblk); 5442 uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL); 5443 5444 if (priv != RCPRIV_PRIVILEGED) 5445 return (B_FALSE); 5446 if (action != RCTL_LOCAL_NOACTION && action != RCTL_LOCAL_DENY) 5447 return (B_FALSE); 5448 return (B_TRUE); 5449 } 5450 5451 boolean_t 5452 zonecfg_valid_rctl(const char *name, const rctlblk_t *rctlblk) 5453 { 5454 rctlblk_t *current, *next; 5455 rctl_qty_t limit = rctlblk_get_value((rctlblk_t *)rctlblk); 5456 uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL); 5457 uint_t global_flags; 5458 5459 if (!zonecfg_valid_rctlblk(rctlblk)) 5460 return (B_FALSE); 5461 if (!zonecfg_valid_rctlname(name)) 5462 return (B_FALSE); 5463 5464 current = alloca(rctlblk_size()); 5465 if (getrctl(name, NULL, current, RCTL_FIRST) != 0) 5466 return (B_TRUE); /* not an rctl on this system */ 5467 /* 5468 * Make sure the proposed value isn't greater than the current system 5469 * value. 5470 */ 5471 next = alloca(rctlblk_size()); 5472 while (rctlblk_get_privilege(current) != RCPRIV_SYSTEM) { 5473 rctlblk_t *tmp; 5474 5475 if (getrctl(name, current, next, RCTL_NEXT) != 0) 5476 return (B_FALSE); /* shouldn't happen */ 5477 tmp = current; 5478 current = next; 5479 next = tmp; 5480 } 5481 if (limit > rctlblk_get_value(current)) 5482 return (B_FALSE); 5483 5484 /* 5485 * Make sure the proposed action is allowed. 5486 */ 5487 global_flags = rctlblk_get_global_flags(current); 5488 if ((global_flags & RCTL_GLOBAL_DENY_NEVER) && 5489 action == RCTL_LOCAL_DENY) 5490 return (B_FALSE); 5491 if ((global_flags & RCTL_GLOBAL_DENY_ALWAYS) && 5492 action == RCTL_LOCAL_NOACTION) 5493 return (B_FALSE); 5494 5495 return (B_TRUE); 5496 } 5497 5498 /* 5499 * There is always a race condition between reading the initial copy of 5500 * a zones state and its state changing. We address this by providing 5501 * zonecfg_notify_critical_enter and zonecfg_noticy_critical_exit functions. 5502 * When zonecfg_critical_enter is called, sets the state field to LOCKED 5503 * and aquires biglock. Biglock protects against other threads executing 5504 * critical_enter and the state field protects against state changes during 5505 * the critical period. 5506 * 5507 * If any state changes occur, zn_cb will set the failed field of the znotify 5508 * structure. This will cause the critical_exit function to re-lock the 5509 * channel and return an error. Since evsnts may be delayed, the critical_exit 5510 * function "flushes" the queue by putting an event on the queue and waiting for 5511 * zn_cb to notify critical_exit that it received the ping event. 5512 */ 5513 static const char * 5514 string_get_tok(const char *in, char delim, int num) 5515 { 5516 int i = 0; 5517 5518 for (; i < num; in++) { 5519 if (*in == delim) 5520 i++; 5521 if (*in == 0) 5522 return (NULL); 5523 } 5524 return (in); 5525 } 5526 5527 static boolean_t 5528 is_ping(sysevent_t *ev) 5529 { 5530 if (strcmp(sysevent_get_subclass_name(ev), 5531 ZONE_EVENT_PING_SUBCLASS) == 0) { 5532 return (B_TRUE); 5533 } else { 5534 return (B_FALSE); 5535 } 5536 } 5537 5538 static boolean_t 5539 is_my_ping(sysevent_t *ev) 5540 { 5541 const char *sender; 5542 char mypid[sizeof (pid_t) * 3 + 1]; 5543 5544 (void) snprintf(mypid, sizeof (mypid), "%i", getpid()); 5545 sender = string_get_tok(sysevent_get_pub(ev), ':', 3); 5546 if (sender == NULL) 5547 return (B_FALSE); 5548 if (strcmp(sender, mypid) != 0) 5549 return (B_FALSE); 5550 return (B_TRUE); 5551 } 5552 5553 static int 5554 do_callback(struct znotify *zevtchan, sysevent_t *ev) 5555 { 5556 nvlist_t *l; 5557 int zid; 5558 char *zonename; 5559 char *newstate; 5560 char *oldstate; 5561 int ret; 5562 hrtime_t when; 5563 5564 if (strcmp(sysevent_get_subclass_name(ev), 5565 ZONE_EVENT_STATUS_SUBCLASS) == 0) { 5566 5567 if (sysevent_get_attr_list(ev, &l) != 0) { 5568 if (errno == ENOMEM) { 5569 zevtchan->zn_failure_count++; 5570 return (EAGAIN); 5571 } 5572 return (0); 5573 } 5574 ret = 0; 5575 5576 if ((nvlist_lookup_string(l, ZONE_CB_NAME, &zonename) == 0) && 5577 (nvlist_lookup_string(l, ZONE_CB_NEWSTATE, &newstate) 5578 == 0) && 5579 (nvlist_lookup_string(l, ZONE_CB_OLDSTATE, &oldstate) 5580 == 0) && 5581 (nvlist_lookup_uint64(l, ZONE_CB_TIMESTAMP, 5582 (uint64_t *)&when) == 0) && 5583 (nvlist_lookup_int32(l, ZONE_CB_ZONEID, &zid) == 0)) { 5584 ret = zevtchan->zn_callback(zonename, zid, newstate, 5585 oldstate, when, zevtchan->zn_private); 5586 } 5587 5588 zevtchan->zn_failure_count = 0; 5589 nvlist_free(l); 5590 return (ret); 5591 } else { 5592 /* 5593 * We have received an event in an unknown subclass. Ignore. 5594 */ 5595 zevtchan->zn_failure_count = 0; 5596 return (0); 5597 } 5598 } 5599 5600 static int 5601 zn_cb(sysevent_t *ev, void *p) 5602 { 5603 struct znotify *zevtchan = p; 5604 int error; 5605 5606 (void) pthread_mutex_lock(&(zevtchan->zn_mutex)); 5607 5608 if (is_ping(ev) && !is_my_ping(ev)) { 5609 (void) pthread_mutex_unlock((&zevtchan->zn_mutex)); 5610 return (0); 5611 } 5612 5613 if (zevtchan->zn_state == ZN_LOCKED) { 5614 assert(!is_ping(ev)); 5615 zevtchan->zn_failed = B_TRUE; 5616 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5617 return (0); 5618 } 5619 5620 if (zevtchan->zn_state == ZN_PING_INFLIGHT) { 5621 if (is_ping(ev)) { 5622 zevtchan->zn_state = ZN_PING_RECEIVED; 5623 (void) pthread_cond_signal(&(zevtchan->zn_cond)); 5624 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5625 return (0); 5626 } else { 5627 zevtchan->zn_failed = B_TRUE; 5628 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5629 return (0); 5630 } 5631 } 5632 5633 if (zevtchan->zn_state == ZN_UNLOCKED) { 5634 5635 error = do_callback(zevtchan, ev); 5636 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5637 /* 5638 * Every ENOMEM failure causes do_callback to increment 5639 * zn_failure_count and every success causes it to 5640 * set zn_failure_count to zero. If we got EAGAIN, 5641 * we will sleep for zn_failure_count seconds and return 5642 * EAGAIN to gpec to try again. 5643 * 5644 * After 55 seconds, or 10 try's we give up and drop the 5645 * event. 5646 */ 5647 if (error == EAGAIN) { 5648 if (zevtchan->zn_failure_count > ZONE_CB_RETRY_COUNT) { 5649 return (0); 5650 } 5651 (void) sleep(zevtchan->zn_failure_count); 5652 } 5653 return (error); 5654 } 5655 5656 if (zevtchan->zn_state == ZN_PING_RECEIVED) { 5657 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5658 return (0); 5659 } 5660 5661 abort(); 5662 return (0); 5663 } 5664 5665 void 5666 zonecfg_notify_critical_enter(void *h) 5667 { 5668 struct znotify *zevtchan = h; 5669 5670 (void) pthread_mutex_lock(&(zevtchan->zn_bigmutex)); 5671 zevtchan->zn_state = ZN_LOCKED; 5672 } 5673 5674 int 5675 zonecfg_notify_critical_exit(void * h) 5676 { 5677 5678 struct znotify *zevtchan = h; 5679 5680 if (zevtchan->zn_state == ZN_UNLOCKED) 5681 return (0); 5682 5683 (void) pthread_mutex_lock(&(zevtchan->zn_mutex)); 5684 zevtchan->zn_state = ZN_PING_INFLIGHT; 5685 5686 (void) sysevent_evc_publish(zevtchan->zn_eventchan, 5687 ZONE_EVENT_STATUS_CLASS, 5688 ZONE_EVENT_PING_SUBCLASS, ZONE_EVENT_PING_PUBLISHER, 5689 zevtchan->zn_subscriber_id, NULL, EVCH_SLEEP); 5690 5691 while (zevtchan->zn_state != ZN_PING_RECEIVED) { 5692 (void) pthread_cond_wait(&(zevtchan->zn_cond), 5693 &(zevtchan->zn_mutex)); 5694 } 5695 5696 if (zevtchan->zn_failed == B_TRUE) { 5697 zevtchan->zn_state = ZN_LOCKED; 5698 zevtchan->zn_failed = B_FALSE; 5699 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5700 return (1); 5701 } 5702 5703 zevtchan->zn_state = ZN_UNLOCKED; 5704 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 5705 (void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex)); 5706 return (0); 5707 } 5708 5709 void 5710 zonecfg_notify_critical_abort(void *h) 5711 { 5712 struct znotify *zevtchan = h; 5713 5714 zevtchan->zn_state = ZN_UNLOCKED; 5715 zevtchan->zn_failed = B_FALSE; 5716 /* 5717 * Don't do anything about zn_lock. If it is held, it could only be 5718 * held by zn_cb and it will be unlocked soon. 5719 */ 5720 (void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex)); 5721 } 5722 5723 void * 5724 zonecfg_notify_bind(int(*func)(const char *zonename, zoneid_t zid, 5725 const char *newstate, const char *oldstate, hrtime_t when, void *p), 5726 void *p) 5727 { 5728 struct znotify *zevtchan; 5729 int i = 1; 5730 int r; 5731 5732 zevtchan = malloc(sizeof (struct znotify)); 5733 5734 if (zevtchan == NULL) 5735 return (NULL); 5736 5737 zevtchan->zn_private = p; 5738 zevtchan->zn_callback = func; 5739 zevtchan->zn_state = ZN_UNLOCKED; 5740 zevtchan->zn_failed = B_FALSE; 5741 5742 if (pthread_mutex_init(&(zevtchan->zn_mutex), NULL)) 5743 goto out3; 5744 if (pthread_cond_init(&(zevtchan->zn_cond), NULL)) { 5745 (void) pthread_mutex_destroy(&(zevtchan->zn_mutex)); 5746 goto out3; 5747 } 5748 if (pthread_mutex_init(&(zevtchan->zn_bigmutex), NULL)) { 5749 (void) pthread_mutex_destroy(&(zevtchan->zn_mutex)); 5750 (void) pthread_cond_destroy(&(zevtchan->zn_cond)); 5751 goto out3; 5752 } 5753 5754 if (sysevent_evc_bind(ZONE_EVENT_CHANNEL, &(zevtchan->zn_eventchan), 5755 0) != 0) 5756 goto out2; 5757 5758 do { 5759 /* 5760 * At 4 digits the subscriber ID gets too long and we have 5761 * no chance of successfully registering. 5762 */ 5763 if (i > 999) 5764 goto out1; 5765 5766 (void) sprintf(zevtchan->zn_subscriber_id, "zone_%li_%i", 5767 getpid() % 999999l, i); 5768 5769 r = sysevent_evc_subscribe(zevtchan->zn_eventchan, 5770 zevtchan->zn_subscriber_id, ZONE_EVENT_STATUS_CLASS, zn_cb, 5771 zevtchan, 0); 5772 5773 i++; 5774 5775 } while (r); 5776 5777 return (zevtchan); 5778 out1: 5779 sysevent_evc_unbind(zevtchan->zn_eventchan); 5780 out2: 5781 (void) pthread_mutex_destroy(&zevtchan->zn_mutex); 5782 (void) pthread_cond_destroy(&zevtchan->zn_cond); 5783 (void) pthread_mutex_destroy(&(zevtchan->zn_bigmutex)); 5784 out3: 5785 free(zevtchan); 5786 5787 return (NULL); 5788 } 5789 5790 void 5791 zonecfg_notify_unbind(void *handle) 5792 { 5793 5794 int ret; 5795 5796 sysevent_evc_unbind(((struct znotify *)handle)->zn_eventchan); 5797 /* 5798 * Check that all evc threads have gone away. This should be 5799 * enforced by sysevent_evc_unbind. 5800 */ 5801 ret = pthread_mutex_trylock(&((struct znotify *)handle)->zn_mutex); 5802 5803 if (ret) 5804 abort(); 5805 5806 (void) pthread_mutex_unlock(&((struct znotify *)handle)->zn_mutex); 5807 (void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_mutex); 5808 (void) pthread_cond_destroy(&((struct znotify *)handle)->zn_cond); 5809 (void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_bigmutex); 5810 5811 free(handle); 5812 } 5813 5814 static int 5815 zonecfg_add_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr) 5816 { 5817 xmlNodePtr newnode, cur = handle->zone_dh_cur; 5818 int err; 5819 5820 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DATASET, NULL); 5821 if ((err = newprop(newnode, DTD_ATTR_NAME, 5822 tabptr->zone_dataset_name)) != Z_OK) 5823 return (err); 5824 return (Z_OK); 5825 } 5826 5827 int 5828 zonecfg_add_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 5829 { 5830 int err; 5831 5832 if (tabptr == NULL) 5833 return (Z_INVAL); 5834 5835 if ((err = operation_prep(handle)) != Z_OK) 5836 return (err); 5837 5838 if ((err = zonecfg_add_ds_core(handle, tabptr)) != Z_OK) 5839 return (err); 5840 5841 return (Z_OK); 5842 } 5843 5844 static int 5845 zonecfg_delete_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr) 5846 { 5847 xmlNodePtr cur = handle->zone_dh_cur; 5848 5849 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 5850 if (xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 5851 continue; 5852 5853 if (match_prop(cur, DTD_ATTR_NAME, 5854 tabptr->zone_dataset_name)) { 5855 xmlUnlinkNode(cur); 5856 xmlFreeNode(cur); 5857 return (Z_OK); 5858 } 5859 } 5860 return (Z_NO_RESOURCE_ID); 5861 } 5862 5863 int 5864 zonecfg_delete_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 5865 { 5866 int err; 5867 5868 if (tabptr == NULL) 5869 return (Z_INVAL); 5870 5871 if ((err = operation_prep(handle)) != Z_OK) 5872 return (err); 5873 5874 if ((err = zonecfg_delete_ds_core(handle, tabptr)) != Z_OK) 5875 return (err); 5876 5877 return (Z_OK); 5878 } 5879 5880 int 5881 zonecfg_modify_ds( 5882 zone_dochandle_t handle, 5883 struct zone_dstab *oldtabptr, 5884 struct zone_dstab *newtabptr) 5885 { 5886 int err; 5887 5888 if (oldtabptr == NULL || newtabptr == NULL) 5889 return (Z_INVAL); 5890 5891 if ((err = operation_prep(handle)) != Z_OK) 5892 return (err); 5893 5894 if ((err = zonecfg_delete_ds_core(handle, oldtabptr)) != Z_OK) 5895 return (err); 5896 5897 if ((err = zonecfg_add_ds_core(handle, newtabptr)) != Z_OK) 5898 return (err); 5899 5900 return (Z_OK); 5901 } 5902 5903 int 5904 zonecfg_lookup_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 5905 { 5906 xmlNodePtr cur, firstmatch; 5907 int err; 5908 char dataset[MAXNAMELEN]; 5909 5910 if (tabptr == NULL) 5911 return (Z_INVAL); 5912 5913 if ((err = operation_prep(handle)) != Z_OK) 5914 return (err); 5915 5916 cur = handle->zone_dh_cur; 5917 firstmatch = NULL; 5918 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 5919 if (xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 5920 continue; 5921 if (strlen(tabptr->zone_dataset_name) > 0) { 5922 if ((fetchprop(cur, DTD_ATTR_NAME, dataset, 5923 sizeof (dataset)) == Z_OK) && 5924 (strcmp(tabptr->zone_dataset_name, 5925 dataset) == 0)) { 5926 if (firstmatch == NULL) 5927 firstmatch = cur; 5928 else 5929 return (Z_INSUFFICIENT_SPEC); 5930 } 5931 } 5932 } 5933 if (firstmatch == NULL) 5934 return (Z_NO_RESOURCE_ID); 5935 5936 cur = firstmatch; 5937 5938 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name, 5939 sizeof (tabptr->zone_dataset_name))) != Z_OK) 5940 return (err); 5941 5942 return (Z_OK); 5943 } 5944 5945 int 5946 zonecfg_setdsent(zone_dochandle_t handle) 5947 { 5948 return (zonecfg_setent(handle)); 5949 } 5950 5951 int 5952 zonecfg_getdsent(zone_dochandle_t handle, struct zone_dstab *tabptr) 5953 { 5954 xmlNodePtr cur; 5955 int err; 5956 5957 if (handle == NULL) 5958 return (Z_INVAL); 5959 5960 if ((cur = handle->zone_dh_cur) == NULL) 5961 return (Z_NO_ENTRY); 5962 5963 for (; cur != NULL; cur = cur->next) 5964 if (!xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 5965 break; 5966 if (cur == NULL) { 5967 handle->zone_dh_cur = handle->zone_dh_top; 5968 return (Z_NO_ENTRY); 5969 } 5970 5971 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name, 5972 sizeof (tabptr->zone_dataset_name))) != Z_OK) { 5973 handle->zone_dh_cur = handle->zone_dh_top; 5974 return (err); 5975 } 5976 5977 handle->zone_dh_cur = cur->next; 5978 return (Z_OK); 5979 } 5980 5981 int 5982 zonecfg_enddsent(zone_dochandle_t handle) 5983 { 5984 return (zonecfg_endent(handle)); 5985 } 5986 5987 /* 5988 * Support for aliased rctls; that is, rctls that have simplified names in 5989 * zonecfg. For example, max-lwps is an alias for a well defined zone.max-lwps 5990 * rctl. If there are multiple existing values for one of these rctls or if 5991 * there is a single value that does not match the well defined template (i.e. 5992 * it has a different action) then we cannot treat the rctl as having an alias 5993 * so we return Z_ALIAS_DISALLOW. That means that the rctl cannot be 5994 * managed in zonecfg via an alias and that the standard rctl syntax must be 5995 * used. 5996 * 5997 * The possible return values are: 5998 * Z_NO_PROPERTY_ID - invalid alias name 5999 * Z_ALIAS_DISALLOW - pre-existing, incompatible rctl definition 6000 * Z_NO_ENTRY - no rctl is configured for this alias 6001 * Z_OK - we got a valid rctl for the specified alias 6002 */ 6003 int 6004 zonecfg_get_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t *rval) 6005 { 6006 boolean_t found = B_FALSE; 6007 boolean_t found_val = B_FALSE; 6008 xmlNodePtr cur, val; 6009 char savedname[MAXNAMELEN]; 6010 struct zone_rctlvaltab rctl; 6011 int i; 6012 int err; 6013 6014 for (i = 0; aliases[i].shortname != NULL; i++) 6015 if (strcmp(name, aliases[i].shortname) == 0) 6016 break; 6017 6018 if (aliases[i].shortname == NULL) 6019 return (Z_NO_PROPERTY_ID); 6020 6021 if ((err = operation_prep(handle)) != Z_OK) 6022 return (err); 6023 6024 cur = handle->zone_dh_cur; 6025 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6026 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL) != 0) 6027 continue; 6028 if ((fetchprop(cur, DTD_ATTR_NAME, savedname, 6029 sizeof (savedname)) == Z_OK) && 6030 (strcmp(savedname, aliases[i].realname) == 0)) { 6031 6032 /* 6033 * If we already saw one of these, we can't have an 6034 * alias since we just found another. 6035 */ 6036 if (found) 6037 return (Z_ALIAS_DISALLOW); 6038 found = B_TRUE; 6039 6040 for (val = cur->xmlChildrenNode; val != NULL; 6041 val = val->next) { 6042 /* 6043 * If we already have one value, we can't have 6044 * an alias since we just found another. 6045 */ 6046 if (found_val) 6047 return (Z_ALIAS_DISALLOW); 6048 found_val = B_TRUE; 6049 6050 if ((fetchprop(val, DTD_ATTR_PRIV, 6051 rctl.zone_rctlval_priv, 6052 sizeof (rctl.zone_rctlval_priv)) != Z_OK)) 6053 break; 6054 if ((fetchprop(val, DTD_ATTR_LIMIT, 6055 rctl.zone_rctlval_limit, 6056 sizeof (rctl.zone_rctlval_limit)) != Z_OK)) 6057 break; 6058 if ((fetchprop(val, DTD_ATTR_ACTION, 6059 rctl.zone_rctlval_action, 6060 sizeof (rctl.zone_rctlval_action)) != Z_OK)) 6061 break; 6062 } 6063 6064 /* check priv and action match the expected vals */ 6065 if (strcmp(rctl.zone_rctlval_priv, 6066 aliases[i].priv) != 0 || 6067 strcmp(rctl.zone_rctlval_action, 6068 aliases[i].action) != 0) 6069 return (Z_ALIAS_DISALLOW); 6070 } 6071 } 6072 6073 if (found) { 6074 *rval = strtoull(rctl.zone_rctlval_limit, NULL, 10); 6075 return (Z_OK); 6076 } 6077 6078 return (Z_NO_ENTRY); 6079 } 6080 6081 int 6082 zonecfg_rm_aliased_rctl(zone_dochandle_t handle, char *name) 6083 { 6084 int i; 6085 uint64_t val; 6086 struct zone_rctltab rctltab; 6087 6088 /* 6089 * First check that we have a valid aliased rctl to remove. 6090 * This will catch an rctl entry with non-standard values or 6091 * multiple rctl values for this name. We need to ignore those 6092 * rctl entries. 6093 */ 6094 if (zonecfg_get_aliased_rctl(handle, name, &val) != Z_OK) 6095 return (Z_OK); 6096 6097 for (i = 0; aliases[i].shortname != NULL; i++) 6098 if (strcmp(name, aliases[i].shortname) == 0) 6099 break; 6100 6101 if (aliases[i].shortname == NULL) 6102 return (Z_NO_RESOURCE_ID); 6103 6104 (void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname, 6105 sizeof (rctltab.zone_rctl_name)); 6106 6107 return (zonecfg_delete_rctl(handle, &rctltab)); 6108 } 6109 6110 boolean_t 6111 zonecfg_aliased_rctl_ok(zone_dochandle_t handle, char *name) 6112 { 6113 uint64_t tmp_val; 6114 6115 switch (zonecfg_get_aliased_rctl(handle, name, &tmp_val)) { 6116 case Z_OK: 6117 /*FALLTHRU*/ 6118 case Z_NO_ENTRY: 6119 return (B_TRUE); 6120 default: 6121 return (B_FALSE); 6122 } 6123 } 6124 6125 int 6126 zonecfg_set_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t val) 6127 { 6128 int i; 6129 int err; 6130 struct zone_rctltab rctltab; 6131 struct zone_rctlvaltab *rctlvaltab; 6132 char buf[128]; 6133 6134 if (!zonecfg_aliased_rctl_ok(handle, name)) 6135 return (Z_ALIAS_DISALLOW); 6136 6137 for (i = 0; aliases[i].shortname != NULL; i++) 6138 if (strcmp(name, aliases[i].shortname) == 0) 6139 break; 6140 6141 if (aliases[i].shortname == NULL) 6142 return (Z_NO_RESOURCE_ID); 6143 6144 /* remove any pre-existing definition for this rctl */ 6145 (void) zonecfg_rm_aliased_rctl(handle, name); 6146 6147 (void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname, 6148 sizeof (rctltab.zone_rctl_name)); 6149 6150 rctltab.zone_rctl_valptr = NULL; 6151 6152 if ((rctlvaltab = calloc(1, sizeof (struct zone_rctlvaltab))) == NULL) 6153 return (Z_NOMEM); 6154 6155 (void) snprintf(buf, sizeof (buf), "%llu", (long long)val); 6156 6157 (void) strlcpy(rctlvaltab->zone_rctlval_priv, aliases[i].priv, 6158 sizeof (rctlvaltab->zone_rctlval_priv)); 6159 (void) strlcpy(rctlvaltab->zone_rctlval_limit, buf, 6160 sizeof (rctlvaltab->zone_rctlval_limit)); 6161 (void) strlcpy(rctlvaltab->zone_rctlval_action, aliases[i].action, 6162 sizeof (rctlvaltab->zone_rctlval_action)); 6163 6164 rctlvaltab->zone_rctlval_next = NULL; 6165 6166 if ((err = zonecfg_add_rctl_value(&rctltab, rctlvaltab)) != Z_OK) 6167 return (err); 6168 6169 return (zonecfg_add_rctl(handle, &rctltab)); 6170 } 6171 6172 static int 6173 delete_tmp_pool(zone_dochandle_t handle) 6174 { 6175 int err; 6176 xmlNodePtr cur = handle->zone_dh_cur; 6177 6178 if ((err = operation_prep(handle)) != Z_OK) 6179 return (err); 6180 6181 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6182 if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) { 6183 xmlUnlinkNode(cur); 6184 xmlFreeNode(cur); 6185 return (Z_OK); 6186 } 6187 } 6188 6189 return (Z_NO_RESOURCE_ID); 6190 } 6191 6192 static int 6193 modify_tmp_pool(zone_dochandle_t handle, char *pool_importance) 6194 { 6195 int err; 6196 xmlNodePtr cur = handle->zone_dh_cur; 6197 xmlNodePtr newnode; 6198 6199 err = delete_tmp_pool(handle); 6200 if (err != Z_OK && err != Z_NO_RESOURCE_ID) 6201 return (err); 6202 6203 if (*pool_importance != '\0') { 6204 if ((err = operation_prep(handle)) != Z_OK) 6205 return (err); 6206 6207 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_TMPPOOL, NULL); 6208 if ((err = newprop(newnode, DTD_ATTR_IMPORTANCE, 6209 pool_importance)) != Z_OK) 6210 return (err); 6211 } 6212 6213 return (Z_OK); 6214 } 6215 6216 static int 6217 add_pset_core(zone_dochandle_t handle, struct zone_psettab *tabptr) 6218 { 6219 xmlNodePtr newnode, cur = handle->zone_dh_cur; 6220 int err; 6221 6222 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PSET, NULL); 6223 if ((err = newprop(newnode, DTD_ATTR_NCPU_MIN, 6224 tabptr->zone_ncpu_min)) != Z_OK) 6225 return (err); 6226 if ((err = newprop(newnode, DTD_ATTR_NCPU_MAX, 6227 tabptr->zone_ncpu_max)) != Z_OK) 6228 return (err); 6229 6230 if ((err = modify_tmp_pool(handle, tabptr->zone_importance)) != Z_OK) 6231 return (err); 6232 6233 return (Z_OK); 6234 } 6235 6236 int 6237 zonecfg_add_pset(zone_dochandle_t handle, struct zone_psettab *tabptr) 6238 { 6239 int err; 6240 6241 if (tabptr == NULL) 6242 return (Z_INVAL); 6243 6244 if ((err = operation_prep(handle)) != Z_OK) 6245 return (err); 6246 6247 if ((err = add_pset_core(handle, tabptr)) != Z_OK) 6248 return (err); 6249 6250 return (Z_OK); 6251 } 6252 6253 int 6254 zonecfg_delete_pset(zone_dochandle_t handle) 6255 { 6256 int err; 6257 int res = Z_NO_RESOURCE_ID; 6258 xmlNodePtr cur = handle->zone_dh_cur; 6259 6260 if ((err = operation_prep(handle)) != Z_OK) 6261 return (err); 6262 6263 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6264 if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) { 6265 xmlUnlinkNode(cur); 6266 xmlFreeNode(cur); 6267 res = Z_OK; 6268 break; 6269 } 6270 } 6271 6272 /* 6273 * Once we have msets, we should check that a mset 6274 * do not exist before we delete the tmp_pool data. 6275 */ 6276 err = delete_tmp_pool(handle); 6277 if (err != Z_OK && err != Z_NO_RESOURCE_ID) 6278 return (err); 6279 6280 return (res); 6281 } 6282 6283 int 6284 zonecfg_modify_pset(zone_dochandle_t handle, struct zone_psettab *tabptr) 6285 { 6286 int err; 6287 6288 if (tabptr == NULL) 6289 return (Z_INVAL); 6290 6291 if ((err = zonecfg_delete_pset(handle)) != Z_OK) 6292 return (err); 6293 6294 if ((err = add_pset_core(handle, tabptr)) != Z_OK) 6295 return (err); 6296 6297 return (Z_OK); 6298 } 6299 6300 int 6301 zonecfg_lookup_pset(zone_dochandle_t handle, struct zone_psettab *tabptr) 6302 { 6303 xmlNodePtr cur; 6304 int err; 6305 int res = Z_NO_ENTRY; 6306 6307 if (tabptr == NULL) 6308 return (Z_INVAL); 6309 6310 if ((err = operation_prep(handle)) != Z_OK) 6311 return (err); 6312 6313 /* this is an optional component */ 6314 tabptr->zone_importance[0] = '\0'; 6315 6316 cur = handle->zone_dh_cur; 6317 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6318 if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) { 6319 if ((err = fetchprop(cur, DTD_ATTR_NCPU_MIN, 6320 tabptr->zone_ncpu_min, 6321 sizeof (tabptr->zone_ncpu_min))) != Z_OK) { 6322 handle->zone_dh_cur = handle->zone_dh_top; 6323 return (err); 6324 } 6325 6326 if ((err = fetchprop(cur, DTD_ATTR_NCPU_MAX, 6327 tabptr->zone_ncpu_max, 6328 sizeof (tabptr->zone_ncpu_max))) != Z_OK) { 6329 handle->zone_dh_cur = handle->zone_dh_top; 6330 return (err); 6331 } 6332 6333 res = Z_OK; 6334 6335 } else if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) { 6336 if ((err = fetchprop(cur, DTD_ATTR_IMPORTANCE, 6337 tabptr->zone_importance, 6338 sizeof (tabptr->zone_importance))) != Z_OK) { 6339 handle->zone_dh_cur = handle->zone_dh_top; 6340 return (err); 6341 } 6342 } 6343 } 6344 6345 return (res); 6346 } 6347 6348 int 6349 zonecfg_getpsetent(zone_dochandle_t handle, struct zone_psettab *tabptr) 6350 { 6351 int err; 6352 6353 if ((err = zonecfg_setent(handle)) != Z_OK) 6354 return (err); 6355 6356 err = zonecfg_lookup_pset(handle, tabptr); 6357 6358 (void) zonecfg_endent(handle); 6359 6360 return (err); 6361 } 6362 6363 static int 6364 add_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 6365 { 6366 xmlNodePtr newnode, cur = handle->zone_dh_cur; 6367 int err; 6368 6369 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_MCAP, NULL); 6370 if ((err = newprop(newnode, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap)) 6371 != Z_OK) 6372 return (err); 6373 6374 return (Z_OK); 6375 } 6376 6377 int 6378 zonecfg_delete_mcap(zone_dochandle_t handle) 6379 { 6380 int err; 6381 xmlNodePtr cur = handle->zone_dh_cur; 6382 6383 if ((err = operation_prep(handle)) != Z_OK) 6384 return (err); 6385 6386 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6387 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0) 6388 continue; 6389 6390 xmlUnlinkNode(cur); 6391 xmlFreeNode(cur); 6392 return (Z_OK); 6393 } 6394 return (Z_NO_RESOURCE_ID); 6395 } 6396 6397 int 6398 zonecfg_modify_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 6399 { 6400 int err; 6401 6402 if (tabptr == NULL) 6403 return (Z_INVAL); 6404 6405 err = zonecfg_delete_mcap(handle); 6406 /* it is ok if there is no mcap entry */ 6407 if (err != Z_OK && err != Z_NO_RESOURCE_ID) 6408 return (err); 6409 6410 if ((err = add_mcap(handle, tabptr)) != Z_OK) 6411 return (err); 6412 6413 return (Z_OK); 6414 } 6415 6416 int 6417 zonecfg_lookup_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 6418 { 6419 xmlNodePtr cur; 6420 int err; 6421 6422 if (tabptr == NULL) 6423 return (Z_INVAL); 6424 6425 if ((err = operation_prep(handle)) != Z_OK) 6426 return (err); 6427 6428 cur = handle->zone_dh_cur; 6429 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6430 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0) 6431 continue; 6432 if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP, 6433 tabptr->zone_physmem_cap, 6434 sizeof (tabptr->zone_physmem_cap))) != Z_OK) { 6435 handle->zone_dh_cur = handle->zone_dh_top; 6436 return (err); 6437 } 6438 6439 return (Z_OK); 6440 } 6441 6442 return (Z_NO_ENTRY); 6443 } 6444 6445 static int 6446 getmcapent_core(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 6447 { 6448 xmlNodePtr cur; 6449 int err; 6450 6451 if (handle == NULL) 6452 return (Z_INVAL); 6453 6454 if ((cur = handle->zone_dh_cur) == NULL) 6455 return (Z_NO_ENTRY); 6456 6457 for (; cur != NULL; cur = cur->next) 6458 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) == 0) 6459 break; 6460 if (cur == NULL) { 6461 handle->zone_dh_cur = handle->zone_dh_top; 6462 return (Z_NO_ENTRY); 6463 } 6464 6465 if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap, 6466 sizeof (tabptr->zone_physmem_cap))) != Z_OK) { 6467 handle->zone_dh_cur = handle->zone_dh_top; 6468 return (err); 6469 } 6470 6471 handle->zone_dh_cur = cur->next; 6472 return (Z_OK); 6473 } 6474 6475 int 6476 zonecfg_getmcapent(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 6477 { 6478 int err; 6479 6480 if ((err = zonecfg_setent(handle)) != Z_OK) 6481 return (err); 6482 6483 err = getmcapent_core(handle, tabptr); 6484 6485 (void) zonecfg_endent(handle); 6486 6487 return (err); 6488 } 6489 6490 int 6491 zonecfg_setpkgent(zone_dochandle_t handle) 6492 { 6493 return (zonecfg_setent(handle)); 6494 } 6495 6496 int 6497 zonecfg_getpkgent(zone_dochandle_t handle, struct zone_pkgtab *tabptr) 6498 { 6499 xmlNodePtr cur; 6500 int err; 6501 6502 if (handle == NULL) 6503 return (Z_INVAL); 6504 6505 if ((cur = handle->zone_dh_cur) == NULL) 6506 return (Z_NO_ENTRY); 6507 6508 for (; cur != NULL; cur = cur->next) 6509 if (!xmlStrcmp(cur->name, DTD_ELEM_PACKAGE)) 6510 break; 6511 if (cur == NULL) { 6512 handle->zone_dh_cur = handle->zone_dh_top; 6513 return (Z_NO_ENTRY); 6514 } 6515 6516 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_pkg_name, 6517 sizeof (tabptr->zone_pkg_name))) != Z_OK) { 6518 handle->zone_dh_cur = handle->zone_dh_top; 6519 return (err); 6520 } 6521 6522 if ((err = fetchprop(cur, DTD_ATTR_VERSION, tabptr->zone_pkg_version, 6523 sizeof (tabptr->zone_pkg_version))) != Z_OK) { 6524 handle->zone_dh_cur = handle->zone_dh_top; 6525 return (err); 6526 } 6527 6528 handle->zone_dh_cur = cur->next; 6529 return (Z_OK); 6530 } 6531 6532 int 6533 zonecfg_endpkgent(zone_dochandle_t handle) 6534 { 6535 return (zonecfg_endent(handle)); 6536 } 6537 6538 int 6539 zonecfg_setpatchent(zone_dochandle_t handle) 6540 { 6541 return (zonecfg_setent(handle)); 6542 } 6543 6544 int 6545 zonecfg_getpatchent(zone_dochandle_t handle, struct zone_patchtab *tabptr) 6546 { 6547 xmlNodePtr cur; 6548 int err; 6549 6550 if (handle == NULL) 6551 return (Z_INVAL); 6552 6553 if ((cur = handle->zone_dh_cur) == NULL) 6554 return (Z_NO_ENTRY); 6555 6556 for (; cur != NULL; cur = cur->next) 6557 if (!xmlStrcmp(cur->name, DTD_ELEM_PATCH)) 6558 break; 6559 if (cur == NULL) { 6560 handle->zone_dh_cur = handle->zone_dh_top; 6561 return (Z_NO_ENTRY); 6562 } 6563 6564 if ((err = fetchprop(cur, DTD_ATTR_ID, tabptr->zone_patch_id, 6565 sizeof (tabptr->zone_patch_id))) != Z_OK) { 6566 handle->zone_dh_cur = handle->zone_dh_top; 6567 return (err); 6568 } 6569 6570 handle->zone_dh_cur = cur->next; 6571 return (Z_OK); 6572 } 6573 6574 int 6575 zonecfg_endpatchent(zone_dochandle_t handle) 6576 { 6577 return (zonecfg_endent(handle)); 6578 } 6579 6580 int 6581 zonecfg_setdevperment(zone_dochandle_t handle) 6582 { 6583 return (zonecfg_setent(handle)); 6584 } 6585 6586 int 6587 zonecfg_getdevperment(zone_dochandle_t handle, struct zone_devpermtab *tabptr) 6588 { 6589 xmlNodePtr cur; 6590 int err; 6591 char buf[128]; 6592 6593 tabptr->zone_devperm_acl = NULL; 6594 6595 if (handle == NULL) 6596 return (Z_INVAL); 6597 6598 if ((cur = handle->zone_dh_cur) == NULL) 6599 return (Z_NO_ENTRY); 6600 6601 for (; cur != NULL; cur = cur->next) 6602 if (!xmlStrcmp(cur->name, DTD_ELEM_DEV_PERM)) 6603 break; 6604 if (cur == NULL) { 6605 handle->zone_dh_cur = handle->zone_dh_top; 6606 return (Z_NO_ENTRY); 6607 } 6608 6609 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_devperm_name, 6610 sizeof (tabptr->zone_devperm_name))) != Z_OK) { 6611 handle->zone_dh_cur = handle->zone_dh_top; 6612 return (err); 6613 } 6614 6615 if ((err = fetchprop(cur, DTD_ATTR_UID, buf, sizeof (buf))) != Z_OK) { 6616 handle->zone_dh_cur = handle->zone_dh_top; 6617 return (err); 6618 } 6619 tabptr->zone_devperm_uid = (uid_t)atol(buf); 6620 6621 if ((err = fetchprop(cur, DTD_ATTR_GID, buf, sizeof (buf))) != Z_OK) { 6622 handle->zone_dh_cur = handle->zone_dh_top; 6623 return (err); 6624 } 6625 tabptr->zone_devperm_gid = (gid_t)atol(buf); 6626 6627 if ((err = fetchprop(cur, DTD_ATTR_MODE, buf, sizeof (buf))) != Z_OK) { 6628 handle->zone_dh_cur = handle->zone_dh_top; 6629 return (err); 6630 } 6631 tabptr->zone_devperm_mode = (mode_t)strtol(buf, (char **)NULL, 8); 6632 6633 if ((err = fetch_alloc_prop(cur, DTD_ATTR_ACL, 6634 &(tabptr->zone_devperm_acl))) != Z_OK) { 6635 handle->zone_dh_cur = handle->zone_dh_top; 6636 return (err); 6637 } 6638 6639 handle->zone_dh_cur = cur->next; 6640 return (Z_OK); 6641 } 6642 6643 int 6644 zonecfg_enddevperment(zone_dochandle_t handle) 6645 { 6646 return (zonecfg_endent(handle)); 6647 } 6648 6649 /* 6650 * Process a list of pkgs from an entry in the contents file, adding each pkg 6651 * name to the list of pkgs. 6652 * 6653 * It is possible for the pkg name to be preceeded by a special character 6654 * which indicates some bookkeeping information for pkging. Check if the 6655 * first char is not an Alpha char. If so, skip over it. 6656 */ 6657 static int 6658 add_pkg_list(char *lastp, char ***plist, int *pcnt) 6659 { 6660 char *p; 6661 int pkg_cnt = *pcnt; 6662 char **pkgs = *plist; 6663 int res = Z_OK; 6664 6665 while ((p = strtok_r(NULL, " ", &lastp)) != NULL) { 6666 char **tmpp; 6667 int i; 6668 6669 /* skip over any special pkg bookkeeping char */ 6670 if (!isalpha(*p)) 6671 p++; 6672 6673 /* Check if the pkg is already in the list */ 6674 for (i = 0; i < pkg_cnt; i++) { 6675 if (strcmp(p, pkgs[i]) == 0) 6676 break; 6677 } 6678 6679 if (i < pkg_cnt) 6680 continue; 6681 6682 /* The pkg is not in the list; add it. */ 6683 if ((tmpp = (char **)realloc(pkgs, 6684 sizeof (char *) * (pkg_cnt + 1))) == NULL) { 6685 res = Z_NOMEM; 6686 break; 6687 } 6688 pkgs = tmpp; 6689 6690 if ((pkgs[pkg_cnt] = strdup(p)) == NULL) { 6691 res = Z_NOMEM; 6692 break; 6693 } 6694 pkg_cnt++; 6695 } 6696 6697 *plist = pkgs; 6698 *pcnt = pkg_cnt; 6699 6700 return (res); 6701 } 6702 6703 /* 6704 * Process an entry from the contents file (type "directory") and if the 6705 * directory path is in the list of paths, add the associated list of pkgs 6706 * to the pkg list. The input parameter "entry" will be broken up by 6707 * the parser within this function so its value will be modified when this 6708 * function exits. 6709 * 6710 * The entries we are looking for will look something like: 6711 * /usr d none 0755 root sys SUNWctpls SUNWidnl SUNWlibCf .... 6712 */ 6713 static int 6714 get_path_pkgs(char *entry, char **paths, int cnt, char ***pkgs, int *pkg_cnt) 6715 { 6716 char *f1; 6717 char *f2; 6718 char *lastp; 6719 int i; 6720 int res = Z_OK; 6721 6722 if ((f1 = strtok_r(entry, " ", &lastp)) == NULL || 6723 (f2 = strtok_r(NULL, " ", &lastp)) == NULL || strcmp(f2, "d") != 0) 6724 return (Z_OK); 6725 6726 /* Check if this directory entry is in the list of paths. */ 6727 for (i = 0; i < cnt; i++) { 6728 if (fnmatch(paths[i], f1, FNM_PATHNAME) == 0) { 6729 /* 6730 * We do want the pkgs for this path. First, skip 6731 * over the next 4 fields in the entry so that we call 6732 * add_pkg_list starting with the pkg names. 6733 */ 6734 int j; 6735 char *nlp; 6736 6737 for (j = 0; j < 4 && 6738 strtok_r(NULL, " ", &lastp) != NULL; j++) 6739 ; 6740 /* 6741 * If there are < 4 fields this entry is corrupt, 6742 * just skip it. 6743 */ 6744 if (j < 4) 6745 return (Z_OK); 6746 6747 /* strip newline from the line */ 6748 nlp = (lastp + strlen(lastp) - 1); 6749 if (*nlp == '\n') 6750 *nlp = '\0'; 6751 6752 res = add_pkg_list(lastp, pkgs, pkg_cnt); 6753 break; 6754 } 6755 } 6756 6757 return (res); 6758 } 6759 6760 /* 6761 * Read an entry from a pkginfo or contents file. Some of these lines can 6762 * either be arbitrarily long or be continued by a backslash at the end of 6763 * the line. This function coalesces lines that are longer than the read 6764 * buffer, and lines that are continued, into one buffer which is returned. 6765 * The caller must free this memory. NULL is returned when we hit EOF or 6766 * if we run out of memory (errno is set to ENOMEM). 6767 */ 6768 static char * 6769 read_pkg_data(FILE *fp) 6770 { 6771 char *start; 6772 char *inp; 6773 char *p; 6774 int char_cnt = 0; 6775 6776 errno = 0; 6777 if ((start = (char *)malloc(PKGINFO_RD_LEN)) == NULL) { 6778 errno = ENOMEM; 6779 return (NULL); 6780 } 6781 6782 inp = start; 6783 while ((p = fgets(inp, PKGINFO_RD_LEN, fp)) != NULL) { 6784 int len; 6785 6786 len = strlen(inp); 6787 if (inp[len - 1] == '\n' && 6788 (len == 1 || inp[len - 2] != '\\')) { 6789 char_cnt = len; 6790 break; 6791 } 6792 6793 if (inp[len - 2] == '\\') 6794 char_cnt += len - 2; 6795 else 6796 char_cnt += PKGINFO_RD_LEN - 1; 6797 6798 if ((p = realloc(start, char_cnt + PKGINFO_RD_LEN)) == NULL) { 6799 errno = ENOMEM; 6800 break; 6801 } 6802 6803 start = p; 6804 inp = start + char_cnt; 6805 } 6806 6807 if (errno == ENOMEM || (p == NULL && char_cnt == 0)) { 6808 free(start); 6809 start = NULL; 6810 } 6811 6812 return (start); 6813 } 6814 6815 static void 6816 free_ipd_pkgs(char **pkgs, int cnt) 6817 { 6818 int i; 6819 6820 for (i = 0; i < cnt; i++) 6821 free(pkgs[i]); 6822 free(pkgs); 6823 } 6824 6825 /* 6826 * Get the list of inherited-pkg-dirs (ipd) for the zone and then get the 6827 * list of pkgs that deliver into those dirs. 6828 */ 6829 static int 6830 get_ipd_pkgs(zone_dochandle_t handle, char ***pkg_list, int *cnt) 6831 { 6832 int res; 6833 struct zone_fstab fstab; 6834 int ipd_cnt = 0; 6835 char **ipds = NULL; 6836 int pkg_cnt = 0; 6837 char **pkgs = NULL; 6838 int i; 6839 6840 if ((res = zonecfg_setipdent(handle)) != Z_OK) 6841 return (res); 6842 6843 while (zonecfg_getipdent(handle, &fstab) == Z_OK) { 6844 char **p; 6845 int len; 6846 6847 if ((p = (char **)realloc(ipds, 6848 sizeof (char *) * (ipd_cnt + 2))) == NULL) { 6849 res = Z_NOMEM; 6850 break; 6851 } 6852 ipds = p; 6853 6854 if ((ipds[ipd_cnt] = strdup(fstab.zone_fs_dir)) == NULL) { 6855 res = Z_NOMEM; 6856 break; 6857 } 6858 ipd_cnt++; 6859 6860 len = strlen(fstab.zone_fs_dir) + 3; 6861 if ((ipds[ipd_cnt] = malloc(len)) == NULL) { 6862 res = Z_NOMEM; 6863 break; 6864 } 6865 6866 (void) snprintf(ipds[ipd_cnt], len, "%s/*", fstab.zone_fs_dir); 6867 ipd_cnt++; 6868 } 6869 6870 (void) zonecfg_endipdent(handle); 6871 6872 if (res != Z_OK) { 6873 for (i = 0; i < ipd_cnt; i++) 6874 free(ipds[i]); 6875 free(ipds); 6876 return (res); 6877 } 6878 6879 /* We only have to process the contents file if we have ipds. */ 6880 if (ipd_cnt > 0) { 6881 FILE *fp; 6882 6883 if ((fp = fopen(CONTENTS_FILE, "r")) != NULL) { 6884 char *buf; 6885 6886 while ((buf = read_pkg_data(fp)) != NULL) { 6887 res = get_path_pkgs(buf, ipds, ipd_cnt, &pkgs, 6888 &pkg_cnt); 6889 free(buf); 6890 if (res != Z_OK) 6891 break; 6892 } 6893 6894 (void) fclose(fp); 6895 } 6896 } 6897 6898 for (i = 0; i < ipd_cnt; i++) 6899 free(ipds[i]); 6900 free(ipds); 6901 6902 if (res != Z_OK) { 6903 free_ipd_pkgs(pkgs, pkg_cnt); 6904 } else { 6905 *pkg_list = pkgs; 6906 *cnt = pkg_cnt; 6907 } 6908 6909 return (res); 6910 } 6911 6912 /* 6913 * Return true if pkg_name is in the list of pkgs that deliver into an 6914 * inherited pkg directory for the zone. 6915 */ 6916 static boolean_t 6917 dir_pkg(char *pkg_name, char **pkg_list, int cnt) 6918 { 6919 int i; 6920 6921 for (i = 0; i < cnt; i++) { 6922 if (strcmp(pkg_name, pkg_list[i]) == 0) 6923 return (B_TRUE); 6924 } 6925 6926 return (B_FALSE); 6927 } 6928 6929 /* 6930 * Start by adding the patch to the sw inventory on the handle. 6931 * 6932 * The info parameter will be the portion of the PATCH_INFO_ entry following 6933 * the '='. For example: 6934 * Installed: Wed Dec 7 07:13:51 PST 2005 From: mum Obsoletes: 120777-03 \ 6935 * 121087-02 119108-07 Requires: 119575-02 119255-06 Incompatibles: 6936 * 6937 * A backed out patch will have an info line of "backed out\n". We should 6938 * skip these patches. 6939 * 6940 * We also want to add the Obsolete and Incompatible patches to the 6941 * sw inventory description of this patch. 6942 */ 6943 static int 6944 add_patch(zone_dochandle_t handle, char *patch, char *info) 6945 { 6946 xmlNodePtr node; 6947 xmlNodePtr cur; 6948 int err; 6949 char *p; 6950 char *lastp; 6951 boolean_t add_info = B_FALSE; 6952 boolean_t obsolete; 6953 6954 if (strcmp(info, "backed out\n") == 0) 6955 return (Z_OK); 6956 6957 if ((err = operation_prep(handle)) != Z_OK) 6958 return (err); 6959 6960 cur = handle->zone_dh_cur; 6961 node = xmlNewTextChild(cur, NULL, DTD_ELEM_PATCH, NULL); 6962 if ((err = newprop(node, DTD_ATTR_ID, patch)) != Z_OK) 6963 return (err); 6964 6965 /* 6966 * Start with the first token. This will probably be "Installed:". 6967 * If we can't tokenize this entry, just return. 6968 */ 6969 if ((p = strtok_r(info, " ", &lastp)) == NULL) 6970 return (Z_OK); 6971 6972 do { 6973 xmlNodePtr new_node; 6974 char *nlp; 6975 6976 if (strcmp(p, "Installed:") == 0 || 6977 strcmp(p, "Requires:") == 0 || 6978 strcmp(p, "From:") == 0) { 6979 add_info = B_FALSE; 6980 continue; 6981 } else if (strcmp(p, "Obsoletes:") == 0) { 6982 obsolete = B_TRUE; 6983 add_info = B_TRUE; 6984 continue; 6985 } else if (strcmp(p, "Incompatibles:") == 0) { 6986 obsolete = B_FALSE; 6987 add_info = B_TRUE; 6988 continue; 6989 } 6990 6991 if (!add_info) 6992 continue; 6993 6994 /* strip newline from last patch in the line */ 6995 nlp = (p + strlen(p) - 1); 6996 if (*nlp == '\n') 6997 *nlp = '\0'; 6998 6999 if (obsolete) 7000 new_node = xmlNewTextChild(node, NULL, 7001 DTD_ELEM_OBSOLETES, NULL); 7002 else 7003 new_node = xmlNewTextChild(node, NULL, 7004 DTD_ELEM_INCOMPATIBLE, NULL); 7005 7006 if ((err = newprop(new_node, DTD_ATTR_ID, p)) != Z_OK) 7007 return (err); 7008 7009 } while ((p = strtok_r(NULL, " ", &lastp)) != NULL); 7010 7011 return (Z_OK); 7012 } 7013 7014 static boolean_t 7015 unique_patch(zone_dochandle_t handle, char *patch) 7016 { 7017 xmlNodePtr cur; 7018 char id[MAXNAMELEN]; 7019 7020 cur = xmlDocGetRootElement(handle->zone_dh_doc); 7021 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 7022 if (xmlStrcmp(cur->name, DTD_ELEM_PATCH) == 0) { 7023 if (fetchprop(cur, DTD_ATTR_ID, id, sizeof (id)) 7024 != Z_OK) 7025 continue; 7026 7027 if (strcmp(patch, id) == 0) 7028 return (B_FALSE); 7029 } 7030 } 7031 7032 return (B_TRUE); 7033 } 7034 7035 /* 7036 * Add the unique patches associated with this pkg to the sw inventory on the 7037 * handle. 7038 * 7039 * We are processing entries of the form: 7040 * PATCH_INFO_121454-02=Installed: Wed Dec 7 07:13:51 PST 2005 From: mum \ 7041 * Obsoletes: 120777-03 121087-02 119108-07 Requires: 119575-02 \ 7042 * 119255-06 Incompatibles: 7043 * 7044 */ 7045 static int 7046 add_patches(zone_dochandle_t handle, struct zone_pkginfo *infop) 7047 { 7048 int i; 7049 int res = Z_OK; 7050 7051 for (i = 0; i < infop->zpi_patch_cnt; i++) { 7052 char *p, *ep; 7053 7054 if (strlen(infop->zpi_patchinfo[i]) < (sizeof (PATCHINFO) - 1)) 7055 continue; 7056 7057 /* Skip over "PATCH_INFO_" to get the patch id. */ 7058 p = infop->zpi_patchinfo[i] + sizeof (PATCHINFO) - 1; 7059 if ((ep = strchr(p, '=')) == NULL) 7060 continue; 7061 7062 *ep = '\0'; 7063 if (unique_patch(handle, p)) 7064 if ((res = add_patch(handle, p, ep + 1)) != Z_OK) 7065 break; 7066 } 7067 7068 return (res); 7069 } 7070 7071 /* 7072 * Add the pkg to the sw inventory on the handle. 7073 */ 7074 static int 7075 add_pkg(zone_dochandle_t handle, char *name, char *version) 7076 { 7077 xmlNodePtr newnode; 7078 xmlNodePtr cur; 7079 int err; 7080 7081 if ((err = operation_prep(handle)) != Z_OK) 7082 return (err); 7083 7084 cur = handle->zone_dh_cur; 7085 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PACKAGE, NULL); 7086 if ((err = newprop(newnode, DTD_ATTR_NAME, name)) != Z_OK) 7087 return (err); 7088 if ((err = newprop(newnode, DTD_ATTR_VERSION, version)) != Z_OK) 7089 return (err); 7090 return (Z_OK); 7091 } 7092 7093 static void 7094 free_pkginfo(struct zone_pkginfo *infop) 7095 { 7096 free(infop->zpi_version); 7097 if (infop->zpi_patch_cnt > 0) { 7098 int i; 7099 7100 for (i = 0; i < infop->zpi_patch_cnt; i++) 7101 free(infop->zpi_patchinfo[i]); 7102 free(infop->zpi_patchinfo); 7103 } 7104 } 7105 7106 /* 7107 * Read the pkginfo file and populate the structure with the data we need 7108 * from this pkg for a sw inventory. 7109 */ 7110 static int 7111 get_pkginfo(char *pkginfo, struct zone_pkginfo *infop) 7112 { 7113 FILE *fp; 7114 char *buf; 7115 int err = 0; 7116 7117 infop->zpi_all_zones = B_FALSE; 7118 infop->zpi_this_zone = B_FALSE; 7119 infop->zpi_version = NULL; 7120 infop->zpi_patch_cnt = 0; 7121 infop->zpi_patchinfo = NULL; 7122 7123 if ((fp = fopen(pkginfo, "r")) == NULL) 7124 return (errno); 7125 7126 while ((buf = read_pkg_data(fp)) != NULL) { 7127 if (strncmp(buf, VERSION, sizeof (VERSION) - 1) == 0) { 7128 int len; 7129 7130 if ((infop->zpi_version = 7131 strdup(buf + sizeof (VERSION) - 1)) == NULL) { 7132 err = ENOMEM; 7133 break; 7134 } 7135 7136 /* remove trailing newline */ 7137 len = strlen(infop->zpi_version); 7138 *(infop->zpi_version + len - 1) = 0; 7139 7140 } else if (strcmp(buf, SUNW_PKG_ALL_ZONES) == 0) { 7141 infop->zpi_all_zones = B_TRUE; 7142 7143 } else if (strcmp(buf, SUNW_PKG_THIS_ZONE) == 0) { 7144 infop->zpi_this_zone = B_TRUE; 7145 7146 } else if (strncmp(buf, PATCHINFO, sizeof (PATCHINFO) - 1) 7147 == 0) { 7148 char **p; 7149 7150 if ((p = (char **)realloc(infop->zpi_patchinfo, 7151 sizeof (char *) * (infop->zpi_patch_cnt + 1))) 7152 == NULL) { 7153 err = ENOMEM; 7154 break; 7155 } 7156 infop->zpi_patchinfo = p; 7157 7158 if ((infop->zpi_patchinfo[infop->zpi_patch_cnt] = 7159 strdup(buf)) == NULL) { 7160 err = ENOMEM; 7161 break; 7162 } 7163 infop->zpi_patch_cnt++; 7164 } 7165 7166 free(buf); 7167 } 7168 7169 free(buf); 7170 7171 if (errno == ENOMEM) { 7172 err = ENOMEM; 7173 /* Clean up anything we did manage to allocate. */ 7174 free_pkginfo(infop); 7175 } 7176 7177 (void) fclose(fp); 7178 7179 return (err); 7180 } 7181 7182 /* 7183 * Take a software inventory of the global zone. We need to get the set of 7184 * packages and patches that are on the global zone that the specified 7185 * non-global zone depends on. The packages we need in the inventory are: 7186 * 7187 * - skip the package if SUNW_PKG_THISZONE is 'true' 7188 * otherwise, 7189 * - add the package if 7190 * a) SUNW_PKG_ALLZONES is 'true', 7191 * or 7192 * b) any file delivered by the package is in a file system that is inherited 7193 * from the global zone. 7194 * If the zone does not inherit any file systems (whole root) 7195 * then (b) will be skipped. 7196 * 7197 * For each of the packages that is being added to the inventory, we will also 7198 * add all of the associated, unique patches to the inventory. 7199 */ 7200 static int 7201 zonecfg_sw_inventory(zone_dochandle_t handle) 7202 { 7203 char pkginfo[MAXPATHLEN]; 7204 int res; 7205 struct dirent *dp; 7206 DIR *dirp; 7207 struct stat buf; 7208 struct zone_pkginfo info; 7209 int pkg_cnt = 0; 7210 char **pkgs = NULL; 7211 7212 if ((res = get_ipd_pkgs(handle, &pkgs, &pkg_cnt)) != Z_OK) 7213 return (res); 7214 7215 if ((dirp = opendir(PKG_PATH)) == NULL) { 7216 free_ipd_pkgs(pkgs, pkg_cnt); 7217 return (Z_OK); 7218 } 7219 7220 while ((dp = readdir(dirp)) != (struct dirent *)0) { 7221 if (strcmp(dp->d_name, ".") == 0 || 7222 strcmp(dp->d_name, "..") == 0) 7223 continue; 7224 7225 (void) snprintf(pkginfo, sizeof (pkginfo), "%s/%s/pkginfo", 7226 PKG_PATH, dp->d_name); 7227 7228 if (stat(pkginfo, &buf) == -1 || !S_ISREG(buf.st_mode)) 7229 continue; 7230 7231 if (get_pkginfo(pkginfo, &info) != 0) { 7232 res = Z_NOMEM; 7233 break; 7234 } 7235 7236 if (!info.zpi_this_zone && 7237 (info.zpi_all_zones || 7238 dir_pkg(dp->d_name, pkgs, pkg_cnt))) { 7239 if ((res = add_pkg(handle, dp->d_name, 7240 info.zpi_version)) == Z_OK) { 7241 if (info.zpi_patch_cnt > 0) 7242 res = add_patches(handle, &info); 7243 } 7244 } 7245 7246 free_pkginfo(&info); 7247 7248 if (res != Z_OK) 7249 break; 7250 } 7251 7252 (void) closedir(dirp); 7253 7254 free_ipd_pkgs(pkgs, pkg_cnt); 7255 7256 if (res == Z_OK) 7257 handle->zone_dh_sw_inv = B_TRUE; 7258 7259 return (res); 7260 } 7261 7262 /* 7263 * zonecfg_devwalk call-back function used during detach to generate the 7264 * dev info in the manifest. 7265 */ 7266 static int 7267 get_detach_dev_entry(const char *name, uid_t uid, gid_t gid, mode_t mode, 7268 const char *acl, void *hdl) 7269 { 7270 zone_dochandle_t handle = (zone_dochandle_t)hdl; 7271 xmlNodePtr newnode; 7272 xmlNodePtr cur; 7273 int err; 7274 char buf[128]; 7275 7276 if ((err = operation_prep(handle)) != Z_OK) 7277 return (err); 7278 7279 cur = handle->zone_dh_cur; 7280 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEV_PERM, NULL); 7281 if ((err = newprop(newnode, DTD_ATTR_NAME, (char *)name)) != Z_OK) 7282 return (err); 7283 (void) snprintf(buf, sizeof (buf), "%lu", uid); 7284 if ((err = newprop(newnode, DTD_ATTR_UID, buf)) != Z_OK) 7285 return (err); 7286 (void) snprintf(buf, sizeof (buf), "%lu", gid); 7287 if ((err = newprop(newnode, DTD_ATTR_GID, buf)) != Z_OK) 7288 return (err); 7289 (void) snprintf(buf, sizeof (buf), "%o", mode); 7290 if ((err = newprop(newnode, DTD_ATTR_MODE, buf)) != Z_OK) 7291 return (err); 7292 if ((err = newprop(newnode, DTD_ATTR_ACL, (char *)acl)) != Z_OK) 7293 return (err); 7294 return (Z_OK); 7295 } 7296 7297 /* 7298 * Get the information required to support detaching a zone. This is 7299 * called on the source system when detaching (the detaching parameter should 7300 * be set to true) and on the destination system before attaching (the 7301 * detaching parameter should be false). 7302 * 7303 * For native Solaris zones, the detach/attach process involves validating 7304 * that the software on the global zone can support the zone when we attach. 7305 * To do this we take a software inventory of the global zone. We also 7306 * have to keep track of the device configuration so that we can properly 7307 * recreate it on the destination. 7308 */ 7309 int 7310 zonecfg_get_detach_info(zone_dochandle_t handle, boolean_t detaching) 7311 { 7312 int res; 7313 7314 if ((res = zonecfg_sw_inventory(handle)) != Z_OK) 7315 return (res); 7316 7317 if (detaching) 7318 res = zonecfg_devwalk(handle, get_detach_dev_entry, handle); 7319 7320 return (res); 7321 } 7322