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