summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgjelinek <none@none>2008-01-14 13:01:24 -0800
committergjelinek <none@none>2008-01-14 13:01:24 -0800
commit6cfd72c6361fc164bc537fc17e829cccc62b0b1f (patch)
tree64b671e3638b18df6d852721d5c5ee93649e1a9f
parent8899fcfafcee5a0a80d70ea19c2ad0870c5d8cb1 (diff)
downloadillumos-joyent-6cfd72c6361fc164bc537fc17e829cccc62b0b1f.tar.gz
PSARC 2007/621 zone update on attach
6480464 RFE: zoneadm attach should patch/update the zone to the new hosts level 6576592 RFE: zoneadm detach/attach should work between sun4u and sun4v architecture 6637869 zone attach doesn't handle obsolete patches correctly
-rw-r--r--usr/src/cmd/zoneadm/Makefile5
-rw-r--r--usr/src/cmd/zoneadm/sw_cmp.c1115
-rw-r--r--usr/src/cmd/zoneadm/zoneadm.c224
-rw-r--r--usr/src/cmd/zoneadm/zoneadm.h5
-rw-r--r--usr/src/cmd/zoneadmd/vplat.c113
-rw-r--r--usr/src/cmd/zoneadmd/zoneadmd.c18
-rw-r--r--usr/src/cmd/zoneadmd/zoneadmd.h19
-rw-r--r--usr/src/head/libzonecfg.h18
-rw-r--r--usr/src/lib/brand/native/zone/Makefile4
-rwxr-xr-xusr/src/lib/brand/native/zone/attach_update.ksh626
-rw-r--r--usr/src/lib/libzonecfg/common/libzonecfg.c590
-rw-r--r--usr/src/lib/libzonecfg/common/mapfile-vers9
-rw-r--r--usr/src/pkgdefs/SUNWzoneu/prototype_com3
13 files changed, 2383 insertions, 366 deletions
diff --git a/usr/src/cmd/zoneadm/Makefile b/usr/src/cmd/zoneadm/Makefile
index 4428c23cb3..0ec4d19bdc 100644
--- a/usr/src/cmd/zoneadm/Makefile
+++ b/usr/src/cmd/zoneadm/Makefile
@@ -20,7 +20,7 @@
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -39,7 +39,8 @@ SRCS = $(OBJS:.o=.c)
POFILE=zoneadm_all.po
POFILES= $(OBJS:%.o=%.po)
-LDLIBS += -lzonecfg -lsocket -lgen -lpool -lbsm -lzfs -luuid -lnvpair -lbrand -ldlpi
+LDLIBS += -lzonecfg -lsocket -lgen -lpool -lbsm -lzfs -luuid -lnvpair -lbrand \
+ -ldlpi -luutil
.KEEP_STATE:
diff --git a/usr/src/cmd/zoneadm/sw_cmp.c b/usr/src/cmd/zoneadm/sw_cmp.c
index 67554c76c2..7dcb06e958 100644
--- a/usr/src/cmd/zoneadm/sw_cmp.c
+++ b/usr/src/cmd/zoneadm/sw_cmp.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -31,217 +31,337 @@
#include <string.h>
#include <locale.h>
#include <libintl.h>
+#include <stddef.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <assert.h>
#include <libzonecfg.h>
#include "zoneadm.h"
+extern int errno;
+
+/* ARGSUSED */
+static int
+pkg_entry_compare(const void *l_arg, const void *r_arg, void *private)
+{
+ zone_pkg_entry_t *l = (zone_pkg_entry_t *)l_arg;
+ zone_pkg_entry_t *r = (zone_pkg_entry_t *)r_arg;
+
+ return (strcmp(l->zpe_name, r->zpe_name));
+}
+
+static boolean_t
+valid_num(char *n)
+{
+ for (; isdigit(*n); n++)
+ ;
+
+ if (*n != NULL)
+ return (B_FALSE);
+ return (B_TRUE);
+}
+
/*
- * Find the specified package in the sw inventory on the handle and check
- * if the version matches what is passed in.
- * Return 0 if the packages match
- * 1 if the package is found but we have a version mismatch
- * -1 if the package is not found
+ * Take an input field, which must look like a positive int, and return the
+ * numeric value of the field. Return -1 if the input field does not look
+ * like something we can convert.
*/
static int
-pkg_cmp(zone_dochandle_t handle, char *pkg_name, char *pkg_vers,
- char *return_vers, int vers_size)
+fld2num(char *fld, char **nfld)
{
- int res = -1;
- struct zone_pkgtab pkgtab;
+ char *ppoint;
+ long n;
- if (zonecfg_setpkgent(handle) != Z_OK) {
- (void) fprintf(stderr,
- gettext("unable to enumerate packages\n"));
- return (Z_ERR);
+ if ((ppoint = strchr(fld, '.')) != NULL) {
+ *ppoint = '\0';
+ *nfld = ppoint + 1;
+ } else {
+ *nfld = NULL;
}
- while (zonecfg_getpkgent(handle, &pkgtab) == Z_OK) {
- if (strcmp(pkg_name, pkgtab.zone_pkg_name) != 0)
- continue;
-
- if (strcmp(pkg_vers, pkgtab.zone_pkg_version) == 0) {
- res = 0;
- break;
- }
+ if (!valid_num(fld))
+ return (-1);
- (void) strlcpy(return_vers, pkgtab.zone_pkg_version, vers_size);
- res = 1;
- break;
- }
+ errno = 0;
+ n = strtol(fld, (char **)NULL, 10);
+ if (errno != 0)
+ return (-1);
- (void) zonecfg_endpkgent(handle);
- return (res);
+ return ((int)n);
}
/*
- * Used in software comparisons to check the packages between the two zone
- * handles. The packages have to match or we print a message telling the
- * user what is out of sync. If flag has SW_CMP_SRC this tells us the first
- * handle is the source machine global zone. This is used to enable the
- * right messages to be printed and also to enable extra version checking
- * that is not needed for the opposite comparison.
+ * Step through two version strings that look like postive ints delimited by
+ * decimals and compare them. Example input can look like 2, 010.3, 75.02.09,
+ * etc. If the input does not look like this then we do a simple lexical
+ * comparison of the two strings. The string can be modified on exit of
+ * this function.
*/
static int
-pkg_check(char *header, zone_dochandle_t handle1, zone_dochandle_t handle2,
- uint_t flag)
+fld_cmp(char *v1, char *v2)
{
- int err;
- int res = Z_OK;
- boolean_t do_header = B_TRUE;
- char other_vers[ZONE_PKG_VERSMAX];
- struct zone_pkgtab pkgtab;
-
- if (zonecfg_setpkgent(handle1) != Z_OK) {
- (void) fprintf(stderr,
- gettext("unable to enumerate packages\n"));
- return (Z_ERR);
- }
-
- while (zonecfg_getpkgent(handle1, &pkgtab) == Z_OK) {
- if ((err = pkg_cmp(handle2, pkgtab.zone_pkg_name,
- pkgtab.zone_pkg_version, other_vers, sizeof (other_vers)))
- != 0) {
- res = Z_ERR;
- if (flag & SW_CMP_SILENT)
- break;
+ char *nxtfld1, *nxtfld2;
+ int n1, n2;
- if (do_header && (err < 0 || flag & SW_CMP_SRC)) {
- /* LINTED E_SEC_PRINTF_VAR_FMT */
- (void) fprintf(stderr, header);
- do_header = B_FALSE;
- }
- if (err < 0)
- (void) fprintf(stderr,
- (flag & SW_CMP_SRC) ?
- gettext("\t%s: not installed\n\t\t(%s)\n") :
- gettext("\t%s (%s)\n"),
- pkgtab.zone_pkg_name,
- pkgtab.zone_pkg_version);
- else if (flag & SW_CMP_SRC)
- (void) fprintf(stderr, gettext(
- "\t%s: version mismatch\n\t\t(%s)"
- "\n\t\t(%s)\n"),
- pkgtab.zone_pkg_name,
- pkgtab.zone_pkg_version, other_vers);
- }
- }
+ for (;;) {
+ n1 = fld2num(v1, &nxtfld1);
+ n2 = fld2num(v2, &nxtfld2);
- (void) zonecfg_endpkgent(handle1);
+ /*
+ * If either field is not a postive int, just compare them
+ * lexically.
+ */
+ if (n1 < 0 || n2 < 0)
+ return (strcmp(v1, v2));
- return (res);
+ if (n1 > n2)
+ return (1);
+
+ if (n1 < n2)
+ return (-1);
+
+ /* They're equal */
+
+ /* No more fields */
+ if (nxtfld1 == NULL && nxtfld2 == NULL)
+ return (0);
+
+ /* Field 2 still has data so it is greater than field 1 */
+ if (nxtfld1 == NULL)
+ return (-1);
+
+ /* Field 1 still has data so it is greater than field 2 */
+ if (nxtfld2 == NULL)
+ return (1);
+
+ /* Both fields still have data, keep going. */
+ v1 = nxtfld1;
+ v2 = nxtfld2;
+ }
}
/*
- * Find the specified patch in the sw inventory on the handle and check
- * if the version matches what is passed in.
- * Return 0 if the patches match
- * 1 if the patches is found but we have a version mismatch
- * -1 if the patches is not found
+ * The result of the comparison is returned in the cmp parameter:
+ * 0 if both versions are equal.
+ * <0 if version1 is less than version 2.
+ * >0 if version1 is greater than version 2.
+ * The function returns B_TRUE if there was an ENOMEM error, B_FALSE otherwise.
+ *
+ * This function handles the various version strings we can get from the
+ * dependent pkg versions. They usually look like:
+ * "1.21,REV=2005.01.17.23.31"
+ * "2.6.0,REV=10.0.3.2004.12.16.18.02"
+ *
+ * We can't do a simple lexical comparison since:
+ * 2.6.0 would be greater than 2.20.0
+ * 12 would be greater than 110
+ *
+ * If the input strings do not look like decimal delimted version strings
+ * then we fall back to doing a simple lexical comparison.
*/
-static int
-patch_cmp(zone_dochandle_t handle, char *patch_id, char *patch_vers,
- char *return_vers, int vers_size)
+static boolean_t
+pkg_vers_cmp(char *vers1, char *vers2, int *cmp)
+{
+ char *v1, *v2;
+ char *rev1, *rev2;
+ int res;
+
+ /* We need to modify the input strings so we dup them. */
+ if ((v1 = strdup(vers1)) == NULL)
+ return (B_TRUE);
+ if ((v2 = strdup(vers2)) == NULL) {
+ free(v1);
+ return (B_TRUE);
+ }
+
+ /* Strip off a revision delimited by a comma. */
+ if ((rev1 = strchr(v1, ',')) != NULL)
+ *rev1++ = '\0';
+ if ((rev2 = strchr(v2, ',')) != NULL)
+ *rev2++ = '\0';
+
+ res = fld_cmp(v1, v2);
+ /* If the primary versions are not equal, return the result */
+ if (res != 0) {
+ *cmp = res;
+ goto done;
+ }
+
+ /*
+ * All of the fields in the primary version strings are equal, check
+ * the rev, if it exists.
+ */
+
+ /* No revs */
+ if (rev1 == NULL && rev2 == NULL) {
+ *cmp = 0;
+ goto done;
+ }
+
+ /* Field 2 has a rev so it is greater than field 1 */
+ if (rev1 == NULL) {
+ *cmp = -1;
+ goto done;
+ }
+
+ /* Field 1 has a rev so it is greater than field 2 */
+ if (rev2 == NULL) {
+ *cmp = 1;
+ goto done;
+ }
+
+ /* If no recognized REV data then just lexically compare them */
+ if (strncmp(rev1, "REV=", 4) != 0 || strncmp(rev2, "REV=", 4) != 0) {
+ *cmp = strcmp(rev1, rev2);
+ goto done;
+ }
+
+ /* Both fields have revs, check them. */
+ *cmp = fld_cmp(rev1 + 4, rev2 + 4);
+
+done:
+ free(v1);
+ free(v2);
+
+ return (B_FALSE);
+}
+
+static void
+pkg_avl_delete(uu_avl_t *pavl)
{
- int res = -1;
- struct zone_patchtab patchtab;
+ zone_pkg_entry_t *p;
+ void *cookie = NULL;
+
+ if (pavl == NULL)
+ return;
- if (zonecfg_setpatchent(handle) != Z_OK) {
- (void) fprintf(stderr,
- gettext("unable to enumerate patches\n"));
- return (Z_ERR);
+ while ((p = uu_avl_teardown(pavl, &cookie)) != NULL) {
+ free(p->zpe_name);
+ free(p->zpe_vers);
+ pkg_avl_delete(p->zpe_patches_avl);
+ free(p);
}
- while (zonecfg_getpatchent(handle, &patchtab) == Z_OK) {
- char *p;
+ uu_avl_destroy(pavl);
+}
- if ((p = strchr(patchtab.zone_patch_id, '-')) != NULL)
- *p++ = '\0';
- else
- p = "";
+/*
+ * Walk all of the patches on the pkg, looking to see if the specified patch
+ * has been obsoleted by one of those patches.
+ */
+static boolean_t
+is_obsolete(zone_pkg_entry_t *pkg, zone_pkg_entry_t *patchid)
+{
+ uu_avl_walk_t *patch_walk;
+ zone_pkg_entry_t *patch;
+ boolean_t res;
+
+ if (pkg->zpe_patches_avl == NULL)
+ return (B_FALSE);
+
+ patch_walk = uu_avl_walk_start(pkg->zpe_patches_avl, UU_WALK_ROBUST);
+ if (patch_walk == NULL)
+ return (B_FALSE);
- if (strcmp(patch_id, patchtab.zone_patch_id) != 0)
+ res = B_FALSE;
+ while ((patch = uu_avl_walk_next(patch_walk)) != NULL) {
+ uu_avl_index_t where;
+
+ if (patch->zpe_patches_avl == NULL)
continue;
- if (strcmp(patch_vers, p) == 0) {
- res = 0;
+ /* Check the obsolete list on the patch. */
+ if (uu_avl_find(patch->zpe_patches_avl, patchid, NULL, &where)
+ != NULL) {
+ res = B_TRUE;
break;
}
-
- (void) strlcpy(return_vers, p, vers_size);
- /*
- * Keep checking. This handles the case where multiple
- * versions of the same patch is installed.
- */
- res = 1;
}
- (void) zonecfg_endpatchent(handle);
+ uu_avl_walk_end(patch_walk);
return (res);
}
/*
- * Used in software comparisons to check the patches between the two zone
- * handles. The patches have to match or we print a message telling the
- * user what is out of sync. If flag has SW_CMP_SRC this tells us the first
- * handle is the source machine global zone. This is used to enable the
- * right messages to be printed. For patches we do need to compare the
- * versions both ways and print the right header and error message. This
- * is because it is possible to have multiple versions of a patch installed
- * and we need to detect the case where the target has a newer version of
- * a patch in addition to the version that was installed on the source.
+ * Build a list of unique patches from the input pkg_patches list.
+ * If the pkg parameter is not null then we will check the patches on that
+ * pkg to see if any of the pkg_patches have been obsoleted. We don't
+ * add those obsoleted patches to the unique list.
+ * Returns B_FALSE if an error occurs.
*/
-static int
-patch_check(char *header, zone_dochandle_t handle1, zone_dochandle_t handle2,
- uint_t flag)
+static boolean_t
+add_patch(uu_avl_t *pkg_patches, uu_avl_t *unique, zone_pkg_entry_t *pkg,
+ uu_avl_pool_t *pkg_pool)
{
- int err;
- int res = Z_OK;
- boolean_t do_header = B_TRUE;
- char other_vers[MAXNAMELEN];
- struct zone_patchtab patchtab;
+ uu_avl_walk_t *walk;
+ zone_pkg_entry_t *pkg_patch;
- if (zonecfg_setpatchent(handle1) != Z_OK) {
- (void) fprintf(stderr,
- gettext("unable to enumerate patches\n"));
- return (Z_ERR);
- }
+ if (pkg_patches == NULL)
+ return (B_TRUE);
- while (zonecfg_getpatchent(handle1, &patchtab) == Z_OK) {
- char *patch_vers;
+ walk = uu_avl_walk_start(pkg_patches, UU_WALK_ROBUST);
+ if (walk == NULL)
+ return (B_FALSE);
- if ((patch_vers = strchr(patchtab.zone_patch_id, '-')) != NULL)
- *patch_vers++ = '\0';
- else
- patch_vers = "";
+ while ((pkg_patch = uu_avl_walk_next(walk)) != NULL) {
+ uu_avl_index_t where;
+ zone_pkg_entry_t *patch;
- if ((err = patch_cmp(handle2, patchtab.zone_patch_id,
- patch_vers, other_vers, sizeof (other_vers))) != 0) {
- res = Z_ERR;
- if (flag & SW_CMP_SILENT)
- break;
+ /* Skip adding it if we already have it. */
+ if (uu_avl_find(unique, pkg_patch, NULL, &where) != NULL)
+ continue;
- if (do_header) {
- /* LINTED E_SEC_PRINTF_VAR_FMT */
- (void) fprintf(stderr, header);
- do_header = B_FALSE;
- }
- if (err < 0)
- (void) fprintf(stderr,
- (flag & SW_CMP_SRC) ?
- gettext("\t%s-%s: not installed\n") :
- gettext("\t%s-%s\n"),
- patchtab.zone_patch_id, patch_vers);
- else
- (void) fprintf(stderr,
- gettext("\t%s: version mismatch\n\t\t(%s) "
- "(%s)\n"), patchtab.zone_patch_id,
- patch_vers, other_vers);
+ /* Likewise, skip adding it if it has been obsoleted. */
+ if (pkg != NULL && is_obsolete(pkg, pkg_patch))
+ continue;
+
+ /* We need to add it so make a duplicate. */
+ if ((patch = (zone_pkg_entry_t *)
+ malloc(sizeof (zone_pkg_entry_t))) == NULL) {
+ uu_avl_walk_end(walk);
+ return (B_FALSE);
}
+
+ if ((patch->zpe_name = strdup(pkg_patch->zpe_name)) == NULL) {
+ free(patch);
+ uu_avl_walk_end(walk);
+ return (B_FALSE);
+ }
+ if ((patch->zpe_vers = strdup(pkg_patch->zpe_vers)) == NULL) {
+ free(patch->zpe_name);
+ free(patch);
+ uu_avl_walk_end(walk);
+ return (B_FALSE);
+ }
+ patch->zpe_patches_avl = NULL;
+
+ /* Insert patch into the unique patch AVL tree. */
+ uu_avl_node_init(patch, &patch->zpe_entry, pkg_pool);
+ uu_avl_insert(unique, patch, where);
}
+ uu_avl_walk_end(walk);
- (void) zonecfg_endpatchent(handle1);
+ return (B_TRUE);
+}
- return (res);
+/*
+ * Common code for sw_cmp which will check flags, update res and print the
+ * section header. Return true if we should be silent.
+ */
+static boolean_t
+prt_header(int *res, uint_t flag, boolean_t *do_header, char *hdr)
+{
+ *res = Z_ERR;
+ if (flag & SW_CMP_SILENT)
+ return (B_TRUE);
+
+ if (*do_header) {
+ /* LINTED E_SEC_PRINTF_VAR_FMT */
+ (void) fprintf(stderr, hdr);
+ *do_header = B_FALSE;
+ }
+ return (B_FALSE);
}
/*
@@ -261,46 +381,681 @@ int
sw_cmp(zone_dochandle_t l_handle, zone_dochandle_t s_handle, uint_t flag)
{
char *hdr;
- int res = Z_OK;
+ int res;
+ int err;
+ boolean_t do_header;
+ uu_avl_pool_t *pkg_pool = NULL;
+ uu_avl_t *src_pkgs = NULL;
+ uu_avl_t *dst_pkgs = NULL;
+ uu_avl_t *src_patches = NULL;
+ uu_avl_t *dst_patches = NULL;
+ zone_pkg_entry_t *src_pkg;
+ zone_pkg_entry_t *dst_pkg;
+ zone_pkg_entry_t *src_patch;
+ zone_pkg_entry_t *dst_patch;
+ uu_avl_walk_t *walk;
+
+ /* Set res to cover any of these memory allocation errors. */
+ res = Z_NOMEM;
+ if ((pkg_pool = uu_avl_pool_create("pkgs_pool",
+ sizeof (zone_pkg_entry_t), offsetof(zone_pkg_entry_t, zpe_entry),
+ pkg_entry_compare, UU_DEFAULT)) == NULL)
+ goto done;
+
+ if ((src_pkgs = uu_avl_create(pkg_pool, NULL, UU_DEFAULT)) == NULL)
+ goto done;
+
+ if ((dst_pkgs = uu_avl_create(pkg_pool, NULL, UU_DEFAULT)) == NULL)
+ goto done;
+
+ if ((src_patches = uu_avl_create(pkg_pool, NULL, UU_DEFAULT)) == NULL)
+ goto done;
+
+ if ((dst_patches = uu_avl_create(pkg_pool, NULL, UU_DEFAULT)) == NULL)
+ goto done;
+
+ res = Z_OK;
+ if ((err = zonecfg_getpkgdata(s_handle, pkg_pool, src_pkgs)) != Z_OK) {
+ res = errno = err;
+ zperror(gettext("could not get package data for detached zone"),
+ B_TRUE);
+ goto done;
+ }
+ if ((err = zonecfg_getpkgdata(l_handle, pkg_pool, dst_pkgs)) != Z_OK) {
+ res = errno = err;
+ zperror(gettext("could not get package data for global zone"),
+ B_TRUE);
+ goto done;
+ }
/*
* Check the source host for pkgs (and versions) that are not on the
* local host.
*/
- if (!(flag & SW_CMP_SILENT))
- hdr = gettext("These packages installed on the source system "
- "are inconsistent with this system:\n");
- if (pkg_check(hdr, s_handle, l_handle, flag | SW_CMP_SRC) != Z_OK)
- res = Z_ERR;
+ hdr = gettext("These packages installed on the source system "
+ "are inconsistent with this system:\n");
+ do_header = B_TRUE;
+
+ if ((walk = uu_avl_walk_start(src_pkgs, UU_WALK_ROBUST)) == NULL) {
+ res = Z_NOMEM;
+ goto done;
+ }
+ while ((src_pkg = uu_avl_walk_next(walk)) != NULL) {
+ int cmp;
+ uu_avl_index_t where;
+
+ dst_pkg = uu_avl_find(dst_pkgs, src_pkg, NULL, &where);
+
+ /*
+ * Build up a list of unique patches for the src system but
+ * don't track patches that are obsoleted on the dst system
+ * since they don't matter.
+ */
+ if (!add_patch(src_pkg->zpe_patches_avl, src_patches, dst_pkg,
+ pkg_pool)) {
+ res = Z_NOMEM;
+ goto done;
+ }
+
+ if (dst_pkg == NULL) {
+ /* src pkg is not installed on dst */
+ if (prt_header(&res, flag, &do_header, hdr))
+ break;
+
+ (void) fprintf(stderr,
+ gettext("\t%s: not installed\n\t\t(%s)\n"),
+ src_pkg->zpe_name, src_pkg->zpe_vers);
+ continue;
+ }
+
+ /* Check pkg version */
+ if (pkg_vers_cmp(src_pkg->zpe_vers, dst_pkg->zpe_vers, &cmp)) {
+ res = Z_NOMEM;
+ goto done;
+ }
+
+ if (cmp != 0) {
+ if (prt_header(&res, flag, &do_header, hdr))
+ break;
+
+ (void) fprintf(stderr, gettext(
+ "\t%s: version mismatch\n\t\t(%s)\n\t\t(%s)\n"),
+ src_pkg->zpe_name, src_pkg->zpe_vers,
+ dst_pkg->zpe_vers);
+ }
+ }
+ uu_avl_walk_end(walk);
/*
* Now check the local host for pkgs that were not on the source host.
* We already handled version mismatches in the loop above.
*/
- if (!(flag & SW_CMP_SILENT))
- hdr = gettext("These packages installed on this system were "
- "not installed on the source system:\n");
- if (pkg_check(hdr, l_handle, s_handle, flag | SW_CMP_NONE) != Z_OK)
- res = Z_ERR;
+ hdr = gettext("These packages installed on this system were "
+ "not installed on the source system:\n");
+ do_header = B_TRUE;
+
+ if ((walk = uu_avl_walk_start(dst_pkgs, UU_WALK_ROBUST)) == NULL) {
+ res = Z_NOMEM;
+ goto done;
+ }
+ while ((dst_pkg = uu_avl_walk_next(walk)) != NULL) {
+ uu_avl_index_t where;
+
+ /*
+ * Build up a list of unique patches for the dst system. We
+ * don't worry about tracking obsolete patches that were on the
+ * src since we only want to report the results of moving to
+ * the dst system.
+ */
+ if (!add_patch(dst_pkg->zpe_patches_avl, dst_patches, NULL,
+ pkg_pool)) {
+ res = Z_NOMEM;
+ goto done;
+ }
+
+ src_pkg = uu_avl_find(src_pkgs, dst_pkg, NULL, &where);
+ if (src_pkg == NULL) {
+ /* dst pkg is not installed on src */
+ if (prt_header(&res, flag, &do_header, hdr))
+ break;
+
+ (void) fprintf(stderr, gettext("\t%s (%s)\n"),
+ dst_pkg->zpe_name, dst_pkg->zpe_vers);
+ }
+ }
+ uu_avl_walk_end(walk);
/*
* Check the source host for patches that are not on the local host.
*/
- if (!(flag & SW_CMP_SILENT))
- hdr = gettext("These patches installed on the source system "
- "are inconsistent with this system:\n");
- if (patch_check(hdr, s_handle, l_handle, flag | SW_CMP_SRC) != Z_OK)
- res = Z_ERR;
+ hdr = gettext("These patches installed on the source system "
+ "are inconsistent with this system:\n");
+ do_header = B_TRUE;
+
+ if ((walk = uu_avl_walk_start(src_patches, UU_WALK_ROBUST)) == NULL) {
+ res = Z_NOMEM;
+ goto done;
+ }
+ while ((src_patch = uu_avl_walk_next(walk)) != NULL) {
+ uu_avl_index_t where;
+
+ dst_patch = uu_avl_find(dst_patches, src_patch, NULL, &where);
+ if (dst_patch == NULL) {
+ /* src patch is not installed on dst */
+ if (prt_header(&res, flag, &do_header, hdr))
+ break;
+
+ (void) fprintf(stderr,
+ gettext("\t%s-%s: not installed\n"),
+ src_patch->zpe_name, src_patch->zpe_vers);
+ continue;
+ }
+
+ /*
+ * Check patch version. We assume the patch versions are
+ * properly structured with a leading 0 if necessary (e.g. 01).
+ */
+ assert(strlen(src_patch->zpe_vers) ==
+ strlen(dst_patch->zpe_vers));
+ if (strcmp(src_patch->zpe_vers, dst_patch->zpe_vers) != 0) {
+ if (prt_header(&res, flag, &do_header, hdr))
+ break;
+
+ (void) fprintf(stderr,
+ gettext("\t%s: version mismatch\n\t\t(%s) (%s)\n"),
+ src_patch->zpe_name, src_patch->zpe_vers,
+ dst_patch->zpe_vers);
+ }
+ }
+ uu_avl_walk_end(walk);
/*
* Check the local host for patches that were not on the source host.
* We already handled version mismatches in the loop above.
*/
- if (!(flag & SW_CMP_SILENT))
- hdr = gettext("These patches installed on this system were "
- "not installed on the source system:\n");
- if (patch_check(hdr, l_handle, s_handle, flag | SW_CMP_NONE) != Z_OK)
- res = Z_ERR;
+ hdr = gettext("These patches installed on this system were "
+ "not installed on the source system:\n");
+ do_header = B_TRUE;
+
+ if ((walk = uu_avl_walk_start(dst_patches, UU_WALK_ROBUST)) == NULL) {
+ res = Z_NOMEM;
+ goto done;
+ }
+ while ((dst_patch = uu_avl_walk_next(walk)) != NULL) {
+ uu_avl_index_t where;
+
+ src_patch = uu_avl_find(src_patches, dst_patch, NULL, &where);
+ if (src_patch == NULL) {
+ /* dst patch is not installed on src */
+ if (prt_header(&res, flag, &do_header, hdr))
+ break;
+
+ (void) fprintf(stderr, gettext("\t%s-%s\n"),
+ dst_patch->zpe_name, dst_patch->zpe_vers);
+ }
+ }
+ uu_avl_walk_end(walk);
+
+done:
+ if (res == Z_NOMEM)
+ zerror(gettext("Out of memory"));
+
+ /* free avl structs */
+ pkg_avl_delete(src_pkgs);
+ pkg_avl_delete(dst_pkgs);
+ pkg_avl_delete(src_patches);
+ pkg_avl_delete(dst_patches);
+ if (pkg_pool != NULL)
+ uu_avl_pool_destroy(pkg_pool);
+
+ return (res);
+}
+
+/*
+ * Compare the software on the local global zone and source system global
+ * zone. Used to determine if/how we have to update the zone during attach.
+ * We generate the data files needed by the update process in this case.
+ * l_handle is for the local system and s_handle is for the source system.
+ * These have a snapshot of the appropriate packages and patches in the global
+ * zone for the two machines.
+ *
+ * The algorithm we use to compare the pkgs is as follows:
+ * 1) pkg on src but not on dst
+ * remove src pkg (allowed in order to handle obsolete pkgs - note that
+ * this only applies to dependent pkgs, not generic pkgs installed into
+ * the zone by the zone admin)
+ * 2) pkg on dst but not on src
+ * add pkg
+ * 3) pkg on src with higher rev than on dst
+ * fail (downgrade)
+ * 4) pkg on dst with higher rev than on src
+ * remove src pkg & add new
+ * 5) pkg version is the same
+ * a) patch on src but not on dst
+ * fail (downgrade, unless obsoleted)
+ * b) patch on dst but not on src
+ * remove src pkg & add new
+ * c) patch on src with higher rev than on dst
+ * fail (downgrade, unless obsoleted)
+ * d) patch on dst with higher rev than on src
+ * remove src pkg & add new
+ *
+ * We run this algorithm in 2 passes, first looking at the pkgs from the src
+ * system and then looking at the pkgs from the dst system.
+ *
+ * As with the sw_cmp function, we return Z_OK if there is no work to be
+ * done (the attach can just happen) or Z_ERR if we have to update the pkgs
+ * within the zone. We can also return Z_FATAL if we had a real error during
+ * this process.
+ */
+int
+sw_up_to_date(zone_dochandle_t l_handle, zone_dochandle_t s_handle,
+ char *zonepath)
+{
+ int res = Z_OK;
+ int err;
+ int cmp;
+ FILE *fp_add = NULL, *fp_rm = NULL;
+ uu_avl_pool_t *pkg_pool = NULL;
+ uu_avl_t *src_pkgs = NULL;
+ uu_avl_t *dst_pkgs = NULL;
+ uu_avl_walk_t *walk;
+ zone_pkg_entry_t *src_pkg;
+ zone_pkg_entry_t *dst_pkg;
+ char fname[MAXPATHLEN];
+
+ (void) snprintf(fname, sizeof (fname), "%s/pkg_add", zonepath);
+ if ((fp_add = fopen(fname, "w")) == NULL) {
+ zperror(gettext("could not save list of packages to add"),
+ B_FALSE);
+ goto fatal;
+ }
+
+ (void) snprintf(fname, sizeof (fname), "%s/pkg_rm", zonepath);
+ if ((fp_rm = fopen(fname, "w")) == NULL) {
+ zperror(gettext("could not save list of packages to remove"),
+ B_FALSE);
+ goto fatal;
+ }
+
+ if ((pkg_pool = uu_avl_pool_create("pkgs_pool",
+ sizeof (zone_pkg_entry_t), offsetof(zone_pkg_entry_t, zpe_entry),
+ pkg_entry_compare, UU_DEFAULT)) == NULL)
+ goto fatal;
+
+ if ((src_pkgs = uu_avl_create(pkg_pool, NULL, UU_DEFAULT)) == NULL)
+ goto fatal;
+
+ if ((dst_pkgs = uu_avl_create(pkg_pool, NULL, UU_DEFAULT)) == NULL)
+ goto fatal;
+
+ if ((err = zonecfg_getpkgdata(s_handle, pkg_pool, src_pkgs)) != Z_OK) {
+ errno = err;
+ zperror(gettext("could not get package data for detached zone"),
+ B_TRUE);
+ goto fatal;
+ }
+ if ((err = zonecfg_getpkgdata(l_handle, pkg_pool, dst_pkgs)) != Z_OK) {
+ errno = err;
+ zperror(gettext("could not get package data for global zone"),
+ B_TRUE);
+ goto fatal;
+ }
+
+ /*
+ * First Pass
+ *
+ * Start by checking each pkg from the src system. We need to handle
+ * the following:
+ * 1) pkg on src but not on dst
+ * rm old pkg (allowed in order to handle obsolete pkgs)
+ * 3) pkg on src with higher rev than on dst
+ * fail (downgrade)
+ * 5) pkg ver same
+ * a) patch on src but not on dst
+ * fail (downgrade)
+ * c) patch on src with higher rev than on dst
+ * fail (downgrade)
+ */
+ if ((walk = uu_avl_walk_start(src_pkgs, UU_WALK_ROBUST)) == NULL) {
+ zerror(gettext("Out of memory"));
+ goto fatal;
+ }
+
+ while ((src_pkg = uu_avl_walk_next(walk)) != NULL) {
+ uu_avl_index_t where;
+ uu_avl_walk_t *patch_walk;
+ zone_pkg_entry_t *src_patch;
+
+ dst_pkg = uu_avl_find(dst_pkgs, src_pkg, NULL, &where);
+
+ if (dst_pkg == NULL) {
+ /* src pkg is not installed on dst */
+ if (fprintf(fp_rm, "%s\n", src_pkg->zpe_name) < 0) {
+ zperror(gettext("could not save list of "
+ "packages to remove"), B_FALSE);
+ goto fatal;
+ }
+ res = Z_ERR;
+ continue;
+ }
+
+ /* Check pkg version to determine how to proceed. */
+ if (pkg_vers_cmp(src_pkg->zpe_vers, dst_pkg->zpe_vers, &cmp)) {
+ zerror(gettext("Out of memory"));
+ goto fatal;
+ }
+
+ if (cmp > 0) {
+ /* src pkg has higher vers than dst pkg */
+ zerror(gettext("ERROR: attempt to downgrade package "
+ "%s %s to version %s"), src_pkg->zpe_name,
+ src_pkg->zpe_vers, dst_pkg->zpe_vers);
+ goto fatal;
+ }
+
+ /*
+ * src pkg has lower vers than dst pkg, we'll handle
+ * this in the loop where we process the dst pkgs.
+ */
+ if (cmp < 0)
+ continue;
+
+ /* src and dst pkgs have the same version. */
+
+ /*
+ * If src pkg has no patches, then we're done with this pkg.
+ * Any patches on the dst pkg are handled in the 2nd pass.
+ */
+ if (src_pkg->zpe_patches_avl == NULL)
+ continue;
+
+ if (dst_pkg->zpe_patches_avl == NULL) {
+ /*
+ * We have the same pkg on the src and dst but the src
+ * pkg has patches and the dst pkg does not, so this
+ * would be a downgrade! Disallow this.
+ */
+ zerror(gettext("ERROR: attempt to downgrade package "
+ "%s, the source had patches but this system does "
+ "not\n"), src_pkg->zpe_name);
+ goto fatal;
+ }
+
+ patch_walk = uu_avl_walk_start(src_pkg->zpe_patches_avl,
+ UU_WALK_ROBUST);
+ if (patch_walk == NULL) {
+ zerror(gettext("Out of memory"));
+ goto fatal;
+ }
+
+ while ((src_patch = uu_avl_walk_next(patch_walk)) != NULL) {
+ zone_pkg_entry_t *dst_patch;
+
+ dst_patch = uu_avl_find(dst_pkg->zpe_patches_avl,
+ src_patch, NULL, &where);
+
+ if (dst_patch == NULL) {
+ /*
+ * We have the same pkg on the src and dst but
+ * the src pkg has a patch that the dst pkg
+ * does not, so this would be a downgrade! We
+ * need to disallow this but first double check
+ * that this patch has not been obsoleted by
+ * some other patch that is installed on the
+ * dst. If the patch is obsolete, the pkg will
+ * be handled in the 2nd pass.
+ */
+ if (is_obsolete(dst_pkg, src_patch))
+ continue;
+
+ zerror(gettext("ERROR: attempt to downgrade "
+ "package %s, the source had patch %s-%s "
+ "which is not installed on this system\n"),
+ src_pkg->zpe_name, src_patch->zpe_name,
+ src_patch->zpe_vers);
+
+ goto fatal;
+ }
+
+ /* Check if the src patch is newer than the dst patch */
+ if (strcmp(src_patch->zpe_vers, dst_patch->zpe_vers)
+ > 0) {
+ /*
+ * We have a patch on the src with higher rev
+ * than the patch on the dst so this would be a
+ * downgrade! We need to disallow this but
+ * first double check that this patch has not
+ * been obsoleted by some other patch that is
+ * installed on the dst. If the patch is
+ * obsolete, the pkg will be handled in the 2nd
+ * pass.
+ */
+ if (is_obsolete(dst_pkg, src_patch))
+ continue;
+
+ zerror(gettext("ERROR: attempt to downgrade "
+ "package %s, the source had patch %s-%s "
+ "but this system only has %s-%s\n"),
+ src_pkg->zpe_name, src_patch->zpe_name,
+ src_patch->zpe_vers, dst_patch->zpe_name,
+ dst_patch->zpe_vers);
+ goto fatal;
+ }
+
+ /*
+ * If the src patch is the same rev or older than the
+ * dst patch we'll handle that in the second pass.
+ */
+ }
+
+ uu_avl_walk_end(patch_walk);
+ }
+
+ uu_avl_walk_end(walk);
+
+ /*
+ * Second Pass
+ *
+ * Now check each pkg from the dst system. We need to handle
+ * the following:
+ * 2) pkg on dst but not on src
+ * add pkg
+ * 4) pkg on dst with higher rev than on src
+ * remove old pkg & add current
+ * 5) pkg ver same
+ * b) patch on dst but not on src
+ * remove old pkg & add
+ * d) patch on dst with higher rev than on src
+ * remove old pkg & add
+ */
+ if ((walk = uu_avl_walk_start(dst_pkgs, UU_WALK_ROBUST)) == NULL) {
+ zerror(gettext("Out of memory"));
+ goto fatal;
+ }
+
+ while ((dst_pkg = uu_avl_walk_next(walk)) != NULL) {
+ uu_avl_index_t where;
+ uu_avl_walk_t *patch_walk;
+ zone_pkg_entry_t *dst_patch;
+
+ src_pkg = uu_avl_find(src_pkgs, dst_pkg, NULL, &where);
+
+ if (src_pkg == NULL) {
+ /* dst pkg was not installed on src */
+ if (fprintf(fp_add, "%s\n", dst_pkg->zpe_name) < 0) {
+ zperror(gettext("could not save list of "
+ "packages to add"), B_FALSE);
+ goto fatal;
+ }
+ res = Z_ERR;
+ continue;
+ }
+
+ /* Check pkg version to determine how to proceed. */
+ if (pkg_vers_cmp(dst_pkg->zpe_vers, src_pkg->zpe_vers, &cmp)) {
+ zerror(gettext("Out of memory"));
+ goto fatal;
+ }
+
+ if (cmp > 0) {
+ /* dst pkg has higher vers than src pkg */
+ if (fprintf(fp_rm, "%s\n", dst_pkg->zpe_name) < 0) {
+ zperror(gettext("could not save list of "
+ "packages to remove"), B_FALSE);
+ goto fatal;
+ }
+ if (fprintf(fp_add, "%s\n", dst_pkg->zpe_name) < 0) {
+ zperror(gettext("could not save list of "
+ "packages to add"), B_FALSE);
+ goto fatal;
+ }
+ res = Z_ERR;
+ continue;
+ }
+
+ /*
+ * cmp < 0 was handled in the first loop. This would
+ * be a downgrade so we should have already failed.
+ */
+ assert(cmp >= 0);
+
+ /* src and dst pkgs have the same version. */
+
+ /* If dst pkg has no patches, then we're done with this pkg. */
+ if (dst_pkg->zpe_patches_avl == NULL)
+ continue;
+
+ if (src_pkg->zpe_patches_avl == NULL) {
+ /*
+ * We have the same pkg on the src and dst
+ * but the dst pkg has patches and the src
+ * pkg does not. Just replace the pkg.
+ */
+ if (fprintf(fp_rm, "%s\n", dst_pkg->zpe_name) < 0) {
+ zperror(gettext("could not save list of "
+ "packages to remove"), B_FALSE);
+ goto fatal;
+ }
+ if (fprintf(fp_add, "%s\n", dst_pkg->zpe_name) < 0) {
+ zperror(gettext("could not save list of "
+ "packages to add"), B_FALSE);
+ goto fatal;
+ }
+ res = Z_ERR;
+ continue;
+ }
+
+ patch_walk = uu_avl_walk_start(dst_pkg->zpe_patches_avl,
+ UU_WALK_ROBUST);
+ if (patch_walk == NULL) {
+ zerror(gettext("Out of memory"));
+ goto fatal;
+ }
+
+ while ((dst_patch = uu_avl_walk_next(patch_walk)) != NULL) {
+ zone_pkg_entry_t *src_patch;
+
+ src_patch = uu_avl_find(src_pkg->zpe_patches_avl,
+ dst_patch, NULL, &where);
+
+ if (src_patch == NULL) {
+ /*
+ * We have the same pkg on the src and dst but
+ * the dst pkg has a patch that the src pkg
+ * does not. Just replace the pkg.
+ */
+ if (fprintf(fp_rm, "%s\n", dst_pkg->zpe_name)
+ < 0) {
+ zperror(gettext("could not save list "
+ "of packages to remove"), B_FALSE);
+ goto fatal;
+ }
+ if (fprintf(fp_add, "%s\n", dst_pkg->zpe_name)
+ < 0) {
+ zperror(gettext("could not save list "
+ "of packages to add"), B_FALSE);
+ goto fatal;
+ }
+ res = Z_ERR;
+ continue;
+ }
+
+ /* Check if the dst patch is newer than the src patch */
+ if (strcmp(dst_patch->zpe_vers, src_patch->zpe_vers)
+ > 0) {
+ /*
+ * We have a patch on the dst with higher rev
+ * than the patch on the src. Just replace the
+ * pkg.
+ */
+ if (fprintf(fp_rm, "%s\n", dst_pkg->zpe_name)
+ < 0) {
+ zperror(gettext("could not save list "
+ "of packages to remove"), B_FALSE);
+ goto fatal;
+ }
+ if (fprintf(fp_add, "%s\n", dst_pkg->zpe_name)
+ < 0) {
+ zperror(gettext("could not save list "
+ "of packages to add"), B_FALSE);
+ goto fatal;
+ }
+ res = Z_ERR;
+ continue;
+ }
+
+ /*
+ * If the dst patch is the same rev then we can ignore
+ * this pkg. If it is older than the src patch we
+ * handled that in the first pass and we should have
+ * already failed.
+ */
+ assert(strcmp(dst_patch->zpe_vers, src_patch->zpe_vers)
+ >= 0);
+ }
+
+ uu_avl_walk_end(patch_walk);
+ }
+
+ uu_avl_walk_end(walk);
+
+ if (fclose(fp_add) != 0) {
+ zperror(gettext("could not save list of packages to add"),
+ B_FALSE);
+ goto fatal;
+ }
+ fp_add = NULL;
+ if (fclose(fp_rm) != 0) {
+ zperror(gettext("could not save list of packages to remove"),
+ B_FALSE);
+ goto fatal;
+ }
+
+ /* free avl structs */
+ pkg_avl_delete(src_pkgs);
+ pkg_avl_delete(dst_pkgs);
+ uu_avl_pool_destroy(pkg_pool);
return (res);
+
+fatal:
+ /* free avl structs */
+ pkg_avl_delete(src_pkgs);
+ pkg_avl_delete(dst_pkgs);
+ if (pkg_pool != NULL)
+ uu_avl_pool_destroy(pkg_pool);
+
+ if (fp_add != NULL)
+ (void) fclose(fp_add);
+ if (fp_rm != NULL)
+ (void) fclose(fp_rm);
+
+ /* clean up data files left behind */
+ (void) snprintf(fname, sizeof (fname), "%s/pkg_add", zonepath);
+ (void) unlink(fname);
+ (void) snprintf(fname, sizeof (fname), "%s/pkg_rm", zonepath);
+ (void) unlink(fname);
+
+ return (Z_FATAL);
}
diff --git a/usr/src/cmd/zoneadm/zoneadm.c b/usr/src/cmd/zoneadm/zoneadm.c
index f8337ae207..1fb836f3a2 100644
--- a/usr/src/cmd/zoneadm/zoneadm.c
+++ b/usr/src/cmd/zoneadm/zoneadm.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -139,7 +139,7 @@ struct cmd {
#define SHELP_CLONE "clone [-m method] [-s <ZFS snapshot>] zonename"
#define SHELP_MOVE "move zonepath"
#define SHELP_DETACH "detach [-n]"
-#define SHELP_ATTACH "attach [-F] [-n <path>]"
+#define SHELP_ATTACH "attach [-F] [-n <path>] [-u]"
#define SHELP_MARK "mark incomplete"
#define EXEC_PREFIX "exec "
@@ -206,6 +206,8 @@ static char *target_uuid;
/* used in do_subproc() and signal handler */
static volatile boolean_t child_killed;
+/* used in attach_func() and signal handler */
+static volatile boolean_t attach_interupted;
static int do_subproc_cnt = 0;
/*
@@ -305,13 +307,15 @@ long_help(int cmd_num)
"successful completion, the zone state will be\n\t"
"'installed'. The system software on the current "
"system must be\n\tcompatible with the software on the "
- "zone's original system.\n\tSpecify -F to force the attach "
- "and skip software compatibility tests.\n\tThe -n option "
- "can be used to specify 'no-execute' mode. When -n is\n\t"
- "used, the information needed to attach the zone is read "
- "from the\n\tspecified path and the configuration is only "
- "validated. The path can\n\tbe '-' to specify standard "
- "input."));
+ "zone's original system or use\n\tthe -u option to update "
+ "the zone to the current system software.\n\tSpecify -F "
+ "to force the attach and skip software compatibility "
+ "tests.\n\tThe -n option can be used to specify "
+ "'no-execute' mode. When -n is\n\tused, the information "
+ "needed to attach the zone is read from the\n\tspecified "
+ "path and the configuration is only validated. The path "
+ "can\n\tbe '-' to specify standard input. The -F, -n and "
+ "-u options are\n\tmutually exclusive."));
case CMD_MARK:
return (gettext("Set the state of the zone. This can be used "
"to force the zone\n\tstate to 'incomplete' "
@@ -4882,7 +4886,7 @@ cleanup:
target_zone, target_zone) >= sizeof (cmdbuf)) {
res = B_FALSE;
} else {
- status = do_subproc(cmdbuf);
+ status = do_subproc_interactive(cmdbuf);
if (subproc_status("rm", status, B_TRUE)
!= ZONE_SUBPROC_OK)
res = B_FALSE;
@@ -4898,6 +4902,150 @@ cleanup:
return (res);
}
+/*
+ * The zone needs to be updated so set it up for the update and initiate the
+ * update within the scratch zone. First set the state to incomplete so we can
+ * force-mount the zone for the update operation. We pass the -U option to the
+ * mount so that the scratch zone is mounted without the zone's /etc and /var
+ * being lofs mounted back into the scratch zone root. This is done by
+ * overloading the bootbuf string in the zone_cmd_arg_t to pass -U as an option
+ * to the mount cmd.
+ */
+static int
+attach_update(zone_dochandle_t handle, char *zonepath)
+{
+ int err;
+ int update_res;
+ int status;
+ zone_cmd_arg_t zarg;
+ FILE *fp;
+ struct zone_fstab fstab;
+ char cmdbuf[(4 * MAXPATHLEN) + 20];
+
+ if ((err = zone_set_state(target_zone, ZONE_STATE_INCOMPLETE))
+ != Z_OK) {
+ errno = err;
+ zperror(gettext("could not set state"), B_TRUE);
+ return (Z_ERR);
+ }
+
+ zarg.cmd = Z_FORCEMOUNT;
+ (void) strlcpy(zarg.bootbuf, "-U", sizeof (zarg.bootbuf));
+ if (call_zoneadmd(target_zone, &zarg) != 0) {
+ zerror(gettext("could not mount zone"));
+
+ /* We reset the state since the zone wasn't modified yet. */
+ if ((err = zone_set_state(target_zone, ZONE_STATE_CONFIGURED))
+ != Z_OK) {
+ errno = err;
+ zperror(gettext("could not reset state"), B_TRUE);
+ }
+ return (Z_ERR);
+ }
+
+ /*
+ * Move data files generated by sw_up_to_date() into the scratch
+ * zone's /tmp.
+ */
+ (void) snprintf(cmdbuf, sizeof (cmdbuf), "exec /usr/bin/mv "
+ "%s/pkg_add %s/pkg_rm %s/lu/tmp",
+ zonepath, zonepath, zonepath);
+
+ status = do_subproc_interactive(cmdbuf);
+ if (subproc_status("mv", status, B_TRUE) != ZONE_SUBPROC_OK) {
+ zperror(gettext("could not mv data files"), B_FALSE);
+ goto fail;
+ }
+
+ /*
+ * Save list of inherit-pkg-dirs into zone. Since the file is in
+ * /tmp we don't have to worry about deleting it.
+ */
+ (void) snprintf(cmdbuf, sizeof (cmdbuf), "%s/lu/tmp/inherited",
+ zonepath);
+ if ((fp = fopen(cmdbuf, "w")) == NULL) {
+ zperror(gettext("could not save inherit-pkg-dirs"), B_FALSE);
+ goto fail;
+ }
+ if (zonecfg_setipdent(handle) != Z_OK) {
+ zperror(gettext("could not enumerate inherit-pkg-dirs"),
+ B_TRUE);
+ goto fail;
+ }
+ while (zonecfg_getipdent(handle, &fstab) == Z_OK) {
+ if (fprintf(fp, "%s\n", fstab.zone_fs_dir) < 0) {
+ zperror(gettext("could not save inherit-pkg-dirs"),
+ B_FALSE);
+ (void) fclose(fp);
+ goto fail;
+ }
+ }
+ (void) zonecfg_endipdent(handle);
+ if (fclose(fp) != 0) {
+ zperror(gettext("could not save inherit-pkg-dirs"), B_FALSE);
+ goto fail;
+ }
+
+ /* run the updater inside the scratch zone */
+ (void) snprintf(cmdbuf, sizeof (cmdbuf),
+ "exec /usr/sbin/zlogin -S %s "
+ "/usr/lib/brand/native/attach_update %s", target_zone, target_zone);
+
+ update_res = Z_OK;
+ status = do_subproc_interactive(cmdbuf);
+ if (subproc_status("attach_update", status, B_TRUE)
+ != ZONE_SUBPROC_OK) {
+ zerror(gettext("could not update zone"));
+ update_res = Z_ERR;
+ }
+
+ zarg.cmd = Z_UNMOUNT;
+ if (call_zoneadmd(target_zone, &zarg) != 0) {
+ zerror(gettext("could not unmount zone"));
+ return (Z_ERR);
+ }
+
+ /*
+ * If the update script within the scratch zone failed for some reason
+ * we will now leave the zone in the incomplete state since we no
+ * longer know the state of the files within the zonepath.
+ */
+ if (update_res == Z_ERR)
+ return (Z_ERR);
+
+ zonecfg_rm_detached(handle, B_FALSE);
+
+ if ((err = zone_set_state(target_zone, ZONE_STATE_INSTALLED)) != Z_OK) {
+ errno = err;
+ zperror(gettext("could not set state"), B_TRUE);
+ return (Z_ERR);
+ }
+
+ return (Z_OK);
+
+fail:
+ zarg.cmd = Z_UNMOUNT;
+ if (call_zoneadmd(target_zone, &zarg) != 0)
+ zerror(gettext("could not unmount zone"));
+
+ /* We reset the state since the zone wasn't modified yet. */
+ if ((err = zone_set_state(target_zone, ZONE_STATE_CONFIGURED))
+ != Z_OK) {
+ errno = err;
+ zperror(gettext("could not reset state"), B_TRUE);
+ }
+
+ return (Z_ERR);
+}
+
+/* ARGSUSED */
+static void
+sigcleanup(int sig)
+{
+ attach_interupted = B_TRUE;
+}
+
+
static int
attach_func(int argc, char *argv[])
{
@@ -4911,6 +5059,7 @@ attach_func(int argc, char *argv[])
char cmdbuf[MAXPATHLEN];
boolean_t execute = B_TRUE;
boolean_t retried = B_FALSE;
+ boolean_t update = B_FALSE;
char *manifest_path;
brand_handle_t bh = NULL;
@@ -4920,7 +5069,7 @@ attach_func(int argc, char *argv[])
}
optind = 0;
- if ((arg = getopt(argc, argv, "?Fn:")) != EOF) {
+ if ((arg = getopt(argc, argv, "?Fn:u")) != EOF) {
switch (arg) {
case '?':
sub_usage(SHELP_ATTACH, CMD_ATTACH);
@@ -4932,12 +5081,21 @@ attach_func(int argc, char *argv[])
execute = B_FALSE;
manifest_path = optarg;
break;
+ case 'u':
+ update = B_TRUE;
+ break;
default:
sub_usage(SHELP_ATTACH, CMD_ATTACH);
return (Z_USAGE);
}
}
+ /* dry-run and update flags are mutually exclusive */
+ if (!execute && update) {
+ zerror(gettext("-n and -u flags are mutually exclusive"));
+ return (Z_ERR);
+ }
+
/*
* If the no-execute option was specified, we need to branch down
* a completely different path since there is no zone required to be
@@ -5072,12 +5230,45 @@ retry:
goto done;
}
- /* sw_cmp prints error msgs as necessary */
- if ((err = sw_cmp(handle, athandle, SW_CMP_NONE)) != Z_OK)
- goto done;
+ /*
+ * If we're doing an update on attach, and the zone does need to be
+ * updated, then run the update.
+ */
+ if (update) {
+ char fname[MAXPATHLEN];
- if ((err = dev_fix(athandle)) != Z_OK)
- goto done;
+ (void) sigset(SIGINT, sigcleanup);
+
+ if ((err = sw_up_to_date(handle, athandle, zonepath)) != Z_OK) {
+ if (err != Z_FATAL && !attach_interupted) {
+ err = Z_FATAL;
+ err = attach_update(handle, zonepath);
+ }
+ if (!attach_interupted || err == Z_OK)
+ goto done;
+ }
+
+ (void) sigset(SIGINT, SIG_DFL);
+
+ /* clean up data files left behind by sw_up_to_date() */
+ (void) snprintf(fname, sizeof (fname), "%s/pkg_add", zonepath);
+ (void) unlink(fname);
+ (void) snprintf(fname, sizeof (fname), "%s/pkg_rm", zonepath);
+ (void) unlink(fname);
+
+ if (attach_interupted) {
+ err = Z_FATAL;
+ goto done;
+ }
+
+ } else {
+ /* sw_cmp prints error msgs as necessary */
+ if ((err = sw_cmp(handle, athandle, SW_CMP_NONE)) != Z_OK)
+ goto done;
+
+ if ((err = dev_fix(athandle)) != Z_OK)
+ goto done;
+ }
forced:
@@ -5326,6 +5517,7 @@ mount_func(int argc, char *argv[])
return (Z_ERR);
zarg.cmd = force ? Z_FORCEMOUNT : Z_MOUNT;
+ zarg.bootbuf[0] = '\0';
if (call_zoneadmd(target_zone, &zarg) != 0) {
zerror(gettext("call to %s failed"), "zoneadmd");
return (Z_ERR);
diff --git a/usr/src/cmd/zoneadm/zoneadm.h b/usr/src/cmd/zoneadm/zoneadm.h
index a299ece135..9cf02b82a5 100644
--- a/usr/src/cmd/zoneadm/zoneadm.h
+++ b/usr/src/cmd/zoneadm/zoneadm.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -56,6 +56,7 @@
#define Z_ERR 1
#define Z_USAGE 2
+#define Z_FATAL 3
#define SW_CMP_NONE 0x0
#define SW_CMP_SRC 0x01
@@ -90,5 +91,7 @@ extern int init_zfs(void);
*/
extern int sw_cmp(zone_dochandle_t l_handle, zone_dochandle_t s_handle,
uint_t flag);
+extern int sw_up_to_date(zone_dochandle_t l_handle, zone_dochandle_t s_handle,
+ char *zonepath);
#endif /* _ZONEADM_H */
diff --git a/usr/src/cmd/zoneadmd/vplat.c b/usr/src/cmd/zoneadmd/vplat.c
index 346fd2ac86..12f0b01eee 100644
--- a/usr/src/cmd/zoneadmd/vplat.c
+++ b/usr/src/cmd/zoneadmd/vplat.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -133,6 +133,8 @@
#define DFSTYPES "/etc/dfs/fstypes"
#define MAXTNZLEN 2048
+#define ALT_MOUNT(mount_cmd) ((mount_cmd) != Z_MNT_BOOT)
+
/* for routing socket */
static int rts_seqno = 0;
@@ -1322,6 +1324,10 @@ free_fs_data(struct zone_fstab *fsarray, uint_t nelem)
* So mounting of localdirs[](/etc and /var) have been moved to the
* build_mounted_post_var() which gets called only after the zone
* specific filesystems are mounted.
+ *
+ * Note that the scratch zone we set up for updating the zone (Z_MNT_UPDATE)
+ * does not loopback mount the zone's own /etc and /var into the root of the
+ * scratch zone.
*/
static boolean_t
build_mounted_pre_var(zlog_t *zlogp, char *rootpath,
@@ -1405,42 +1411,61 @@ build_mounted_pre_var(zlog_t *zlogp, char *rootpath,
static boolean_t
-build_mounted_post_var(zlog_t *zlogp, char *rootpath, const char *luroot)
+build_mounted_post_var(zlog_t *zlogp, zone_mnt_t mount_cmd, char *rootpath,
+ const char *luroot)
{
char tmp[MAXPATHLEN], fromdir[MAXPATHLEN];
const char **cpp;
+ const char **loopdirs;
+ const char **tmpdirs;
static const char *localdirs[] = {
"/etc", "/var", NULL
};
- static const char *loopdirs[] = {
+ static const char *scr_loopdirs[] = {
"/etc/lib", "/etc/fs", "/lib", "/sbin", "/platform",
"/usr", NULL
};
- static const char *tmpdirs[] = {
+ static const char *upd_loopdirs[] = {
+ "/etc", "/kernel", "/lib", "/opt", "/platform", "/sbin",
+ "/usr", "/var", NULL
+ };
+ static const char *scr_tmpdirs[] = {
"/tmp", "/var/run", NULL
};
+ static const char *upd_tmpdirs[] = {
+ "/tmp", "/var/run", "/var/tmp", NULL
+ };
struct stat st;
- /*
- * These are mounted read-write from the zone undergoing upgrade. We
- * must be careful not to 'leak' things from the main system into the
- * zone, and this accomplishes that goal.
- */
- for (cpp = localdirs; *cpp != NULL; cpp++) {
- (void) snprintf(tmp, sizeof (tmp), "%s%s", luroot, *cpp);
- (void) snprintf(fromdir, sizeof (fromdir), "%s%s", rootpath,
- *cpp);
- if (mkdir(tmp, 0755) != 0) {
- zerror(zlogp, B_TRUE, "cannot create %s", tmp);
- return (B_FALSE);
- }
- if (domount(zlogp, MNTTYPE_LOFS, "", fromdir, tmp) != 0) {
- zerror(zlogp, B_TRUE, "cannot mount %s on %s", tmp,
+ if (mount_cmd == Z_MNT_SCRATCH) {
+ /*
+ * These are mounted read-write from the zone undergoing
+ * upgrade. We must be careful not to 'leak' things from the
+ * main system into the zone, and this accomplishes that goal.
+ */
+ for (cpp = localdirs; *cpp != NULL; cpp++) {
+ (void) snprintf(tmp, sizeof (tmp), "%s%s", luroot,
*cpp);
- return (B_FALSE);
+ (void) snprintf(fromdir, sizeof (fromdir), "%s%s",
+ rootpath, *cpp);
+ if (mkdir(tmp, 0755) != 0) {
+ zerror(zlogp, B_TRUE, "cannot create %s", tmp);
+ return (B_FALSE);
+ }
+ if (domount(zlogp, MNTTYPE_LOFS, "", fromdir, tmp)
+ != 0) {
+ zerror(zlogp, B_TRUE, "cannot mount %s on %s",
+ tmp, *cpp);
+ return (B_FALSE);
+ }
}
}
+ if (mount_cmd == Z_MNT_UPDATE)
+ loopdirs = upd_loopdirs;
+ else
+ loopdirs = scr_loopdirs;
+
/*
* These are things mounted read-only from the running system because
* they contain binaries that must match system.
@@ -1473,12 +1498,18 @@ build_mounted_post_var(zlog_t *zlogp, char *rootpath, const char *luroot)
}
}
+ if (mount_cmd == Z_MNT_UPDATE)
+ tmpdirs = upd_tmpdirs;
+ else
+ tmpdirs = scr_tmpdirs;
+
/*
* These are things with tmpfs mounted inside.
*/
for (cpp = tmpdirs; *cpp != NULL; cpp++) {
(void) snprintf(tmp, sizeof (tmp), "%s%s", luroot, *cpp);
- if (mkdir(tmp, 0755) != 0 && errno != EEXIST) {
+ if (mount_cmd == Z_MNT_SCRATCH && mkdir(tmp, 0755) != 0 &&
+ errno != EEXIST) {
zerror(zlogp, B_TRUE, "cannot create %s", tmp);
return (B_FALSE);
}
@@ -1595,7 +1626,7 @@ mount_filesystems_ipdent(zone_dochandle_t handle, zlog_t *zlogp,
static int
mount_filesystems_fsent(zone_dochandle_t handle, zlog_t *zlogp,
- struct zone_fstab **fs_tabp, int *num_fsp, int mount_cmd)
+ struct zone_fstab **fs_tabp, int *num_fsp, zone_mnt_t mount_cmd)
{
struct zone_fstab *tmp_ptr, *fs_ptr, *fsp, fstab;
int num_fs;
@@ -1613,7 +1644,8 @@ mount_filesystems_fsent(zone_dochandle_t handle, zlog_t *zlogp,
* root, since the pool will not be known. Ignore them in this
* case.
*/
- if (mount_cmd && strcmp(fstab.zone_fs_type, MNTTYPE_ZFS) == 0)
+ if (ALT_MOUNT(mount_cmd) &&
+ strcmp(fstab.zone_fs_type, MNTTYPE_ZFS) == 0)
continue;
num_fs++;
@@ -1660,7 +1692,7 @@ mount_filesystems_fsent(zone_dochandle_t handle, zlog_t *zlogp,
}
static int
-mount_filesystems(zlog_t *zlogp, boolean_t mount_cmd)
+mount_filesystems(zlog_t *zlogp, zone_mnt_t mount_cmd)
{
char rootpath[MAXPATHLEN];
char zonepath[MAXPATHLEN];
@@ -1774,15 +1806,14 @@ mount_filesystems(zlog_t *zlogp, boolean_t mount_cmd)
* 3) Set up the rest of the scratch zone environment
* (build_mounted_post_var()).
*/
- if (mount_cmd &&
- !build_mounted_pre_var(zlogp,
+ if (ALT_MOUNT(mount_cmd) && !build_mounted_pre_var(zlogp,
rootpath, sizeof (rootpath), zonepath, luroot, sizeof (luroot)))
goto bad;
qsort(fs_ptr, num_fs, sizeof (*fs_ptr), fs_compare);
for (i = 0; i < num_fs; i++) {
- if (mount_cmd &&
+ if (ALT_MOUNT(mount_cmd) &&
strcmp(fs_ptr[i].zone_fs_dir, "/dev") == 0) {
size_t slen = strlen(rootpath) - 2;
@@ -1802,14 +1833,15 @@ mount_filesystems(zlog_t *zlogp, boolean_t mount_cmd)
if (mount_one(zlogp, &fs_ptr[i], rootpath) != 0)
goto bad;
}
- if (mount_cmd &&
- !build_mounted_post_var(zlogp, rootpath, luroot))
+ if (ALT_MOUNT(mount_cmd) &&
+ !build_mounted_post_var(zlogp, mount_cmd, rootpath, luroot))
goto bad;
/*
* For Trusted Extensions cross-mount each lower level /export/home
*/
- if (!mount_cmd && tsol_mounts(zlogp, zone_name, rootpath) != 0)
+ if (mount_cmd == Z_MNT_BOOT &&
+ tsol_mounts(zlogp, zone_name, rootpath) != 0)
goto bad;
free_fs_data(fs_ptr, num_fs);
@@ -2907,7 +2939,7 @@ tcp_abort_connections(zlog_t *zlogp, zoneid_t zoneid)
}
static int
-get_privset(zlog_t *zlogp, priv_set_t *privs, boolean_t mount_cmd)
+get_privset(zlog_t *zlogp, priv_set_t *privs, zone_mnt_t mount_cmd)
{
int error = -1;
zone_dochandle_t handle;
@@ -2923,7 +2955,7 @@ get_privset(zlog_t *zlogp, priv_set_t *privs, boolean_t mount_cmd)
return (-1);
}
- if (mount_cmd) {
+ if (ALT_MOUNT(mount_cmd)) {
zone_iptype_t iptype;
const char *curr_iptype;
@@ -4010,7 +4042,7 @@ setup_zone_rm(zlog_t *zlogp, char *zone_name, zoneid_t zoneid)
}
zoneid_t
-vplat_create(zlog_t *zlogp, boolean_t mount_cmd)
+vplat_create(zlog_t *zlogp, zone_mnt_t mount_cmd)
{
zoneid_t rval = -1;
priv_set_t *privs;
@@ -4060,7 +4092,8 @@ vplat_create(zlog_t *zlogp, boolean_t mount_cmd)
if (get_privset(zlogp, privs, mount_cmd) != 0)
goto error;
- if (!mount_cmd && get_rctls(zlogp, &rctlbuf, &rctlbufsz) != 0) {
+ if (mount_cmd == Z_MNT_BOOT &&
+ get_rctls(zlogp, &rctlbuf, &rctlbufsz) != 0) {
zerror(zlogp, B_FALSE, "Unable to get list of rctls");
goto error;
}
@@ -4070,7 +4103,7 @@ vplat_create(zlog_t *zlogp, boolean_t mount_cmd)
goto error;
}
- if (!mount_cmd && is_system_labeled()) {
+ if (mount_cmd == Z_MNT_BOOT && is_system_labeled()) {
zcent = get_zone_label(zlogp, privs);
if (zcent != NULL) {
match = zcent->zc_match;
@@ -4094,7 +4127,7 @@ vplat_create(zlog_t *zlogp, boolean_t mount_cmd)
if (duplicate_reachable_path(zlogp, rootpath))
goto error;
- if (mount_cmd) {
+ if (ALT_MOUNT(mount_cmd)) {
assert(zone_isnative || zone_iscluster);
root_to_lu(zlogp, rootpath, sizeof (rootpath), B_TRUE);
@@ -4222,7 +4255,7 @@ vplat_create(zlog_t *zlogp, boolean_t mount_cmd)
* The following actions are not performed when merely mounting a zone
* for administrative use.
*/
- if (!mount_cmd) {
+ if (mount_cmd == Z_MNT_BOOT) {
if (setup_zone_rm(zlogp, zone_name, zoneid) != Z_OK) {
(void) zone_shutdown(zoneid);
goto error;
@@ -4325,11 +4358,11 @@ write_index_file(zoneid_t zoneid)
}
int
-vplat_bringup(zlog_t *zlogp, boolean_t mount_cmd, zoneid_t zoneid)
+vplat_bringup(zlog_t *zlogp, zone_mnt_t mount_cmd, zoneid_t zoneid)
{
char zonepath[MAXPATHLEN];
- if (!mount_cmd && validate_datasets(zlogp) != 0) {
+ if (mount_cmd == Z_MNT_BOOT && validate_datasets(zlogp) != 0) {
lofs_discard_mnttab();
return (-1);
}
@@ -4356,7 +4389,7 @@ vplat_bringup(zlog_t *zlogp, boolean_t mount_cmd, zoneid_t zoneid)
return (-1);
}
- if (!mount_cmd) {
+ if (mount_cmd == Z_MNT_BOOT) {
zone_iptype_t iptype;
if (get_iptype(zlogp, &iptype) < 0) {
diff --git a/usr/src/cmd/zoneadmd/zoneadmd.c b/usr/src/cmd/zoneadmd/zoneadmd.c
index 7ba467160c..b7f9dfadf7 100644
--- a/usr/src/cmd/zoneadmd/zoneadmd.c
+++ b/usr/src/cmd/zoneadmd/zoneadmd.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -446,7 +446,7 @@ mkzonedir(zlog_t *zlogp)
* subcommand.
*/
static int
-zone_ready(zlog_t *zlogp, boolean_t mount_cmd)
+zone_ready(zlog_t *zlogp, zone_mnt_t mount_cmd)
{
int err;
@@ -464,7 +464,7 @@ zone_ready(zlog_t *zlogp, boolean_t mount_cmd)
}
if (vplat_bringup(zlogp, mount_cmd, zone_id) != 0) {
bringup_failure_recovery = B_TRUE;
- (void) vplat_teardown(NULL, mount_cmd, B_FALSE);
+ (void) vplat_teardown(NULL, (mount_cmd != Z_MNT_BOOT), B_FALSE);
if ((err = zonecfg_destroy_snapshot(zone_name)) != Z_OK)
zerror(zlogp, B_FALSE, "destroying snapshot: %s",
zonecfg_strerror(err));
@@ -1032,14 +1032,14 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp,
case ZONE_STATE_INSTALLED:
switch (cmd) {
case Z_READY:
- rval = zone_ready(zlogp, B_FALSE);
+ rval = zone_ready(zlogp, Z_MNT_BOOT);
if (rval == 0)
eventstream_write(Z_EVT_ZONE_READIED);
break;
case Z_BOOT:
case Z_FORCEBOOT:
eventstream_write(Z_EVT_ZONE_BOOTING);
- if ((rval = zone_ready(zlogp, B_FALSE)) == 0)
+ if ((rval = zone_ready(zlogp, Z_MNT_BOOT)) == 0)
rval = zone_bootup(zlogp, zargp->bootbuf);
audit_put_record(zlogp, uc, rval, "boot");
if (rval != 0) {
@@ -1089,7 +1089,9 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp,
break;
}
- rval = zone_ready(zlogp, B_TRUE);
+ rval = zone_ready(zlogp,
+ strcmp(zargp->bootbuf, "-U") == 0 ?
+ Z_MNT_UPDATE : Z_MNT_SCRATCH);
if (rval != 0)
break;
@@ -1209,7 +1211,7 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp,
case Z_READY:
if ((rval = zone_halt(zlogp, B_FALSE, B_TRUE)) != 0)
break;
- if ((rval = zone_ready(zlogp, B_FALSE)) == 0)
+ if ((rval = zone_ready(zlogp, Z_MNT_BOOT)) == 0)
eventstream_write(Z_EVT_ZONE_READIED);
else
eventstream_write(Z_EVT_ZONE_HALTED);
@@ -1238,7 +1240,7 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp,
boot_args[0] = '\0';
break;
}
- if ((rval = zone_ready(zlogp, B_FALSE)) != 0) {
+ if ((rval = zone_ready(zlogp, Z_MNT_BOOT)) != 0) {
eventstream_write(Z_EVT_ZONE_BOOTFAILED);
boot_args[0] = '\0';
break;
diff --git a/usr/src/cmd/zoneadmd/zoneadmd.h b/usr/src/cmd/zoneadmd/zoneadmd.h
index d8612b73b9..f7e2114666 100644
--- a/usr/src/cmd/zoneadmd/zoneadmd.h
+++ b/usr/src/cmd/zoneadmd/zoneadmd.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -111,10 +111,23 @@ extern int eventstream_init();
extern void eventstream_write(zone_evt_t evt);
/*
+ * Zone mount styles. Boot is the standard mount we do when booting the zone,
+ * scratch is the standard scratch zone mount for upgrade and update is a
+ * variation on the scratch zone where we don't lofs mount the zone's /etc
+ * and /var back into the scratch zone so that we can then do an
+ * 'update on attach' within the scratch zone.
+ */
+typedef enum {
+ Z_MNT_BOOT = 0,
+ Z_MNT_SCRATCH,
+ Z_MNT_UPDATE
+} zone_mnt_t;
+
+/*
* Virtual platform interfaces.
*/
-extern zoneid_t vplat_create(zlog_t *, boolean_t);
-extern int vplat_bringup(zlog_t *, boolean_t, zoneid_t);
+extern zoneid_t vplat_create(zlog_t *, zone_mnt_t);
+extern int vplat_bringup(zlog_t *, zone_mnt_t, zoneid_t);
extern int vplat_teardown(zlog_t *, boolean_t, boolean_t);
/*
diff --git a/usr/src/head/libzonecfg.h b/usr/src/head/libzonecfg.h
index 2eaf2e218a..ec122addda 100644
--- a/usr/src/head/libzonecfg.h
+++ b/usr/src/head/libzonecfg.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -50,6 +50,7 @@ extern "C" {
#include <zone.h>
#include <libbrand.h>
#include <sys/uuid.h>
+#include <libuutil.h>
#define ZONE_ID_UNDEFINED -1
@@ -239,6 +240,13 @@ struct zone_devpermtab {
char *zone_devperm_acl;
};
+typedef struct {
+ uu_avl_node_t zpe_entry;
+ char *zpe_name;
+ char *zpe_vers;
+ uu_avl_t *zpe_patches_avl;
+} zone_pkg_entry_t;
+
typedef enum zone_iptype {
ZS_SHARED,
ZS_EXCLUSIVE
@@ -457,12 +465,8 @@ extern int zonecfg_getdsent(zone_dochandle_t, struct zone_dstab *);
extern int zonecfg_enddsent(zone_dochandle_t);
extern int zonecfg_getpsetent(zone_dochandle_t, struct zone_psettab *);
extern int zonecfg_getmcapent(zone_dochandle_t, struct zone_mcaptab *);
-extern int zonecfg_setpkgent(zone_dochandle_t);
-extern int zonecfg_getpkgent(zone_dochandle_t, struct zone_pkgtab *);
-extern int zonecfg_endpkgent(zone_dochandle_t);
-extern int zonecfg_setpatchent(zone_dochandle_t);
-extern int zonecfg_getpatchent(zone_dochandle_t, struct zone_patchtab *);
-extern int zonecfg_endpatchent(zone_dochandle_t);
+extern int zonecfg_getpkgdata(zone_dochandle_t, uu_avl_pool_t *,
+ uu_avl_t *);
extern int zonecfg_setdevperment(zone_dochandle_t);
extern int zonecfg_getdevperment(zone_dochandle_t,
struct zone_devpermtab *);
diff --git a/usr/src/lib/brand/native/zone/Makefile b/usr/src/lib/brand/native/zone/Makefile
index 6912c2dd0f..1d1a92fe92 100644
--- a/usr/src/lib/brand/native/zone/Makefile
+++ b/usr/src/lib/brand/native/zone/Makefile
@@ -20,14 +20,14 @@
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
#
BRAND= native
-PROGS= postclone
+PROGS= postclone attach_update
XMLDOCS= config.xml platform.xml
TEMPLATES= SUNWdefault.xml SUNWblank.xml
diff --git a/usr/src/lib/brand/native/zone/attach_update.ksh b/usr/src/lib/brand/native/zone/attach_update.ksh
new file mode 100755
index 0000000000..1cc7f87650
--- /dev/null
+++ b/usr/src/lib/brand/native/zone/attach_update.ksh
@@ -0,0 +1,626 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+#
+# This script runs within the scratch zone and updates the dependent files and
+# pkg metadata within the zone to match the global zone.
+#
+# The algorithm for this is as follows:
+# 1) Build the list of editable files and files to install based on the
+# dependent pkgs. This is done in get_ed_cp_list().
+# Editable files are saved in gz_ed_list.
+# Files to install are saved in gz_cp_list
+# get_ed_cp_list() makes a pass through the global zone's contents file.
+# 2) Build the list of files to remove in get_rm_list().
+# Files to remove are saved in rmlist.
+# The zone's editable files are saved in ngz_ed_list.
+# At the end we figure out which zone editable files are obsolete and those
+# are added to the rmlist.
+# get_rm_list() makes a pass through the non-global zone's contents file.
+# 3) Remove the files listed in remove_files
+# 4) Remove the old pkg metadata listed in remove_pkg
+# 5) Copy files from the scratch zone (i.e. global zone) into the zone using
+# the gz_cp_list file. Do this by running cpio.
+# 6) Update the pkg metadata for the new pkgs using add_pkg.
+# 7) Fix the editable file entries in the contents file using installf.
+#
+# We don't have to remove or add the pkg's in dependency order since we are
+# not doing normal pkgrm or pkgadd operations. We are simply updating pkg
+# metadata with those commands. The actual files will already be installed
+# separately from the base files in the global zone using the same approach we
+# use when we install a fresh zone.
+#
+# The script uses the following data files during the update process:
+# pkg_rm - list of pkgs to remove - provided by zoneadm
+# pkg_add - list of pkgs to add - provided by zoneadm
+# inherited - list of ipd's - provided by zoneadm
+#
+# gz_ed_list - generated in get_ed_cp_list - GZ editable files
+# gz_cp_list - generated in get_ed_cp_list - files to copy from GZ
+# rmlist - generated in get_rm_list - list of file to remove
+# ngz_ed_list - generated in get_rm_list - NGZ editable files
+# These files are stored in the scratch zone /tmp so there won't be any
+# name conflicts with existing tmp files.
+#
+
+fatal()
+{
+ printf "${e_fatal}\n" "$@" >>$LOGFILE
+ printf "${e_fatal}\n" "$@"
+ printf "${v_loginfo}\n"
+ exit 1
+}
+
+verbose_log()
+{
+ printf "$@" >>$LOGFILE
+ printf "$@"
+}
+
+# Clean up on interrupt
+trap_cleanup()
+{
+ printf "${e_intr}\n" >>$LOGFILE
+ printf "${e_intr}\n"
+ exit 1
+}
+
+save_to_log()
+{
+ FILENAME=$1
+
+ echo "***** $FILENAME *****" >>$LOGFILE
+ cat /tmp/$FILENAME >>$LOGFILE
+ echo >>$LOGFILE
+}
+
+# 1) Build the list of editable files and files to install based on the
+# dependent pkgs.
+# Processes the GZ contents file.
+get_ed_cp_list()
+{
+ nawk '
+ BEGIN {
+ # Get the list of pkgs to add and see if they are hollow pkgs.
+ while (getline p <"/tmp/pkg_add" > 0) {
+ pkgs[p] = 1;
+
+ pkginfo="/var/sadm/pkg/" p "/pkginfo";
+ while (getline pi <pkginfo > 0) {
+ if (pi ~ "SUNW_PKG_HOLLOW=true") {
+ hollow[p] = 1;
+ break;
+ }
+ }
+ close(pkginfo);
+ }
+ close("/tmp/pkg_add");
+
+ load_inherited();
+ ndirs=0;
+ }
+ {
+ # Read entries in the contents file, figure out what kind of
+ # entry this is and where the pkg data is.
+ # tp indicates what type of entry this is:
+ # editable or volatile files are tp == 0
+ # files are tp == 1
+ # dirs are tp == 2
+ # symlinks or hardlinks are tp == 1
+ # fld is the field where the pkg names begin.
+ # nm is the file/dir entry name.
+ if ($2 == "e" || $2 == "v") {
+ fld=10;
+ nm=$1;
+ tp=0;
+ } else if ($2 == "f") {
+ fld=10;
+ nm=$1;
+ tp=1;
+ } else if ($2 == "d") {
+ fld=7;
+ nm=$1;
+ tp=2;
+ } else if ($2 == "s" || $2 == "l") {
+ fld=4;
+ split($1, a, "=");
+ nm=a[1];
+ tp=1;
+ } else {
+ next;
+ }
+
+ # Skip it if it is in an ipd.
+ if (is_inherited(nm))
+ next;
+
+ # Determine if this entry is part of a pkg to install
+ # and if it is in a hollow pkg.
+ installpkg = 0;
+ nhollow = 0;
+ for (i = fld; i <= NF; i++) {
+ pname = get_pkg_name($i)
+
+ if (pkgs[pname] == 1)
+ installpkg = 1;
+ if (hollow[pname] == 1)
+ nhollow++;
+ }
+
+ if (installpkg == 0)
+ next;
+
+ # If this entry is only in hollow pkgs, skip it.
+ if (nhollow >= (NF - fld + 1))
+ next;
+
+ if (tp == 0) {
+ # editable or volatile file
+ printf("/a%s\n", nm) >>"/tmp/gz_ed_list";
+ } else if (tp == 1) {
+ # regular file or link
+ printf("%s\n", nm) > "/tmp/gz_cp_list";
+ } else {
+ # directory
+ dirs[ndirs++] = nm;
+ }
+ }
+ END {
+ for (i = ndirs - 1; i >= 0; i--)
+ printf("%s\n", dirs[i]) > "/tmp/gz_cp_list";
+ }
+
+ # Get the list of inherited directories.
+ # We are creating an array of regular expression matches here.
+ function load_inherited() {
+ nint=0
+ while (getline p <"/tmp/inherited" > 0) {
+ inherited[nint] = "^" p "/";
+ nint++;
+ inherited[nint] = "^" p "$";
+ nint++;
+ }
+ close("/tmp/inherited");
+ }
+
+ # Check if this entry is in an inherited-pkg-dir.
+ function is_inherited(nm) {
+ for (i = 0; i < nint; i++) {
+ if (nm ~ inherited[i])
+ return (1);
+ }
+ return (0);
+ }
+
+ # Get the clean pkg name from the fld entry.
+ function get_pkg_name(fld) {
+ # Remove any pkg control prefix (e.g. *, !)
+ first = substr(fld, 1, 1)
+ if (match(first, /[A-Za-z]/)) {
+ pname = fld
+ } else {
+ pname = substr(fld, 2)
+ }
+
+ # Then remove any class action script name
+ pos = index(pname, ":")
+ if (pos != 0)
+ pname = substr(pname, 1, pos - 1)
+
+ return (pname)
+ }
+
+ ' /var/sadm/install/contents || fatal "get_ed_cp_list"
+}
+
+create_admin_file()
+{
+ cat <<-EOF > /tmp/admin.dflt || fatal "create_admin_file"
+ mail=
+ instance=overwrite
+ partial=nocheck
+ runlevel=nocheck
+ idepend=nocheck
+ rdepend=nocheck
+ space=nocheck
+ setuid=nocheck
+ conflict=nocheck
+ action=nocheck
+ basedir=default
+ EOF
+}
+
+# 2) Build the list of files to remove.
+# Similar structure to get_ed_cp_list() but we're processing the NGZ contents
+# file.
+get_rm_list()
+{
+ nawk '
+ BEGIN {
+ while (getline p <"/tmp/pkg_rm" > 0)
+ pkgs[p] = 1;
+ close("/tmp/pkg_rm");
+ load_inherited();
+ }
+ {
+ # fld is the field where the pkg names begin.
+ # nm is the file/dir entry name.
+ # rm is set if we should remove the entry.
+ if ($2 == "e" || $2 == "v") {
+ fld=10;
+ nm=$1;
+ rm=0;
+ } else if ($2 == "f") {
+ fld=10;
+ nm=$1;
+ rm=1;
+ } else if ($2 == "d") {
+ fld=7;
+ nm=$1;
+ rm=1;
+ } else if ($2 == "s" || $2 == "l") {
+ fld=4;
+ split($1, a, "=");
+ nm=a[1];
+ rm=1;
+ } else {
+ next;
+ }
+
+ # Skip it if it is in an ipd.
+ if (is_inherited(nm))
+ next;
+
+ # Check if this entry is part of a pkg to remove. Files,
+ # including editable files, can be delivered by multiple pkgs.
+ # We should only add this entry to the rm list or ed list if
+ # all of the pkgs delivering this entry are being removed.
+ for (i = fld; i <= NF; i++) {
+ pname = get_pkg_name($i)
+
+ # If this is in a pkg we are not removing, we are done.
+ if (pkgs[pname] == 0)
+ next;
+ }
+
+ if (rm == 1)
+ printf("/a%s\n", nm) >>"/tmp/rmlist";
+ else
+ printf("/a%s\n", nm) >>"/tmp/ngz_ed_list";
+
+ }
+
+ # Get the list of inherited directories.
+ # We are creating an array of regular expression matches here.
+ function load_inherited() {
+ nint=0
+ while (getline p <"/tmp/inherited" > 0) {
+ inherited[nint] = "^" p "/";
+ nint++;
+ inherited[nint] = "^" p "$";
+ nint++;
+ }
+ close("/tmp/inherited");
+ }
+
+ # Check if this entry is in an inherited-pkg-dir.
+ function is_inherited(nm) {
+ for (i = 0; i < nint; i++) {
+ if (nm ~ inherited[i])
+ return (1);
+ }
+ return (0);
+ }
+
+ # Get the clean pkg name from the fld entry.
+ function get_pkg_name(fld) {
+ # Remove any pkg control prefix (e.g. *, !)
+ first = substr(fld, 1, 1)
+ if (match(first, /[A-Za-z]/)) {
+ pname = fld
+ } else {
+ pname = substr(fld, 2)
+ }
+
+ # Then remove any class action script name
+ pos = index(pname, ":")
+ if (pos != 0)
+ pname = substr(pname, 1, pos - 1)
+
+ return (pname)
+ }
+
+ ' /a/var/sadm/install/contents || fatal "get_rm_list"
+
+ # Add the obsolete editable files to the rm list.
+ # comm assumes the files are sorted. Since the contents file is
+ # sorted and we wrote the files as we processed the contents file,
+ # these files are already sorted.
+ comm -13 /tmp/gz_ed_list /tmp/ngz_ed_list >>/tmp/rmlist || \
+ fatal "get_rm_list"
+}
+
+remove_files()
+{
+ for path in `cat /tmp/rmlist`
+ do
+ if [ "$path" != "" ] ; then
+ # Check for symlink first since -d follows links.
+ if [ -h $path ]; then
+ rm -f $path || fatal "remove_files"
+ elif [ -d $path ]; then
+ # ignore errs since dir might not be empty
+ rmdir $path >/dev/null 2>&1
+ else
+ rm -f $path || fatal "remove_files"
+ fi
+ fi
+ done
+}
+
+remove_pkg()
+{
+ PKG=$1
+ NUM=$2
+ CNT=$3
+
+ # pkgremove options:
+ # -a same as public pkgrm option
+ # -F private - used by upgrade to suppress actual removal of files
+ # delivered by the pkg
+ # -M same as public pkgrm option
+ # -n same as public pkgrm option
+ # -O inherited-filesystem={IPD} private - used to specify the zone's
+ # inherited-pkg-dir entries
+ # -R same as public pkgrm option
+ /usr/sadm/install/bin/pkgremove -R /a -M -F -a /tmp/admin.dflt -n \
+ $IPDS $PKG >>$LOGFILE 2>&1
+ errcode=$?
+ printf "${v_rmpkgs}" $NUM $CNT
+ # errcode 99 means the pkg doesn't exist.
+ if [ $errcode -ne 0 -a $errcode -ne 99 ]; then
+ ERR_PKGS=`echo $ERR_PKGS $PKG`
+ fi
+}
+
+add_pkg()
+{
+ PKG=$1
+ NUM=$2
+ CNT=$3
+
+ echo "===== ${PKG} ====" >>$LOGFILE
+ # pkginstall options:
+ # -a same as public pkgrm option
+ # -C private - disable checksums since files are installed via a
+ # separate copy from the global zone
+ # -h private - enable hollow pkg support
+ # -N pkgadd private - error msgs use the name "pkgadd" instead
+ # of "pkginstall"
+ # -n same as public pkgrm option
+ # -O addzonename private - error msgs include zonename
+ # -O inherited-filesystem={IPD} private - used to specify the zone's
+ # inherited-pkg-dir entries
+ # -R same as public pkgrm option
+ # -S private - suppress copyright output
+ # -t private - suppress spooled pkg creation
+ # -z private - install zone pkg data from spooled pkg data
+ /usr/sadm/install/bin/pkginstall -S -A -C -N pkgadd -R /a \
+ -a /etc/lu/zones_pkgadd_admin -h -n -t -z $IPDS -O addzonename \
+ /var/sadm/pkg/${PKG}/save/pspool $PKG >>$LOGFILE 2>&1
+ errcode=$?
+ printf "${v_addpkgs}" $NUM $CNT
+ if [ $errcode -ne 0 ]; then
+ ERR_PKGS=`echo $ERR_PKGS $PKG`
+ fi
+}
+
+# installf the editable file so that the pkg metadata is correct.
+finalize()
+{
+ nawk -v lf=$LOGFILE '
+ BEGIN {
+ logfile = " >>" lf " 2>&1"
+
+ while (getline e <"/tmp/ngz_ed_list" > 0) {
+ # remove /a/ prefix from the name
+ nm=substr(e, 3)
+ ed_path[nm] = 1;
+ }
+ close("/tmp/ngz_ed_list");
+ }
+ {
+ if ($2 != "e" && $2 != "v")
+ next;
+
+ # For the contents file format:
+ # editable and volatile entry pkg names start at field 10
+ # $1 is filename, $2 is type (e or v), $3 is class name
+ # That is:
+ # installf -R /a -c class pkgname filename type
+ for (i = 10; i <= NF; i++) {
+ if (ed_path[$1] == 1) {
+ pname = get_pkg_name($i)
+
+ pkg[pname] = 1;
+ printf("%s\n", $1);
+ basecmd = "/usr/sbin/installf -R /a -c "
+ cmd = basecmd $3 " " pname " " $1 " " $2 logfile
+ if (system(cmd) != 0)
+ printf("ERROR: %s\n", cmd);
+ }
+ }
+ }
+ END {
+ for (p in pkg) {
+ printf("Finalize %s\n", p);
+ cmd = "/usr/sbin/installf -R /a -f " p logfile
+ if (system(cmd) != 0)
+ printf("ERROR: %s\n", cmd);
+ }
+ }
+
+ # Get the clean pkg name from the fld entry.
+ function get_pkg_name(fld) {
+ # Remove any pkg control prefix (e.g. *, !)
+ first = substr(fld, 1, 1)
+ if (match(first, /[A-Za-z]/)) {
+ pname = fld
+ } else {
+ pname = substr(fld, 2)
+ }
+
+ # Then remove any class action script name
+ pos = index(pname, ":")
+ if (pos != 0)
+ pname = substr(pname, 1, pos - 1)
+
+ return (pname)
+ }
+
+ ' /a/var/sadm/install/contents >>$LOGFILE || fatal "finalize"
+}
+
+PATH=/sbin:/usr/bin:/usr/sbin; export PATH
+
+SUNW_PKG_INSTALL_ZONENAME=$1
+export SUNW_PKG_INSTALL_ZONENAME
+
+# Setup i18n output
+TEXTDOMAIN="SUNW_OST_OSCMD"
+export TEXTDOMAIN
+
+v_gathering=$(gettext "Getting the list of files to remove")
+v_rmfiles=$(gettext "Removing %d files")
+v_rmpkgs=$(gettext "Remove %d of %d packages\r")
+v_instfiles=$(gettext "Installing %d files")
+v_addpkgs=$(gettext "Add %d of %d packages\r")
+v_updating=$(gettext "Updating editable files")
+v_loginfo=$(gettext "The file </var/sadm/system/logs/update_log> within the zone contains a log of the zone update.")
+e_intr=$(gettext "update cancelled due to interrupt")
+e_rmpkgs=$(gettext "Problems removing the following pkgs: %s")
+e_instkgs=$(gettext "Installation of these packages generated warnings: %s")
+e_fatal=$(gettext "ERROR: zone update fatal error at: %s")
+
+LOGFILE=/a/var/sadm/system/logs/update_log
+
+if [ -f $LOGFILE ]; then
+ tmpnm=$LOGFILE.`date +%y%m%d-%H:%M:%S`
+ mv $LOGFILE $tmpnm || fatal "backup log file"
+fi
+
+trap trap_cleanup INT
+
+echo "`date`" >$LOGFILE
+echo >>$LOGFILE
+
+# Save file lists to LOGFILE
+save_to_log inherited
+save_to_log pkg_rm
+save_to_log pkg_add
+
+printf "${v_gathering}\n"
+
+# Make sure we have these files, even though they might be empty.
+touch /tmp/gz_ed_list /tmp/ngz_ed_list /tmp/gz_cp_list || fatal "touch files"
+
+# Get the list of editable files for the dependent pkgs. We do this to make
+# sure we delete obsolete editable files as part of the removal of the files
+# within the zone. In the same pass through the contents file we get the
+# list of files to copy into the zone.
+get_ed_cp_list
+
+save_to_log gz_cp_list
+save_to_log gz_ed_list
+
+get_rm_list
+sort -r -o /tmp/rmlist /tmp/rmlist || fatal "sort rmlist"
+
+save_to_log ngz_ed_list
+save_to_log rmlist
+
+CNT=`wc -l /tmp/rmlist | nawk '{print $1}'`
+verbose_log "${v_rmfiles}\n" $CNT
+remove_files
+
+IPDS=""
+for i in `cat /tmp/inherited`
+do
+ IPDS=`echo $IPDS -O inherited-filesystem=$i`
+done
+
+create_admin_file
+
+echo "***** remove_pkg *****" >>$LOGFILE
+
+ERR_PKGS=""
+CNT=`wc -l /tmp/pkg_rm | nawk '{print $1}'`
+num=1
+for i in `cat /tmp/pkg_rm`
+do
+ remove_pkg $i $num $CNT
+ num=`expr $num + 1`
+done
+
+echo
+if [ -n "$ERR_PKGS" ]; then
+ verbose_log "${e_rmpkgs}\n" "$ERR_PKGS"
+fi
+
+echo >>$LOGFILE
+
+CNT=`wc -l /tmp/gz_cp_list | nawk '{print $1}'`
+verbose_log "${v_instfiles}\n" $CNT
+echo "***** cpio *****" >>$LOGFILE
+cpio -pcdmu /a < /tmp/gz_cp_list >>$LOGFILE 2>&1
+
+echo >>$LOGFILE
+echo "***** add_pkg *****" >>$LOGFILE
+
+ERR_PKGS=""
+CNT=`wc -l /tmp/pkg_add | nawk '{print $1}'`
+num=1
+for i in `cat /tmp/pkg_add`
+do
+ add_pkg $i $num $CNT
+ num=`expr $num + 1`
+done
+
+echo
+if [ -n "$ERR_PKGS" ]; then
+ verbose_log "${e_instkgs}\n" "$ERR_PKGS"
+fi
+
+echo >>$LOGFILE
+echo "***** finalize *****" >>$LOGFILE
+
+verbose_log "${v_updating}\n"
+finalize
+
+verbose_log "${v_loginfo}\n"
+
+exit 0
diff --git a/usr/src/lib/libzonecfg/common/libzonecfg.c b/usr/src/lib/libzonecfg/common/libzonecfg.c
index 6fac6b36f9..94644741dd 100644
--- a/usr/src/lib/libzonecfg/common/libzonecfg.c
+++ b/usr/src/lib/libzonecfg/common/libzonecfg.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -89,6 +89,7 @@
#define DTD_ELEM_MCAP (const xmlChar *) "mcap"
#define DTD_ELEM_PACKAGE (const xmlChar *) "package"
#define DTD_ELEM_PATCH (const xmlChar *) "patch"
+#define DTD_ELEM_OBSOLETES (const xmlChar *) "obsoletes"
#define DTD_ELEM_DEV_PERM (const xmlChar *) "dev-perm"
#define DTD_ATTR_ACTION (const xmlChar *) "action"
@@ -226,9 +227,15 @@ typedef struct {
uu_avl_node_t patch_node;
char *patch_num;
char *patch_vers;
+ uu_list_t *obs_patches;
} patch_node_t;
typedef struct {
+ uu_list_node_t link;
+ char *patch_num;
+} obs_patch_node_t;
+
+typedef struct {
uu_avl_t *obs_patches_avl;
zone_dochandle_t handle;
int res;
@@ -6504,94 +6511,214 @@ zonecfg_getmcapent(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
return (err);
}
+/*
+ * Get the full tree of pkg/patch metadata in a set of nested AVL trees.
+ * pkgs_avl is an AVL tree of pkgs. Each pkg element contains a
+ * zpe_patches_avl member which holds an AVL tree of patches for that pkg.
+ * The patch elements have the same zpe_patches_avl member, each of which can
+ * hold an AVL tree of patches that are obsoleted by the patch.
+ *
+ * The zone xml data contains DTD_ELEM_PACKAGE elements, followed by
+ * DTD_ELEM_PATCH elements. The DTD_ELEM_PATCH patch element applies to the
+ * DTD_ELEM_PACKAGE that precedes it. The DTD_ELEM_PATCH element may have
+ * child DTD_ELEM_OBSOLETES nodes associated with it. The DTD_ELEM_PACKAGE
+ * really should have had the DTD_ELEM_PATCH elements as children but it
+ * was not defined that way initially so we are stuck with the DTD definition
+ * now. However, we can safely assume the ordering for compatibility.
+ */
int
-zonecfg_setpkgent(zone_dochandle_t handle)
-{
- return (zonecfg_setent(handle));
-}
-
-int
-zonecfg_getpkgent(zone_dochandle_t handle, struct zone_pkgtab *tabptr)
+zonecfg_getpkgdata(zone_dochandle_t handle, uu_avl_pool_t *pkg_pool,
+ uu_avl_t *pkgs_avl)
{
xmlNodePtr cur;
- int err;
+ int res;
+ zone_pkg_entry_t *pkg;
+ char name[MAXNAMELEN];
+ char version[ZONE_PKG_VERSMAX];
if (handle == NULL)
return (Z_INVAL);
- if ((cur = handle->zone_dh_cur) == NULL)
- return (Z_NO_ENTRY);
+ if ((res = zonecfg_setent(handle)) != Z_OK)
+ return (res);
- for (; cur != NULL; cur = cur->next)
- if (!xmlStrcmp(cur->name, DTD_ELEM_PACKAGE))
- break;
- if (cur == NULL) {
- handle->zone_dh_cur = handle->zone_dh_top;
- return (Z_NO_ENTRY);
+ if ((cur = handle->zone_dh_cur) == NULL) {
+ res = Z_NO_ENTRY;
+ goto done;
}
- if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_pkg_name,
- sizeof (tabptr->zone_pkg_name))) != Z_OK) {
- handle->zone_dh_cur = handle->zone_dh_top;
- return (err);
- }
+ for (; cur != NULL; cur = cur->next) {
+ if (xmlStrcmp(cur->name, DTD_ELEM_PACKAGE) == 0) {
+ uu_avl_index_t where;
- if ((err = fetchprop(cur, DTD_ATTR_VERSION, tabptr->zone_pkg_version,
- sizeof (tabptr->zone_pkg_version))) != Z_OK) {
- handle->zone_dh_cur = handle->zone_dh_top;
- return (err);
- }
+ if ((res = fetchprop(cur, DTD_ATTR_NAME, name,
+ sizeof (name))) != Z_OK)
+ goto done;
- handle->zone_dh_cur = cur->next;
- return (Z_OK);
-}
+ if ((res = fetchprop(cur, DTD_ATTR_VERSION, version,
+ sizeof (version))) != Z_OK)
+ goto done;
-int
-zonecfg_endpkgent(zone_dochandle_t handle)
-{
- return (zonecfg_endent(handle));
-}
+ if ((pkg = (zone_pkg_entry_t *)
+ malloc(sizeof (zone_pkg_entry_t))) == NULL) {
+ res = Z_NOMEM;
+ goto done;
+ }
-int
-zonecfg_setpatchent(zone_dochandle_t handle)
-{
- return (zonecfg_setent(handle));
-}
+ if ((pkg->zpe_name = strdup(name)) == NULL) {
+ free(pkg);
+ res = Z_NOMEM;
+ goto done;
+ }
-int
-zonecfg_getpatchent(zone_dochandle_t handle, struct zone_patchtab *tabptr)
-{
- xmlNodePtr cur;
- int err;
+ if ((pkg->zpe_vers = strdup(version)) == NULL) {
+ free(pkg->zpe_name);
+ free(pkg);
+ res = Z_NOMEM;
+ goto done;
+ }
- if (handle == NULL)
- return (Z_INVAL);
+ pkg->zpe_patches_avl = NULL;
- if ((cur = handle->zone_dh_cur) == NULL)
- return (Z_NO_ENTRY);
+ uu_avl_node_init(pkg, &pkg->zpe_entry, pkg_pool);
+ if (uu_avl_find(pkgs_avl, pkg, NULL, &where) != NULL) {
+ free(pkg->zpe_name);
+ free(pkg->zpe_vers);
+ free(pkg);
+ } else {
+ uu_avl_insert(pkgs_avl, pkg, where);
+ }
- for (; cur != NULL; cur = cur->next)
- if (!xmlStrcmp(cur->name, DTD_ELEM_PATCH))
- break;
- if (cur == NULL) {
- handle->zone_dh_cur = handle->zone_dh_top;
- return (Z_NO_ENTRY);
- }
+ } else if (xmlStrcmp(cur->name, DTD_ELEM_PATCH) == 0) {
+ zone_pkg_entry_t *patch;
+ uu_avl_index_t where;
+ char *p;
+ char *dashp = NULL;
+ xmlNodePtr child;
- if ((err = fetchprop(cur, DTD_ATTR_ID, tabptr->zone_patch_id,
- sizeof (tabptr->zone_patch_id))) != Z_OK) {
- handle->zone_dh_cur = handle->zone_dh_top;
- return (err);
- }
+ if ((res = fetchprop(cur, DTD_ATTR_ID, name,
+ sizeof (name))) != Z_OK)
+ goto done;
- handle->zone_dh_cur = cur->next;
- return (Z_OK);
-}
+ if ((patch = (zone_pkg_entry_t *)
+ malloc(sizeof (zone_pkg_entry_t))) == NULL) {
+ res = Z_NOMEM;
+ goto done;
+ }
-int
-zonecfg_endpatchent(zone_dochandle_t handle)
-{
- return (zonecfg_endent(handle));
+ if ((p = strchr(name, '-')) != NULL) {
+ dashp = p;
+ *p++ = '\0';
+ } else {
+ p = "";
+ }
+
+ if ((patch->zpe_name = strdup(name)) == NULL) {
+ free(patch);
+ res = Z_NOMEM;
+ goto done;
+ }
+
+ if ((patch->zpe_vers = strdup(p)) == NULL) {
+ free(patch->zpe_name);
+ free(patch);
+ res = Z_NOMEM;
+ goto done;
+ }
+
+ if (dashp != NULL)
+ *dashp = '-';
+
+ patch->zpe_patches_avl = NULL;
+
+ if (pkg->zpe_patches_avl == NULL) {
+ pkg->zpe_patches_avl = uu_avl_create(pkg_pool,
+ NULL, UU_DEFAULT);
+ if (pkg->zpe_patches_avl == NULL) {
+ free(patch->zpe_name);
+ free(patch->zpe_vers);
+ free(patch);
+ res = Z_NOMEM;
+ goto done;
+ }
+ }
+
+ uu_avl_node_init(patch, &patch->zpe_entry, pkg_pool);
+ if (uu_avl_find(pkg->zpe_patches_avl, patch, NULL,
+ &where) != NULL) {
+ free(patch->zpe_name);
+ free(patch->zpe_vers);
+ free(patch);
+ } else {
+ uu_avl_insert(pkg->zpe_patches_avl, patch,
+ where);
+ }
+
+ /* Add any patches this patch obsoletes. */
+ for (child = cur->xmlChildrenNode; child != NULL;
+ child = child->next) {
+ zone_pkg_entry_t *obs;
+
+ if (xmlStrcmp(child->name, DTD_ELEM_OBSOLETES)
+ != 0)
+ continue;
+
+ if ((res = fetchprop(child, DTD_ATTR_ID,
+ name, sizeof (name))) != Z_OK)
+ goto done;
+
+ if ((obs = (zone_pkg_entry_t *)malloc(
+ sizeof (zone_pkg_entry_t))) == NULL) {
+ res = Z_NOMEM;
+ goto done;
+ }
+
+ if ((obs->zpe_name = strdup(name)) == NULL) {
+ free(obs);
+ res = Z_NOMEM;
+ goto done;
+ }
+ /*
+ * The version doesn't matter for obsoleted
+ * patches.
+ */
+ obs->zpe_vers = NULL;
+ obs->zpe_patches_avl = NULL;
+
+ /*
+ * If this is the first obsolete patch, add an
+ * AVL tree to the parent patch element.
+ */
+ if (patch->zpe_patches_avl == NULL) {
+ patch->zpe_patches_avl =
+ uu_avl_create(pkg_pool, NULL,
+ UU_DEFAULT);
+ if (patch->zpe_patches_avl == NULL) {
+ free(obs->zpe_name);
+ free(obs);
+ res = Z_NOMEM;
+ goto done;
+ }
+ }
+
+ /* Insert obsolete patch into the AVL tree. */
+ uu_avl_node_init(obs, &obs->zpe_entry,
+ pkg_pool);
+ if (uu_avl_find(patch->zpe_patches_avl, obs,
+ NULL, &where) != NULL) {
+ free(obs->zpe_name);
+ free(obs);
+ } else {
+ uu_avl_insert(patch->zpe_patches_avl,
+ obs, where);
+ }
+ }
+ }
+ }
+
+done:
+ (void) zonecfg_endent(handle);
+ return (res);
}
int
@@ -7065,13 +7192,43 @@ dir_pkg(char *pkg_name, char **pkg_list, int cnt)
}
/*
+ * Keep track of obsoleted patches for this specific patch. We don't need to
+ * keep track of the patch version since once a patch is obsoleted, all prior
+ * versions are also obsolete and there won't be any new versions.
+ */
+static int
+add_obs_patch(patch_node_t *patch, char *num, uu_list_pool_t *patches_pool)
+{
+ obs_patch_node_t *obs;
+
+ if (patch->obs_patches == NULL) {
+ if ((patch->obs_patches = uu_list_create(patches_pool, NULL,
+ 0)) == NULL)
+ return (Z_NOMEM);
+ }
+
+ if ((obs = (obs_patch_node_t *)malloc(sizeof (obs_patch_node_t)))
+ == NULL)
+ return (Z_NOMEM);
+
+ if ((obs->patch_num = strdup(num)) == NULL) {
+ free(obs);
+ return (Z_NOMEM);
+ }
+
+ uu_list_node_init(obs, &obs->link, patches_pool);
+ (void) uu_list_insert_before(patch->obs_patches, NULL, obs);
+
+ return (Z_OK);
+}
+
+/*
* Keep track of obsoleted patches. We don't need to keep track of the patch
* version since once a patch is obsoleted, all prior versions are also
* obsolete and there won't be any new versions.
*/
static int
-save_obs_patch(char *num, uu_avl_pool_t *patches_pool,
- uu_avl_t *obs_patches_avl)
+save_obs_patch(char *num, uu_avl_pool_t *patches_pool, uu_avl_t *obs_patches)
{
patch_node_t *patch;
uu_avl_index_t where;
@@ -7085,15 +7242,17 @@ save_obs_patch(char *num, uu_avl_pool_t *patches_pool,
}
patch->patch_vers = NULL;
+ patch->obs_patches = NULL;
+
uu_avl_node_init(patch, &patch->patch_node, patches_pool);
- if (uu_avl_find(obs_patches_avl, patch, NULL, &where) != NULL) {
+ if (uu_avl_find(obs_patches, patch, NULL, &where) != NULL) {
free(patch->patch_num);
free(patch);
return (Z_OK);
}
- uu_avl_insert(obs_patches_avl, patch, where);
+ uu_avl_insert(obs_patches, patch, where);
return (Z_OK);
}
@@ -7134,11 +7293,11 @@ save_patch(patch_node_t *patch, uu_avl_t *patches_avl)
* are also obsolete and there won't be any new versions.
*/
static boolean_t
-obsolete_patch(patch_node_t *patch, uu_avl_t *obs_patches_avl)
+obsolete_patch(patch_node_t *patch, uu_avl_t *obs_patches)
{
uu_avl_index_t where;
- if (uu_avl_find(obs_patches_avl, patch, NULL, &where) != NULL)
+ if (uu_avl_find(obs_patches, patch, NULL, &where) != NULL)
return (B_TRUE);
return (B_FALSE);
@@ -7172,12 +7331,13 @@ patch_node_compare(const void *l_arg, const void *r_arg, void *private)
* 119255-06 Incompatibles:
*
* A backed out patch will have "backed out\n" as the status. We should
- * skip these patches. We also also ignore any entries that seem to be
- * corrupted.
+ * skip these patches. We also ignore any entries that seem to be
+ * corrupted. Obsolete patches are saved in the obs_patches parameter
+ * AVL list.
*/
static int
parse_info(char *patchinfo, uu_avl_pool_t *patches_pool, uu_avl_t *patches_avl,
- uu_avl_t *obs_patches_avl)
+ uu_avl_t *obs_patches, uu_list_pool_t *list_pool)
{
char *p;
char *lastp;
@@ -7222,6 +7382,7 @@ parse_info(char *patchinfo, uu_avl_pool_t *patches_pool, uu_avl_t *patches_avl,
free(patch);
return (Z_NOMEM);
}
+ patch->obs_patches = NULL;
uu_avl_node_init(patch, &patch->patch_node, patches_pool);
save_patch(patch, patches_avl);
@@ -7251,7 +7412,17 @@ parse_info(char *patchinfo, uu_avl_pool_t *patches_pool, uu_avl_t *patches_avl,
if ((pvers = strchr(p, '-')) != NULL)
*pvers = '\0';
- if (save_obs_patch(p, patches_pool, obs_patches_avl) != Z_OK)
+ /*
+ * We save all of the obsolete patches in one big list in the
+ * obs_patches AVL tree so that we know not to output those as
+ * part of the sw dependencies. However, we also need to save
+ * the obsolete patch information for this sepcific patch so
+ * so that we can do the cross manifest patch checking
+ * correctly.
+ */
+ if (save_obs_patch(p, patches_pool, obs_patches) != Z_OK)
+ return (Z_NOMEM);
+ if (add_obs_patch(patch, p, list_pool) != Z_OK)
return (Z_NOMEM);
} while ((p = strtok_r(NULL, " ", &lastp)) != NULL);
@@ -7294,6 +7465,21 @@ add_patch(void *e, void *p)
if ((args->res = newprop(node, DTD_ATTR_ID, id)) != Z_OK)
return (UU_WALK_DONE);
+ if (patch->obs_patches != NULL) {
+ obs_patch_node_t *op;
+ xmlNodePtr node2;
+
+ for (op = uu_list_first(patch->obs_patches); op != NULL;
+ op = uu_list_next(patch->obs_patches, op)) {
+ (void) snprintf(id, sizeof (id), "%s", op->patch_num);
+ node2 = xmlNewTextChild(node, NULL, DTD_ELEM_OBSOLETES,
+ NULL);
+ if ((args->res = newprop(node2, DTD_ATTR_ID, id))
+ != Z_OK)
+ return (UU_WALK_DONE);
+ }
+ }
+
return (UU_WALK_NEXT);
}
@@ -7308,6 +7494,19 @@ patch_avl_delete(uu_avl_t *patches_avl)
&cookie)) != NULL) {
free(p->patch_num);
free(p->patch_vers);
+
+ if (p->obs_patches != NULL) {
+ obs_patch_node_t *op;
+ void *cookie2 = NULL;
+
+ while ((op = uu_list_teardown(p->obs_patches,
+ &cookie2)) != NULL) {
+ free(op->patch_num);
+ free(op);
+ }
+ uu_list_destroy(p->obs_patches);
+ }
+
free(p);
}
@@ -7321,7 +7520,8 @@ patch_avl_delete(uu_avl_t *patches_avl)
*/
static int
add_patches(zone_dochandle_t handle, struct zone_pkginfo *infop,
- uu_avl_pool_t *patches_pool, uu_avl_t *obs_patches_avl)
+ uu_avl_pool_t *patches_pool, uu_avl_t *obs_patches,
+ uu_list_pool_t *list_pool)
{
int i;
int res;
@@ -7334,13 +7534,13 @@ add_patches(zone_dochandle_t handle, struct zone_pkginfo *infop,
for (i = 0; i < infop->zpi_patch_cnt; i++) {
if ((res = parse_info(infop->zpi_patchinfo[i], patches_pool,
- patches_avl, obs_patches_avl)) != Z_OK) {
+ patches_avl, obs_patches, list_pool)) != Z_OK) {
patch_avl_delete(patches_avl);
return (res);
}
}
- args.obs_patches_avl = obs_patches_avl;
+ args.obs_patches_avl = obs_patches;
args.handle = handle;
args.res = Z_OK;
@@ -7351,6 +7551,44 @@ add_patches(zone_dochandle_t handle, struct zone_pkginfo *infop,
}
/*
+ * Keep track of the pkgs we have already processed so that we can quickly
+ * skip those pkgs while recursively doing dependents.
+ */
+static boolean_t
+pkg_in_manifest(uu_avl_t *saw_pkgs, char *pname, uu_avl_pool_t *pkgs_pool)
+{
+ uu_avl_index_t where;
+
+ if (uu_avl_find(saw_pkgs, pname, NULL, &where) == NULL) {
+ zone_pkg_entry_t *pkg;
+
+ /*
+ * We need to add it. If we don't have memory we just skip
+ * this pkg since this routine improves performance but the
+ * algorithm is still correct without it.
+ */
+ if ((pkg = (zone_pkg_entry_t *)
+ malloc(sizeof (zone_pkg_entry_t))) == NULL)
+ return (B_FALSE);
+
+ if ((pkg->zpe_name = strdup(pname)) == NULL) {
+ free(pkg);
+ return (B_FALSE);
+ }
+
+ pkg->zpe_vers = NULL;
+ pkg->zpe_patches_avl = NULL;
+
+ /* Insert pkg into the AVL tree. */
+ uu_avl_node_init(pkg, &pkg->zpe_entry, pkgs_pool);
+ uu_avl_insert(saw_pkgs, pkg, where);
+ return (B_FALSE);
+ }
+
+ return (B_TRUE);
+}
+
+/*
* Add the pkg to the sw inventory on the handle.
*/
static int
@@ -7462,6 +7700,114 @@ get_pkginfo(char *pkginfo, struct zone_pkginfo *infop)
}
/*
+ * Add any dependent pkgs to the list. The pkg depend file lists pkg
+ * dependencies, one per line with an entry that looks like:
+ * P SUNWcar Core Architecture, (Root)
+ * See the depend(4) man page.
+ */
+static int
+add_dependents(zone_dochandle_t handle, char *pname,
+ uu_avl_pool_t *patches_pool, uu_avl_t *obs_patches,
+ uu_list_pool_t *list_pool, uu_avl_t *saw_pkgs, uu_avl_pool_t *pkgs_pool)
+{
+ int res = Z_OK;
+ FILE *fp;
+ char depend[MAXPATHLEN];
+ char *buf;
+ struct stat sbuf;
+
+ (void) snprintf(depend, sizeof (depend), "%s/%s/install/depend",
+ PKG_PATH, pname);
+
+ if (stat(depend, &sbuf) == -1 || !S_ISREG(sbuf.st_mode))
+ return (Z_OK);
+
+ if ((fp = fopen(depend, "r")) == NULL)
+ return (Z_OK);
+
+ while ((buf = read_pkg_data(fp)) != NULL) {
+ char *deppkg;
+ char *delims = " \t";
+ char pkginfo[MAXPATHLEN];
+ struct zone_pkginfo info;
+
+ if (*buf != 'P') {
+ free(buf);
+ continue;
+ }
+
+ /* Skip past the leading 'P '. */
+ if ((deppkg = strtok(buf + 2, delims)) == NULL) {
+ free(buf);
+ continue;
+ }
+
+ /* If the pkg is already in the manifest don't add it again. */
+ if (pkg_in_manifest(saw_pkgs, deppkg, pkgs_pool)) {
+ free(buf);
+ continue;
+ }
+
+ (void) snprintf(pkginfo, sizeof (pkginfo), "%s/%s/pkginfo",
+ PKG_PATH, deppkg);
+
+ if (stat(pkginfo, &sbuf) == -1 || !S_ISREG(sbuf.st_mode)) {
+ free(buf);
+ continue;
+ }
+
+ if (get_pkginfo(pkginfo, &info) != 0) {
+ res = Z_NOMEM;
+ free(buf);
+ break;
+ }
+
+ if ((res = add_dependents(handle, deppkg, patches_pool,
+ obs_patches, list_pool, saw_pkgs, pkgs_pool)) == Z_OK &&
+ (res = add_pkg(handle, deppkg, info.zpi_version)) == Z_OK) {
+ if (info.zpi_patch_cnt > 0)
+ res = add_patches(handle, &info, patches_pool,
+ obs_patches, list_pool);
+ }
+
+ free(buf);
+ free_pkginfo(&info);
+
+ if (res != Z_OK)
+ break;
+ }
+
+ (void) fclose(fp);
+ return (res);
+}
+
+/* ARGSUSED */
+static int
+pkg_entry_compare(const void *l_arg, const void *r_arg, void *private)
+{
+ zone_pkg_entry_t *pkg = (zone_pkg_entry_t *)l_arg;
+ char *name = (char *)r_arg;
+
+ return (strcmp(pkg->zpe_name, name));
+}
+
+static void
+pkg_avl_delete(uu_avl_t *pavl)
+{
+ if (pavl != NULL) {
+ zone_pkg_entry_t *p;
+ void *cookie = NULL;
+
+ while ((p = uu_avl_teardown(pavl, &cookie)) != NULL) {
+ free(p->zpe_name);
+ free(p);
+ }
+
+ uu_avl_destroy(pavl);
+ }
+}
+
+/*
* Take a software inventory of the global zone. We need to get the set of
* packages and patches that are on the global zone that the specified
* non-global zone depends on. The packages we need in the inventory are:
@@ -7477,7 +7823,13 @@ get_pkginfo(char *pkginfo, struct zone_pkginfo *infop)
* then (b) will be skipped.
*
* For each of the packages that is being added to the inventory, we will also
+ * add its dependent packages to the inventory.
+ *
+ * For each of the packages that is being added to the inventory, we will also
* add all of the associated, unique patches to the inventory.
+ *
+ * See the comment for zonecfg_getpkgdata() for compatability restrictions on
+ * how we must save the XML representation of the software inventory.
*/
static int
zonecfg_sw_inventory(zone_dochandle_t handle)
@@ -7490,32 +7842,56 @@ zonecfg_sw_inventory(zone_dochandle_t handle)
struct zone_pkginfo info;
int pkg_cnt = 0;
char **pkgs = NULL;
- uu_avl_pool_t *patches_pool;
- uu_avl_t *obs_patches_avl;
+ uu_avl_pool_t *pkgs_pool = NULL;
+ uu_avl_pool_t *patches_pool = NULL;
+ uu_list_pool_t *list_pool = NULL;
+ uu_avl_t *saw_pkgs = NULL;
+ uu_avl_t *obs_patches = NULL;
+
+ if ((pkgs_pool = uu_avl_pool_create("pkgs_pool",
+ sizeof (zone_pkg_entry_t), offsetof(zone_pkg_entry_t, zpe_entry),
+ pkg_entry_compare, UU_DEFAULT)) == NULL) {
+ res = Z_NOMEM;
+ goto done;
+ }
+
+ if ((saw_pkgs = uu_avl_create(pkgs_pool, NULL, UU_DEFAULT)) == NULL) {
+ res = Z_NOMEM;
+ goto done;
+ }
if ((patches_pool = uu_avl_pool_create("patches_pool",
sizeof (patch_node_t), offsetof(patch_node_t, patch_node),
patch_node_compare, UU_DEFAULT)) == NULL) {
- return (Z_NOMEM);
+ res = Z_NOMEM;
+ goto done;
}
- if ((obs_patches_avl = uu_avl_create(patches_pool, NULL, UU_DEFAULT))
+ if ((list_pool = uu_list_pool_create("list_pool",
+ sizeof (obs_patch_node_t), offsetof(obs_patch_node_t, link), NULL,
+ UU_DEFAULT)) == NULL) {
+ res = Z_NOMEM;
+ goto done;
+ }
+
+ /*
+ * The obs_patches AVL tree saves all of the obsolete patches so
+ * that we know not to output those as part of the sw dependencies.
+ */
+ if ((obs_patches = uu_avl_create(patches_pool, NULL, UU_DEFAULT))
== NULL) {
- uu_avl_pool_destroy(patches_pool);
- return (Z_NOMEM);
+ res = Z_NOMEM;
+ goto done;
}
if ((res = get_ipd_pkgs(handle, &pkgs, &pkg_cnt)) != Z_OK) {
- patch_avl_delete(obs_patches_avl);
- uu_avl_pool_destroy(patches_pool);
- return (res);
+ res = Z_NOMEM;
+ goto done;
}
if ((dirp = opendir(PKG_PATH)) == NULL) {
- patch_avl_delete(obs_patches_avl);
- uu_avl_pool_destroy(patches_pool);
- free_ipd_pkgs(pkgs, pkg_cnt);
- return (Z_OK);
+ res = Z_NOMEM;
+ goto done;
}
while ((dp = readdir(dirp)) != (struct dirent *)0) {
@@ -7536,12 +7912,21 @@ zonecfg_sw_inventory(zone_dochandle_t handle)
if (!info.zpi_this_zone &&
(info.zpi_all_zones ||
- dir_pkg(dp->d_name, pkgs, pkg_cnt))) {
- if ((res = add_pkg(handle, dp->d_name,
+ dir_pkg(dp->d_name, pkgs, pkg_cnt)) &&
+ !pkg_in_manifest(saw_pkgs, dp->d_name, pkgs_pool)) {
+ /*
+ * Add dependents first so any patches will get
+ * associated with the right pkg in the xml file.
+ */
+ if ((res = add_dependents(handle, dp->d_name,
+ patches_pool, obs_patches, list_pool, saw_pkgs,
+ pkgs_pool)) == Z_OK &&
+ (res = add_pkg(handle, dp->d_name,
info.zpi_version)) == Z_OK) {
if (info.zpi_patch_cnt > 0)
res = add_patches(handle, &info,
- patches_pool, obs_patches_avl);
+ patches_pool, obs_patches,
+ list_pool);
}
}
@@ -7553,8 +7938,15 @@ zonecfg_sw_inventory(zone_dochandle_t handle)
(void) closedir(dirp);
- patch_avl_delete(obs_patches_avl);
- uu_avl_pool_destroy(patches_pool);
+done:
+ pkg_avl_delete(saw_pkgs);
+ patch_avl_delete(obs_patches);
+ if (pkgs_pool != NULL)
+ uu_avl_pool_destroy(pkgs_pool);
+ if (patches_pool != NULL)
+ uu_avl_pool_destroy(patches_pool);
+ if (list_pool != NULL)
+ uu_list_pool_destroy(list_pool);
free_ipd_pkgs(pkgs, pkg_cnt);
if (res == Z_OK)
diff --git a/usr/src/lib/libzonecfg/common/mapfile-vers b/usr/src/lib/libzonecfg/common/mapfile-vers
index 384641b1a7..e36565f19d 100644
--- a/usr/src/lib/libzonecfg/common/mapfile-vers
+++ b/usr/src/lib/libzonecfg/common/mapfile-vers
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -80,8 +80,6 @@ SUNWprivate_1.1 {
zonecfg_endfsent;
zonecfg_endipdent;
zonecfg_endnwifent;
- zonecfg_endpatchent;
- zonecfg_endpkgent;
zonecfg_endrctlent;
zonecfg_find_mounts;
zonecfg_find_scratch;
@@ -112,8 +110,7 @@ SUNWprivate_1.1 {
zonecfg_get_name;
zonecfg_get_name_by_uuid;
zonecfg_getnwifent;
- zonecfg_getpatchent;
- zonecfg_getpkgent;
+ zonecfg_getpkgdata;
zonecfg_get_pool;
zonecfg_get_privset;
zonecfg_getpsetent;
@@ -178,8 +175,6 @@ SUNWprivate_1.1 {
zonecfg_set_limitpriv;
zonecfg_set_name;
zonecfg_setnwifent;
- zonecfg_setpatchent;
- zonecfg_setpkgent;
zonecfg_set_pool;
zonecfg_setrctlent;
zonecfg_set_root;
diff --git a/usr/src/pkgdefs/SUNWzoneu/prototype_com b/usr/src/pkgdefs/SUNWzoneu/prototype_com
index 358607fd25..2020693704 100644
--- a/usr/src/pkgdefs/SUNWzoneu/prototype_com
+++ b/usr/src/pkgdefs/SUNWzoneu/prototype_com
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -52,6 +52,7 @@ d none usr/kernel/drv 755 root sys
d none usr/lib 755 root bin
d none usr/lib/brand 755 root bin
d none usr/lib/brand/native 755 root sys
+f none usr/lib/brand/native/attach_update 755 root bin
f none usr/lib/brand/native/config.xml 444 root bin
f none usr/lib/brand/native/platform.xml 444 root bin
f none usr/lib/brand/native/postclone 755 root bin