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 2006 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 <ftw.h> 49 50 #include <arpa/inet.h> 51 #include <netdb.h> 52 53 #include <libxml/xmlmemory.h> 54 #include <libxml/parser.h> 55 56 #include <libdevinfo.h> 57 #include <uuid/uuid.h> 58 #include <dirent.h> 59 #include <libbrand.h> 60 61 #include <libzonecfg.h> 62 #include "zonecfg_impl.h" 63 64 65 #define _PATH_TMPFILE "/zonecfg.XXXXXX" 66 #define ZONE_CB_RETRY_COUNT 10 67 #define ZONE_EVENT_PING_SUBCLASS "ping" 68 #define ZONE_EVENT_PING_PUBLISHER "solaris" 69 70 /* Hard-code the DTD element/attribute/entity names just once, here. */ 71 #define DTD_ELEM_ATTR (const xmlChar *) "attr" 72 #define DTD_ELEM_COMMENT (const xmlChar *) "comment" 73 #define DTD_ELEM_DEVICE (const xmlChar *) "device" 74 #define DTD_ELEM_FS (const xmlChar *) "filesystem" 75 #define DTD_ELEM_FSOPTION (const xmlChar *) "fsoption" 76 #define DTD_ELEM_IPD (const xmlChar *) "inherited-pkg-dir" 77 #define DTD_ELEM_NET (const xmlChar *) "network" 78 #define DTD_ELEM_RCTL (const xmlChar *) "rctl" 79 #define DTD_ELEM_RCTLVALUE (const xmlChar *) "rctl-value" 80 #define DTD_ELEM_ZONE (const xmlChar *) "zone" 81 #define DTD_ELEM_DATASET (const xmlChar *) "dataset" 82 #define DTD_ELEM_PACKAGE (const xmlChar *) "package" 83 #define DTD_ELEM_PATCH (const xmlChar *) "patch" 84 #define DTD_ELEM_OBSOLETES (const xmlChar *) "obsoletes" 85 #define DTD_ELEM_INCOMPATIBLE (const xmlChar *) "incompatible" 86 #define DTD_ELEM_DEV_PERM (const xmlChar *) "dev-perm" 87 88 #define DTD_ATTR_ACTION (const xmlChar *) "action" 89 #define DTD_ATTR_ADDRESS (const xmlChar *) "address" 90 #define DTD_ATTR_AUTOBOOT (const xmlChar *) "autoboot" 91 #define DTD_ATTR_DIR (const xmlChar *) "directory" 92 #define DTD_ATTR_LIMIT (const xmlChar *) "limit" 93 #define DTD_ATTR_LIMITPRIV (const xmlChar *) "limitpriv" 94 #define DTD_ATTR_BOOTARGS (const xmlChar *) "bootargs" 95 #define DTD_ATTR_MATCH (const xmlChar *) "match" 96 #define DTD_ATTR_NAME (const xmlChar *) "name" 97 #define DTD_ATTR_PHYSICAL (const xmlChar *) "physical" 98 #define DTD_ATTR_POOL (const xmlChar *) "pool" 99 #define DTD_ATTR_PRIV (const xmlChar *) "priv" 100 #define DTD_ATTR_RAW (const xmlChar *) "raw" 101 #define DTD_ATTR_SPECIAL (const xmlChar *) "special" 102 #define DTD_ATTR_TYPE (const xmlChar *) "type" 103 #define DTD_ATTR_VALUE (const xmlChar *) "value" 104 #define DTD_ATTR_ZONEPATH (const xmlChar *) "zonepath" 105 #define DTD_ATTR_VERSION (const xmlChar *) "version" 106 #define DTD_ATTR_ID (const xmlChar *) "id" 107 #define DTD_ATTR_UID (const xmlChar *) "uid" 108 #define DTD_ATTR_GID (const xmlChar *) "gid" 109 #define DTD_ATTR_MODE (const xmlChar *) "mode" 110 #define DTD_ATTR_ACL (const xmlChar *) "acl" 111 #define DTD_ATTR_BRAND (const xmlChar *) "brand" 112 113 #define DTD_ENTITY_BOOLEAN "boolean" 114 #define DTD_ENTITY_DEVPATH "devpath" 115 #define DTD_ENTITY_DRIVER "driver" 116 #define DTD_ENTITY_DRVMIN "drv_min" 117 #define DTD_ENTITY_FALSE "false" 118 #define DTD_ENTITY_INT "int" 119 #define DTD_ENTITY_STRING "string" 120 #define DTD_ENTITY_TRUE "true" 121 #define DTD_ENTITY_UINT "uint" 122 123 #define DTD_ENTITY_BOOL_LEN 6 /* "false" */ 124 125 #define DETACHED "SUNWdetached.xml" 126 #define ATTACH_FORCED "SUNWattached.xml" 127 #define PKG_PATH "/var/sadm/pkg" 128 #define CONTENTS_FILE "/var/sadm/install/contents" 129 #define SUNW_PKG_ALL_ZONES "SUNW_PKG_ALLZONES=true\n" 130 #define SUNW_PKG_THIS_ZONE "SUNW_PKG_THISZONE=true\n" 131 #define VERSION "VERSION=" 132 #define PATCHLIST "PATCHLIST=" 133 #define PATCHINFO "PATCH_INFO_" 134 #define PKGINFO_RD_LEN 128 135 136 struct zone_dochandle { 137 char *zone_dh_rootdir; 138 xmlDocPtr zone_dh_doc; 139 xmlNodePtr zone_dh_cur; 140 xmlNodePtr zone_dh_top; 141 boolean_t zone_dh_newzone; 142 boolean_t zone_dh_snapshot; 143 boolean_t zone_dh_sw_inv; 144 char zone_dh_delete_name[ZONENAME_MAX]; 145 }; 146 147 struct znotify { 148 void * zn_private; 149 evchan_t *zn_eventchan; 150 int (*zn_callback)(const char *zonename, zoneid_t zid, 151 const char *newstate, const char *oldstate, hrtime_t when, void *p); 152 pthread_mutex_t zn_mutex; 153 pthread_cond_t zn_cond; 154 pthread_mutex_t zn_bigmutex; 155 volatile enum {ZN_UNLOCKED, ZN_LOCKED, ZN_PING_INFLIGHT, 156 ZN_PING_RECEIVED} zn_state; 157 char zn_subscriber_id[MAX_SUBID_LEN]; 158 volatile boolean_t zn_failed; 159 int zn_failure_count; 160 }; 161 162 struct zone_pkginfo { 163 boolean_t zpi_all_zones; 164 boolean_t zpi_this_zone; 165 int zpi_patch_cnt; 166 char *zpi_version; 167 char **zpi_patchinfo; 168 }; 169 170 char *zonecfg_root = ""; 171 172 /* 173 * For functions which return int, which is most of the functions herein, 174 * the return values should be from the Z_foo set defined in <libzonecfg.h>. 175 * In some instances, we take pains mapping some libc errno values to Z_foo 176 * values from this set. 177 */ 178 179 /* 180 * Set the root (/) path for all zonecfg configuration files. This is a 181 * private interface used by Live Upgrade extensions to access zone 182 * configuration inside mounted alternate boot environments. 183 */ 184 void 185 zonecfg_set_root(const char *rootpath) 186 { 187 if (*zonecfg_root != '\0') 188 free(zonecfg_root); 189 if (rootpath == NULL || rootpath[0] == '\0' || rootpath[1] == '\0' || 190 (zonecfg_root = strdup(rootpath)) == NULL) 191 zonecfg_root = ""; 192 } 193 194 const char * 195 zonecfg_get_root(void) 196 { 197 return (zonecfg_root); 198 } 199 200 boolean_t 201 zonecfg_in_alt_root(void) 202 { 203 return (*zonecfg_root != '\0'); 204 } 205 206 /* 207 * Callers of the _file_path() functions are expected to have the second 208 * parameter be a (char foo[MAXPATHLEN]). 209 */ 210 211 static boolean_t 212 config_file_path(const char *zonename, char *answer) 213 { 214 return (snprintf(answer, MAXPATHLEN, "%s%s/%s.xml", zonecfg_root, 215 ZONE_CONFIG_ROOT, zonename) < MAXPATHLEN); 216 } 217 218 static boolean_t 219 snap_file_path(const char *zonename, char *answer) 220 { 221 return (snprintf(answer, MAXPATHLEN, "%s%s/%s.snapshot.xml", 222 zonecfg_root, ZONE_SNAPSHOT_ROOT, zonename) < MAXPATHLEN); 223 } 224 225 /*ARGSUSED*/ 226 static void 227 zonecfg_error_func(void *ctx, const char *msg, ...) 228 { 229 /* 230 * This function does nothing by design. Its purpose is to prevent 231 * libxml from dumping unwanted messages to stdout/stderr. 232 */ 233 } 234 235 zone_dochandle_t 236 zonecfg_init_handle(void) 237 { 238 zone_dochandle_t handle = calloc(1, sizeof (struct zone_dochandle)); 239 if (handle == NULL) { 240 errno = Z_NOMEM; 241 return (NULL); 242 } 243 244 /* generic libxml initialization */ 245 xmlLineNumbersDefault(1); 246 xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS; 247 xmlDoValidityCheckingDefaultValue = 1; 248 (void) xmlKeepBlanksDefault(0); 249 xmlGetWarningsDefaultValue = 0; 250 xmlSetGenericErrorFunc(NULL, zonecfg_error_func); 251 252 return (handle); 253 } 254 255 int 256 zonecfg_check_handle(zone_dochandle_t handle) 257 { 258 if (handle == NULL || handle->zone_dh_doc == NULL) 259 return (Z_BAD_HANDLE); 260 return (Z_OK); 261 } 262 263 void 264 zonecfg_fini_handle(zone_dochandle_t handle) 265 { 266 if (zonecfg_check_handle(handle) == Z_OK) 267 xmlFreeDoc(handle->zone_dh_doc); 268 if (handle != NULL) 269 free(handle); 270 } 271 272 static int 273 zonecfg_destroy_impl(char *filename) 274 { 275 if (unlink(filename) == -1) { 276 if (errno == EACCES) 277 return (Z_ACCES); 278 if (errno == ENOENT) 279 return (Z_NO_ZONE); 280 return (Z_MISC_FS); 281 } 282 return (Z_OK); 283 } 284 285 int 286 zonecfg_destroy(const char *zonename, boolean_t force) 287 { 288 char path[MAXPATHLEN]; 289 struct zoneent ze; 290 int err, state_err; 291 zone_state_t state; 292 293 if (!config_file_path(zonename, path)) 294 return (Z_MISC_FS); 295 296 state_err = zone_get_state((char *)zonename, &state); 297 err = access(path, W_OK); 298 299 /* 300 * If there is no file, and no index entry, reliably indicate that no 301 * such zone exists. 302 */ 303 if ((state_err == Z_NO_ZONE) && (err == -1) && (errno == ENOENT)) 304 return (Z_NO_ZONE); 305 306 /* 307 * Handle any other filesystem related errors (except if the XML 308 * file is missing, which we treat silently), unless we're forcing, 309 * in which case we plow on. 310 */ 311 if (err == -1 && errno != ENOENT) { 312 if (errno == EACCES) 313 return (Z_ACCES); 314 else if (!force) 315 return (Z_MISC_FS); 316 } 317 318 if (state > ZONE_STATE_INSTALLED) 319 return (Z_BAD_ZONE_STATE); 320 321 if (!force && state > ZONE_STATE_CONFIGURED) 322 return (Z_BAD_ZONE_STATE); 323 324 /* 325 * Index deletion succeeds even if the entry doesn't exist. So this 326 * will fail only if we've had some more severe problem. 327 */ 328 bzero(&ze, sizeof (ze)); 329 (void) strlcpy(ze.zone_name, zonename, sizeof (ze.zone_name)); 330 if ((err = putzoneent(&ze, PZE_REMOVE)) != Z_OK) 331 if (!force) 332 return (err); 333 334 err = zonecfg_destroy_impl(path); 335 336 /* 337 * Treat failure to find the XML file silently, since, well, it's 338 * gone, and with the index file cleaned up, we're done. 339 */ 340 if (err == Z_OK || err == Z_NO_ZONE) 341 return (Z_OK); 342 return (err); 343 } 344 345 int 346 zonecfg_destroy_snapshot(const char *zonename) 347 { 348 char path[MAXPATHLEN]; 349 350 if (!snap_file_path(zonename, path)) 351 return (Z_MISC_FS); 352 return (zonecfg_destroy_impl(path)); 353 } 354 355 static int 356 getroot(zone_dochandle_t handle, xmlNodePtr *root) 357 { 358 if (zonecfg_check_handle(handle) == Z_BAD_HANDLE) 359 return (Z_BAD_HANDLE); 360 361 *root = xmlDocGetRootElement(handle->zone_dh_doc); 362 363 if (*root == NULL) 364 return (Z_EMPTY_DOCUMENT); 365 366 if (xmlStrcmp((*root)->name, DTD_ELEM_ZONE)) 367 return (Z_WRONG_DOC_TYPE); 368 369 return (Z_OK); 370 } 371 372 static int 373 operation_prep(zone_dochandle_t handle) 374 { 375 xmlNodePtr root; 376 int err; 377 378 if ((err = getroot(handle, &root)) != 0) 379 return (err); 380 381 handle->zone_dh_cur = root; 382 handle->zone_dh_top = root; 383 return (Z_OK); 384 } 385 386 static int 387 fetchprop(xmlNodePtr cur, const xmlChar *propname, char *dst, size_t dstsize) 388 { 389 xmlChar *property; 390 size_t srcsize; 391 392 if ((property = xmlGetProp(cur, propname)) == NULL) 393 return (Z_BAD_PROPERTY); 394 srcsize = strlcpy(dst, (char *)property, dstsize); 395 xmlFree(property); 396 if (srcsize >= dstsize) 397 return (Z_TOO_BIG); 398 return (Z_OK); 399 } 400 401 static int 402 fetch_alloc_prop(xmlNodePtr cur, const xmlChar *propname, char **dst) 403 { 404 xmlChar *property; 405 406 if ((property = xmlGetProp(cur, propname)) == NULL) 407 return (Z_BAD_PROPERTY); 408 if ((*dst = strdup((char *)property)) == NULL) { 409 xmlFree(property); 410 return (Z_NOMEM); 411 } 412 xmlFree(property); 413 return (Z_OK); 414 } 415 416 static int 417 getrootattr(zone_dochandle_t handle, const xmlChar *propname, 418 char *propval, size_t propsize) 419 { 420 xmlNodePtr root; 421 int err; 422 423 if ((err = getroot(handle, &root)) != 0) 424 return (err); 425 426 return (fetchprop(root, propname, propval, propsize)); 427 } 428 429 static int 430 get_alloc_rootattr(zone_dochandle_t handle, const xmlChar *propname, 431 char **propval) 432 { 433 xmlNodePtr root; 434 int err; 435 436 if ((err = getroot(handle, &root)) != 0) 437 return (err); 438 439 return (fetch_alloc_prop(root, propname, propval)); 440 } 441 442 static int 443 setrootattr(zone_dochandle_t handle, const xmlChar *propname, 444 const char *propval) 445 { 446 int err; 447 xmlNodePtr root; 448 449 if (propval == NULL) 450 return (Z_INVAL); 451 452 if ((err = getroot(handle, &root)) != Z_OK) 453 return (err); 454 455 if (xmlSetProp(root, propname, (const xmlChar *) propval) == NULL) 456 return (Z_INVAL); 457 return (Z_OK); 458 } 459 460 static void 461 addcomment(zone_dochandle_t handle, const char *comment) 462 { 463 xmlNodePtr node; 464 node = xmlNewComment((xmlChar *) comment); 465 466 if (node != NULL) 467 (void) xmlAddPrevSibling(handle->zone_dh_top, node); 468 } 469 470 static void 471 stripcomments(zone_dochandle_t handle) 472 { 473 xmlDocPtr top; 474 xmlNodePtr child, next; 475 476 top = handle->zone_dh_doc; 477 for (child = top->xmlChildrenNode; child != NULL; child = next) { 478 next = child->next; 479 if (child->name == NULL) 480 continue; 481 if (xmlStrcmp(child->name, DTD_ELEM_COMMENT) == 0) { 482 next = child->next; 483 xmlUnlinkNode(child); 484 xmlFreeNode(child); 485 } 486 } 487 } 488 489 static void 490 strip_sw_inv(zone_dochandle_t handle) 491 { 492 xmlNodePtr root, child, next; 493 494 root = xmlDocGetRootElement(handle->zone_dh_doc); 495 for (child = root->xmlChildrenNode; child != NULL; child = next) { 496 next = child->next; 497 if (child->name == NULL) 498 continue; 499 if (xmlStrcmp(child->name, DTD_ELEM_PACKAGE) == 0 || 500 xmlStrcmp(child->name, DTD_ELEM_PATCH) == 0) { 501 next = child->next; 502 xmlUnlinkNode(child); 503 xmlFreeNode(child); 504 } 505 } 506 } 507 508 static int 509 zonecfg_get_handle_impl(const char *zonename, const char *filename, 510 zone_dochandle_t handle) 511 { 512 xmlValidCtxtPtr cvp; 513 struct stat statbuf; 514 int valid; 515 516 if (zonename == NULL) 517 return (Z_NO_ZONE); 518 519 if ((handle->zone_dh_doc = xmlParseFile(filename)) == NULL) { 520 /* distinguish file not found vs. found but not parsed */ 521 if (stat(filename, &statbuf) == 0) 522 return (Z_INVALID_DOCUMENT); 523 return (Z_NO_ZONE); 524 } 525 if ((cvp = xmlNewValidCtxt()) == NULL) 526 return (Z_NOMEM); 527 cvp->error = zonecfg_error_func; 528 cvp->warning = zonecfg_error_func; 529 valid = xmlValidateDocument(cvp, handle->zone_dh_doc); 530 xmlFreeValidCtxt(cvp); 531 if (valid == 0) 532 return (Z_INVALID_DOCUMENT); 533 534 /* delete any comments such as inherited Sun copyright / ident str */ 535 stripcomments(handle); 536 return (Z_OK); 537 } 538 539 int 540 zonecfg_get_handle(const char *zonename, zone_dochandle_t handle) 541 { 542 char path[MAXPATHLEN]; 543 544 if (!config_file_path(zonename, path)) 545 return (Z_MISC_FS); 546 handle->zone_dh_newzone = B_FALSE; 547 548 return (zonecfg_get_handle_impl(zonename, path, handle)); 549 } 550 551 int 552 zonecfg_get_attach_handle(const char *path, const char *zonename, 553 boolean_t preserve_sw, zone_dochandle_t handle) 554 { 555 char migpath[MAXPATHLEN]; 556 int err; 557 struct stat buf; 558 559 if (snprintf(migpath, sizeof (migpath), "%s/root", path) >= 560 sizeof (migpath)) 561 return (Z_NOMEM); 562 563 if (stat(migpath, &buf) == -1 || !S_ISDIR(buf.st_mode)) 564 return (Z_NO_ZONE); 565 566 if (snprintf(migpath, sizeof (migpath), "%s/%s", path, DETACHED) >= 567 sizeof (migpath)) 568 return (Z_NOMEM); 569 570 if ((err = zonecfg_get_handle_impl(zonename, migpath, handle)) != Z_OK) 571 return (err); 572 573 if (!preserve_sw) 574 strip_sw_inv(handle); 575 576 handle->zone_dh_newzone = B_TRUE; 577 if ((err = setrootattr(handle, DTD_ATTR_ZONEPATH, path)) != Z_OK) 578 return (err); 579 580 return (setrootattr(handle, DTD_ATTR_NAME, zonename)); 581 } 582 583 int 584 zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle) 585 { 586 char path[MAXPATHLEN]; 587 588 if (!snap_file_path(zonename, path)) 589 return (Z_MISC_FS); 590 handle->zone_dh_newzone = B_FALSE; 591 return (zonecfg_get_handle_impl(zonename, path, handle)); 592 } 593 594 int 595 zonecfg_get_template_handle(const char *template, const char *zonename, 596 zone_dochandle_t handle) 597 { 598 char path[MAXPATHLEN]; 599 int err; 600 601 if (!config_file_path(template, path)) 602 return (Z_MISC_FS); 603 604 if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK) 605 return (err); 606 handle->zone_dh_newzone = B_TRUE; 607 return (setrootattr(handle, DTD_ATTR_NAME, zonename)); 608 } 609 610 int 611 zonecfg_get_xml_handle(const char *path, zone_dochandle_t handle) 612 { 613 struct stat buf; 614 int err; 615 616 if (stat(path, &buf) == -1) 617 return (Z_MISC_FS); 618 619 if ((err = zonecfg_get_handle_impl("xml", path, handle)) != Z_OK) 620 return (err); 621 handle->zone_dh_newzone = B_TRUE; 622 return (Z_OK); 623 } 624 625 /* 626 * Initialize two handles from the manifest read on fd. The rem_handle 627 * is initialized from the input file, including the sw inventory. The 628 * local_handle is initialized with the same zone configuration but with 629 * no sw inventory. 630 */ 631 int 632 zonecfg_attach_manifest(int fd, zone_dochandle_t local_handle, 633 zone_dochandle_t rem_handle) 634 { 635 xmlValidCtxtPtr cvp; 636 int valid; 637 638 /* load the manifest into the handle for the remote system */ 639 if ((rem_handle->zone_dh_doc = xmlReadFd(fd, NULL, NULL, 0)) == NULL) { 640 return (Z_INVALID_DOCUMENT); 641 } 642 if ((cvp = xmlNewValidCtxt()) == NULL) 643 return (Z_NOMEM); 644 cvp->error = zonecfg_error_func; 645 cvp->warning = zonecfg_error_func; 646 valid = xmlValidateDocument(cvp, rem_handle->zone_dh_doc); 647 xmlFreeValidCtxt(cvp); 648 if (valid == 0) 649 return (Z_INVALID_DOCUMENT); 650 651 /* delete any comments such as inherited Sun copyright / ident str */ 652 stripcomments(rem_handle); 653 654 rem_handle->zone_dh_newzone = B_TRUE; 655 rem_handle->zone_dh_sw_inv = B_TRUE; 656 657 /* 658 * Now use the remote system handle to generate a local system handle 659 * with an identical zones configuration but no sw inventory. 660 */ 661 if ((local_handle->zone_dh_doc = xmlCopyDoc(rem_handle->zone_dh_doc, 662 1)) == NULL) { 663 return (Z_INVALID_DOCUMENT); 664 } 665 666 /* 667 * We need to re-run xmlValidateDocument on local_handle to properly 668 * update the in-core representation of the configuration. 669 */ 670 if ((cvp = xmlNewValidCtxt()) == NULL) 671 return (Z_NOMEM); 672 cvp->error = zonecfg_error_func; 673 cvp->warning = zonecfg_error_func; 674 valid = xmlValidateDocument(cvp, local_handle->zone_dh_doc); 675 xmlFreeValidCtxt(cvp); 676 if (valid == 0) 677 return (Z_INVALID_DOCUMENT); 678 679 strip_sw_inv(local_handle); 680 681 local_handle->zone_dh_newzone = B_TRUE; 682 local_handle->zone_dh_sw_inv = B_FALSE; 683 684 return (Z_OK); 685 } 686 687 static boolean_t 688 is_renaming(zone_dochandle_t handle) 689 { 690 if (handle->zone_dh_newzone) 691 return (B_FALSE); 692 if (strlen(handle->zone_dh_delete_name) > 0) 693 return (B_TRUE); 694 return (B_FALSE); 695 } 696 697 static boolean_t 698 is_new(zone_dochandle_t handle) 699 { 700 return (handle->zone_dh_newzone || handle->zone_dh_snapshot); 701 } 702 703 static boolean_t 704 is_snapshot(zone_dochandle_t handle) 705 { 706 return (handle->zone_dh_snapshot); 707 } 708 709 /* 710 * It would be great to be able to use libc's ctype(3c) macros, but we 711 * can't, as they are locale sensitive, and it would break our limited thread 712 * safety if this routine had to change the app locale on the fly. 713 */ 714 int 715 zonecfg_validate_zonename(const char *zone) 716 { 717 int i; 718 719 if (strcmp(zone, GLOBAL_ZONENAME) == 0) 720 return (Z_BOGUS_ZONE_NAME); 721 722 if (strlen(zone) >= ZONENAME_MAX) 723 return (Z_BOGUS_ZONE_NAME); 724 725 if (!((zone[0] >= 'a' && zone[0] <= 'z') || 726 (zone[0] >= 'A' && zone[0] <= 'Z') || 727 (zone[0] >= '0' && zone[0] <= '9'))) 728 return (Z_BOGUS_ZONE_NAME); 729 730 for (i = 1; zone[i] != '\0'; i++) { 731 if (!((zone[i] >= 'a' && zone[i] <= 'z') || 732 (zone[i] >= 'A' && zone[i] <= 'Z') || 733 (zone[i] >= '0' && zone[i] <= '9') || 734 (zone[i] == '-') || (zone[i] == '_') || (zone[i] == '.'))) 735 return (Z_BOGUS_ZONE_NAME); 736 } 737 738 return (Z_OK); 739 } 740 741 /* 742 * Changing the zone name requires us to track both the old and new 743 * name of the zone until commit time. 744 */ 745 int 746 zonecfg_get_name(zone_dochandle_t handle, char *name, size_t namesize) 747 { 748 return (getrootattr(handle, DTD_ATTR_NAME, name, namesize)); 749 } 750 751 int 752 zonecfg_set_name(zone_dochandle_t handle, char *name) 753 { 754 zone_state_t state; 755 char curname[ZONENAME_MAX], old_delname[ZONENAME_MAX]; 756 int err; 757 758 if ((err = getrootattr(handle, DTD_ATTR_NAME, curname, 759 sizeof (curname))) != Z_OK) 760 return (err); 761 762 if (strcmp(name, curname) == 0) 763 return (Z_OK); 764 765 /* 766 * Switching zone names to one beginning with SUNW is not permitted. 767 */ 768 if (strncmp(name, "SUNW", 4) == 0) 769 return (Z_BOGUS_ZONE_NAME); 770 771 if ((err = zonecfg_validate_zonename(name)) != Z_OK) 772 return (err); 773 774 /* 775 * Setting the name back to the original name (effectively a revert of 776 * the name) is fine. But if we carry on, we'll falsely identify the 777 * name as "in use," so special case here. 778 */ 779 if (strcmp(name, handle->zone_dh_delete_name) == 0) { 780 err = setrootattr(handle, DTD_ATTR_NAME, name); 781 handle->zone_dh_delete_name[0] = '\0'; 782 return (err); 783 } 784 785 /* Check to see if new name chosen is already in use */ 786 if (zone_get_state(name, &state) != Z_NO_ZONE) 787 return (Z_NAME_IN_USE); 788 789 /* 790 * If this isn't already "new" or in a renaming transition, then 791 * we're initiating a rename here; so stash the "delete name" 792 * (i.e. the name of the zone we'll be removing) for the rename. 793 */ 794 (void) strlcpy(old_delname, handle->zone_dh_delete_name, 795 sizeof (old_delname)); 796 if (!is_new(handle) && !is_renaming(handle)) { 797 /* 798 * Name change is allowed only when the zone we're altering 799 * is not ready or running. 800 */ 801 err = zone_get_state(curname, &state); 802 if (err == Z_OK) { 803 if (state > ZONE_STATE_INSTALLED) 804 return (Z_BAD_ZONE_STATE); 805 } else if (err != Z_NO_ZONE) { 806 return (err); 807 } 808 809 (void) strlcpy(handle->zone_dh_delete_name, curname, 810 sizeof (handle->zone_dh_delete_name)); 811 assert(is_renaming(handle)); 812 } else if (is_renaming(handle)) { 813 err = zone_get_state(handle->zone_dh_delete_name, &state); 814 if (err == Z_OK) { 815 if (state > ZONE_STATE_INSTALLED) 816 return (Z_BAD_ZONE_STATE); 817 } else if (err != Z_NO_ZONE) { 818 return (err); 819 } 820 } 821 822 if ((err = setrootattr(handle, DTD_ATTR_NAME, name)) != Z_OK) { 823 /* 824 * Restore the deletename to whatever it was at the 825 * top of the routine, since we've had a failure. 826 */ 827 (void) strlcpy(handle->zone_dh_delete_name, old_delname, 828 sizeof (handle->zone_dh_delete_name)); 829 return (err); 830 } 831 832 return (Z_OK); 833 } 834 835 int 836 zonecfg_get_zonepath(zone_dochandle_t handle, char *path, size_t pathsize) 837 { 838 size_t len; 839 840 if ((len = strlcpy(path, zonecfg_root, pathsize)) >= pathsize) 841 return (Z_TOO_BIG); 842 return (getrootattr(handle, DTD_ATTR_ZONEPATH, path + len, 843 pathsize - len)); 844 } 845 846 int 847 zonecfg_set_zonepath(zone_dochandle_t handle, char *zonepath) 848 { 849 size_t len; 850 851 /* 852 * The user deals in absolute paths in the running global zone, but the 853 * internal configuration files deal with boot environment relative 854 * paths. Strip out the alternate root when specified. 855 */ 856 len = strlen(zonecfg_root); 857 if (strncmp(zonepath, zonecfg_root, len) != 0 || zonepath[len] != '/') 858 return (Z_BAD_PROPERTY); 859 zonepath += len; 860 return (setrootattr(handle, DTD_ATTR_ZONEPATH, zonepath)); 861 } 862 863 int 864 zonecfg_get_brand(zone_dochandle_t handle, char *brand, size_t brandsize) 865 { 866 int ret, sz; 867 868 ret = getrootattr(handle, DTD_ATTR_BRAND, brand, brandsize); 869 870 /* If the zone has no brand, it is native. */ 871 if (ret == Z_OK && brand[0] == '\0') { 872 sz = strlcpy(brand, NATIVE_BRAND_NAME, brandsize); 873 if (sz >= brandsize) 874 ret = Z_TOO_BIG; 875 else 876 ret = Z_OK; 877 } 878 879 return (ret); 880 } 881 882 int 883 zonecfg_set_brand(zone_dochandle_t handle, char *brand) 884 { 885 return (setrootattr(handle, DTD_ATTR_BRAND, brand)); 886 } 887 888 int 889 zonecfg_get_autoboot(zone_dochandle_t handle, boolean_t *autoboot) 890 { 891 char autobootstr[DTD_ENTITY_BOOL_LEN]; 892 int ret; 893 894 if ((ret = getrootattr(handle, DTD_ATTR_AUTOBOOT, autobootstr, 895 sizeof (autobootstr))) != Z_OK) 896 return (ret); 897 898 if (strcmp(autobootstr, DTD_ENTITY_TRUE) == 0) 899 *autoboot = B_TRUE; 900 else if (strcmp(autobootstr, DTD_ENTITY_FALSE) == 0) 901 *autoboot = B_FALSE; 902 else 903 ret = Z_BAD_PROPERTY; 904 return (ret); 905 } 906 907 int 908 zonecfg_set_autoboot(zone_dochandle_t handle, boolean_t autoboot) 909 { 910 return (setrootattr(handle, DTD_ATTR_AUTOBOOT, 911 autoboot ? DTD_ENTITY_TRUE : DTD_ENTITY_FALSE)); 912 } 913 914 int 915 zonecfg_get_pool(zone_dochandle_t handle, char *pool, size_t poolsize) 916 { 917 return (getrootattr(handle, DTD_ATTR_POOL, pool, poolsize)); 918 } 919 920 int 921 zonecfg_set_pool(zone_dochandle_t handle, char *pool) 922 { 923 return (setrootattr(handle, DTD_ATTR_POOL, pool)); 924 } 925 926 int 927 zonecfg_get_limitpriv(zone_dochandle_t handle, char **limitpriv) 928 { 929 return (get_alloc_rootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv)); 930 } 931 932 int 933 zonecfg_set_limitpriv(zone_dochandle_t handle, char *limitpriv) 934 { 935 return (setrootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv)); 936 } 937 938 int 939 zonecfg_get_bootargs(zone_dochandle_t handle, char *bargs, size_t bargssize) 940 { 941 return (getrootattr(handle, DTD_ATTR_BOOTARGS, bargs, bargssize)); 942 } 943 944 int 945 zonecfg_set_bootargs(zone_dochandle_t handle, char *bargs) 946 { 947 return (setrootattr(handle, DTD_ATTR_BOOTARGS, bargs)); 948 } 949 950 /* 951 * /etc/zones/index caches a vital piece of information which is also 952 * in the <zonename>.xml file: the path to the zone. This is for performance, 953 * since we need to walk all zonepath's in order to be able to detect conflicts 954 * (see crosscheck_zonepaths() in the zoneadm command). 955 * 956 * An additional complexity is that when doing a rename, we'd like the entire 957 * index update operation (rename, and potential state changes) to be atomic. 958 * In general, the operation of this function should succeed or fail as 959 * a unit. 960 */ 961 int 962 zonecfg_refresh_index_file(zone_dochandle_t handle) 963 { 964 char name[ZONENAME_MAX], zonepath[MAXPATHLEN]; 965 struct zoneent ze; 966 int err; 967 int opcode; 968 char *zn; 969 970 bzero(&ze, sizeof (ze)); 971 ze.zone_state = -1; /* Preserve existing state in index */ 972 973 if ((err = zonecfg_get_name(handle, name, sizeof (name))) != Z_OK) 974 return (err); 975 (void) strlcpy(ze.zone_name, name, sizeof (ze.zone_name)); 976 977 if ((err = zonecfg_get_zonepath(handle, zonepath, 978 sizeof (zonepath))) != Z_OK) 979 return (err); 980 (void) strlcpy(ze.zone_path, zonepath + strlen(zonecfg_root), 981 sizeof (ze.zone_path)); 982 983 if (is_renaming(handle)) { 984 opcode = PZE_MODIFY; 985 (void) strlcpy(ze.zone_name, handle->zone_dh_delete_name, 986 sizeof (ze.zone_name)); 987 (void) strlcpy(ze.zone_newname, name, sizeof (ze.zone_newname)); 988 } else if (is_new(handle)) { 989 FILE *cookie; 990 /* 991 * Be tolerant of the zone already existing in the index file, 992 * since we might be forcibly overwriting an existing 993 * configuration with a new one (for example 'create -F' 994 * in zonecfg). 995 */ 996 opcode = PZE_ADD; 997 cookie = setzoneent(); 998 while ((zn = getzoneent(cookie)) != NULL) { 999 if (strcmp(zn, name) == 0) { 1000 opcode = PZE_MODIFY; 1001 free(zn); 1002 break; 1003 } 1004 free(zn); 1005 } 1006 endzoneent(cookie); 1007 ze.zone_state = ZONE_STATE_CONFIGURED; 1008 } else { 1009 opcode = PZE_MODIFY; 1010 } 1011 1012 if ((err = putzoneent(&ze, opcode)) != Z_OK) 1013 return (err); 1014 1015 return (Z_OK); 1016 } 1017 1018 /* 1019 * The goal of this routine is to cause the index file update and the 1020 * document save to happen as an atomic operation. We do the document 1021 * first, saving a backup copy using a hard link; if that succeeds, we go 1022 * on to the index. If that fails, we roll the document back into place. 1023 * 1024 * Strategy: 1025 * 1026 * New zone 'foo' configuration: 1027 * Create tmpfile (zonecfg.xxxxxx) 1028 * Write XML to tmpfile 1029 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml) 1030 * Add entry to index file 1031 * If it fails, delete foo.xml, leaving nothing behind. 1032 * 1033 * Save existing zone 'foo': 1034 * Make backup of foo.xml -> .backup 1035 * Create tmpfile (zonecfg.xxxxxx) 1036 * Write XML to tmpfile 1037 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml) 1038 * Modify index file as needed 1039 * If it fails, recover from .backup -> foo.xml 1040 * 1041 * Rename 'foo' to 'bar': 1042 * Create tmpfile (zonecfg.xxxxxx) 1043 * Write XML to tmpfile 1044 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> bar.xml) 1045 * Add entry for 'bar' to index file, Remove entry for 'foo' (refresh) 1046 * If it fails, delete bar.xml; foo.xml is left behind. 1047 */ 1048 static int 1049 zonecfg_save_impl(zone_dochandle_t handle, char *filename) 1050 { 1051 char tmpfile[MAXPATHLEN]; 1052 char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN]; 1053 int tmpfd, err, valid; 1054 xmlValidCtxt cvp = { NULL }; 1055 boolean_t backup; 1056 1057 (void) strlcpy(tmpfile, filename, sizeof (tmpfile)); 1058 (void) dirname(tmpfile); 1059 (void) strlcat(tmpfile, _PATH_TMPFILE, sizeof (tmpfile)); 1060 1061 tmpfd = mkstemp(tmpfile); 1062 if (tmpfd == -1) { 1063 (void) unlink(tmpfile); 1064 return (Z_TEMP_FILE); 1065 } 1066 (void) close(tmpfd); 1067 1068 cvp.error = zonecfg_error_func; 1069 cvp.warning = zonecfg_error_func; 1070 1071 /* 1072 * We do a final validation of the document. Since the library has 1073 * malfunctioned if it fails to validate, we follow-up with an 1074 * assert() that the doc is valid. 1075 */ 1076 valid = xmlValidateDocument(&cvp, handle->zone_dh_doc); 1077 assert(valid != 0); 1078 1079 if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0) 1080 goto err; 1081 1082 (void) chmod(tmpfile, 0644); 1083 1084 /* 1085 * In the event we are doing a standard save, hard link a copy of the 1086 * original file in .backup.<pid>.filename so we can restore it if 1087 * something goes wrong. 1088 */ 1089 if (!is_new(handle) && !is_renaming(handle)) { 1090 backup = B_TRUE; 1091 1092 (void) strlcpy(bakdir, filename, sizeof (bakdir)); 1093 (void) strlcpy(bakbase, filename, sizeof (bakbase)); 1094 (void) snprintf(bakfile, sizeof (bakfile), "%s/.backup.%d.%s", 1095 dirname(bakdir), getpid(), basename(bakbase)); 1096 1097 if (link(filename, bakfile) == -1) { 1098 err = errno; 1099 (void) unlink(tmpfile); 1100 if (errno == EACCES) 1101 return (Z_ACCES); 1102 return (Z_MISC_FS); 1103 } 1104 } 1105 1106 /* 1107 * Move the new document over top of the old. 1108 * i.e.: zonecfg.XXXXXX -> myzone.xml 1109 */ 1110 if (rename(tmpfile, filename) == -1) { 1111 err = errno; 1112 (void) unlink(tmpfile); 1113 if (backup) 1114 (void) unlink(bakfile); 1115 if (err == EACCES) 1116 return (Z_ACCES); 1117 return (Z_MISC_FS); 1118 } 1119 1120 /* 1121 * If this is a snapshot, we're done-- don't add an index entry. 1122 */ 1123 if (is_snapshot(handle)) 1124 return (Z_OK); 1125 1126 /* now update the index file to reflect whatever we just did */ 1127 if ((err = zonecfg_refresh_index_file(handle)) != Z_OK) { 1128 if (backup) { 1129 /* 1130 * Try to restore from our backup. 1131 */ 1132 (void) unlink(filename); 1133 (void) rename(bakfile, filename); 1134 } else { 1135 /* 1136 * Either the zone is new, in which case we can delete 1137 * new.xml, or we're doing a rename, so ditto. 1138 */ 1139 assert(is_new(handle) || is_renaming(handle)); 1140 (void) unlink(filename); 1141 } 1142 return (Z_UPDATING_INDEX); 1143 } 1144 1145 if (backup) 1146 (void) unlink(bakfile); 1147 1148 return (Z_OK); 1149 1150 err: 1151 (void) unlink(tmpfile); 1152 return (Z_SAVING_FILE); 1153 } 1154 1155 int 1156 zonecfg_save(zone_dochandle_t handle) 1157 { 1158 char zname[ZONENAME_MAX], path[MAXPATHLEN]; 1159 char delpath[MAXPATHLEN]; 1160 int err = Z_SAVING_FILE; 1161 1162 if (zonecfg_check_handle(handle) != Z_OK) 1163 return (Z_BAD_HANDLE); 1164 1165 /* 1166 * We don't support saving snapshots or a tree containing a sw 1167 * inventory at this time. 1168 */ 1169 if (handle->zone_dh_snapshot || handle->zone_dh_sw_inv) 1170 return (Z_INVAL); 1171 1172 if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK) 1173 return (err); 1174 1175 if (!config_file_path(zname, path)) 1176 return (Z_MISC_FS); 1177 1178 addcomment(handle, "\n DO NOT EDIT THIS " 1179 "FILE. Use zonecfg(1M) instead.\n"); 1180 1181 err = zonecfg_save_impl(handle, path); 1182 1183 stripcomments(handle); 1184 1185 if (err != Z_OK) 1186 return (err); 1187 1188 handle->zone_dh_newzone = B_FALSE; 1189 1190 if (is_renaming(handle)) { 1191 if (config_file_path(handle->zone_dh_delete_name, delpath)) 1192 (void) unlink(delpath); 1193 handle->zone_dh_delete_name[0] = '\0'; 1194 } 1195 1196 return (Z_OK); 1197 } 1198 1199 int 1200 zonecfg_verify_save(zone_dochandle_t handle, char *filename) 1201 { 1202 int valid; 1203 1204 xmlValidCtxt cvp = { NULL }; 1205 1206 if (zonecfg_check_handle(handle) != Z_OK) 1207 return (Z_BAD_HANDLE); 1208 1209 cvp.error = zonecfg_error_func; 1210 cvp.warning = zonecfg_error_func; 1211 1212 /* 1213 * We do a final validation of the document. Since the library has 1214 * malfunctioned if it fails to validate, we follow-up with an 1215 * assert() that the doc is valid. 1216 */ 1217 valid = xmlValidateDocument(&cvp, handle->zone_dh_doc); 1218 assert(valid != 0); 1219 1220 if (xmlSaveFormatFile(filename, handle->zone_dh_doc, 1) <= 0) 1221 return (Z_SAVING_FILE); 1222 1223 return (Z_OK); 1224 } 1225 1226 int 1227 zonecfg_detach_save(zone_dochandle_t handle, uint_t flags) 1228 { 1229 char zname[ZONENAME_MAX]; 1230 char path[MAXPATHLEN]; 1231 char migpath[MAXPATHLEN]; 1232 xmlValidCtxt cvp = { NULL }; 1233 int err = Z_SAVING_FILE; 1234 int valid; 1235 1236 if (zonecfg_check_handle(handle) != Z_OK) 1237 return (Z_BAD_HANDLE); 1238 1239 /* 1240 * We can only detach if we have taken a sw inventory. 1241 */ 1242 if (!handle->zone_dh_sw_inv) 1243 return (Z_INVAL); 1244 1245 if (flags & ZONE_DRY_RUN) { 1246 (void) strlcpy(migpath, "-", sizeof (migpath)); 1247 } else { 1248 if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) 1249 != Z_OK) 1250 return (err); 1251 1252 if ((err = zone_get_zonepath(zname, path, sizeof (path))) 1253 != Z_OK) 1254 return (err); 1255 1256 if (snprintf(migpath, sizeof (migpath), "%s/%s", path, DETACHED) 1257 >= sizeof (migpath)) 1258 return (Z_NOMEM); 1259 } 1260 1261 if ((err = operation_prep(handle)) != Z_OK) 1262 return (err); 1263 1264 addcomment(handle, "\n DO NOT EDIT THIS FILE. " 1265 "Use zonecfg(1M) and zoneadm(1M) attach.\n"); 1266 1267 cvp.error = zonecfg_error_func; 1268 cvp.warning = zonecfg_error_func; 1269 1270 /* 1271 * We do a final validation of the document. Since the library has 1272 * malfunctioned if it fails to validate, we follow-up with an 1273 * assert() that the doc is valid. 1274 */ 1275 valid = xmlValidateDocument(&cvp, handle->zone_dh_doc); 1276 assert(valid != 0); 1277 1278 if (xmlSaveFormatFile(migpath, handle->zone_dh_doc, 1) <= 0) 1279 return (Z_SAVING_FILE); 1280 1281 if (!(flags & ZONE_DRY_RUN)) 1282 (void) chmod(migpath, 0644); 1283 1284 stripcomments(handle); 1285 1286 handle->zone_dh_newzone = B_FALSE; 1287 1288 return (Z_OK); 1289 } 1290 1291 boolean_t 1292 zonecfg_detached(const char *path) 1293 { 1294 char migpath[MAXPATHLEN]; 1295 struct stat buf; 1296 1297 if (snprintf(migpath, sizeof (migpath), "%s/%s", path, DETACHED) >= 1298 sizeof (migpath)) 1299 return (B_FALSE); 1300 1301 if (stat(migpath, &buf) != -1) 1302 return (B_TRUE); 1303 1304 return (B_FALSE); 1305 } 1306 1307 void 1308 zonecfg_rm_detached(zone_dochandle_t handle, boolean_t forced) 1309 { 1310 char zname[ZONENAME_MAX]; 1311 char path[MAXPATHLEN]; 1312 char detached[MAXPATHLEN]; 1313 char attached[MAXPATHLEN]; 1314 1315 if (zonecfg_check_handle(handle) != Z_OK) 1316 return; 1317 1318 if (zonecfg_get_name(handle, zname, sizeof (zname)) != Z_OK) 1319 return; 1320 1321 if (zone_get_zonepath(zname, path, sizeof (path)) != Z_OK) 1322 return; 1323 1324 (void) snprintf(detached, sizeof (detached), "%s/%s", path, DETACHED); 1325 (void) snprintf(attached, sizeof (attached), "%s/%s", path, 1326 ATTACH_FORCED); 1327 1328 if (forced) { 1329 (void) rename(detached, attached); 1330 } else { 1331 (void) unlink(attached); 1332 (void) unlink(detached); 1333 } 1334 } 1335 1336 /* 1337 * Special case: if access(2) fails with ENOENT, then try again using 1338 * ZONE_CONFIG_ROOT instead of config_file_path(zonename). This is how we 1339 * work around the case of a config file which has not been created yet: 1340 * the user will need access to the directory so use that as a heuristic. 1341 */ 1342 1343 int 1344 zonecfg_access(const char *zonename, int amode) 1345 { 1346 char path[MAXPATHLEN]; 1347 1348 if (!config_file_path(zonename, path)) 1349 return (Z_INVAL); 1350 if (access(path, amode) == 0) 1351 return (Z_OK); 1352 if (errno == ENOENT) { 1353 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root, 1354 ZONE_CONFIG_ROOT) >= sizeof (path)) 1355 return (Z_INVAL); 1356 if (access(path, amode) == 0) 1357 return (Z_OK); 1358 } 1359 if (errno == EACCES) 1360 return (Z_ACCES); 1361 if (errno == EINVAL) 1362 return (Z_INVAL); 1363 return (Z_MISC_FS); 1364 } 1365 1366 int 1367 zonecfg_create_snapshot(const char *zonename) 1368 { 1369 zone_dochandle_t handle; 1370 char path[MAXPATHLEN], zonepath[MAXPATHLEN], rpath[MAXPATHLEN]; 1371 int error = Z_OK, res; 1372 1373 if ((handle = zonecfg_init_handle()) == NULL) { 1374 return (Z_NOMEM); 1375 } 1376 1377 handle->zone_dh_newzone = B_TRUE; 1378 handle->zone_dh_snapshot = B_TRUE; 1379 1380 if ((error = zonecfg_get_handle(zonename, handle)) != Z_OK) 1381 goto out; 1382 if ((error = operation_prep(handle)) != Z_OK) 1383 goto out; 1384 error = zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)); 1385 if (error != Z_OK) 1386 goto out; 1387 if ((res = resolvepath(zonepath, rpath, sizeof (rpath))) == -1) { 1388 error = Z_RESOLVED_PATH; 1389 goto out; 1390 } 1391 /* 1392 * If the resolved path is not the same as the original path, then 1393 * save the resolved path in the snapshot, thus preventing any 1394 * potential problems down the line when zoneadmd goes to unmount 1395 * file systems and depends on initial string matches with resolved 1396 * paths. 1397 */ 1398 rpath[res] = '\0'; 1399 if (strcmp(zonepath, rpath) != 0) { 1400 if ((error = zonecfg_set_zonepath(handle, rpath)) != Z_OK) 1401 goto out; 1402 } 1403 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root, 1404 ZONE_SNAPSHOT_ROOT) >= sizeof (path)) { 1405 error = Z_MISC_FS; 1406 goto out; 1407 } 1408 if ((mkdir(path, S_IRWXU) == -1) && (errno != EEXIST)) { 1409 error = Z_MISC_FS; 1410 goto out; 1411 } 1412 1413 if (!snap_file_path(zonename, path)) { 1414 error = Z_MISC_FS; 1415 goto out; 1416 } 1417 1418 addcomment(handle, "\n DO NOT EDIT THIS FILE. " 1419 "It is a snapshot of running zone state.\n"); 1420 1421 error = zonecfg_save_impl(handle, path); 1422 1423 stripcomments(handle); 1424 1425 out: 1426 zonecfg_fini_handle(handle); 1427 return (error); 1428 } 1429 1430 static int 1431 newprop(xmlNodePtr node, const xmlChar *attrname, char *src) 1432 { 1433 xmlAttrPtr newattr; 1434 1435 newattr = xmlNewProp(node, attrname, (xmlChar *)src); 1436 if (newattr == NULL) { 1437 xmlUnlinkNode(node); 1438 xmlFreeNode(node); 1439 return (Z_BAD_PROPERTY); 1440 } 1441 return (Z_OK); 1442 } 1443 1444 static int 1445 zonecfg_add_filesystem_core(zone_dochandle_t handle, struct zone_fstab *tabptr) 1446 { 1447 xmlNodePtr newnode, cur = handle->zone_dh_cur, options_node; 1448 zone_fsopt_t *ptr; 1449 int err; 1450 1451 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_FS, NULL); 1452 if ((err = newprop(newnode, DTD_ATTR_SPECIAL, 1453 tabptr->zone_fs_special)) != Z_OK) 1454 return (err); 1455 if (tabptr->zone_fs_raw[0] != '\0' && 1456 (err = newprop(newnode, DTD_ATTR_RAW, tabptr->zone_fs_raw)) != Z_OK) 1457 return (err); 1458 if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK) 1459 return (err); 1460 if ((err = newprop(newnode, DTD_ATTR_TYPE, 1461 tabptr->zone_fs_type)) != Z_OK) 1462 return (err); 1463 if (tabptr->zone_fs_options != NULL) { 1464 for (ptr = tabptr->zone_fs_options; ptr != NULL; 1465 ptr = ptr->zone_fsopt_next) { 1466 options_node = xmlNewTextChild(newnode, NULL, 1467 DTD_ELEM_FSOPTION, NULL); 1468 if ((err = newprop(options_node, DTD_ATTR_NAME, 1469 ptr->zone_fsopt_opt)) != Z_OK) 1470 return (err); 1471 } 1472 } 1473 return (Z_OK); 1474 } 1475 1476 int 1477 zonecfg_add_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr) 1478 { 1479 int err; 1480 1481 if (tabptr == NULL) 1482 return (Z_INVAL); 1483 1484 if ((err = operation_prep(handle)) != Z_OK) 1485 return (err); 1486 1487 if ((err = zonecfg_add_filesystem_core(handle, tabptr)) != Z_OK) 1488 return (err); 1489 1490 return (Z_OK); 1491 } 1492 1493 static int 1494 zonecfg_add_ipd_core(zone_dochandle_t handle, struct zone_fstab *tabptr) 1495 { 1496 xmlNodePtr newnode, cur = handle->zone_dh_cur; 1497 int err; 1498 1499 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_IPD, NULL); 1500 if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK) 1501 return (err); 1502 return (Z_OK); 1503 } 1504 1505 int 1506 zonecfg_add_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr) 1507 { 1508 int err; 1509 1510 if (tabptr == NULL) 1511 return (Z_INVAL); 1512 1513 if ((err = operation_prep(handle)) != Z_OK) 1514 return (err); 1515 1516 if ((err = zonecfg_add_ipd_core(handle, tabptr)) != Z_OK) 1517 return (err); 1518 1519 return (Z_OK); 1520 } 1521 1522 int 1523 zonecfg_add_fs_option(struct zone_fstab *tabptr, char *option) 1524 { 1525 zone_fsopt_t *last, *old, *new; 1526 1527 last = tabptr->zone_fs_options; 1528 for (old = last; old != NULL; old = old->zone_fsopt_next) 1529 last = old; /* walk to the end of the list */ 1530 new = (zone_fsopt_t *)malloc(sizeof (zone_fsopt_t)); 1531 if (new == NULL) 1532 return (Z_NOMEM); 1533 (void) strlcpy(new->zone_fsopt_opt, option, 1534 sizeof (new->zone_fsopt_opt)); 1535 new->zone_fsopt_next = NULL; 1536 if (last == NULL) 1537 tabptr->zone_fs_options = new; 1538 else 1539 last->zone_fsopt_next = new; 1540 return (Z_OK); 1541 } 1542 1543 int 1544 zonecfg_remove_fs_option(struct zone_fstab *tabptr, char *option) 1545 { 1546 zone_fsopt_t *last, *this, *next; 1547 1548 last = tabptr->zone_fs_options; 1549 for (this = last; this != NULL; this = this->zone_fsopt_next) { 1550 if (strcmp(this->zone_fsopt_opt, option) == 0) { 1551 next = this->zone_fsopt_next; 1552 if (this == tabptr->zone_fs_options) 1553 tabptr->zone_fs_options = next; 1554 else 1555 last->zone_fsopt_next = next; 1556 free(this); 1557 return (Z_OK); 1558 } else 1559 last = this; 1560 } 1561 return (Z_NO_PROPERTY_ID); 1562 } 1563 1564 void 1565 zonecfg_free_fs_option_list(zone_fsopt_t *list) 1566 { 1567 zone_fsopt_t *this, *next; 1568 1569 for (this = list; this != NULL; this = next) { 1570 next = this->zone_fsopt_next; 1571 free(this); 1572 } 1573 } 1574 1575 void 1576 zonecfg_free_rctl_value_list(struct zone_rctlvaltab *valtab) 1577 { 1578 if (valtab == NULL) 1579 return; 1580 zonecfg_free_rctl_value_list(valtab->zone_rctlval_next); 1581 free(valtab); 1582 } 1583 1584 static boolean_t 1585 match_prop(xmlNodePtr cur, const xmlChar *attr, char *user_prop) 1586 { 1587 xmlChar *gotten_prop; 1588 int prop_result; 1589 1590 gotten_prop = xmlGetProp(cur, attr); 1591 if (gotten_prop == NULL) /* shouldn't happen */ 1592 return (B_FALSE); 1593 prop_result = xmlStrcmp(gotten_prop, (const xmlChar *) user_prop); 1594 xmlFree(gotten_prop); 1595 return ((prop_result == 0)); 1596 } 1597 1598 static int 1599 zonecfg_delete_filesystem_core(zone_dochandle_t handle, 1600 struct zone_fstab *tabptr) 1601 { 1602 xmlNodePtr cur = handle->zone_dh_cur; 1603 boolean_t dir_match, spec_match, raw_match, type_match; 1604 1605 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1606 if (xmlStrcmp(cur->name, DTD_ELEM_FS)) 1607 continue; 1608 dir_match = match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir); 1609 spec_match = match_prop(cur, DTD_ATTR_SPECIAL, 1610 tabptr->zone_fs_special); 1611 raw_match = match_prop(cur, DTD_ATTR_RAW, 1612 tabptr->zone_fs_raw); 1613 type_match = match_prop(cur, DTD_ATTR_TYPE, 1614 tabptr->zone_fs_type); 1615 if (dir_match && spec_match && raw_match && type_match) { 1616 xmlUnlinkNode(cur); 1617 xmlFreeNode(cur); 1618 return (Z_OK); 1619 } 1620 } 1621 return (Z_NO_RESOURCE_ID); 1622 } 1623 1624 int 1625 zonecfg_delete_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr) 1626 { 1627 int err; 1628 1629 if (tabptr == NULL) 1630 return (Z_INVAL); 1631 1632 if ((err = operation_prep(handle)) != Z_OK) 1633 return (err); 1634 1635 if ((err = zonecfg_delete_filesystem_core(handle, tabptr)) != Z_OK) 1636 return (err); 1637 1638 return (Z_OK); 1639 } 1640 1641 int 1642 zonecfg_modify_filesystem( 1643 zone_dochandle_t handle, 1644 struct zone_fstab *oldtabptr, 1645 struct zone_fstab *newtabptr) 1646 { 1647 int err; 1648 1649 if (oldtabptr == NULL || newtabptr == NULL) 1650 return (Z_INVAL); 1651 1652 if ((err = operation_prep(handle)) != Z_OK) 1653 return (err); 1654 1655 if ((err = zonecfg_delete_filesystem_core(handle, oldtabptr)) != Z_OK) 1656 return (err); 1657 1658 if ((err = zonecfg_add_filesystem_core(handle, newtabptr)) != Z_OK) 1659 return (err); 1660 1661 return (Z_OK); 1662 } 1663 1664 static int 1665 zonecfg_delete_ipd_core(zone_dochandle_t handle, struct zone_fstab *tabptr) 1666 { 1667 xmlNodePtr cur = handle->zone_dh_cur; 1668 1669 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1670 if (xmlStrcmp(cur->name, DTD_ELEM_IPD)) 1671 continue; 1672 if (match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir)) { 1673 xmlUnlinkNode(cur); 1674 xmlFreeNode(cur); 1675 return (Z_OK); 1676 } 1677 } 1678 return (Z_NO_RESOURCE_ID); 1679 } 1680 1681 int 1682 zonecfg_delete_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr) 1683 { 1684 int err; 1685 1686 if (tabptr == NULL) 1687 return (Z_INVAL); 1688 1689 if ((err = operation_prep(handle)) != Z_OK) 1690 return (err); 1691 1692 if ((err = zonecfg_delete_ipd_core(handle, tabptr)) != Z_OK) 1693 return (err); 1694 1695 return (Z_OK); 1696 } 1697 1698 int 1699 zonecfg_modify_ipd(zone_dochandle_t handle, struct zone_fstab *oldtabptr, 1700 struct zone_fstab *newtabptr) 1701 { 1702 int err; 1703 1704 if (oldtabptr == NULL || newtabptr == NULL) 1705 return (Z_INVAL); 1706 1707 if ((err = operation_prep(handle)) != Z_OK) 1708 return (err); 1709 1710 if ((err = zonecfg_delete_ipd_core(handle, oldtabptr)) != Z_OK) 1711 return (err); 1712 1713 if ((err = zonecfg_add_ipd_core(handle, newtabptr)) != Z_OK) 1714 return (err); 1715 1716 return (Z_OK); 1717 } 1718 1719 int 1720 zonecfg_lookup_filesystem( 1721 zone_dochandle_t handle, 1722 struct zone_fstab *tabptr) 1723 { 1724 xmlNodePtr cur, options, firstmatch; 1725 int err; 1726 char dirname[MAXPATHLEN], special[MAXPATHLEN], raw[MAXPATHLEN]; 1727 char type[FSTYPSZ]; 1728 char options_str[MAX_MNTOPT_STR]; 1729 1730 if (tabptr == NULL) 1731 return (Z_INVAL); 1732 1733 if ((err = operation_prep(handle)) != Z_OK) 1734 return (err); 1735 1736 /* 1737 * Walk the list of children looking for matches on any properties 1738 * specified in the fstab parameter. If more than one resource 1739 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return 1740 * Z_NO_RESOURCE_ID. 1741 */ 1742 cur = handle->zone_dh_cur; 1743 firstmatch = NULL; 1744 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1745 if (xmlStrcmp(cur->name, DTD_ELEM_FS)) 1746 continue; 1747 if (strlen(tabptr->zone_fs_dir) > 0) { 1748 if ((fetchprop(cur, DTD_ATTR_DIR, dirname, 1749 sizeof (dirname)) == Z_OK) && 1750 (strcmp(tabptr->zone_fs_dir, dirname) == 0)) { 1751 if (firstmatch == NULL) 1752 firstmatch = cur; 1753 else 1754 return (Z_INSUFFICIENT_SPEC); 1755 } 1756 } 1757 if (strlen(tabptr->zone_fs_special) > 0) { 1758 if ((fetchprop(cur, DTD_ATTR_SPECIAL, special, 1759 sizeof (special)) == Z_OK)) { 1760 if (strcmp(tabptr->zone_fs_special, 1761 special) == 0) { 1762 if (firstmatch == NULL) 1763 firstmatch = cur; 1764 else if (firstmatch != cur) 1765 return (Z_INSUFFICIENT_SPEC); 1766 } else { 1767 /* 1768 * If another property matched but this 1769 * one doesn't then reset firstmatch. 1770 */ 1771 if (firstmatch == cur) 1772 firstmatch = NULL; 1773 } 1774 } 1775 } 1776 if (strlen(tabptr->zone_fs_raw) > 0) { 1777 if ((fetchprop(cur, DTD_ATTR_RAW, raw, 1778 sizeof (raw)) == Z_OK)) { 1779 if (strcmp(tabptr->zone_fs_raw, raw) == 0) { 1780 if (firstmatch == NULL) 1781 firstmatch = cur; 1782 else if (firstmatch != cur) 1783 return (Z_INSUFFICIENT_SPEC); 1784 } else { 1785 /* 1786 * If another property matched but this 1787 * one doesn't then reset firstmatch. 1788 */ 1789 if (firstmatch == cur) 1790 firstmatch = NULL; 1791 } 1792 } 1793 } 1794 if (strlen(tabptr->zone_fs_type) > 0) { 1795 if ((fetchprop(cur, DTD_ATTR_TYPE, type, 1796 sizeof (type)) == Z_OK)) { 1797 if (strcmp(tabptr->zone_fs_type, type) == 0) { 1798 if (firstmatch == NULL) 1799 firstmatch = cur; 1800 else if (firstmatch != cur) 1801 return (Z_INSUFFICIENT_SPEC); 1802 } else { 1803 /* 1804 * If another property matched but this 1805 * one doesn't then reset firstmatch. 1806 */ 1807 if (firstmatch == cur) 1808 firstmatch = NULL; 1809 } 1810 } 1811 } 1812 } 1813 1814 if (firstmatch == NULL) 1815 return (Z_NO_RESOURCE_ID); 1816 1817 cur = firstmatch; 1818 1819 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 1820 sizeof (tabptr->zone_fs_dir))) != Z_OK) 1821 return (err); 1822 1823 if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special, 1824 sizeof (tabptr->zone_fs_special))) != Z_OK) 1825 return (err); 1826 1827 if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw, 1828 sizeof (tabptr->zone_fs_raw))) != Z_OK) 1829 return (err); 1830 1831 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type, 1832 sizeof (tabptr->zone_fs_type))) != Z_OK) 1833 return (err); 1834 1835 /* options are optional */ 1836 tabptr->zone_fs_options = NULL; 1837 for (options = cur->xmlChildrenNode; options != NULL; 1838 options = options->next) { 1839 if ((fetchprop(options, DTD_ATTR_NAME, options_str, 1840 sizeof (options_str)) != Z_OK)) 1841 break; 1842 if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK) 1843 break; 1844 } 1845 return (Z_OK); 1846 } 1847 1848 int 1849 zonecfg_lookup_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr) 1850 { 1851 xmlNodePtr cur, match; 1852 int err; 1853 char dirname[MAXPATHLEN]; 1854 1855 if (tabptr == NULL) 1856 return (Z_INVAL); 1857 1858 if ((err = operation_prep(handle)) != Z_OK) 1859 return (err); 1860 1861 /* 1862 * General algorithm: 1863 * Walk the list of children looking for matches on any properties 1864 * specified in the fstab parameter. If more than one resource 1865 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return 1866 * Z_NO_RESOURCE_ID. 1867 */ 1868 cur = handle->zone_dh_cur; 1869 match = NULL; 1870 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1871 if (xmlStrcmp(cur->name, DTD_ELEM_IPD)) 1872 continue; 1873 if (strlen(tabptr->zone_fs_dir) > 0) { 1874 if ((fetchprop(cur, DTD_ATTR_DIR, dirname, 1875 sizeof (dirname)) == Z_OK) && 1876 (strcmp(tabptr->zone_fs_dir, dirname) == 0)) { 1877 if (match == NULL) 1878 match = cur; 1879 else 1880 return (Z_INSUFFICIENT_SPEC); 1881 } 1882 } 1883 } 1884 1885 if (match == NULL) 1886 return (Z_NO_RESOURCE_ID); 1887 1888 cur = match; 1889 1890 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 1891 sizeof (tabptr->zone_fs_dir))) != Z_OK) 1892 return (err); 1893 1894 return (Z_OK); 1895 } 1896 1897 /* 1898 * Compare two IP addresses in string form. Allow for the possibility that 1899 * one might have "/<prefix-length>" at the end: allow a match on just the 1900 * IP address (or host name) part. 1901 */ 1902 1903 boolean_t 1904 zonecfg_same_net_address(char *a1, char *a2) 1905 { 1906 char *slashp, *slashp1, *slashp2; 1907 int result; 1908 1909 if (strcmp(a1, a2) == 0) 1910 return (B_TRUE); 1911 1912 /* 1913 * If neither has a slash or both do, they need to match to be 1914 * considered the same, but they did not match above, so fail. 1915 */ 1916 slashp1 = strchr(a1, '/'); 1917 slashp2 = strchr(a2, '/'); 1918 if ((slashp1 == NULL && slashp2 == NULL) || 1919 (slashp1 != NULL && slashp2 != NULL)) 1920 return (B_FALSE); 1921 1922 /* 1923 * Only one had a slash: pick that one, zero out the slash, compare 1924 * the "address only" strings, restore the slash, and return the 1925 * result of the comparison. 1926 */ 1927 slashp = (slashp1 == NULL) ? slashp2 : slashp1; 1928 *slashp = '\0'; 1929 result = strcmp(a1, a2); 1930 *slashp = '/'; 1931 return ((result == 0)); 1932 } 1933 1934 int 1935 zonecfg_valid_net_address(char *address, struct lifreq *lifr) 1936 { 1937 struct sockaddr_in *sin4; 1938 struct sockaddr_in6 *sin6; 1939 struct addrinfo hints, *result; 1940 char *slashp = strchr(address, '/'); 1941 1942 bzero(lifr, sizeof (struct lifreq)); 1943 sin4 = (struct sockaddr_in *)&lifr->lifr_addr; 1944 sin6 = (struct sockaddr_in6 *)&lifr->lifr_addr; 1945 if (slashp != NULL) 1946 *slashp = '\0'; 1947 if (inet_pton(AF_INET, address, &sin4->sin_addr) == 1) { 1948 sin4->sin_family = AF_INET; 1949 } else if (inet_pton(AF_INET6, address, &sin6->sin6_addr) == 1) { 1950 if (slashp == NULL) 1951 return (Z_IPV6_ADDR_PREFIX_LEN); 1952 sin6->sin6_family = AF_INET6; 1953 } else { 1954 /* "address" may be a host name */ 1955 (void) memset(&hints, 0, sizeof (hints)); 1956 hints.ai_family = PF_INET; 1957 if (getaddrinfo(address, NULL, &hints, &result) != 0) 1958 return (Z_BOGUS_ADDRESS); 1959 sin4->sin_family = result->ai_family; 1960 1961 (void) memcpy(&sin4->sin_addr, 1962 /* LINTED E_BAD_PTR_CAST_ALIGN */ 1963 &((struct sockaddr_in *)result->ai_addr)->sin_addr, 1964 sizeof (struct in_addr)); 1965 1966 freeaddrinfo(result); 1967 } 1968 return (Z_OK); 1969 } 1970 1971 int 1972 zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 1973 { 1974 xmlNodePtr cur, firstmatch; 1975 int err; 1976 char address[INET6_ADDRSTRLEN], physical[LIFNAMSIZ]; 1977 1978 if (tabptr == NULL) 1979 return (Z_INVAL); 1980 1981 if ((err = operation_prep(handle)) != Z_OK) 1982 return (err); 1983 1984 cur = handle->zone_dh_cur; 1985 firstmatch = NULL; 1986 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1987 if (xmlStrcmp(cur->name, DTD_ELEM_NET)) 1988 continue; 1989 if (strlen(tabptr->zone_nwif_physical) > 0) { 1990 if ((fetchprop(cur, DTD_ATTR_PHYSICAL, physical, 1991 sizeof (physical)) == Z_OK) && 1992 (strcmp(tabptr->zone_nwif_physical, 1993 physical) == 0)) { 1994 if (firstmatch == NULL) 1995 firstmatch = cur; 1996 else 1997 return (Z_INSUFFICIENT_SPEC); 1998 } 1999 } 2000 if (strlen(tabptr->zone_nwif_address) > 0) { 2001 if ((fetchprop(cur, DTD_ATTR_ADDRESS, address, 2002 sizeof (address)) == Z_OK)) { 2003 if (zonecfg_same_net_address( 2004 tabptr->zone_nwif_address, address)) { 2005 if (firstmatch == NULL) 2006 firstmatch = cur; 2007 else if (firstmatch != cur) 2008 return (Z_INSUFFICIENT_SPEC); 2009 } else { 2010 /* 2011 * If another property matched but this 2012 * one doesn't then reset firstmatch. 2013 */ 2014 if (firstmatch == cur) 2015 firstmatch = NULL; 2016 } 2017 } 2018 } 2019 } 2020 if (firstmatch == NULL) 2021 return (Z_NO_RESOURCE_ID); 2022 2023 cur = firstmatch; 2024 2025 if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical, 2026 sizeof (tabptr->zone_nwif_physical))) != Z_OK) 2027 return (err); 2028 2029 if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address, 2030 sizeof (tabptr->zone_nwif_address))) != Z_OK) 2031 return (err); 2032 2033 return (Z_OK); 2034 } 2035 2036 static int 2037 zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 2038 { 2039 xmlNodePtr newnode, cur = handle->zone_dh_cur; 2040 int err; 2041 2042 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL); 2043 if ((err = newprop(newnode, DTD_ATTR_ADDRESS, 2044 tabptr->zone_nwif_address)) != Z_OK) 2045 return (err); 2046 if ((err = newprop(newnode, DTD_ATTR_PHYSICAL, 2047 tabptr->zone_nwif_physical)) != Z_OK) 2048 return (err); 2049 return (Z_OK); 2050 } 2051 2052 int 2053 zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 2054 { 2055 int err; 2056 2057 if (tabptr == NULL) 2058 return (Z_INVAL); 2059 2060 if ((err = operation_prep(handle)) != Z_OK) 2061 return (err); 2062 2063 if ((err = zonecfg_add_nwif_core(handle, tabptr)) != Z_OK) 2064 return (err); 2065 2066 return (Z_OK); 2067 } 2068 2069 static int 2070 zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 2071 { 2072 xmlNodePtr cur = handle->zone_dh_cur; 2073 boolean_t addr_match, phys_match; 2074 2075 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2076 if (xmlStrcmp(cur->name, DTD_ELEM_NET)) 2077 continue; 2078 2079 addr_match = match_prop(cur, DTD_ATTR_ADDRESS, 2080 tabptr->zone_nwif_address); 2081 phys_match = match_prop(cur, DTD_ATTR_PHYSICAL, 2082 tabptr->zone_nwif_physical); 2083 2084 if (addr_match && phys_match) { 2085 xmlUnlinkNode(cur); 2086 xmlFreeNode(cur); 2087 return (Z_OK); 2088 } 2089 } 2090 return (Z_NO_RESOURCE_ID); 2091 } 2092 2093 int 2094 zonecfg_delete_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 2095 { 2096 int err; 2097 2098 if (tabptr == NULL) 2099 return (Z_INVAL); 2100 2101 if ((err = operation_prep(handle)) != Z_OK) 2102 return (err); 2103 2104 if ((err = zonecfg_delete_nwif_core(handle, tabptr)) != Z_OK) 2105 return (err); 2106 2107 return (Z_OK); 2108 } 2109 2110 int 2111 zonecfg_modify_nwif( 2112 zone_dochandle_t handle, 2113 struct zone_nwiftab *oldtabptr, 2114 struct zone_nwiftab *newtabptr) 2115 { 2116 int err; 2117 2118 if (oldtabptr == NULL || newtabptr == NULL) 2119 return (Z_INVAL); 2120 2121 if ((err = operation_prep(handle)) != Z_OK) 2122 return (err); 2123 2124 if ((err = zonecfg_delete_nwif_core(handle, oldtabptr)) != Z_OK) 2125 return (err); 2126 2127 if ((err = zonecfg_add_nwif_core(handle, newtabptr)) != Z_OK) 2128 return (err); 2129 2130 return (Z_OK); 2131 } 2132 2133 int 2134 zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) 2135 { 2136 xmlNodePtr cur, firstmatch; 2137 int err; 2138 char match[MAXPATHLEN]; 2139 2140 if (tabptr == NULL) 2141 return (Z_INVAL); 2142 2143 if ((err = operation_prep(handle)) != Z_OK) 2144 return (err); 2145 2146 cur = handle->zone_dh_cur; 2147 firstmatch = NULL; 2148 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2149 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) 2150 continue; 2151 if (strlen(tabptr->zone_dev_match) == 0) 2152 continue; 2153 2154 if ((fetchprop(cur, DTD_ATTR_MATCH, match, 2155 sizeof (match)) == Z_OK)) { 2156 if (strcmp(tabptr->zone_dev_match, 2157 match) == 0) { 2158 if (firstmatch == NULL) 2159 firstmatch = cur; 2160 else if (firstmatch != cur) 2161 return (Z_INSUFFICIENT_SPEC); 2162 } else { 2163 /* 2164 * If another property matched but this 2165 * one doesn't then reset firstmatch. 2166 */ 2167 if (firstmatch == cur) 2168 firstmatch = NULL; 2169 } 2170 } 2171 } 2172 if (firstmatch == NULL) 2173 return (Z_NO_RESOURCE_ID); 2174 2175 cur = firstmatch; 2176 2177 if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match, 2178 sizeof (tabptr->zone_dev_match))) != Z_OK) 2179 return (err); 2180 2181 return (Z_OK); 2182 } 2183 2184 static int 2185 zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr) 2186 { 2187 xmlNodePtr newnode, cur = handle->zone_dh_cur; 2188 int err; 2189 2190 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL); 2191 2192 if ((err = newprop(newnode, DTD_ATTR_MATCH, 2193 tabptr->zone_dev_match)) != Z_OK) 2194 return (err); 2195 2196 return (Z_OK); 2197 } 2198 2199 int 2200 zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) 2201 { 2202 int err; 2203 2204 if (tabptr == NULL) 2205 return (Z_INVAL); 2206 2207 if ((err = operation_prep(handle)) != Z_OK) 2208 return (err); 2209 2210 if ((err = zonecfg_add_dev_core(handle, tabptr)) != Z_OK) 2211 return (err); 2212 2213 return (Z_OK); 2214 } 2215 2216 static int 2217 zonecfg_delete_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr) 2218 { 2219 xmlNodePtr cur = handle->zone_dh_cur; 2220 int match_match; 2221 2222 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2223 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) 2224 continue; 2225 2226 match_match = match_prop(cur, DTD_ATTR_MATCH, 2227 tabptr->zone_dev_match); 2228 2229 if (match_match) { 2230 xmlUnlinkNode(cur); 2231 xmlFreeNode(cur); 2232 return (Z_OK); 2233 } 2234 } 2235 return (Z_NO_RESOURCE_ID); 2236 } 2237 2238 int 2239 zonecfg_delete_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) 2240 { 2241 int err; 2242 2243 if (tabptr == NULL) 2244 return (Z_INVAL); 2245 2246 if ((err = operation_prep(handle)) != Z_OK) 2247 return (err); 2248 2249 if ((err = zonecfg_delete_dev_core(handle, tabptr)) != Z_OK) 2250 return (err); 2251 2252 return (Z_OK); 2253 } 2254 2255 int 2256 zonecfg_modify_dev( 2257 zone_dochandle_t handle, 2258 struct zone_devtab *oldtabptr, 2259 struct zone_devtab *newtabptr) 2260 { 2261 int err; 2262 2263 if (oldtabptr == NULL || newtabptr == NULL) 2264 return (Z_INVAL); 2265 2266 if ((err = operation_prep(handle)) != Z_OK) 2267 return (err); 2268 2269 if ((err = zonecfg_delete_dev_core(handle, oldtabptr)) != Z_OK) 2270 return (err); 2271 2272 if ((err = zonecfg_add_dev_core(handle, newtabptr)) != Z_OK) 2273 return (err); 2274 2275 return (Z_OK); 2276 } 2277 2278 /* Lock to serialize all zonecfg_devwalks */ 2279 static pthread_mutex_t zonecfg_devwalk_lock = PTHREAD_MUTEX_INITIALIZER; 2280 /* 2281 * Global variables used to pass data from zonecfg_devwalk to the nftw 2282 * call-back (zonecfg_devwalk_cb). g_devwalk_data is really the void* 2283 * parameter and g_devwalk_cb is really the *cb parameter from zonecfg_devwalk. 2284 */ 2285 static void *g_devwalk_data; 2286 static int (*g_devwalk_cb)(const char *, uid_t, gid_t, mode_t, const char *, 2287 void *); 2288 static size_t g_devwalk_skip_prefix; 2289 2290 /* 2291 * This is the nftw call-back function used by zonecfg_devwalk. It is 2292 * responsible for calling the actual call-back that is passed in to 2293 * zonecfg_devwalk as the *cb argument. 2294 */ 2295 /* ARGSUSED2 */ 2296 static int 2297 zonecfg_devwalk_cb(const char *path, const struct stat *st, int f, 2298 struct FTW *ftw) 2299 { 2300 acl_t *acl; 2301 char *acl_txt = NULL; 2302 2303 /* skip all but character and block devices */ 2304 if (!S_ISBLK(st->st_mode) && !S_ISCHR(st->st_mode)) 2305 return (0); 2306 2307 if ((acl_get(path, ACL_NO_TRIVIAL, &acl) == 0) && 2308 acl != NULL) { 2309 acl_txt = acl_totext(acl, ACL_NORESOLVE); 2310 acl_free(acl); 2311 } 2312 2313 if (strlen(path) <= g_devwalk_skip_prefix) 2314 return (0); 2315 2316 g_devwalk_cb(path + g_devwalk_skip_prefix, st->st_uid, st->st_gid, 2317 st->st_mode & S_IAMB, acl_txt != NULL ? acl_txt : "", 2318 g_devwalk_data); 2319 free(acl_txt); 2320 return (0); 2321 } 2322 2323 /* 2324 * Walk the dev tree for the zone specified by hdl and call the call-back (cb) 2325 * function for each entry in the tree. The call-back will be passed the 2326 * name, uid, gid, mode, acl string and the void *data input parameter 2327 * for each dev entry. 2328 * 2329 * Data is passed to the zonecfg_devwalk_cb through the global variables 2330 * g_devwalk_data, *g_devwalk_cb, and g_devwalk_skip_prefix. The 2331 * zonecfg_devwalk_cb function will actually call *cb. 2332 */ 2333 int 2334 zonecfg_devwalk(zone_dochandle_t hdl, 2335 int (*cb)(const char *, uid_t, gid_t, mode_t, const char *, void *), 2336 void *data) 2337 { 2338 char path[MAXPATHLEN]; 2339 int ret; 2340 2341 if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK) 2342 return (ret); 2343 2344 if (strlcat(path, "/dev", sizeof (path)) >= sizeof (path)) 2345 return (Z_TOO_BIG); 2346 g_devwalk_skip_prefix = strlen(path) + 1; 2347 2348 /* 2349 * We have to serialize all zonecfg_devwalks in the same process 2350 * (which should be fine), since nftw() is so badly designed. 2351 */ 2352 (void) pthread_mutex_lock(&zonecfg_devwalk_lock); 2353 2354 g_devwalk_data = data; 2355 g_devwalk_cb = cb; 2356 (void) nftw(path, zonecfg_devwalk_cb, 0, FTW_PHYS); 2357 2358 (void) pthread_mutex_unlock(&zonecfg_devwalk_lock); 2359 return (Z_OK); 2360 } 2361 2362 /* 2363 * Update the owner, group, mode and acl on the specified dev (inpath) for 2364 * the zone (hdl). This function can be used to fix up the dev tree after 2365 * attaching a migrated zone. 2366 */ 2367 int 2368 zonecfg_devperms_apply(zone_dochandle_t hdl, const char *inpath, uid_t owner, 2369 gid_t group, mode_t mode, const char *acltxt) 2370 { 2371 int ret; 2372 char path[MAXPATHLEN]; 2373 struct stat st; 2374 acl_t *aclp; 2375 2376 if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK) 2377 return (ret); 2378 2379 if (strlcat(path, "/dev/", sizeof (path)) >= sizeof (path)) 2380 return (Z_TOO_BIG); 2381 if (strlcat(path, inpath, sizeof (path)) >= sizeof (path)) 2382 return (Z_TOO_BIG); 2383 2384 if (stat(path, &st) == -1) 2385 return (Z_INVAL); 2386 2387 /* make sure we're only touching device nodes */ 2388 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) 2389 return (Z_INVAL); 2390 2391 if (chown(path, owner, group) == -1) 2392 return (Z_SYSTEM); 2393 2394 if (chmod(path, mode) == -1) 2395 return (Z_SYSTEM); 2396 2397 if ((acltxt == NULL) || (strcmp(acltxt, "") == 0)) 2398 return (Z_OK); 2399 2400 if (acl_fromtext(acltxt, &aclp) != 0) 2401 return (Z_SYSTEM); 2402 2403 errno = 0; 2404 if (acl_set(path, aclp) == -1) { 2405 free(aclp); 2406 return (Z_SYSTEM); 2407 } 2408 2409 free(aclp); 2410 return (Z_OK); 2411 } 2412 2413 /* 2414 * This function finds everything mounted under a zone's rootpath. 2415 * This returns the number of mounts under rootpath, or -1 on error. 2416 * callback is called once per mount found with the first argument 2417 * pointing to the mount point. 2418 * 2419 * If the callback function returns non-zero zonecfg_find_mounts 2420 * aborts with an error. 2421 */ 2422 int 2423 zonecfg_find_mounts(char *rootpath, int (*callback)(const char *, void *), 2424 void *priv) { 2425 FILE *mnttab; 2426 struct mnttab m; 2427 size_t l; 2428 int zfsl; 2429 int rv = 0; 2430 char zfs_path[MAXPATHLEN]; 2431 2432 assert(rootpath != NULL); 2433 2434 if ((zfsl = snprintf(zfs_path, sizeof (zfs_path), "%s/.zfs/", rootpath)) 2435 >= sizeof (zfs_path)) 2436 return (-1); 2437 2438 l = strlen(rootpath); 2439 2440 mnttab = fopen("/etc/mnttab", "r"); 2441 2442 if (mnttab == NULL) 2443 return (-1); 2444 2445 if (ioctl(fileno(mnttab), MNTIOC_SHOWHIDDEN, NULL) < 0) { 2446 rv = -1; 2447 goto out; 2448 } 2449 2450 while (!getmntent(mnttab, &m)) { 2451 if ((strncmp(rootpath, m.mnt_mountp, l) == 0) && 2452 (m.mnt_mountp[l] == '/') && 2453 (strncmp(zfs_path, m.mnt_mountp, zfsl) != 0)) { 2454 rv++; 2455 if (callback == NULL) 2456 continue; 2457 if (callback(m.mnt_mountp, priv)) { 2458 rv = -1; 2459 goto out; 2460 2461 } 2462 } 2463 } 2464 2465 out: 2466 (void) fclose(mnttab); 2467 return (rv); 2468 } 2469 2470 int 2471 zonecfg_lookup_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2472 { 2473 xmlNodePtr cur, firstmatch; 2474 int err; 2475 char name[MAXNAMELEN], type[MAXNAMELEN], value[MAXNAMELEN]; 2476 2477 if (tabptr == NULL) 2478 return (Z_INVAL); 2479 2480 if ((err = operation_prep(handle)) != Z_OK) 2481 return (err); 2482 2483 cur = handle->zone_dh_cur; 2484 firstmatch = NULL; 2485 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2486 if (xmlStrcmp(cur->name, DTD_ELEM_ATTR)) 2487 continue; 2488 if (strlen(tabptr->zone_attr_name) > 0) { 2489 if ((fetchprop(cur, DTD_ATTR_NAME, name, 2490 sizeof (name)) == Z_OK) && 2491 (strcmp(tabptr->zone_attr_name, name) == 0)) { 2492 if (firstmatch == NULL) 2493 firstmatch = cur; 2494 else 2495 return (Z_INSUFFICIENT_SPEC); 2496 } 2497 } 2498 if (strlen(tabptr->zone_attr_type) > 0) { 2499 if ((fetchprop(cur, DTD_ATTR_TYPE, type, 2500 sizeof (type)) == Z_OK)) { 2501 if (strcmp(tabptr->zone_attr_type, type) == 0) { 2502 if (firstmatch == NULL) 2503 firstmatch = cur; 2504 else if (firstmatch != cur) 2505 return (Z_INSUFFICIENT_SPEC); 2506 } else { 2507 /* 2508 * If another property matched but this 2509 * one doesn't then reset firstmatch. 2510 */ 2511 if (firstmatch == cur) 2512 firstmatch = NULL; 2513 } 2514 } 2515 } 2516 if (strlen(tabptr->zone_attr_value) > 0) { 2517 if ((fetchprop(cur, DTD_ATTR_VALUE, value, 2518 sizeof (value)) == Z_OK)) { 2519 if (strcmp(tabptr->zone_attr_value, value) == 2520 0) { 2521 if (firstmatch == NULL) 2522 firstmatch = cur; 2523 else if (firstmatch != cur) 2524 return (Z_INSUFFICIENT_SPEC); 2525 } else { 2526 /* 2527 * If another property matched but this 2528 * one doesn't then reset firstmatch. 2529 */ 2530 if (firstmatch == cur) 2531 firstmatch = NULL; 2532 } 2533 } 2534 } 2535 } 2536 if (firstmatch == NULL) 2537 return (Z_NO_RESOURCE_ID); 2538 2539 cur = firstmatch; 2540 2541 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name, 2542 sizeof (tabptr->zone_attr_name))) != Z_OK) 2543 return (err); 2544 2545 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type, 2546 sizeof (tabptr->zone_attr_type))) != Z_OK) 2547 return (err); 2548 2549 if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value, 2550 sizeof (tabptr->zone_attr_value))) != Z_OK) 2551 return (err); 2552 2553 return (Z_OK); 2554 } 2555 2556 static int 2557 zonecfg_add_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2558 { 2559 xmlNodePtr newnode, cur = handle->zone_dh_cur; 2560 int err; 2561 2562 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ATTR, NULL); 2563 err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_attr_name); 2564 if (err != Z_OK) 2565 return (err); 2566 err = newprop(newnode, DTD_ATTR_TYPE, tabptr->zone_attr_type); 2567 if (err != Z_OK) 2568 return (err); 2569 err = newprop(newnode, DTD_ATTR_VALUE, tabptr->zone_attr_value); 2570 if (err != Z_OK) 2571 return (err); 2572 return (Z_OK); 2573 } 2574 2575 int 2576 zonecfg_add_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2577 { 2578 int err; 2579 2580 if (tabptr == NULL) 2581 return (Z_INVAL); 2582 2583 if ((err = operation_prep(handle)) != Z_OK) 2584 return (err); 2585 2586 if ((err = zonecfg_add_attr_core(handle, tabptr)) != Z_OK) 2587 return (err); 2588 2589 return (Z_OK); 2590 } 2591 2592 static int 2593 zonecfg_delete_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2594 { 2595 xmlNodePtr cur = handle->zone_dh_cur; 2596 int name_match, type_match, value_match; 2597 2598 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2599 if (xmlStrcmp(cur->name, DTD_ELEM_ATTR)) 2600 continue; 2601 2602 name_match = match_prop(cur, DTD_ATTR_NAME, 2603 tabptr->zone_attr_name); 2604 type_match = match_prop(cur, DTD_ATTR_TYPE, 2605 tabptr->zone_attr_type); 2606 value_match = match_prop(cur, DTD_ATTR_VALUE, 2607 tabptr->zone_attr_value); 2608 2609 if (name_match && type_match && value_match) { 2610 xmlUnlinkNode(cur); 2611 xmlFreeNode(cur); 2612 return (Z_OK); 2613 } 2614 } 2615 return (Z_NO_RESOURCE_ID); 2616 } 2617 2618 int 2619 zonecfg_delete_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2620 { 2621 int err; 2622 2623 if (tabptr == NULL) 2624 return (Z_INVAL); 2625 2626 if ((err = operation_prep(handle)) != Z_OK) 2627 return (err); 2628 2629 if ((err = zonecfg_delete_attr_core(handle, tabptr)) != Z_OK) 2630 return (err); 2631 2632 return (Z_OK); 2633 } 2634 2635 int 2636 zonecfg_modify_attr( 2637 zone_dochandle_t handle, 2638 struct zone_attrtab *oldtabptr, 2639 struct zone_attrtab *newtabptr) 2640 { 2641 int err; 2642 2643 if (oldtabptr == NULL || newtabptr == NULL) 2644 return (Z_INVAL); 2645 2646 if ((err = operation_prep(handle)) != Z_OK) 2647 return (err); 2648 2649 if ((err = zonecfg_delete_attr_core(handle, oldtabptr)) != Z_OK) 2650 return (err); 2651 2652 if ((err = zonecfg_add_attr_core(handle, newtabptr)) != Z_OK) 2653 return (err); 2654 2655 return (Z_OK); 2656 } 2657 2658 int 2659 zonecfg_get_attr_boolean(const struct zone_attrtab *attr, boolean_t *value) 2660 { 2661 if (attr == NULL) 2662 return (Z_INVAL); 2663 2664 if (strcmp(attr->zone_attr_type, DTD_ENTITY_BOOLEAN) != 0) 2665 return (Z_INVAL); 2666 2667 if (strcmp(attr->zone_attr_value, DTD_ENTITY_TRUE) == 0) { 2668 *value = B_TRUE; 2669 return (Z_OK); 2670 } 2671 if (strcmp(attr->zone_attr_value, DTD_ENTITY_FALSE) == 0) { 2672 *value = B_FALSE; 2673 return (Z_OK); 2674 } 2675 return (Z_INVAL); 2676 } 2677 2678 int 2679 zonecfg_get_attr_int(const struct zone_attrtab *attr, int64_t *value) 2680 { 2681 long long result; 2682 char *endptr; 2683 2684 if (attr == NULL) 2685 return (Z_INVAL); 2686 2687 if (strcmp(attr->zone_attr_type, DTD_ENTITY_INT) != 0) 2688 return (Z_INVAL); 2689 2690 errno = 0; 2691 result = strtoll(attr->zone_attr_value, &endptr, 10); 2692 if (errno != 0 || *endptr != '\0') 2693 return (Z_INVAL); 2694 *value = result; 2695 return (Z_OK); 2696 } 2697 2698 int 2699 zonecfg_get_attr_string(const struct zone_attrtab *attr, char *value, 2700 size_t val_sz) 2701 { 2702 if (attr == NULL) 2703 return (Z_INVAL); 2704 2705 if (strcmp(attr->zone_attr_type, DTD_ENTITY_STRING) != 0) 2706 return (Z_INVAL); 2707 2708 if (strlcpy(value, attr->zone_attr_value, val_sz) >= val_sz) 2709 return (Z_TOO_BIG); 2710 return (Z_OK); 2711 } 2712 2713 int 2714 zonecfg_get_attr_uint(const struct zone_attrtab *attr, uint64_t *value) 2715 { 2716 unsigned long long result; 2717 long long neg_result; 2718 char *endptr; 2719 2720 if (attr == NULL) 2721 return (Z_INVAL); 2722 2723 if (strcmp(attr->zone_attr_type, DTD_ENTITY_UINT) != 0) 2724 return (Z_INVAL); 2725 2726 errno = 0; 2727 result = strtoull(attr->zone_attr_value, &endptr, 10); 2728 if (errno != 0 || *endptr != '\0') 2729 return (Z_INVAL); 2730 errno = 0; 2731 neg_result = strtoll(attr->zone_attr_value, &endptr, 10); 2732 /* 2733 * Incredibly, strtoull("<negative number>", ...) will not fail but 2734 * return whatever (negative) number cast as a u_longlong_t, so we 2735 * need to look for this here. 2736 */ 2737 if (errno == 0 && neg_result < 0) 2738 return (Z_INVAL); 2739 *value = result; 2740 return (Z_OK); 2741 } 2742 2743 int 2744 zonecfg_lookup_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2745 { 2746 xmlNodePtr cur, val; 2747 char savedname[MAXNAMELEN]; 2748 struct zone_rctlvaltab *valptr; 2749 int err; 2750 2751 if (tabptr->zone_rctl_name == NULL || 2752 strlen(tabptr->zone_rctl_name) == 0) 2753 return (Z_INVAL); 2754 2755 if ((err = operation_prep(handle)) != Z_OK) 2756 return (err); 2757 2758 cur = handle->zone_dh_cur; 2759 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2760 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 2761 continue; 2762 if ((fetchprop(cur, DTD_ATTR_NAME, savedname, 2763 sizeof (savedname)) == Z_OK) && 2764 (strcmp(savedname, tabptr->zone_rctl_name) == 0)) { 2765 tabptr->zone_rctl_valptr = NULL; 2766 for (val = cur->xmlChildrenNode; val != NULL; 2767 val = val->next) { 2768 valptr = (struct zone_rctlvaltab *)malloc( 2769 sizeof (struct zone_rctlvaltab)); 2770 if (valptr == NULL) 2771 return (Z_NOMEM); 2772 if ((fetchprop(val, DTD_ATTR_PRIV, 2773 valptr->zone_rctlval_priv, 2774 sizeof (valptr->zone_rctlval_priv)) != 2775 Z_OK)) 2776 break; 2777 if ((fetchprop(val, DTD_ATTR_LIMIT, 2778 valptr->zone_rctlval_limit, 2779 sizeof (valptr->zone_rctlval_limit)) != 2780 Z_OK)) 2781 break; 2782 if ((fetchprop(val, DTD_ATTR_ACTION, 2783 valptr->zone_rctlval_action, 2784 sizeof (valptr->zone_rctlval_action)) != 2785 Z_OK)) 2786 break; 2787 if (zonecfg_add_rctl_value(tabptr, valptr) != 2788 Z_OK) 2789 break; 2790 } 2791 return (Z_OK); 2792 } 2793 } 2794 return (Z_NO_RESOURCE_ID); 2795 } 2796 2797 static int 2798 zonecfg_add_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2799 { 2800 xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode; 2801 struct zone_rctlvaltab *valptr; 2802 int err; 2803 2804 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_RCTL, NULL); 2805 err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_rctl_name); 2806 if (err != Z_OK) 2807 return (err); 2808 for (valptr = tabptr->zone_rctl_valptr; valptr != NULL; 2809 valptr = valptr->zone_rctlval_next) { 2810 valnode = xmlNewTextChild(newnode, NULL, 2811 DTD_ELEM_RCTLVALUE, NULL); 2812 err = newprop(valnode, DTD_ATTR_PRIV, 2813 valptr->zone_rctlval_priv); 2814 if (err != Z_OK) 2815 return (err); 2816 err = newprop(valnode, DTD_ATTR_LIMIT, 2817 valptr->zone_rctlval_limit); 2818 if (err != Z_OK) 2819 return (err); 2820 err = newprop(valnode, DTD_ATTR_ACTION, 2821 valptr->zone_rctlval_action); 2822 if (err != Z_OK) 2823 return (err); 2824 } 2825 return (Z_OK); 2826 } 2827 2828 int 2829 zonecfg_add_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2830 { 2831 int err; 2832 2833 if (tabptr == NULL || tabptr->zone_rctl_name == NULL) 2834 return (Z_INVAL); 2835 2836 if ((err = operation_prep(handle)) != Z_OK) 2837 return (err); 2838 2839 if ((err = zonecfg_add_rctl_core(handle, tabptr)) != Z_OK) 2840 return (err); 2841 2842 return (Z_OK); 2843 } 2844 2845 static int 2846 zonecfg_delete_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2847 { 2848 xmlNodePtr cur = handle->zone_dh_cur; 2849 xmlChar *savedname; 2850 int name_result; 2851 2852 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2853 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 2854 continue; 2855 2856 savedname = xmlGetProp(cur, DTD_ATTR_NAME); 2857 if (savedname == NULL) /* shouldn't happen */ 2858 continue; 2859 name_result = xmlStrcmp(savedname, 2860 (const xmlChar *) tabptr->zone_rctl_name); 2861 xmlFree(savedname); 2862 2863 if (name_result == 0) { 2864 xmlUnlinkNode(cur); 2865 xmlFreeNode(cur); 2866 return (Z_OK); 2867 } 2868 } 2869 return (Z_NO_RESOURCE_ID); 2870 } 2871 2872 int 2873 zonecfg_delete_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2874 { 2875 int err; 2876 2877 if (tabptr == NULL || tabptr->zone_rctl_name == NULL) 2878 return (Z_INVAL); 2879 2880 if ((err = operation_prep(handle)) != Z_OK) 2881 return (err); 2882 2883 if ((err = zonecfg_delete_rctl_core(handle, tabptr)) != Z_OK) 2884 return (err); 2885 2886 return (Z_OK); 2887 } 2888 2889 int 2890 zonecfg_modify_rctl( 2891 zone_dochandle_t handle, 2892 struct zone_rctltab *oldtabptr, 2893 struct zone_rctltab *newtabptr) 2894 { 2895 int err; 2896 2897 if (oldtabptr == NULL || oldtabptr->zone_rctl_name == NULL || 2898 newtabptr == NULL || newtabptr->zone_rctl_name == NULL) 2899 return (Z_INVAL); 2900 2901 if ((err = operation_prep(handle)) != Z_OK) 2902 return (err); 2903 2904 if ((err = zonecfg_delete_rctl_core(handle, oldtabptr)) != Z_OK) 2905 return (err); 2906 2907 if ((err = zonecfg_add_rctl_core(handle, newtabptr)) != Z_OK) 2908 return (err); 2909 2910 return (Z_OK); 2911 } 2912 2913 int 2914 zonecfg_add_rctl_value( 2915 struct zone_rctltab *tabptr, 2916 struct zone_rctlvaltab *valtabptr) 2917 { 2918 struct zone_rctlvaltab *last, *old, *new; 2919 rctlblk_t *rctlblk = alloca(rctlblk_size()); 2920 2921 last = tabptr->zone_rctl_valptr; 2922 for (old = last; old != NULL; old = old->zone_rctlval_next) 2923 last = old; /* walk to the end of the list */ 2924 new = valtabptr; /* alloc'd by caller */ 2925 new->zone_rctlval_next = NULL; 2926 if (zonecfg_construct_rctlblk(valtabptr, rctlblk) != Z_OK) 2927 return (Z_INVAL); 2928 if (!zonecfg_valid_rctlblk(rctlblk)) 2929 return (Z_INVAL); 2930 if (last == NULL) 2931 tabptr->zone_rctl_valptr = new; 2932 else 2933 last->zone_rctlval_next = new; 2934 return (Z_OK); 2935 } 2936 2937 int 2938 zonecfg_remove_rctl_value( 2939 struct zone_rctltab *tabptr, 2940 struct zone_rctlvaltab *valtabptr) 2941 { 2942 struct zone_rctlvaltab *last, *this, *next; 2943 2944 last = tabptr->zone_rctl_valptr; 2945 for (this = last; this != NULL; this = this->zone_rctlval_next) { 2946 if (strcmp(this->zone_rctlval_priv, 2947 valtabptr->zone_rctlval_priv) == 0 && 2948 strcmp(this->zone_rctlval_limit, 2949 valtabptr->zone_rctlval_limit) == 0 && 2950 strcmp(this->zone_rctlval_action, 2951 valtabptr->zone_rctlval_action) == 0) { 2952 next = this->zone_rctlval_next; 2953 if (this == tabptr->zone_rctl_valptr) 2954 tabptr->zone_rctl_valptr = next; 2955 else 2956 last->zone_rctlval_next = next; 2957 free(this); 2958 return (Z_OK); 2959 } else 2960 last = this; 2961 } 2962 return (Z_NO_PROPERTY_ID); 2963 } 2964 2965 char * 2966 zonecfg_strerror(int errnum) 2967 { 2968 switch (errnum) { 2969 case Z_OK: 2970 return (dgettext(TEXT_DOMAIN, "OK")); 2971 case Z_EMPTY_DOCUMENT: 2972 return (dgettext(TEXT_DOMAIN, "Empty document")); 2973 case Z_WRONG_DOC_TYPE: 2974 return (dgettext(TEXT_DOMAIN, "Wrong document type")); 2975 case Z_BAD_PROPERTY: 2976 return (dgettext(TEXT_DOMAIN, "Bad document property")); 2977 case Z_TEMP_FILE: 2978 return (dgettext(TEXT_DOMAIN, 2979 "Problem creating temporary file")); 2980 case Z_SAVING_FILE: 2981 return (dgettext(TEXT_DOMAIN, "Problem saving file")); 2982 case Z_NO_ENTRY: 2983 return (dgettext(TEXT_DOMAIN, "No such entry")); 2984 case Z_BOGUS_ZONE_NAME: 2985 return (dgettext(TEXT_DOMAIN, "Bogus zone name")); 2986 case Z_REQD_RESOURCE_MISSING: 2987 return (dgettext(TEXT_DOMAIN, "Required resource missing")); 2988 case Z_REQD_PROPERTY_MISSING: 2989 return (dgettext(TEXT_DOMAIN, "Required property missing")); 2990 case Z_BAD_HANDLE: 2991 return (dgettext(TEXT_DOMAIN, "Bad handle")); 2992 case Z_NOMEM: 2993 return (dgettext(TEXT_DOMAIN, "Out of memory")); 2994 case Z_INVAL: 2995 return (dgettext(TEXT_DOMAIN, "Invalid argument")); 2996 case Z_ACCES: 2997 return (dgettext(TEXT_DOMAIN, "Permission denied")); 2998 case Z_TOO_BIG: 2999 return (dgettext(TEXT_DOMAIN, "Argument list too long")); 3000 case Z_MISC_FS: 3001 return (dgettext(TEXT_DOMAIN, 3002 "Miscellaneous file system error")); 3003 case Z_NO_ZONE: 3004 return (dgettext(TEXT_DOMAIN, "No such zone configured")); 3005 case Z_NO_RESOURCE_TYPE: 3006 return (dgettext(TEXT_DOMAIN, "No such resource type")); 3007 case Z_NO_RESOURCE_ID: 3008 return (dgettext(TEXT_DOMAIN, "No such resource with that id")); 3009 case Z_NO_PROPERTY_TYPE: 3010 return (dgettext(TEXT_DOMAIN, "No such property type")); 3011 case Z_NO_PROPERTY_ID: 3012 return (dgettext(TEXT_DOMAIN, "No such property with that id")); 3013 case Z_BAD_ZONE_STATE: 3014 return (dgettext(TEXT_DOMAIN, 3015 "Zone state is invalid for the requested operation")); 3016 case Z_INVALID_DOCUMENT: 3017 return (dgettext(TEXT_DOMAIN, "Invalid document")); 3018 case Z_NAME_IN_USE: 3019 return (dgettext(TEXT_DOMAIN, "Zone name already in use")); 3020 case Z_NO_SUCH_ID: 3021 return (dgettext(TEXT_DOMAIN, "No such zone ID")); 3022 case Z_UPDATING_INDEX: 3023 return (dgettext(TEXT_DOMAIN, "Problem updating index file")); 3024 case Z_LOCKING_FILE: 3025 return (dgettext(TEXT_DOMAIN, "Locking index file")); 3026 case Z_UNLOCKING_FILE: 3027 return (dgettext(TEXT_DOMAIN, "Unlocking index file")); 3028 case Z_INSUFFICIENT_SPEC: 3029 return (dgettext(TEXT_DOMAIN, "Insufficient specification")); 3030 case Z_RESOLVED_PATH: 3031 return (dgettext(TEXT_DOMAIN, "Resolved path mismatch")); 3032 case Z_IPV6_ADDR_PREFIX_LEN: 3033 return (dgettext(TEXT_DOMAIN, 3034 "IPv6 address missing required prefix length")); 3035 case Z_BOGUS_ADDRESS: 3036 return (dgettext(TEXT_DOMAIN, 3037 "Neither an IPv4 nor an IPv6 address nor a host name")); 3038 case Z_PRIV_PROHIBITED: 3039 return (dgettext(TEXT_DOMAIN, 3040 "Specified privilege is prohibited")); 3041 case Z_PRIV_REQUIRED: 3042 return (dgettext(TEXT_DOMAIN, 3043 "Required privilege is missing")); 3044 case Z_PRIV_UNKNOWN: 3045 return (dgettext(TEXT_DOMAIN, 3046 "Specified privilege is unknown")); 3047 case Z_BRAND_ERROR: 3048 return (dgettext(TEXT_DOMAIN, 3049 "Brand-specific error")); 3050 default: 3051 return (dgettext(TEXT_DOMAIN, "Unknown error")); 3052 } 3053 } 3054 3055 /* 3056 * Note that the zonecfg_setXent() and zonecfg_endXent() calls are all the 3057 * same, as they just turn around and call zonecfg_setent() / zonecfg_endent(). 3058 */ 3059 3060 static int 3061 zonecfg_setent(zone_dochandle_t handle) 3062 { 3063 xmlNodePtr cur; 3064 int err; 3065 3066 if (handle == NULL) 3067 return (Z_INVAL); 3068 3069 if ((err = operation_prep(handle)) != Z_OK) { 3070 handle->zone_dh_cur = NULL; 3071 return (err); 3072 } 3073 cur = handle->zone_dh_cur; 3074 cur = cur->xmlChildrenNode; 3075 handle->zone_dh_cur = cur; 3076 return (Z_OK); 3077 } 3078 3079 static int 3080 zonecfg_endent(zone_dochandle_t handle) 3081 { 3082 if (handle == NULL) 3083 return (Z_INVAL); 3084 3085 handle->zone_dh_cur = handle->zone_dh_top; 3086 return (Z_OK); 3087 } 3088 3089 int 3090 zonecfg_setfsent(zone_dochandle_t handle) 3091 { 3092 return (zonecfg_setent(handle)); 3093 } 3094 3095 int 3096 zonecfg_getfsent(zone_dochandle_t handle, struct zone_fstab *tabptr) 3097 { 3098 xmlNodePtr cur, options; 3099 char options_str[MAX_MNTOPT_STR]; 3100 int err; 3101 3102 if (handle == NULL) 3103 return (Z_INVAL); 3104 3105 if ((cur = handle->zone_dh_cur) == NULL) 3106 return (Z_NO_ENTRY); 3107 3108 for (; cur != NULL; cur = cur->next) 3109 if (!xmlStrcmp(cur->name, DTD_ELEM_FS)) 3110 break; 3111 if (cur == NULL) { 3112 handle->zone_dh_cur = handle->zone_dh_top; 3113 return (Z_NO_ENTRY); 3114 } 3115 3116 if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special, 3117 sizeof (tabptr->zone_fs_special))) != Z_OK) { 3118 handle->zone_dh_cur = handle->zone_dh_top; 3119 return (err); 3120 } 3121 3122 if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw, 3123 sizeof (tabptr->zone_fs_raw))) != Z_OK) { 3124 handle->zone_dh_cur = handle->zone_dh_top; 3125 return (err); 3126 } 3127 3128 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 3129 sizeof (tabptr->zone_fs_dir))) != Z_OK) { 3130 handle->zone_dh_cur = handle->zone_dh_top; 3131 return (err); 3132 } 3133 3134 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type, 3135 sizeof (tabptr->zone_fs_type))) != Z_OK) { 3136 handle->zone_dh_cur = handle->zone_dh_top; 3137 return (err); 3138 } 3139 3140 /* OK for options to be NULL */ 3141 tabptr->zone_fs_options = NULL; 3142 for (options = cur->xmlChildrenNode; options != NULL; 3143 options = options->next) { 3144 if (fetchprop(options, DTD_ATTR_NAME, options_str, 3145 sizeof (options_str)) != Z_OK) 3146 break; 3147 if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK) 3148 break; 3149 } 3150 3151 handle->zone_dh_cur = cur->next; 3152 return (Z_OK); 3153 } 3154 3155 int 3156 zonecfg_endfsent(zone_dochandle_t handle) 3157 { 3158 return (zonecfg_endent(handle)); 3159 } 3160 3161 int 3162 zonecfg_setipdent(zone_dochandle_t handle) 3163 { 3164 return (zonecfg_setent(handle)); 3165 } 3166 3167 int 3168 zonecfg_getipdent(zone_dochandle_t handle, struct zone_fstab *tabptr) 3169 { 3170 xmlNodePtr cur; 3171 int err; 3172 3173 if (handle == NULL) 3174 return (Z_INVAL); 3175 3176 if ((cur = handle->zone_dh_cur) == NULL) 3177 return (Z_NO_ENTRY); 3178 3179 for (; cur != NULL; cur = cur->next) 3180 if (!xmlStrcmp(cur->name, DTD_ELEM_IPD)) 3181 break; 3182 if (cur == NULL) { 3183 handle->zone_dh_cur = handle->zone_dh_top; 3184 return (Z_NO_ENTRY); 3185 } 3186 3187 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 3188 sizeof (tabptr->zone_fs_dir))) != Z_OK) { 3189 handle->zone_dh_cur = handle->zone_dh_top; 3190 return (err); 3191 } 3192 3193 handle->zone_dh_cur = cur->next; 3194 return (Z_OK); 3195 } 3196 3197 int 3198 zonecfg_endipdent(zone_dochandle_t handle) 3199 { 3200 return (zonecfg_endent(handle)); 3201 } 3202 3203 int 3204 zonecfg_setnwifent(zone_dochandle_t handle) 3205 { 3206 return (zonecfg_setent(handle)); 3207 } 3208 3209 int 3210 zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 3211 { 3212 xmlNodePtr cur; 3213 int err; 3214 3215 if (handle == NULL) 3216 return (Z_INVAL); 3217 3218 if ((cur = handle->zone_dh_cur) == NULL) 3219 return (Z_NO_ENTRY); 3220 3221 for (; cur != NULL; cur = cur->next) 3222 if (!xmlStrcmp(cur->name, DTD_ELEM_NET)) 3223 break; 3224 if (cur == NULL) { 3225 handle->zone_dh_cur = handle->zone_dh_top; 3226 return (Z_NO_ENTRY); 3227 } 3228 3229 if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address, 3230 sizeof (tabptr->zone_nwif_address))) != Z_OK) { 3231 handle->zone_dh_cur = handle->zone_dh_top; 3232 return (err); 3233 } 3234 3235 if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical, 3236 sizeof (tabptr->zone_nwif_physical))) != Z_OK) { 3237 handle->zone_dh_cur = handle->zone_dh_top; 3238 return (err); 3239 } 3240 3241 handle->zone_dh_cur = cur->next; 3242 return (Z_OK); 3243 } 3244 3245 int 3246 zonecfg_endnwifent(zone_dochandle_t handle) 3247 { 3248 return (zonecfg_endent(handle)); 3249 } 3250 3251 int 3252 zonecfg_setdevent(zone_dochandle_t handle) 3253 { 3254 return (zonecfg_setent(handle)); 3255 } 3256 3257 int 3258 zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr) 3259 { 3260 xmlNodePtr cur; 3261 int err; 3262 3263 if (handle == NULL) 3264 return (Z_INVAL); 3265 3266 if ((cur = handle->zone_dh_cur) == NULL) 3267 return (Z_NO_ENTRY); 3268 3269 for (; cur != NULL; cur = cur->next) 3270 if (!xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) 3271 break; 3272 if (cur == NULL) { 3273 handle->zone_dh_cur = handle->zone_dh_top; 3274 return (Z_NO_ENTRY); 3275 } 3276 3277 if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match, 3278 sizeof (tabptr->zone_dev_match))) != Z_OK) { 3279 handle->zone_dh_cur = handle->zone_dh_top; 3280 return (err); 3281 } 3282 3283 handle->zone_dh_cur = cur->next; 3284 return (Z_OK); 3285 } 3286 3287 int 3288 zonecfg_enddevent(zone_dochandle_t handle) 3289 { 3290 return (zonecfg_endent(handle)); 3291 } 3292 3293 int 3294 zonecfg_setrctlent(zone_dochandle_t handle) 3295 { 3296 return (zonecfg_setent(handle)); 3297 } 3298 3299 int 3300 zonecfg_getrctlent(zone_dochandle_t handle, struct zone_rctltab *tabptr) 3301 { 3302 xmlNodePtr cur, val; 3303 struct zone_rctlvaltab *valptr; 3304 int err; 3305 3306 if (handle == NULL) 3307 return (Z_INVAL); 3308 3309 if ((cur = handle->zone_dh_cur) == NULL) 3310 return (Z_NO_ENTRY); 3311 3312 for (; cur != NULL; cur = cur->next) 3313 if (!xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 3314 break; 3315 if (cur == NULL) { 3316 handle->zone_dh_cur = handle->zone_dh_top; 3317 return (Z_NO_ENTRY); 3318 } 3319 3320 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_rctl_name, 3321 sizeof (tabptr->zone_rctl_name))) != Z_OK) { 3322 handle->zone_dh_cur = handle->zone_dh_top; 3323 return (err); 3324 } 3325 3326 tabptr->zone_rctl_valptr = NULL; 3327 for (val = cur->xmlChildrenNode; val != NULL; val = val->next) { 3328 valptr = (struct zone_rctlvaltab *)malloc( 3329 sizeof (struct zone_rctlvaltab)); 3330 if (valptr == NULL) 3331 return (Z_NOMEM); 3332 if (fetchprop(val, DTD_ATTR_PRIV, valptr->zone_rctlval_priv, 3333 sizeof (valptr->zone_rctlval_priv)) != Z_OK) 3334 break; 3335 if (fetchprop(val, DTD_ATTR_LIMIT, valptr->zone_rctlval_limit, 3336 sizeof (valptr->zone_rctlval_limit)) != Z_OK) 3337 break; 3338 if (fetchprop(val, DTD_ATTR_ACTION, valptr->zone_rctlval_action, 3339 sizeof (valptr->zone_rctlval_action)) != Z_OK) 3340 break; 3341 if (zonecfg_add_rctl_value(tabptr, valptr) != Z_OK) 3342 break; 3343 } 3344 3345 handle->zone_dh_cur = cur->next; 3346 return (Z_OK); 3347 } 3348 3349 int 3350 zonecfg_endrctlent(zone_dochandle_t handle) 3351 { 3352 return (zonecfg_endent(handle)); 3353 } 3354 3355 int 3356 zonecfg_setattrent(zone_dochandle_t handle) 3357 { 3358 return (zonecfg_setent(handle)); 3359 } 3360 3361 int 3362 zonecfg_getattrent(zone_dochandle_t handle, struct zone_attrtab *tabptr) 3363 { 3364 xmlNodePtr cur; 3365 int err; 3366 3367 if (handle == NULL) 3368 return (Z_INVAL); 3369 3370 if ((cur = handle->zone_dh_cur) == NULL) 3371 return (Z_NO_ENTRY); 3372 3373 for (; cur != NULL; cur = cur->next) 3374 if (!xmlStrcmp(cur->name, DTD_ELEM_ATTR)) 3375 break; 3376 if (cur == NULL) { 3377 handle->zone_dh_cur = handle->zone_dh_top; 3378 return (Z_NO_ENTRY); 3379 } 3380 3381 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name, 3382 sizeof (tabptr->zone_attr_name))) != Z_OK) { 3383 handle->zone_dh_cur = handle->zone_dh_top; 3384 return (err); 3385 } 3386 3387 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type, 3388 sizeof (tabptr->zone_attr_type))) != Z_OK) { 3389 handle->zone_dh_cur = handle->zone_dh_top; 3390 return (err); 3391 } 3392 3393 if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value, 3394 sizeof (tabptr->zone_attr_value))) != Z_OK) { 3395 handle->zone_dh_cur = handle->zone_dh_top; 3396 return (err); 3397 } 3398 3399 handle->zone_dh_cur = cur->next; 3400 return (Z_OK); 3401 } 3402 3403 int 3404 zonecfg_endattrent(zone_dochandle_t handle) 3405 { 3406 return (zonecfg_endent(handle)); 3407 } 3408 3409 /* 3410 * The privileges available on the system and described in privileges(5) 3411 * fall into four categories with respect to non-global zones: 3412 * 3413 * Default set of privileges considered safe for all non-global 3414 * zones. These privileges are "safe" in the sense that a 3415 * privileged process in the zone cannot affect processes in any 3416 * other zone on the system. 3417 * 3418 * Set of privileges not currently permitted within a non-global 3419 * zone. These privileges are considered by default, "unsafe," 3420 * and include ones which affect global resources (such as the 3421 * system clock or physical memory) or are overly broad and cover 3422 * more than one mechanism in the system. In other cases, there 3423 * has not been sufficient virtualization in the parts of the 3424 * system the privilege covers to allow its use within a 3425 * non-global zone. 3426 * 3427 * Set of privileges required in order to get a zone booted and 3428 * init(1M) started. These cannot be removed from the zone's 3429 * privilege set. 3430 * 3431 * All other privileges are optional and are potentially useful for 3432 * processes executing inside a non-global zone. 3433 * 3434 * When privileges are added to the system, a determination needs to be 3435 * made as to which category the privilege belongs to. Ideally, 3436 * privileges should be fine-grained enough and the mechanisms they cover 3437 * virtualized enough so that they can be made available to non-global 3438 * zones. 3439 */ 3440 3441 /* 3442 * Define some of the tokens that priv_str_to_set(3C) recognizes. Since 3443 * the privilege string separator can be any character, although it is 3444 * usually a comma character, define these here as well in the event that 3445 * they change or are augmented in the future. 3446 */ 3447 #define BASIC_TOKEN "basic" 3448 #define DEFAULT_TOKEN "default" 3449 #define ZONE_TOKEN "zone" 3450 #define TOKEN_PRIV_CHAR ',' 3451 #define TOKEN_PRIV_STR "," 3452 3453 typedef struct priv_node { 3454 struct priv_node *pn_next; /* Next privilege */ 3455 char *pn_priv; /* Privileges name */ 3456 } priv_node_t; 3457 3458 /* Privileges lists can differ across brands */ 3459 typedef struct priv_lists { 3460 /* Privileges considered safe for all non-global zones of a brand */ 3461 struct priv_node *pl_default; 3462 3463 /* Privileges not permitted for all non-global zones of a brand */ 3464 struct priv_node *pl_prohibited; 3465 3466 /* Privileges required for all non-global zones of a brand */ 3467 struct priv_node *pl_required; 3468 } priv_lists_t; 3469 3470 static int 3471 priv_lists_cb(void *data, const char *name, const char *set) 3472 { 3473 priv_lists_t *plp = (priv_lists_t *)data; 3474 priv_node_t *pnp; 3475 3476 /* Allocate a new priv list node. */ 3477 if ((pnp = malloc(sizeof (*pnp))) == NULL) 3478 return (-1); 3479 if ((pnp->pn_priv = strdup(name)) == NULL) { 3480 free(pnp); 3481 return (-1); 3482 } 3483 3484 /* Insert the new priv list node into the right list */ 3485 if (strcmp(set, "default") == 0) { 3486 pnp->pn_next = plp->pl_default; 3487 plp->pl_default = pnp; 3488 } else if (strcmp(set, "prohibited") == 0) { 3489 pnp->pn_next = plp->pl_prohibited; 3490 plp->pl_prohibited = pnp; 3491 } else if (strcmp(set, "required") == 0) { 3492 pnp->pn_next = plp->pl_required; 3493 plp->pl_required = pnp; 3494 } else { 3495 free(pnp->pn_priv); 3496 free(pnp); 3497 return (-1); 3498 } 3499 return (0); 3500 } 3501 3502 static void 3503 priv_lists_destroy(priv_lists_t *plp) 3504 { 3505 priv_node_t *pnp; 3506 3507 assert(plp != NULL); 3508 3509 while ((pnp = plp->pl_default) != NULL) { 3510 plp->pl_default = pnp->pn_next; 3511 free(pnp->pn_priv); 3512 free(pnp); 3513 } 3514 while ((pnp = plp->pl_prohibited) != NULL) { 3515 plp->pl_prohibited = pnp->pn_next; 3516 free(pnp->pn_priv); 3517 free(pnp); 3518 } 3519 while ((pnp = plp->pl_required) != NULL) { 3520 plp->pl_required = pnp->pn_next; 3521 free(pnp->pn_priv); 3522 free(pnp); 3523 } 3524 free(plp); 3525 } 3526 3527 static int 3528 priv_lists_create(zone_dochandle_t handle, priv_lists_t **plpp) 3529 { 3530 priv_lists_t *plp; 3531 brand_handle_t bh; 3532 char brand[MAXNAMELEN]; 3533 3534 if (handle != NULL) { 3535 if (zonecfg_get_brand(handle, brand, sizeof (brand)) != 0) 3536 return (Z_BRAND_ERROR); 3537 } else { 3538 (void) strlcpy(brand, NATIVE_BRAND_NAME, MAXNAMELEN); 3539 } 3540 3541 if ((bh = brand_open(brand)) == NULL) 3542 return (Z_BRAND_ERROR); 3543 3544 if ((plp = calloc(1, sizeof (priv_lists_t))) == NULL) { 3545 brand_close(bh); 3546 return (Z_NOMEM); 3547 } 3548 3549 /* construct the privilege lists */ 3550 if (brand_config_iter_privilege(bh, priv_lists_cb, plp) != 0) { 3551 priv_lists_destroy(plp); 3552 brand_close(bh); 3553 return (Z_BRAND_ERROR); 3554 } 3555 3556 brand_close(bh); 3557 *plpp = plp; 3558 return (Z_OK); 3559 } 3560 3561 static int 3562 get_default_privset(priv_set_t *privs, priv_lists_t *plp) 3563 { 3564 priv_node_t *pnp; 3565 priv_set_t *basic; 3566 3567 basic = priv_str_to_set(BASIC_TOKEN, TOKEN_PRIV_STR, NULL); 3568 if (basic == NULL) 3569 return (errno == ENOMEM ? Z_NOMEM : Z_INVAL); 3570 3571 priv_union(basic, privs); 3572 priv_freeset(basic); 3573 3574 for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next) { 3575 if (priv_addset(privs, pnp->pn_priv) != 0) 3576 return (Z_INVAL); 3577 } 3578 3579 return (Z_OK); 3580 } 3581 3582 int 3583 zonecfg_default_privset(priv_set_t *privs) 3584 { 3585 priv_lists_t *plp; 3586 int ret; 3587 3588 if ((ret = priv_lists_create(NULL, &plp)) != Z_OK) 3589 return (ret); 3590 ret = get_default_privset(privs, plp); 3591 priv_lists_destroy(plp); 3592 return (ret); 3593 } 3594 3595 void 3596 append_priv_token(char *priv, char *str, size_t strlen) 3597 { 3598 if (*str != '\0') 3599 (void) strlcat(str, TOKEN_PRIV_STR, strlen); 3600 (void) strlcat(str, priv, strlen); 3601 } 3602 3603 /* 3604 * Verify that the supplied string is a valid privilege limit set for a 3605 * non-global zone. This string must not only be acceptable to 3606 * priv_str_to_set(3C) which parses it, but it also must resolve to a 3607 * privilege set that includes certain required privileges and lacks 3608 * certain prohibited privileges. 3609 */ 3610 static int 3611 verify_privset(char *privbuf, priv_set_t *privs, char **privname, 3612 boolean_t add_default, priv_lists_t *plp) 3613 { 3614 priv_node_t *pnp; 3615 char *tmp, *cp, *lasts; 3616 size_t len; 3617 priv_set_t *mergeset; 3618 const char *token; 3619 3620 /* 3621 * The verification of the privilege string occurs in several 3622 * phases. In the first phase, the supplied string is scanned for 3623 * the ZONE_TOKEN token which is not support as part of the 3624 * "limitpriv" property. 3625 * 3626 * Duplicate the supplied privilege string since strtok_r(3C) 3627 * tokenizes its input by null-terminating the tokens. 3628 */ 3629 if ((tmp = strdup(privbuf)) == NULL) 3630 return (Z_NOMEM); 3631 for (cp = strtok_r(tmp, TOKEN_PRIV_STR, &lasts); cp != NULL; 3632 cp = strtok_r(NULL, TOKEN_PRIV_STR, &lasts)) { 3633 if (strcmp(cp, ZONE_TOKEN) == 0) { 3634 free(tmp); 3635 if ((*privname = strdup(ZONE_TOKEN)) == NULL) 3636 return (Z_NOMEM); 3637 else 3638 return (Z_PRIV_UNKNOWN); 3639 } 3640 } 3641 free(tmp); 3642 3643 if (add_default) { 3644 /* 3645 * If DEFAULT_TOKEN was specified, a string needs to be 3646 * built containing the privileges from the default, safe 3647 * set along with those of the "limitpriv" property. 3648 */ 3649 len = strlen(privbuf) + sizeof (BASIC_TOKEN) + 2; 3650 3651 for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next) 3652 len += strlen(pnp->pn_priv) + 1; 3653 tmp = alloca(len); 3654 *tmp = '\0'; 3655 3656 append_priv_token(BASIC_TOKEN, tmp, len); 3657 for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next) 3658 append_priv_token(pnp->pn_priv, tmp, len); 3659 (void) strlcat(tmp, TOKEN_PRIV_STR, len); 3660 (void) strlcat(tmp, privbuf, len); 3661 } else { 3662 tmp = privbuf; 3663 } 3664 3665 3666 /* 3667 * In the next phase, attempt to convert the merged privilege 3668 * string into a privilege set. In the case of an error, either 3669 * there was a memory allocation failure or there was an invalid 3670 * privilege token in the string. In either case, return an 3671 * appropriate error code but in the event of an invalid token, 3672 * allocate a string containing its name and return that back to 3673 * the caller. 3674 */ 3675 mergeset = priv_str_to_set(tmp, TOKEN_PRIV_STR, &token); 3676 if (mergeset == NULL) { 3677 if (token == NULL) 3678 return (Z_NOMEM); 3679 if ((cp = strchr(token, TOKEN_PRIV_CHAR)) != NULL) 3680 *cp = '\0'; 3681 if ((*privname = strdup(token)) == NULL) 3682 return (Z_NOMEM); 3683 else 3684 return (Z_PRIV_UNKNOWN); 3685 } 3686 3687 /* 3688 * Next, verify that none of the prohibited zone privileges are 3689 * present in the merged privilege set. 3690 */ 3691 for (pnp = plp->pl_prohibited; pnp != NULL; pnp = pnp->pn_next) { 3692 if (priv_ismember(mergeset, pnp->pn_priv)) { 3693 priv_freeset(mergeset); 3694 if ((*privname = strdup(pnp->pn_priv)) == NULL) 3695 return (Z_NOMEM); 3696 else 3697 return (Z_PRIV_PROHIBITED); 3698 } 3699 } 3700 3701 /* 3702 * Finally, verify that all of the required zone privileges are 3703 * present in the merged privilege set. 3704 */ 3705 for (pnp = plp->pl_required; pnp != NULL; pnp = pnp->pn_next) { 3706 if (!priv_ismember(mergeset, pnp->pn_priv)) { 3707 priv_freeset(mergeset); 3708 if ((*privname = strdup(pnp->pn_priv)) == NULL) 3709 return (Z_NOMEM); 3710 else 3711 return (Z_PRIV_REQUIRED); 3712 } 3713 } 3714 3715 priv_copyset(mergeset, privs); 3716 priv_freeset(mergeset); 3717 return (Z_OK); 3718 } 3719 3720 /* 3721 * Fill in the supplied privilege set with either the default, safe set of 3722 * privileges suitable for a non-global zone, or one based on the 3723 * "limitpriv" property in the zone's configuration. 3724 * 3725 * In the event of an invalid privilege specification in the 3726 * configuration, a string is allocated and returned containing the 3727 * "privilege" causing the issue. It is the caller's responsibility to 3728 * free this memory when it is done with it. 3729 */ 3730 int 3731 zonecfg_get_privset(zone_dochandle_t handle, priv_set_t *privs, 3732 char **privname) 3733 { 3734 priv_lists_t *plp; 3735 char *cp, *limitpriv = NULL; 3736 int err, limitlen; 3737 3738 /* 3739 * Attempt to lookup the "limitpriv" property. If it does not 3740 * exist or matches the string DEFAULT_TOKEN exactly, then the 3741 * default, safe privilege set is returned. 3742 */ 3743 if ((err = zonecfg_get_limitpriv(handle, &limitpriv)) != Z_OK) 3744 return (err); 3745 3746 if ((err = priv_lists_create(handle, &plp)) != Z_OK) 3747 return (err); 3748 3749 limitlen = strlen(limitpriv); 3750 if (limitlen == 0 || strcmp(limitpriv, DEFAULT_TOKEN) == 0) { 3751 free(limitpriv); 3752 err = get_default_privset(privs, plp); 3753 priv_lists_destroy(plp); 3754 return (err); 3755 } 3756 3757 /* 3758 * Check if the string DEFAULT_TOKEN is the first token in a list 3759 * of privileges. 3760 */ 3761 cp = strchr(limitpriv, TOKEN_PRIV_CHAR); 3762 if (cp != NULL && 3763 strncmp(limitpriv, DEFAULT_TOKEN, cp - limitpriv) == 0) 3764 err = verify_privset(cp + 1, privs, privname, B_TRUE, plp); 3765 else 3766 err = verify_privset(limitpriv, privs, privname, B_FALSE, plp); 3767 3768 free(limitpriv); 3769 priv_lists_destroy(plp); 3770 return (err); 3771 } 3772 3773 int 3774 zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz) 3775 { 3776 zone_dochandle_t handle; 3777 boolean_t found = B_FALSE; 3778 struct zoneent *ze; 3779 FILE *cookie; 3780 int err; 3781 char *cp; 3782 3783 if (zone_name == NULL) 3784 return (Z_INVAL); 3785 3786 (void) strlcpy(zonepath, zonecfg_root, rp_sz); 3787 cp = zonepath + strlen(zonepath); 3788 while (cp > zonepath && cp[-1] == '/') 3789 *--cp = '\0'; 3790 3791 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) { 3792 if (zonepath[0] == '\0') 3793 (void) strlcpy(zonepath, "/", rp_sz); 3794 return (Z_OK); 3795 } 3796 3797 /* 3798 * First check the index file. Because older versions did not have 3799 * a copy of the zone path, allow for it to be zero length, in which 3800 * case we ignore this result and fall back to the XML files. 3801 */ 3802 cookie = setzoneent(); 3803 while ((ze = getzoneent_private(cookie)) != NULL) { 3804 if (strcmp(ze->zone_name, zone_name) == 0) { 3805 found = B_TRUE; 3806 if (ze->zone_path[0] != '\0') 3807 (void) strlcpy(cp, ze->zone_path, 3808 rp_sz - (cp - zonepath)); 3809 } 3810 free(ze); 3811 if (found) 3812 break; 3813 } 3814 endzoneent(cookie); 3815 if (found && *cp != '\0') 3816 return (Z_OK); 3817 3818 /* Fall back to the XML files. */ 3819 if ((handle = zonecfg_init_handle()) == NULL) 3820 return (Z_NOMEM); 3821 3822 /* 3823 * Check the snapshot first: if a zone is running, its zonepath 3824 * may have changed. 3825 */ 3826 if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) { 3827 if ((err = zonecfg_get_handle(zone_name, handle)) != Z_OK) 3828 return (err); 3829 } 3830 err = zonecfg_get_zonepath(handle, zonepath, rp_sz); 3831 zonecfg_fini_handle(handle); 3832 return (err); 3833 } 3834 3835 int 3836 zone_get_rootpath(char *zone_name, char *rootpath, size_t rp_sz) 3837 { 3838 int err; 3839 3840 /* This function makes sense for non-global zones only. */ 3841 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) 3842 return (Z_BOGUS_ZONE_NAME); 3843 if ((err = zone_get_zonepath(zone_name, rootpath, rp_sz)) != Z_OK) 3844 return (err); 3845 if (strlcat(rootpath, "/root", rp_sz) >= rp_sz) 3846 return (Z_TOO_BIG); 3847 return (Z_OK); 3848 } 3849 3850 int 3851 zone_get_brand(char *zone_name, char *brandname, size_t rp_sz) 3852 { 3853 int err; 3854 zone_dochandle_t handle; 3855 char myzone[MAXNAMELEN]; 3856 int myzoneid = getzoneid(); 3857 3858 /* 3859 * If we are not in the global zone, then we don't have the zone 3860 * .xml files with the brand name available. Thus, we are going to 3861 * have to ask the kernel for the information. 3862 */ 3863 if (myzoneid != GLOBAL_ZONEID) { 3864 if (zone_getattr(myzoneid, ZONE_ATTR_NAME, myzone, 3865 sizeof (myzone)) < 0) 3866 return (Z_NO_ZONE); 3867 if (strncmp(zone_name, myzone, MAXNAMELEN) != NULL) 3868 return (Z_NO_ZONE); 3869 err = zone_getattr(myzoneid, ZONE_ATTR_BRAND, brandname, rp_sz); 3870 if (err < 0) 3871 return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL); 3872 return (Z_OK); 3873 } 3874 3875 if (strcmp(zone_name, "global") == NULL) { 3876 (void) strlcpy(brandname, NATIVE_BRAND_NAME, rp_sz); 3877 return (0); 3878 } 3879 if ((handle = zonecfg_init_handle()) == NULL) 3880 return (Z_NOMEM); 3881 3882 err = zonecfg_get_handle((char *)zone_name, handle); 3883 if (err == Z_OK) 3884 err = zonecfg_get_brand(handle, brandname, rp_sz); 3885 3886 zonecfg_fini_handle(handle); 3887 return (err); 3888 } 3889 3890 /* 3891 * Return the appropriate root for the active /dev. 3892 * For normal zone, the path is $ZONEPATH/root; 3893 * for scratch zone, the dev path is $ZONEPATH/lu. 3894 */ 3895 int 3896 zone_get_devroot(char *zone_name, char *devroot, size_t rp_sz) 3897 { 3898 int err; 3899 char *suffix; 3900 zone_state_t state; 3901 3902 /* This function makes sense for non-global zones only. */ 3903 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) 3904 return (Z_BOGUS_ZONE_NAME); 3905 if ((err = zone_get_zonepath(zone_name, devroot, rp_sz)) != Z_OK) 3906 return (err); 3907 3908 if (zone_get_state(zone_name, &state) == Z_OK && 3909 state == ZONE_STATE_MOUNTED) 3910 suffix = "/lu"; 3911 else 3912 suffix = "/root"; 3913 if (strlcat(devroot, suffix, rp_sz) >= rp_sz) 3914 return (Z_TOO_BIG); 3915 return (Z_OK); 3916 } 3917 3918 static zone_state_t 3919 kernel_state_to_user_state(zoneid_t zoneid, zone_status_t kernel_state) 3920 { 3921 char zoneroot[MAXPATHLEN]; 3922 size_t zlen; 3923 3924 assert(kernel_state <= ZONE_MAX_STATE); 3925 switch (kernel_state) { 3926 case ZONE_IS_UNINITIALIZED: 3927 return (ZONE_STATE_READY); 3928 case ZONE_IS_READY: 3929 /* 3930 * If the zone's root is mounted on $ZONEPATH/lu, then 3931 * it's a mounted scratch zone. 3932 */ 3933 if (zone_getattr(zoneid, ZONE_ATTR_ROOT, zoneroot, 3934 sizeof (zoneroot)) >= 0) { 3935 zlen = strlen(zoneroot); 3936 if (zlen > 3 && 3937 strcmp(zoneroot + zlen - 3, "/lu") == 0) 3938 return (ZONE_STATE_MOUNTED); 3939 } 3940 return (ZONE_STATE_READY); 3941 case ZONE_IS_BOOTING: 3942 case ZONE_IS_RUNNING: 3943 return (ZONE_STATE_RUNNING); 3944 case ZONE_IS_SHUTTING_DOWN: 3945 case ZONE_IS_EMPTY: 3946 return (ZONE_STATE_SHUTTING_DOWN); 3947 case ZONE_IS_DOWN: 3948 case ZONE_IS_DYING: 3949 case ZONE_IS_DEAD: 3950 default: 3951 return (ZONE_STATE_DOWN); 3952 } 3953 /* NOTREACHED */ 3954 } 3955 3956 int 3957 zone_get_state(char *zone_name, zone_state_t *state_num) 3958 { 3959 zone_status_t status; 3960 zoneid_t zone_id; 3961 struct zoneent *ze; 3962 boolean_t found = B_FALSE; 3963 FILE *cookie; 3964 char kernzone[ZONENAME_MAX]; 3965 FILE *fp; 3966 3967 if (zone_name == NULL) 3968 return (Z_INVAL); 3969 3970 /* 3971 * If we're looking at an alternate root, then we need to query the 3972 * kernel using the scratch zone name. 3973 */ 3974 zone_id = -1; 3975 if (*zonecfg_root != '\0' && !zonecfg_is_scratch(zone_name)) { 3976 if ((fp = zonecfg_open_scratch("", B_FALSE)) != NULL) { 3977 if (zonecfg_find_scratch(fp, zone_name, zonecfg_root, 3978 kernzone, sizeof (kernzone)) == 0) 3979 zone_id = getzoneidbyname(kernzone); 3980 zonecfg_close_scratch(fp); 3981 } 3982 } else { 3983 zone_id = getzoneidbyname(zone_name); 3984 } 3985 3986 /* check to see if zone is running */ 3987 if (zone_id != -1 && 3988 zone_getattr(zone_id, ZONE_ATTR_STATUS, &status, 3989 sizeof (status)) >= 0) { 3990 *state_num = kernel_state_to_user_state(zone_id, status); 3991 return (Z_OK); 3992 } 3993 3994 cookie = setzoneent(); 3995 while ((ze = getzoneent_private(cookie)) != NULL) { 3996 if (strcmp(ze->zone_name, zone_name) == 0) { 3997 found = B_TRUE; 3998 *state_num = ze->zone_state; 3999 } 4000 free(ze); 4001 if (found) 4002 break; 4003 } 4004 endzoneent(cookie); 4005 return ((found) ? Z_OK : Z_NO_ZONE); 4006 } 4007 4008 int 4009 zone_set_state(char *zone, zone_state_t state) 4010 { 4011 struct zoneent ze; 4012 4013 if (state != ZONE_STATE_CONFIGURED && state != ZONE_STATE_INSTALLED && 4014 state != ZONE_STATE_INCOMPLETE) 4015 return (Z_INVAL); 4016 4017 bzero(&ze, sizeof (ze)); 4018 (void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name)); 4019 ze.zone_state = state; 4020 (void) strlcpy(ze.zone_path, "", sizeof (ze.zone_path)); 4021 return (putzoneent(&ze, PZE_MODIFY)); 4022 } 4023 4024 /* 4025 * Get id (if any) for specified zone. There are four possible outcomes: 4026 * - If the string corresponds to the numeric id of an active (booted) 4027 * zone, sets *zip to the zone id and returns 0. 4028 * - If the string corresponds to the name of an active (booted) zone, 4029 * sets *zip to the zone id and returns 0. 4030 * - If the string is a name in the configuration but is not booted, 4031 * sets *zip to ZONE_ID_UNDEFINED and returns 0. 4032 * - Otherwise, leaves *zip unchanged and returns -1. 4033 * 4034 * This function acts as an auxiliary filter on the function of the same 4035 * name in libc; the linker binds to this version if libzonecfg exists, 4036 * and the libc version if it doesn't. Any changes to this version of 4037 * the function should probably be reflected in the libc version as well. 4038 */ 4039 int 4040 zone_get_id(const char *str, zoneid_t *zip) 4041 { 4042 zone_dochandle_t hdl; 4043 zoneid_t zoneid; 4044 char *cp; 4045 int err; 4046 4047 /* first try looking for active zone by id */ 4048 errno = 0; 4049 zoneid = (zoneid_t)strtol(str, &cp, 0); 4050 if (errno == 0 && cp != str && *cp == '\0' && 4051 getzonenamebyid(zoneid, NULL, 0) != -1) { 4052 *zip = zoneid; 4053 return (0); 4054 } 4055 4056 /* then look for active zone by name */ 4057 if ((zoneid = getzoneidbyname(str)) != -1) { 4058 *zip = zoneid; 4059 return (0); 4060 } 4061 4062 /* if in global zone, try looking up name in configuration database */ 4063 if (getzoneid() != GLOBAL_ZONEID || 4064 (hdl = zonecfg_init_handle()) == NULL) 4065 return (-1); 4066 4067 if (zonecfg_get_handle(str, hdl) == Z_OK) { 4068 /* zone exists but isn't active */ 4069 *zip = ZONE_ID_UNDEFINED; 4070 err = 0; 4071 } else { 4072 err = -1; 4073 } 4074 4075 zonecfg_fini_handle(hdl); 4076 return (err); 4077 } 4078 4079 char * 4080 zone_state_str(zone_state_t state_num) 4081 { 4082 switch (state_num) { 4083 case ZONE_STATE_CONFIGURED: 4084 return (ZONE_STATE_STR_CONFIGURED); 4085 case ZONE_STATE_INCOMPLETE: 4086 return (ZONE_STATE_STR_INCOMPLETE); 4087 case ZONE_STATE_INSTALLED: 4088 return (ZONE_STATE_STR_INSTALLED); 4089 case ZONE_STATE_READY: 4090 return (ZONE_STATE_STR_READY); 4091 case ZONE_STATE_MOUNTED: 4092 return (ZONE_STATE_STR_MOUNTED); 4093 case ZONE_STATE_RUNNING: 4094 return (ZONE_STATE_STR_RUNNING); 4095 case ZONE_STATE_SHUTTING_DOWN: 4096 return (ZONE_STATE_STR_SHUTTING_DOWN); 4097 case ZONE_STATE_DOWN: 4098 return (ZONE_STATE_STR_DOWN); 4099 default: 4100 return ("unknown"); 4101 } 4102 } 4103 4104 /* 4105 * Given a UUID value, find an associated zone name. This is intended to be 4106 * used by callers who set up some 'default' name (corresponding to the 4107 * expected name for the zone) in the zonename buffer, and thus the function 4108 * doesn't touch this buffer on failure. 4109 */ 4110 int 4111 zonecfg_get_name_by_uuid(const uuid_t uuidin, char *zonename, size_t namelen) 4112 { 4113 FILE *fp; 4114 struct zoneent *ze; 4115 uchar_t *uuid; 4116 4117 /* 4118 * A small amount of subterfuge via casts is necessary here because 4119 * libuuid doesn't use const correctly, but we don't want to export 4120 * this brokenness to our clients. 4121 */ 4122 uuid = (uchar_t *)uuidin; 4123 if (uuid_is_null(uuid)) 4124 return (Z_NO_ZONE); 4125 if ((fp = setzoneent()) == NULL) 4126 return (Z_NO_ZONE); 4127 while ((ze = getzoneent_private(fp)) != NULL) { 4128 if (uuid_compare(uuid, ze->zone_uuid) == 0) 4129 break; 4130 free(ze); 4131 } 4132 endzoneent(fp); 4133 if (ze != NULL) { 4134 (void) strlcpy(zonename, ze->zone_name, namelen); 4135 free(ze); 4136 return (Z_OK); 4137 } else { 4138 return (Z_NO_ZONE); 4139 } 4140 } 4141 4142 /* 4143 * Given a zone name, get its UUID. Returns a "NULL" UUID value if the zone 4144 * exists but the file doesn't have a value set yet. Returns an error if the 4145 * zone cannot be located. 4146 */ 4147 int 4148 zonecfg_get_uuid(const char *zonename, uuid_t uuid) 4149 { 4150 FILE *fp; 4151 struct zoneent *ze; 4152 4153 if ((fp = setzoneent()) == NULL) 4154 return (Z_NO_ZONE); 4155 while ((ze = getzoneent_private(fp)) != NULL) { 4156 if (strcmp(ze->zone_name, zonename) == 0) 4157 break; 4158 free(ze); 4159 } 4160 endzoneent(fp); 4161 if (ze != NULL) { 4162 uuid_copy(uuid, ze->zone_uuid); 4163 free(ze); 4164 return (Z_OK); 4165 } else { 4166 return (Z_NO_ZONE); 4167 } 4168 } 4169 4170 /* 4171 * File-system convenience functions. 4172 */ 4173 boolean_t 4174 zonecfg_valid_fs_type(const char *type) 4175 { 4176 /* 4177 * We already know which FS types don't work. 4178 */ 4179 if (strcmp(type, "proc") == 0 || 4180 strcmp(type, "mntfs") == 0 || 4181 strcmp(type, "autofs") == 0 || 4182 strncmp(type, "nfs", sizeof ("nfs") - 1) == 0 || 4183 strcmp(type, "cachefs") == 0) 4184 return (B_FALSE); 4185 /* 4186 * The caller may do more detailed verification to make sure other 4187 * aspects of this filesystem type make sense. 4188 */ 4189 return (B_TRUE); 4190 } 4191 4192 /* 4193 * Generally uninteresting rctl convenience functions. 4194 */ 4195 4196 int 4197 zonecfg_construct_rctlblk(const struct zone_rctlvaltab *rctlval, 4198 rctlblk_t *rctlblk) 4199 { 4200 unsigned long long ull; 4201 char *endp; 4202 rctl_priv_t priv; 4203 rctl_qty_t limit; 4204 uint_t action; 4205 4206 /* Get the privilege */ 4207 if (strcmp(rctlval->zone_rctlval_priv, "basic") == 0) { 4208 priv = RCPRIV_BASIC; 4209 } else if (strcmp(rctlval->zone_rctlval_priv, "privileged") == 0) { 4210 priv = RCPRIV_PRIVILEGED; 4211 } else { 4212 /* Invalid privilege */ 4213 return (Z_INVAL); 4214 } 4215 4216 /* deal with negative input; strtoull(3c) doesn't do what we want */ 4217 if (rctlval->zone_rctlval_limit[0] == '-') 4218 return (Z_INVAL); 4219 /* Get the limit */ 4220 errno = 0; 4221 ull = strtoull(rctlval->zone_rctlval_limit, &endp, 0); 4222 if (errno != 0 || *endp != '\0') { 4223 /* parse failed */ 4224 return (Z_INVAL); 4225 } 4226 limit = (rctl_qty_t)ull; 4227 4228 /* Get the action */ 4229 if (strcmp(rctlval->zone_rctlval_action, "none") == 0) { 4230 action = RCTL_LOCAL_NOACTION; 4231 } else if (strcmp(rctlval->zone_rctlval_action, "signal") == 0) { 4232 action = RCTL_LOCAL_SIGNAL; 4233 } else if (strcmp(rctlval->zone_rctlval_action, "deny") == 0) { 4234 action = RCTL_LOCAL_DENY; 4235 } else { 4236 /* Invalid Action */ 4237 return (Z_INVAL); 4238 } 4239 rctlblk_set_local_action(rctlblk, action, 0); 4240 rctlblk_set_privilege(rctlblk, priv); 4241 rctlblk_set_value(rctlblk, limit); 4242 return (Z_OK); 4243 } 4244 4245 static int 4246 rctl_check(const char *rctlname, void *arg) 4247 { 4248 const char *attrname = arg; 4249 4250 /* 4251 * Returning 1 here is our signal to zonecfg_is_rctl() that it is 4252 * indeed an rctl name recognized by the system. 4253 */ 4254 return (strcmp(rctlname, attrname) == 0 ? 1 : 0); 4255 } 4256 4257 boolean_t 4258 zonecfg_is_rctl(const char *name) 4259 { 4260 return (rctl_walk(rctl_check, (void *)name) == 1); 4261 } 4262 4263 boolean_t 4264 zonecfg_valid_rctlname(const char *name) 4265 { 4266 const char *c; 4267 4268 if (strncmp(name, "zone.", sizeof ("zone.") - 1) != 0) 4269 return (B_FALSE); 4270 if (strlen(name) == sizeof ("zone.") - 1) 4271 return (B_FALSE); 4272 for (c = name + sizeof ("zone.") - 1; *c != '\0'; c++) { 4273 if (!isalpha(*c) && *c != '-') 4274 return (B_FALSE); 4275 } 4276 return (B_TRUE); 4277 } 4278 4279 boolean_t 4280 zonecfg_valid_rctlblk(const rctlblk_t *rctlblk) 4281 { 4282 rctl_priv_t priv = rctlblk_get_privilege((rctlblk_t *)rctlblk); 4283 uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL); 4284 4285 if (priv != RCPRIV_PRIVILEGED) 4286 return (B_FALSE); 4287 if (action != RCTL_LOCAL_NOACTION && action != RCTL_LOCAL_DENY) 4288 return (B_FALSE); 4289 return (B_TRUE); 4290 } 4291 4292 boolean_t 4293 zonecfg_valid_rctl(const char *name, const rctlblk_t *rctlblk) 4294 { 4295 rctlblk_t *current, *next; 4296 rctl_qty_t limit = rctlblk_get_value((rctlblk_t *)rctlblk); 4297 uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL); 4298 uint_t global_flags; 4299 4300 if (!zonecfg_valid_rctlblk(rctlblk)) 4301 return (B_FALSE); 4302 if (!zonecfg_valid_rctlname(name)) 4303 return (B_FALSE); 4304 4305 current = alloca(rctlblk_size()); 4306 if (getrctl(name, NULL, current, RCTL_FIRST) != 0) 4307 return (B_TRUE); /* not an rctl on this system */ 4308 /* 4309 * Make sure the proposed value isn't greater than the current system 4310 * value. 4311 */ 4312 next = alloca(rctlblk_size()); 4313 while (rctlblk_get_privilege(current) != RCPRIV_SYSTEM) { 4314 rctlblk_t *tmp; 4315 4316 if (getrctl(name, current, next, RCTL_NEXT) != 0) 4317 return (B_FALSE); /* shouldn't happen */ 4318 tmp = current; 4319 current = next; 4320 next = tmp; 4321 } 4322 if (limit > rctlblk_get_value(current)) 4323 return (B_FALSE); 4324 4325 /* 4326 * Make sure the proposed action is allowed. 4327 */ 4328 global_flags = rctlblk_get_global_flags(current); 4329 if ((global_flags & RCTL_GLOBAL_DENY_NEVER) && 4330 action == RCTL_LOCAL_DENY) 4331 return (B_FALSE); 4332 if ((global_flags & RCTL_GLOBAL_DENY_ALWAYS) && 4333 action == RCTL_LOCAL_NOACTION) 4334 return (B_FALSE); 4335 4336 return (B_TRUE); 4337 } 4338 4339 /* 4340 * There is always a race condition between reading the initial copy of 4341 * a zones state and its state changing. We address this by providing 4342 * zonecfg_notify_critical_enter and zonecfg_noticy_critical_exit functions. 4343 * When zonecfg_critical_enter is called, sets the state field to LOCKED 4344 * and aquires biglock. Biglock protects against other threads executing 4345 * critical_enter and the state field protects against state changes during 4346 * the critical period. 4347 * 4348 * If any state changes occur, zn_cb will set the failed field of the znotify 4349 * structure. This will cause the critical_exit function to re-lock the 4350 * channel and return an error. Since evsnts may be delayed, the critical_exit 4351 * function "flushes" the queue by putting an event on the queue and waiting for 4352 * zn_cb to notify critical_exit that it received the ping event. 4353 */ 4354 static const char * 4355 string_get_tok(const char *in, char delim, int num) 4356 { 4357 int i = 0; 4358 4359 for (; i < num; in++) { 4360 if (*in == delim) 4361 i++; 4362 if (*in == 0) 4363 return (NULL); 4364 } 4365 return (in); 4366 } 4367 4368 static boolean_t 4369 is_ping(sysevent_t *ev) 4370 { 4371 if (strcmp(sysevent_get_subclass_name(ev), 4372 ZONE_EVENT_PING_SUBCLASS) == 0) { 4373 return (B_TRUE); 4374 } else { 4375 return (B_FALSE); 4376 } 4377 } 4378 4379 static boolean_t 4380 is_my_ping(sysevent_t *ev) 4381 { 4382 const char *sender; 4383 char mypid[sizeof (pid_t) * 3 + 1]; 4384 4385 (void) snprintf(mypid, sizeof (mypid), "%i", getpid()); 4386 sender = string_get_tok(sysevent_get_pub(ev), ':', 3); 4387 if (sender == NULL) 4388 return (B_FALSE); 4389 if (strcmp(sender, mypid) != 0) 4390 return (B_FALSE); 4391 return (B_TRUE); 4392 } 4393 4394 static int 4395 do_callback(struct znotify *zevtchan, sysevent_t *ev) 4396 { 4397 nvlist_t *l; 4398 int zid; 4399 char *zonename; 4400 char *newstate; 4401 char *oldstate; 4402 int ret; 4403 hrtime_t when; 4404 4405 if (strcmp(sysevent_get_subclass_name(ev), 4406 ZONE_EVENT_STATUS_SUBCLASS) == 0) { 4407 4408 if (sysevent_get_attr_list(ev, &l) != 0) { 4409 if (errno == ENOMEM) { 4410 zevtchan->zn_failure_count++; 4411 return (EAGAIN); 4412 } 4413 return (0); 4414 } 4415 ret = 0; 4416 4417 if ((nvlist_lookup_string(l, ZONE_CB_NAME, &zonename) == 0) && 4418 (nvlist_lookup_string(l, ZONE_CB_NEWSTATE, &newstate) 4419 == 0) && 4420 (nvlist_lookup_string(l, ZONE_CB_OLDSTATE, &oldstate) 4421 == 0) && 4422 (nvlist_lookup_uint64(l, ZONE_CB_TIMESTAMP, 4423 (uint64_t *)&when) == 0) && 4424 (nvlist_lookup_int32(l, ZONE_CB_ZONEID, &zid) == 0)) { 4425 ret = zevtchan->zn_callback(zonename, zid, newstate, 4426 oldstate, when, zevtchan->zn_private); 4427 } 4428 4429 zevtchan->zn_failure_count = 0; 4430 nvlist_free(l); 4431 return (ret); 4432 } else { 4433 /* 4434 * We have received an event in an unknown subclass. Ignore. 4435 */ 4436 zevtchan->zn_failure_count = 0; 4437 return (0); 4438 } 4439 } 4440 4441 static int 4442 zn_cb(sysevent_t *ev, void *p) 4443 { 4444 struct znotify *zevtchan = p; 4445 int error; 4446 4447 (void) pthread_mutex_lock(&(zevtchan->zn_mutex)); 4448 4449 if (is_ping(ev) && !is_my_ping(ev)) { 4450 (void) pthread_mutex_unlock((&zevtchan->zn_mutex)); 4451 return (0); 4452 } 4453 4454 if (zevtchan->zn_state == ZN_LOCKED) { 4455 assert(!is_ping(ev)); 4456 zevtchan->zn_failed = B_TRUE; 4457 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4458 return (0); 4459 } 4460 4461 if (zevtchan->zn_state == ZN_PING_INFLIGHT) { 4462 if (is_ping(ev)) { 4463 zevtchan->zn_state = ZN_PING_RECEIVED; 4464 (void) pthread_cond_signal(&(zevtchan->zn_cond)); 4465 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4466 return (0); 4467 } else { 4468 zevtchan->zn_failed = B_TRUE; 4469 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4470 return (0); 4471 } 4472 } 4473 4474 if (zevtchan->zn_state == ZN_UNLOCKED) { 4475 4476 error = do_callback(zevtchan, ev); 4477 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4478 /* 4479 * Every ENOMEM failure causes do_callback to increment 4480 * zn_failure_count and every success causes it to 4481 * set zn_failure_count to zero. If we got EAGAIN, 4482 * we will sleep for zn_failure_count seconds and return 4483 * EAGAIN to gpec to try again. 4484 * 4485 * After 55 seconds, or 10 try's we give up and drop the 4486 * event. 4487 */ 4488 if (error == EAGAIN) { 4489 if (zevtchan->zn_failure_count > ZONE_CB_RETRY_COUNT) { 4490 return (0); 4491 } 4492 (void) sleep(zevtchan->zn_failure_count); 4493 } 4494 return (error); 4495 } 4496 4497 if (zevtchan->zn_state == ZN_PING_RECEIVED) { 4498 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4499 return (0); 4500 } 4501 4502 abort(); 4503 return (0); 4504 } 4505 4506 void 4507 zonecfg_notify_critical_enter(void *h) 4508 { 4509 struct znotify *zevtchan = h; 4510 4511 (void) pthread_mutex_lock(&(zevtchan->zn_bigmutex)); 4512 zevtchan->zn_state = ZN_LOCKED; 4513 } 4514 4515 int 4516 zonecfg_notify_critical_exit(void * h) 4517 { 4518 4519 struct znotify *zevtchan = h; 4520 4521 if (zevtchan->zn_state == ZN_UNLOCKED) 4522 return (0); 4523 4524 (void) pthread_mutex_lock(&(zevtchan->zn_mutex)); 4525 zevtchan->zn_state = ZN_PING_INFLIGHT; 4526 4527 (void) sysevent_evc_publish(zevtchan->zn_eventchan, 4528 ZONE_EVENT_STATUS_CLASS, 4529 ZONE_EVENT_PING_SUBCLASS, ZONE_EVENT_PING_PUBLISHER, 4530 zevtchan->zn_subscriber_id, NULL, EVCH_SLEEP); 4531 4532 while (zevtchan->zn_state != ZN_PING_RECEIVED) { 4533 (void) pthread_cond_wait(&(zevtchan->zn_cond), 4534 &(zevtchan->zn_mutex)); 4535 } 4536 4537 if (zevtchan->zn_failed == B_TRUE) { 4538 zevtchan->zn_state = ZN_LOCKED; 4539 zevtchan->zn_failed = B_FALSE; 4540 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4541 return (1); 4542 } 4543 4544 zevtchan->zn_state = ZN_UNLOCKED; 4545 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4546 (void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex)); 4547 return (0); 4548 } 4549 4550 void 4551 zonecfg_notify_critical_abort(void *h) 4552 { 4553 struct znotify *zevtchan = h; 4554 4555 zevtchan->zn_state = ZN_UNLOCKED; 4556 zevtchan->zn_failed = B_FALSE; 4557 /* 4558 * Don't do anything about zn_lock. If it is held, it could only be 4559 * held by zn_cb and it will be unlocked soon. 4560 */ 4561 (void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex)); 4562 } 4563 4564 void * 4565 zonecfg_notify_bind(int(*func)(const char *zonename, zoneid_t zid, 4566 const char *newstate, const char *oldstate, hrtime_t when, void *p), 4567 void *p) 4568 { 4569 struct znotify *zevtchan; 4570 int i = 1; 4571 int r; 4572 4573 zevtchan = malloc(sizeof (struct znotify)); 4574 4575 if (zevtchan == NULL) 4576 return (NULL); 4577 4578 zevtchan->zn_private = p; 4579 zevtchan->zn_callback = func; 4580 zevtchan->zn_state = ZN_UNLOCKED; 4581 zevtchan->zn_failed = B_FALSE; 4582 4583 if (pthread_mutex_init(&(zevtchan->zn_mutex), NULL)) 4584 goto out3; 4585 if (pthread_cond_init(&(zevtchan->zn_cond), NULL)) { 4586 (void) pthread_mutex_destroy(&(zevtchan->zn_mutex)); 4587 goto out3; 4588 } 4589 if (pthread_mutex_init(&(zevtchan->zn_bigmutex), NULL)) { 4590 (void) pthread_mutex_destroy(&(zevtchan->zn_mutex)); 4591 (void) pthread_cond_destroy(&(zevtchan->zn_cond)); 4592 goto out3; 4593 } 4594 4595 if (sysevent_evc_bind(ZONE_EVENT_CHANNEL, &(zevtchan->zn_eventchan), 4596 0) != 0) 4597 goto out2; 4598 4599 do { 4600 /* 4601 * At 4 digits the subscriber ID gets too long and we have 4602 * no chance of successfully registering. 4603 */ 4604 if (i > 999) 4605 goto out1; 4606 4607 (void) sprintf(zevtchan->zn_subscriber_id, "zone_%li_%i", 4608 getpid() % 999999l, i); 4609 4610 r = sysevent_evc_subscribe(zevtchan->zn_eventchan, 4611 zevtchan->zn_subscriber_id, ZONE_EVENT_STATUS_CLASS, zn_cb, 4612 zevtchan, 0); 4613 4614 i++; 4615 4616 } while (r); 4617 4618 return (zevtchan); 4619 out1: 4620 sysevent_evc_unbind(zevtchan->zn_eventchan); 4621 out2: 4622 (void) pthread_mutex_destroy(&zevtchan->zn_mutex); 4623 (void) pthread_cond_destroy(&zevtchan->zn_cond); 4624 (void) pthread_mutex_destroy(&(zevtchan->zn_bigmutex)); 4625 out3: 4626 free(zevtchan); 4627 4628 return (NULL); 4629 } 4630 4631 void 4632 zonecfg_notify_unbind(void *handle) 4633 { 4634 4635 int ret; 4636 4637 sysevent_evc_unbind(((struct znotify *)handle)->zn_eventchan); 4638 /* 4639 * Check that all evc threads have gone away. This should be 4640 * enforced by sysevent_evc_unbind. 4641 */ 4642 ret = pthread_mutex_trylock(&((struct znotify *)handle)->zn_mutex); 4643 4644 if (ret) 4645 abort(); 4646 4647 (void) pthread_mutex_unlock(&((struct znotify *)handle)->zn_mutex); 4648 (void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_mutex); 4649 (void) pthread_cond_destroy(&((struct znotify *)handle)->zn_cond); 4650 (void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_bigmutex); 4651 4652 free(handle); 4653 } 4654 4655 static int 4656 zonecfg_add_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr) 4657 { 4658 xmlNodePtr newnode, cur = handle->zone_dh_cur; 4659 int err; 4660 4661 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DATASET, NULL); 4662 if ((err = newprop(newnode, DTD_ATTR_NAME, 4663 tabptr->zone_dataset_name)) != Z_OK) 4664 return (err); 4665 return (Z_OK); 4666 } 4667 4668 int 4669 zonecfg_add_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 4670 { 4671 int err; 4672 4673 if (tabptr == NULL) 4674 return (Z_INVAL); 4675 4676 if ((err = operation_prep(handle)) != Z_OK) 4677 return (err); 4678 4679 if ((err = zonecfg_add_ds_core(handle, tabptr)) != Z_OK) 4680 return (err); 4681 4682 return (Z_OK); 4683 } 4684 4685 static int 4686 zonecfg_delete_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr) 4687 { 4688 xmlNodePtr cur = handle->zone_dh_cur; 4689 4690 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 4691 if (xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 4692 continue; 4693 4694 if (match_prop(cur, DTD_ATTR_NAME, 4695 tabptr->zone_dataset_name)) { 4696 xmlUnlinkNode(cur); 4697 xmlFreeNode(cur); 4698 return (Z_OK); 4699 } 4700 } 4701 return (Z_NO_RESOURCE_ID); 4702 } 4703 4704 int 4705 zonecfg_delete_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 4706 { 4707 int err; 4708 4709 if (tabptr == NULL) 4710 return (Z_INVAL); 4711 4712 if ((err = operation_prep(handle)) != Z_OK) 4713 return (err); 4714 4715 if ((err = zonecfg_delete_ds_core(handle, tabptr)) != Z_OK) 4716 return (err); 4717 4718 return (Z_OK); 4719 } 4720 4721 int 4722 zonecfg_modify_ds( 4723 zone_dochandle_t handle, 4724 struct zone_dstab *oldtabptr, 4725 struct zone_dstab *newtabptr) 4726 { 4727 int err; 4728 4729 if (oldtabptr == NULL || newtabptr == NULL) 4730 return (Z_INVAL); 4731 4732 if ((err = operation_prep(handle)) != Z_OK) 4733 return (err); 4734 4735 if ((err = zonecfg_delete_ds_core(handle, oldtabptr)) != Z_OK) 4736 return (err); 4737 4738 if ((err = zonecfg_add_ds_core(handle, newtabptr)) != Z_OK) 4739 return (err); 4740 4741 return (Z_OK); 4742 } 4743 4744 int 4745 zonecfg_lookup_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 4746 { 4747 xmlNodePtr cur, firstmatch; 4748 int err; 4749 char dataset[MAXNAMELEN]; 4750 4751 if (tabptr == NULL) 4752 return (Z_INVAL); 4753 4754 if ((err = operation_prep(handle)) != Z_OK) 4755 return (err); 4756 4757 cur = handle->zone_dh_cur; 4758 firstmatch = NULL; 4759 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 4760 if (xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 4761 continue; 4762 if (strlen(tabptr->zone_dataset_name) > 0) { 4763 if ((fetchprop(cur, DTD_ATTR_NAME, dataset, 4764 sizeof (dataset)) == Z_OK) && 4765 (strcmp(tabptr->zone_dataset_name, 4766 dataset) == 0)) { 4767 if (firstmatch == NULL) 4768 firstmatch = cur; 4769 else 4770 return (Z_INSUFFICIENT_SPEC); 4771 } 4772 } 4773 } 4774 if (firstmatch == NULL) 4775 return (Z_NO_RESOURCE_ID); 4776 4777 cur = firstmatch; 4778 4779 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name, 4780 sizeof (tabptr->zone_dataset_name))) != Z_OK) 4781 return (err); 4782 4783 return (Z_OK); 4784 } 4785 4786 int 4787 zonecfg_setdsent(zone_dochandle_t handle) 4788 { 4789 return (zonecfg_setent(handle)); 4790 } 4791 4792 int 4793 zonecfg_getdsent(zone_dochandle_t handle, struct zone_dstab *tabptr) 4794 { 4795 xmlNodePtr cur; 4796 int err; 4797 4798 if (handle == NULL) 4799 return (Z_INVAL); 4800 4801 if ((cur = handle->zone_dh_cur) == NULL) 4802 return (Z_NO_ENTRY); 4803 4804 for (; cur != NULL; cur = cur->next) 4805 if (!xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 4806 break; 4807 if (cur == NULL) { 4808 handle->zone_dh_cur = handle->zone_dh_top; 4809 return (Z_NO_ENTRY); 4810 } 4811 4812 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name, 4813 sizeof (tabptr->zone_dataset_name))) != Z_OK) { 4814 handle->zone_dh_cur = handle->zone_dh_top; 4815 return (err); 4816 } 4817 4818 handle->zone_dh_cur = cur->next; 4819 return (Z_OK); 4820 } 4821 4822 int 4823 zonecfg_enddsent(zone_dochandle_t handle) 4824 { 4825 return (zonecfg_endent(handle)); 4826 } 4827 4828 int 4829 zonecfg_setpkgent(zone_dochandle_t handle) 4830 { 4831 return (zonecfg_setent(handle)); 4832 } 4833 4834 int 4835 zonecfg_getpkgent(zone_dochandle_t handle, struct zone_pkgtab *tabptr) 4836 { 4837 xmlNodePtr cur; 4838 int err; 4839 4840 if (handle == NULL) 4841 return (Z_INVAL); 4842 4843 if ((cur = handle->zone_dh_cur) == NULL) 4844 return (Z_NO_ENTRY); 4845 4846 for (; cur != NULL; cur = cur->next) 4847 if (!xmlStrcmp(cur->name, DTD_ELEM_PACKAGE)) 4848 break; 4849 if (cur == NULL) { 4850 handle->zone_dh_cur = handle->zone_dh_top; 4851 return (Z_NO_ENTRY); 4852 } 4853 4854 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_pkg_name, 4855 sizeof (tabptr->zone_pkg_name))) != Z_OK) { 4856 handle->zone_dh_cur = handle->zone_dh_top; 4857 return (err); 4858 } 4859 4860 if ((err = fetchprop(cur, DTD_ATTR_VERSION, tabptr->zone_pkg_version, 4861 sizeof (tabptr->zone_pkg_version))) != Z_OK) { 4862 handle->zone_dh_cur = handle->zone_dh_top; 4863 return (err); 4864 } 4865 4866 handle->zone_dh_cur = cur->next; 4867 return (Z_OK); 4868 } 4869 4870 int 4871 zonecfg_endpkgent(zone_dochandle_t handle) 4872 { 4873 return (zonecfg_endent(handle)); 4874 } 4875 4876 int 4877 zonecfg_setpatchent(zone_dochandle_t handle) 4878 { 4879 return (zonecfg_setent(handle)); 4880 } 4881 4882 int 4883 zonecfg_getpatchent(zone_dochandle_t handle, struct zone_patchtab *tabptr) 4884 { 4885 xmlNodePtr cur; 4886 int err; 4887 4888 if (handle == NULL) 4889 return (Z_INVAL); 4890 4891 if ((cur = handle->zone_dh_cur) == NULL) 4892 return (Z_NO_ENTRY); 4893 4894 for (; cur != NULL; cur = cur->next) 4895 if (!xmlStrcmp(cur->name, DTD_ELEM_PATCH)) 4896 break; 4897 if (cur == NULL) { 4898 handle->zone_dh_cur = handle->zone_dh_top; 4899 return (Z_NO_ENTRY); 4900 } 4901 4902 if ((err = fetchprop(cur, DTD_ATTR_ID, tabptr->zone_patch_id, 4903 sizeof (tabptr->zone_patch_id))) != Z_OK) { 4904 handle->zone_dh_cur = handle->zone_dh_top; 4905 return (err); 4906 } 4907 4908 handle->zone_dh_cur = cur->next; 4909 return (Z_OK); 4910 } 4911 4912 int 4913 zonecfg_endpatchent(zone_dochandle_t handle) 4914 { 4915 return (zonecfg_endent(handle)); 4916 } 4917 4918 int 4919 zonecfg_setdevperment(zone_dochandle_t handle) 4920 { 4921 return (zonecfg_setent(handle)); 4922 } 4923 4924 int 4925 zonecfg_getdevperment(zone_dochandle_t handle, struct zone_devpermtab *tabptr) 4926 { 4927 xmlNodePtr cur; 4928 int err; 4929 char buf[128]; 4930 4931 tabptr->zone_devperm_acl = NULL; 4932 4933 if (handle == NULL) 4934 return (Z_INVAL); 4935 4936 if ((cur = handle->zone_dh_cur) == NULL) 4937 return (Z_NO_ENTRY); 4938 4939 for (; cur != NULL; cur = cur->next) 4940 if (!xmlStrcmp(cur->name, DTD_ELEM_DEV_PERM)) 4941 break; 4942 if (cur == NULL) { 4943 handle->zone_dh_cur = handle->zone_dh_top; 4944 return (Z_NO_ENTRY); 4945 } 4946 4947 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_devperm_name, 4948 sizeof (tabptr->zone_devperm_name))) != Z_OK) { 4949 handle->zone_dh_cur = handle->zone_dh_top; 4950 return (err); 4951 } 4952 4953 if ((err = fetchprop(cur, DTD_ATTR_UID, buf, sizeof (buf))) != Z_OK) { 4954 handle->zone_dh_cur = handle->zone_dh_top; 4955 return (err); 4956 } 4957 tabptr->zone_devperm_uid = (uid_t)atol(buf); 4958 4959 if ((err = fetchprop(cur, DTD_ATTR_GID, buf, sizeof (buf))) != Z_OK) { 4960 handle->zone_dh_cur = handle->zone_dh_top; 4961 return (err); 4962 } 4963 tabptr->zone_devperm_gid = (gid_t)atol(buf); 4964 4965 if ((err = fetchprop(cur, DTD_ATTR_MODE, buf, sizeof (buf))) != Z_OK) { 4966 handle->zone_dh_cur = handle->zone_dh_top; 4967 return (err); 4968 } 4969 tabptr->zone_devperm_mode = (mode_t)strtol(buf, (char **)NULL, 8); 4970 4971 if ((err = fetch_alloc_prop(cur, DTD_ATTR_ACL, 4972 &(tabptr->zone_devperm_acl))) != Z_OK) { 4973 handle->zone_dh_cur = handle->zone_dh_top; 4974 return (err); 4975 } 4976 4977 handle->zone_dh_cur = cur->next; 4978 return (Z_OK); 4979 } 4980 4981 int 4982 zonecfg_enddevperment(zone_dochandle_t handle) 4983 { 4984 return (zonecfg_endent(handle)); 4985 } 4986 4987 /* 4988 * Process a list of pkgs from an entry in the contents file, adding each pkg 4989 * name to the list of pkgs. 4990 * 4991 * It is possible for the pkg name to be preceeded by a special character 4992 * which indicates some bookkeeping information for pkging. Check if the 4993 * first char is not an Alpha char. If so, skip over it. 4994 */ 4995 static int 4996 add_pkg_list(char *lastp, char ***plist, int *pcnt) 4997 { 4998 char *p; 4999 int pkg_cnt = *pcnt; 5000 char **pkgs = *plist; 5001 int res = Z_OK; 5002 5003 while ((p = strtok_r(NULL, " ", &lastp)) != NULL) { 5004 char **tmpp; 5005 int i; 5006 5007 /* skip over any special pkg bookkeeping char */ 5008 if (!isalpha(*p)) 5009 p++; 5010 5011 /* Check if the pkg is already in the list */ 5012 for (i = 0; i < pkg_cnt; i++) { 5013 if (strcmp(p, pkgs[i]) == 0) 5014 break; 5015 } 5016 5017 if (i < pkg_cnt) 5018 continue; 5019 5020 /* The pkg is not in the list; add it. */ 5021 if ((tmpp = (char **)realloc(pkgs, 5022 sizeof (char *) * (pkg_cnt + 1))) == NULL) { 5023 res = Z_NOMEM; 5024 break; 5025 } 5026 pkgs = tmpp; 5027 5028 if ((pkgs[pkg_cnt] = strdup(p)) == NULL) { 5029 res = Z_NOMEM; 5030 break; 5031 } 5032 pkg_cnt++; 5033 } 5034 5035 *plist = pkgs; 5036 *pcnt = pkg_cnt; 5037 5038 return (res); 5039 } 5040 5041 /* 5042 * Process an entry from the contents file (type "directory") and if the 5043 * directory path is in the list of paths, add the associated list of pkgs 5044 * to the pkg list. The input parameter "entry" will be broken up by 5045 * the parser within this function so its value will be modified when this 5046 * function exits. 5047 * 5048 * The entries we are looking for will look something like: 5049 * /usr d none 0755 root sys SUNWctpls SUNWidnl SUNWlibCf .... 5050 */ 5051 static int 5052 get_path_pkgs(char *entry, char **paths, int cnt, char ***pkgs, int *pkg_cnt) 5053 { 5054 char *f1; 5055 char *f2; 5056 char *lastp; 5057 int i; 5058 int res = Z_OK; 5059 5060 if ((f1 = strtok_r(entry, " ", &lastp)) == NULL || 5061 (f2 = strtok_r(NULL, " ", &lastp)) == NULL || strcmp(f2, "d") != 0) 5062 return (Z_OK); 5063 5064 /* Check if this directory entry is in the list of paths. */ 5065 for (i = 0; i < cnt; i++) { 5066 if (fnmatch(paths[i], f1, FNM_PATHNAME) == 0) { 5067 /* 5068 * We do want the pkgs for this path. First, skip 5069 * over the next 4 fields in the entry so that we call 5070 * add_pkg_list starting with the pkg names. 5071 */ 5072 int j; 5073 char *nlp; 5074 5075 for (j = 0; j < 4 && 5076 strtok_r(NULL, " ", &lastp) != NULL; j++) 5077 ; 5078 /* 5079 * If there are < 4 fields this entry is corrupt, 5080 * just skip it. 5081 */ 5082 if (j < 4) 5083 return (Z_OK); 5084 5085 /* strip newline from the line */ 5086 nlp = (lastp + strlen(lastp) - 1); 5087 if (*nlp == '\n') 5088 *nlp = '\0'; 5089 5090 res = add_pkg_list(lastp, pkgs, pkg_cnt); 5091 break; 5092 } 5093 } 5094 5095 return (res); 5096 } 5097 5098 /* 5099 * Read an entry from a pkginfo or contents file. Some of these lines can 5100 * either be arbitrarily long or be continued by a backslash at the end of 5101 * the line. This function coalesces lines that are longer than the read 5102 * buffer, and lines that are continued, into one buffer which is returned. 5103 * The caller must free this memory. NULL is returned when we hit EOF or 5104 * if we run out of memory (errno is set to ENOMEM). 5105 */ 5106 static char * 5107 read_pkg_data(FILE *fp) 5108 { 5109 char *start; 5110 char *inp; 5111 char *p; 5112 int char_cnt = 0; 5113 5114 errno = 0; 5115 if ((start = (char *)malloc(PKGINFO_RD_LEN)) == NULL) { 5116 errno = ENOMEM; 5117 return (NULL); 5118 } 5119 5120 inp = start; 5121 while ((p = fgets(inp, PKGINFO_RD_LEN, fp)) != NULL) { 5122 int len; 5123 5124 len = strlen(inp); 5125 if (inp[len - 1] == '\n' && 5126 (len == 1 || inp[len - 2] != '\\')) { 5127 char_cnt = len; 5128 break; 5129 } 5130 5131 if (inp[len - 2] == '\\') 5132 char_cnt += len - 2; 5133 else 5134 char_cnt += PKGINFO_RD_LEN - 1; 5135 5136 if ((p = realloc(start, char_cnt + PKGINFO_RD_LEN)) == NULL) { 5137 errno = ENOMEM; 5138 break; 5139 } 5140 5141 start = p; 5142 inp = start + char_cnt; 5143 } 5144 5145 if (errno == ENOMEM || (p == NULL && char_cnt == 0)) { 5146 free(start); 5147 start = NULL; 5148 } 5149 5150 return (start); 5151 } 5152 5153 static void 5154 free_ipd_pkgs(char **pkgs, int cnt) 5155 { 5156 int i; 5157 5158 for (i = 0; i < cnt; i++) 5159 free(pkgs[i]); 5160 free(pkgs); 5161 } 5162 5163 /* 5164 * Get the list of inherited-pkg-dirs (ipd) for the zone and then get the 5165 * list of pkgs that deliver into those dirs. 5166 */ 5167 static int 5168 get_ipd_pkgs(zone_dochandle_t handle, char ***pkg_list, int *cnt) 5169 { 5170 int res; 5171 struct zone_fstab fstab; 5172 int ipd_cnt = 0; 5173 char **ipds = NULL; 5174 int pkg_cnt = 0; 5175 char **pkgs = NULL; 5176 int i; 5177 5178 if ((res = zonecfg_setipdent(handle)) != Z_OK) 5179 return (res); 5180 5181 while (zonecfg_getipdent(handle, &fstab) == Z_OK) { 5182 char **p; 5183 int len; 5184 5185 if ((p = (char **)realloc(ipds, 5186 sizeof (char *) * (ipd_cnt + 2))) == NULL) { 5187 res = Z_NOMEM; 5188 break; 5189 } 5190 ipds = p; 5191 5192 if ((ipds[ipd_cnt] = strdup(fstab.zone_fs_dir)) == NULL) { 5193 res = Z_NOMEM; 5194 break; 5195 } 5196 ipd_cnt++; 5197 5198 len = strlen(fstab.zone_fs_dir) + 3; 5199 if ((ipds[ipd_cnt] = malloc(len)) == NULL) { 5200 res = Z_NOMEM; 5201 break; 5202 } 5203 5204 (void) snprintf(ipds[ipd_cnt], len, "%s/*", fstab.zone_fs_dir); 5205 ipd_cnt++; 5206 } 5207 5208 (void) zonecfg_endipdent(handle); 5209 5210 if (res != Z_OK) { 5211 for (i = 0; i < ipd_cnt; i++) 5212 free(ipds[i]); 5213 free(ipds); 5214 return (res); 5215 } 5216 5217 /* We only have to process the contents file if we have ipds. */ 5218 if (ipd_cnt > 0) { 5219 FILE *fp; 5220 5221 if ((fp = fopen(CONTENTS_FILE, "r")) != NULL) { 5222 char *buf; 5223 5224 while ((buf = read_pkg_data(fp)) != NULL) { 5225 res = get_path_pkgs(buf, ipds, ipd_cnt, &pkgs, 5226 &pkg_cnt); 5227 free(buf); 5228 if (res != Z_OK) 5229 break; 5230 } 5231 5232 (void) fclose(fp); 5233 } 5234 } 5235 5236 for (i = 0; i < ipd_cnt; i++) 5237 free(ipds[i]); 5238 free(ipds); 5239 5240 if (res != Z_OK) { 5241 free_ipd_pkgs(pkgs, pkg_cnt); 5242 } else { 5243 *pkg_list = pkgs; 5244 *cnt = pkg_cnt; 5245 } 5246 5247 return (res); 5248 } 5249 5250 /* 5251 * Return true if pkg_name is in the list of pkgs that deliver into an 5252 * inherited pkg directory for the zone. 5253 */ 5254 static boolean_t 5255 dir_pkg(char *pkg_name, char **pkg_list, int cnt) 5256 { 5257 int i; 5258 5259 for (i = 0; i < cnt; i++) { 5260 if (strcmp(pkg_name, pkg_list[i]) == 0) 5261 return (B_TRUE); 5262 } 5263 5264 return (B_FALSE); 5265 } 5266 5267 /* 5268 * Start by adding the patch to the sw inventory on the handle. 5269 * 5270 * The info parameter will be the portion of the PATCH_INFO_ entry following 5271 * the '='. For example: 5272 * Installed: Wed Dec 7 07:13:51 PST 2005 From: mum Obsoletes: 120777-03 \ 5273 * 121087-02 119108-07 Requires: 119575-02 119255-06 Incompatibles: 5274 * 5275 * A backed out patch will have an info line of "backed out\n". We should 5276 * skip these patches. 5277 * 5278 * We also want to add the Obsolete and Incompatible patches to the 5279 * sw inventory description of this patch. 5280 */ 5281 static int 5282 add_patch(zone_dochandle_t handle, char *patch, char *info) 5283 { 5284 xmlNodePtr node; 5285 xmlNodePtr cur; 5286 int err; 5287 char *p; 5288 char *lastp; 5289 boolean_t add_info = B_FALSE; 5290 boolean_t obsolete; 5291 5292 if (strcmp(info, "backed out\n") == 0) 5293 return (Z_OK); 5294 5295 if ((err = operation_prep(handle)) != Z_OK) 5296 return (err); 5297 5298 cur = handle->zone_dh_cur; 5299 node = xmlNewTextChild(cur, NULL, DTD_ELEM_PATCH, NULL); 5300 if ((err = newprop(node, DTD_ATTR_ID, patch)) != Z_OK) 5301 return (err); 5302 5303 /* 5304 * Start with the first token. This will probably be "Installed:". 5305 * If we can't tokenize this entry, just return. 5306 */ 5307 if ((p = strtok_r(info, " ", &lastp)) == NULL) 5308 return (Z_OK); 5309 5310 do { 5311 xmlNodePtr new_node; 5312 char *nlp; 5313 5314 if (strcmp(p, "Installed:") == 0 || 5315 strcmp(p, "Requires:") == 0 || 5316 strcmp(p, "From:") == 0) { 5317 add_info = B_FALSE; 5318 continue; 5319 } else if (strcmp(p, "Obsoletes:") == 0) { 5320 obsolete = B_TRUE; 5321 add_info = B_TRUE; 5322 continue; 5323 } else if (strcmp(p, "Incompatibles:") == 0) { 5324 obsolete = B_FALSE; 5325 add_info = B_TRUE; 5326 continue; 5327 } 5328 5329 if (!add_info) 5330 continue; 5331 5332 /* strip newline from last patch in the line */ 5333 nlp = (p + strlen(p) - 1); 5334 if (*nlp == '\n') 5335 *nlp = '\0'; 5336 5337 if (obsolete) 5338 new_node = xmlNewTextChild(node, NULL, 5339 DTD_ELEM_OBSOLETES, NULL); 5340 else 5341 new_node = xmlNewTextChild(node, NULL, 5342 DTD_ELEM_INCOMPATIBLE, NULL); 5343 5344 if ((err = newprop(new_node, DTD_ATTR_ID, p)) != Z_OK) 5345 return (err); 5346 5347 } while ((p = strtok_r(NULL, " ", &lastp)) != NULL); 5348 5349 return (Z_OK); 5350 } 5351 5352 static boolean_t 5353 unique_patch(zone_dochandle_t handle, char *patch) 5354 { 5355 xmlNodePtr cur; 5356 char id[MAXNAMELEN]; 5357 5358 cur = xmlDocGetRootElement(handle->zone_dh_doc); 5359 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 5360 if (xmlStrcmp(cur->name, DTD_ELEM_PATCH) == 0) { 5361 if (fetchprop(cur, DTD_ATTR_ID, id, sizeof (id)) 5362 != Z_OK) 5363 continue; 5364 5365 if (strcmp(patch, id) == 0) 5366 return (B_FALSE); 5367 } 5368 } 5369 5370 return (B_TRUE); 5371 } 5372 5373 /* 5374 * Add the unique patches associated with this pkg to the sw inventory on the 5375 * handle. 5376 * 5377 * We are processing entries of the form: 5378 * PATCH_INFO_121454-02=Installed: Wed Dec 7 07:13:51 PST 2005 From: mum \ 5379 * Obsoletes: 120777-03 121087-02 119108-07 Requires: 119575-02 \ 5380 * 119255-06 Incompatibles: 5381 * 5382 */ 5383 static int 5384 add_patches(zone_dochandle_t handle, struct zone_pkginfo *infop) 5385 { 5386 int i; 5387 int res = Z_OK; 5388 5389 for (i = 0; i < infop->zpi_patch_cnt; i++) { 5390 char *p, *ep; 5391 5392 if (strlen(infop->zpi_patchinfo[i]) < (sizeof (PATCHINFO) - 1)) 5393 continue; 5394 5395 /* Skip over "PATCH_INFO_" to get the patch id. */ 5396 p = infop->zpi_patchinfo[i] + sizeof (PATCHINFO) - 1; 5397 if ((ep = strchr(p, '=')) == NULL) 5398 continue; 5399 5400 *ep = '\0'; 5401 if (unique_patch(handle, p)) 5402 if ((res = add_patch(handle, p, ep + 1)) != Z_OK) 5403 break; 5404 } 5405 5406 return (res); 5407 } 5408 5409 /* 5410 * Add the pkg to the sw inventory on the handle. 5411 */ 5412 static int 5413 add_pkg(zone_dochandle_t handle, char *name, char *version) 5414 { 5415 xmlNodePtr newnode; 5416 xmlNodePtr cur; 5417 int err; 5418 5419 if ((err = operation_prep(handle)) != Z_OK) 5420 return (err); 5421 5422 cur = handle->zone_dh_cur; 5423 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PACKAGE, NULL); 5424 if ((err = newprop(newnode, DTD_ATTR_NAME, name)) != Z_OK) 5425 return (err); 5426 if ((err = newprop(newnode, DTD_ATTR_VERSION, version)) != Z_OK) 5427 return (err); 5428 return (Z_OK); 5429 } 5430 5431 static void 5432 free_pkginfo(struct zone_pkginfo *infop) 5433 { 5434 free(infop->zpi_version); 5435 if (infop->zpi_patch_cnt > 0) { 5436 int i; 5437 5438 for (i = 0; i < infop->zpi_patch_cnt; i++) 5439 free(infop->zpi_patchinfo[i]); 5440 free(infop->zpi_patchinfo); 5441 } 5442 } 5443 5444 /* 5445 * Read the pkginfo file and populate the structure with the data we need 5446 * from this pkg for a sw inventory. 5447 */ 5448 static int 5449 get_pkginfo(char *pkginfo, struct zone_pkginfo *infop) 5450 { 5451 FILE *fp; 5452 char *buf; 5453 int err = 0; 5454 5455 infop->zpi_all_zones = B_FALSE; 5456 infop->zpi_this_zone = B_FALSE; 5457 infop->zpi_version = NULL; 5458 infop->zpi_patch_cnt = 0; 5459 infop->zpi_patchinfo = NULL; 5460 5461 if ((fp = fopen(pkginfo, "r")) == NULL) 5462 return (errno); 5463 5464 while ((buf = read_pkg_data(fp)) != NULL) { 5465 if (strncmp(buf, VERSION, sizeof (VERSION) - 1) == 0) { 5466 int len; 5467 5468 if ((infop->zpi_version = 5469 strdup(buf + sizeof (VERSION) - 1)) == NULL) { 5470 err = ENOMEM; 5471 break; 5472 } 5473 5474 /* remove trailing newline */ 5475 len = strlen(infop->zpi_version); 5476 *(infop->zpi_version + len - 1) = 0; 5477 5478 } else if (strcmp(buf, SUNW_PKG_ALL_ZONES) == 0) { 5479 infop->zpi_all_zones = B_TRUE; 5480 5481 } else if (strcmp(buf, SUNW_PKG_THIS_ZONE) == 0) { 5482 infop->zpi_this_zone = B_TRUE; 5483 5484 } else if (strncmp(buf, PATCHINFO, sizeof (PATCHINFO) - 1) 5485 == 0) { 5486 char **p; 5487 5488 if ((p = (char **)realloc(infop->zpi_patchinfo, 5489 sizeof (char *) * (infop->zpi_patch_cnt + 1))) 5490 == NULL) { 5491 err = ENOMEM; 5492 break; 5493 } 5494 infop->zpi_patchinfo = p; 5495 5496 if ((infop->zpi_patchinfo[infop->zpi_patch_cnt] = 5497 strdup(buf)) == NULL) { 5498 err = ENOMEM; 5499 break; 5500 } 5501 infop->zpi_patch_cnt++; 5502 } 5503 5504 free(buf); 5505 } 5506 5507 free(buf); 5508 5509 if (errno == ENOMEM) { 5510 err = ENOMEM; 5511 /* Clean up anything we did manage to allocate. */ 5512 free_pkginfo(infop); 5513 } 5514 5515 (void) fclose(fp); 5516 5517 return (err); 5518 } 5519 5520 /* 5521 * Take a software inventory of the global zone. We need to get the set of 5522 * packages and patches that are on the global zone that the specified 5523 * non-global zone depends on. The packages we need in the inventory are: 5524 * 5525 * - skip the package if SUNW_PKG_THISZONE is 'true' 5526 * otherwise, 5527 * - add the package if 5528 * a) SUNW_PKG_ALLZONES is 'true', 5529 * or 5530 * b) any file delivered by the package is in a file system that is inherited 5531 * from the global zone. 5532 * If the zone does not inherit any file systems (whole root) 5533 * then (b) will be skipped. 5534 * 5535 * For each of the packages that is being added to the inventory, we will also 5536 * add all of the associated, unique patches to the inventory. 5537 */ 5538 static int 5539 zonecfg_sw_inventory(zone_dochandle_t handle) 5540 { 5541 char pkginfo[MAXPATHLEN]; 5542 int res; 5543 struct dirent *dp; 5544 DIR *dirp; 5545 struct stat buf; 5546 struct zone_pkginfo info; 5547 int pkg_cnt = 0; 5548 char **pkgs = NULL; 5549 5550 if ((res = get_ipd_pkgs(handle, &pkgs, &pkg_cnt)) != Z_OK) 5551 return (res); 5552 5553 if ((dirp = opendir(PKG_PATH)) == NULL) { 5554 free_ipd_pkgs(pkgs, pkg_cnt); 5555 return (Z_OK); 5556 } 5557 5558 while ((dp = readdir(dirp)) != (struct dirent *)0) { 5559 if (strcmp(dp->d_name, ".") == 0 || 5560 strcmp(dp->d_name, "..") == 0) 5561 continue; 5562 5563 (void) snprintf(pkginfo, sizeof (pkginfo), "%s/%s/pkginfo", 5564 PKG_PATH, dp->d_name); 5565 5566 if (stat(pkginfo, &buf) == -1 || !S_ISREG(buf.st_mode)) 5567 continue; 5568 5569 if (get_pkginfo(pkginfo, &info) != 0) { 5570 res = Z_NOMEM; 5571 break; 5572 } 5573 5574 if (!info.zpi_this_zone && 5575 (info.zpi_all_zones || 5576 dir_pkg(dp->d_name, pkgs, pkg_cnt))) { 5577 if ((res = add_pkg(handle, dp->d_name, 5578 info.zpi_version)) == Z_OK) { 5579 if (info.zpi_patch_cnt > 0) 5580 res = add_patches(handle, &info); 5581 } 5582 } 5583 5584 free_pkginfo(&info); 5585 5586 if (res != Z_OK) 5587 break; 5588 } 5589 5590 (void) closedir(dirp); 5591 5592 free_ipd_pkgs(pkgs, pkg_cnt); 5593 5594 if (res == Z_OK) 5595 handle->zone_dh_sw_inv = B_TRUE; 5596 5597 return (res); 5598 } 5599 5600 /* 5601 * zonecfg_devwalk call-back function used during detach to generate the 5602 * dev info in the manifest. 5603 */ 5604 static int 5605 get_detach_dev_entry(const char *name, uid_t uid, gid_t gid, mode_t mode, 5606 const char *acl, void *hdl) 5607 { 5608 zone_dochandle_t handle = (zone_dochandle_t)hdl; 5609 xmlNodePtr newnode; 5610 xmlNodePtr cur; 5611 int err; 5612 char buf[128]; 5613 5614 if ((err = operation_prep(handle)) != Z_OK) 5615 return (err); 5616 5617 cur = handle->zone_dh_cur; 5618 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEV_PERM, NULL); 5619 if ((err = newprop(newnode, DTD_ATTR_NAME, (char *)name)) != Z_OK) 5620 return (err); 5621 (void) snprintf(buf, sizeof (buf), "%lu", uid); 5622 if ((err = newprop(newnode, DTD_ATTR_UID, buf)) != Z_OK) 5623 return (err); 5624 (void) snprintf(buf, sizeof (buf), "%lu", gid); 5625 if ((err = newprop(newnode, DTD_ATTR_GID, buf)) != Z_OK) 5626 return (err); 5627 (void) snprintf(buf, sizeof (buf), "%o", mode); 5628 if ((err = newprop(newnode, DTD_ATTR_MODE, buf)) != Z_OK) 5629 return (err); 5630 if ((err = newprop(newnode, DTD_ATTR_ACL, (char *)acl)) != Z_OK) 5631 return (err); 5632 return (Z_OK); 5633 } 5634 5635 /* 5636 * Get the information required to support detaching a zone. This is 5637 * called on the source system when detaching (the detaching parameter should 5638 * be set to true) and on the destination system before attaching (the 5639 * detaching parameter should be false). 5640 * 5641 * For native Solaris zones, the detach/attach process involves validating 5642 * that the software on the global zone can support the zone when we attach. 5643 * To do this we take a software inventory of the global zone. We also 5644 * have to keep track of the device configuration so that we can properly 5645 * recreate it on the destination. 5646 */ 5647 int 5648 zonecfg_get_detach_info(zone_dochandle_t handle, boolean_t detaching) 5649 { 5650 int res; 5651 5652 if ((res = zonecfg_sw_inventory(handle)) != Z_OK) 5653 return (res); 5654 5655 if (detaching) 5656 res = zonecfg_devwalk(handle, get_detach_dev_entry, handle); 5657 5658 return (res); 5659 } 5660