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