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