diff options
| author | jv227347 <Jordan.Vaughan@Sun.com> | 2010-05-18 12:28:09 -0700 |
|---|---|---|
| committer | jv227347 <Jordan.Vaughan@Sun.com> | 2010-05-18 12:28:09 -0700 |
| commit | 98f4f4f656cf8a11e7013e69b0cc54f82fa9b79b (patch) | |
| tree | 2e455de4d988e42a601e16b1a9d890bd0a2337da /usr/src/lib | |
| parent | 28d97a71b8094bcc695c914ba67d41bee3cd3a8a (diff) | |
| download | illumos-joyent-98f4f4f656cf8a11e7013e69b0cc54f82fa9b79b.tar.gz | |
6909222 reboot of system upgraded from 128 to build 129 generated error from an s10 zone due to boot-archive
6927878 removing patches that affect solaris10 emulation hoses solaris10-branded zones
6947847 Solaris 10 Containers need s10_replacefile to support S10 patch tools
Diffstat (limited to 'usr/src/lib')
| -rw-r--r-- | usr/src/lib/brand/solaris10/Makefile | 6 | ||||
| -rw-r--r-- | usr/src/lib/brand/solaris10/s10_replacefile/Makefile | 52 | ||||
| -rw-r--r-- | usr/src/lib/brand/solaris10/s10_replacefile/s10_replacefile.c | 141 | ||||
| -rw-r--r-- | usr/src/lib/brand/solaris10/s10_support/s10_support.c | 129 | ||||
| -rw-r--r-- | usr/src/lib/brand/solaris10/zone/p2v.ksh | 94 |
5 files changed, 401 insertions, 21 deletions
diff --git a/usr/src/lib/brand/solaris10/Makefile b/usr/src/lib/brand/solaris10/Makefile index 2d4ffe0058..2fc25a7dab 100644 --- a/usr/src/lib/brand/solaris10/Makefile +++ b/usr/src/lib/brand/solaris10/Makefile @@ -19,8 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # default: all @@ -30,7 +29,8 @@ include Makefile.s10 # Build everything in parallel; use .WAIT for dependencies .PARALLEL: -SUBDIRS = librtld_db s10_npreload s10_brand s10_support zone cmd +SUBDIRS = librtld_db s10_npreload s10_brand s10_support s10_replacefile \ + zone cmd MSGSUBDIRS = s10_support zone all := TARGET= all diff --git a/usr/src/lib/brand/solaris10/s10_replacefile/Makefile b/usr/src/lib/brand/solaris10/s10_replacefile/Makefile new file mode 100644 index 0000000000..dd0bebe3c3 --- /dev/null +++ b/usr/src/lib/brand/solaris10/s10_replacefile/Makefile @@ -0,0 +1,52 @@ +# +# 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 (c) 2010, Oracle and/or its affiliates. All rights reserved. +# + +PROG = s10_replacefile +PROGS = $(PROG) +OBJS = s10_replacefile + +all: $(PROG) + +include ../Makefile.s10 +include $(SRC)/cmd/Makefile.cmd + +# override the install directory +ROOTBIN = $(ROOTBRANDDIR) +CLOBBERFILES = $(OBJS) $(ROOTPROGS) + +UTSBASE = $(SRC)/uts + +CFLAGS += $(CCVERBOSE) +CPPFLAGS += -D_REENTRANT + +.KEEP_STATE: + +install: all $(ROOTPROGS) + +clean: + $(RM) $(PROG) $(OBJS) + +lint: lint_PROG + +include $(SRC)/cmd/Makefile.targ diff --git a/usr/src/lib/brand/solaris10/s10_replacefile/s10_replacefile.c b/usr/src/lib/brand/solaris10/s10_replacefile/s10_replacefile.c new file mode 100644 index 0000000000..49c82c3594 --- /dev/null +++ b/usr/src/lib/brand/solaris10/s10_replacefile/s10_replacefile.c @@ -0,0 +1,141 @@ +/* + * 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 (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include <stdio.h> +#include <strings.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/mount.h> +#include <sys/mntent.h> +#include <unistd.h> + +/* + * This program aids the Solaris 10 patch tools (specifically + * /usr/lib/patch/patch_common_lib) in DAP patching. + * + * Whenever the patch tools replace a critical system component (e.g., + * /lib/libc.so.1), they move the old component to a temporary location, + * move the new component to where the old component was, and establish + * an overlay mount of the old component on top of the new component. + * The patch tools do this with a shell script; consequently, the three + * operations occur in three processes. + * + * This doesn't work inside Solaris 10 Containers (S10Cs). Suppose the + * patch tools need to replace /lib/libc.so.1. The tools will move the old + * libc.so.1 to a temporary location. But when they try to move the new + * libc.so.1, they fork a mv(1) process, which loads the solaris10 brand's + * emulation library. The emulation library will try to load the zone's + * libc.so.1, but the library no longer exists; consequently, the emulation + * library aborts and the zone's users won't be able to start any processes. + * + * This program solves the problem by combining the move and mount operations + * into a single process. The emulation library will already have loaded + * libc.so.1 for the process by the time the process starts to replace + * libc.so.1. + * + * This program takes six parameters that correspond to six variables within + * /usr/lib/patch/patch_common_lib:InstallSafemodeObject(): + * + * argv[1] - dstActual (the path to the file that will be replaced) + * argv[2] - tmp_file (the temporary location to which the file will be + * moved) + * argv[3] - tmpDst (the path to the replacement file) + * argv[4] - tmpFile (the path to a temporary copy of the running system's + * version of the file being replaced; the source [special] of + * the overlay mount) + * argv[5] - cksumTmpDst (checksum of the file represented by tmpDst) + * argv[6] - cksumTmpFile (checksum of the file represented by tmpFile) + * + * NOTE: This program will only establish an overlay mount if argv[4] or argv[5] + * is emtpy or if argv[4] and argv[5] differ. + * + * This program returns zero when it succeeds. Non-negative values indicate + * failure. + */ +int +main(int argc, char **argv) +{ + struct stat statbuf; + char mntoptions[MAX_MNTOPT_STR]; + + /* + * Check the number of arguments that were passed to s10_replacefile. + */ + if (argc != 7) { + (void) fprintf(stderr, "Usage: %s dstActual tmp_file tmpDst " + "tmpFile cksumTmpDst cksumTmpFile\n", argv[0]); + return (1); + } + + /* + * Move the destination file (dstActual) out of the way and move the + * new file (tmpDst) into its place. + * + * NOTE: s10_replacefile won't print error messages here because + * the Solaris 10 patch tools will. + */ + if (rename(argv[1], argv[2]) != 0) + return (2); + if (rename(argv[3], argv[1]) != 0) + return (3); + + /* + * If there was a lofs mount on dstActual (which we just moved), then + * s10_replacefile should reestablish the lofs mount. A lofs mount + * existed if tmpFile exists. + */ + if (stat(argv[4], &statbuf) == 0 && (statbuf.st_mode & S_IFREG)) { + /* + * Create a lofs overlay mount only if the checksums of the + * old file at dstActual and the new file at dstActual differ. + */ + if (argv[5][0] == '\0' || argv[6][0] == '\0' || + strcmp(argv[5], argv[6]) != 0) { + mntoptions[0] = '\0'; + if (mount(argv[4], argv[1], MS_OVERLAY | MS_OPTIONSTR, + MNTTYPE_LOFS, NULL, 0, mntoptions, + sizeof (mntoptions)) != 0) { + /* + * Although the patch tools will print error + * messages, the tools won't know that + * s10_replacefile failed to establish an + * overlay mount. Printing an error message + * here clarifies the problem for the user. + */ + (void) fprintf(stderr, "ERROR: Failed to " + "overlay mount %s onto %s\n", argv[4], + argv[1]); + return (4); + } + } else { + /* + * dstActual does not need an overlay mount. Delete + * tmpFile. + */ + (void) unlink(argv[4]); + } + } + return (0); +} diff --git a/usr/src/lib/brand/solaris10/s10_support/s10_support.c b/usr/src/lib/brand/solaris10/s10_support/s10_support.c index e05aed8253..a80ab9ed42 100644 --- a/usr/src/lib/brand/solaris10/s10_support/s10_support.c +++ b/usr/src/lib/brand/solaris10/s10_support/s10_support.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -64,6 +63,13 @@ static boolean_t override = B_FALSE; static char *bname = NULL; +/* + * DELETE_LIST_PATH represents the path to a solaris10-branded zone's "delete + * list", which is generated by patchrm when it needs to remove files after + * the zone reboots. See set_zone_emul_bitmap() below for additional details. + */ +#define DELETE_LIST_PATH "/var/sadm/patch/.delete_list" + #define PKGINFO_RD_LEN 128 #define PATCHLIST "PATCHLIST=" @@ -338,6 +344,26 @@ have_valid_ku(char *zonename) } /* + * Convert the specified file basename into an unsigned integer. If the + * basename contains characters that cannot be converted into digits or the + * basename isn't NULL or newline-terminated, then this function returns + * the unsigned equivalent of -1. + */ +static unsigned int +basename_to_uint(const char *basenamep) +{ + char *filename_endptr; + unsigned int bit_index; + + errno = 0; + bit_index = (unsigned int)strtoul(basenamep, &filename_endptr, 10); + if (errno != 0 || (*filename_endptr != '\n' && + *filename_endptr != '\0') || filename_endptr == basenamep) + return ((unsigned int)-1); + return (bit_index); +} + +/* * Determine which features/behaviors should be emulated and construct a bitmap * representing the results. Associate the bitmap with the zone so that * the brand's emulation library will be able to retrieve the bitmap and @@ -348,26 +374,27 @@ have_valid_ku(char *zonename) static void set_zone_emul_bitmap(char *zonename) { - char req_emulation_dir_path[MAXPATHLEN]; + char zoneroot[MAXPATHLEN]; + char path[MAXPATHLEN]; DIR *req_emulation_dirp; struct dirent *emul_feature_filep; - char *filename_endptr; s10_emul_bitmap_t bitmap; unsigned int bit_index; zoneid_t zoneid; + FILE *delete_listp; /* * If the Solaris 10 directory containing emulation feature files * doesn't exist in the zone, then assume that it only needs the * most basic emulation and, therefore, doesn't need a bitmap. */ - if (zone_get_rootpath(zonename, req_emulation_dir_path, - sizeof (req_emulation_dir_path)) != Z_OK) + if (zone_get_rootpath(zonename, zoneroot, sizeof (zoneroot)) != Z_OK) s10_err(gettext("error getting zone's path")); - if (strlcat(req_emulation_dir_path, S10_REQ_EMULATION_DIR, - sizeof (req_emulation_dir_path)) >= sizeof (req_emulation_dir_path)) - s10_err(gettext("error formatting version path")); - if ((req_emulation_dirp = opendir(req_emulation_dir_path)) == NULL) + if (snprintf(path, sizeof (path), "%s" S10_REQ_EMULATION_DIR, + zoneroot) >= sizeof (path)) + s10_err(gettext("zone's emulation versioning directory's path " + "%s" S10_REQ_EMULATION_DIR " is too long"), zoneroot); + if ((req_emulation_dirp = opendir(path)) == NULL) return; bzero(bitmap, sizeof (bitmap)); @@ -384,11 +411,8 @@ set_zone_emul_bitmap(char *zonename) * Convert the file's name to an unsigned integer. Ignore * files whose names aren't unsigned integers. */ - errno = 0; - bit_index = (unsigned int)strtoul(emul_feature_filep->d_name, - &filename_endptr, 10); - if (errno != 0 || *filename_endptr != '\0' || - filename_endptr == emul_feature_filep->d_name) + bit_index = basename_to_uint(emul_feature_filep->d_name); + if (bit_index == (unsigned int)-1) continue; /* @@ -412,11 +436,84 @@ set_zone_emul_bitmap(char *zonename) bitmap[(bit_index >> 3)] |= (1 << (bit_index & 0x7)); } } + (void) closedir(req_emulation_dirp); + + /* + * The zone's administrator might have removed a patch that delivered + * an emulation feature file the last time the zone ran. If so, then + * the zone's patch utilities won't delete the file until the zone's + * svc:/system/patch-finish:delete SMF service runs. This is + * problematic because the zone will be using system libraries whose + * ioctl structures and syscall invocations will differ from those + * expected by the emulation library. For example, if an administrator + * removes a patch that affects the formats of MNTFS ioctls, then the + * administrator's zone will use a version of libc.so.1 that issues + * MNTFS ioctls that use older structure versions than the zone's + * emulation library will expect. + * + * Fortunately, the patchrm utility creates a hidden file, + * /var/sadm/patch/.delete_list, which lists all files that + * svc:/system/patch-finish:delete will delete. We'll determine whether + * this file exists in the zone and disable the emulation bits + * associated with the emulation feature files that will be deleted. + * + * NOTE: The patch tools lofs mount backup copies of critical system + * libraries, such as /lib/libc.so.1, over their replacements whenever + * administrators add or remove DAP patches. Consequently, there isn't + * a window of vulnerability between patch addition or removal and + * zone reboot. The aforementioned problem only occurs after a zone + * reboots. + */ + if (snprintf(path, sizeof (path), "%s" DELETE_LIST_PATH, zoneroot) >= + sizeof (path)) + s10_err(gettext("zone's delete list's path %s" DELETE_LIST_PATH + " is too long"), zoneroot); + if ((delete_listp = fopen(path, "r")) != NULL) { + while (fgets(path, sizeof (path), delete_listp) != NULL) { + char *const basenamep = path + + sizeof (S10_REQ_EMULATION_DIR); + + /* + * Make sure that the file is in the directory + * containing emulation feature files. If it is, + * then basenamep should refer to the basename of + * the file. + */ + if (strncmp(path, S10_REQ_EMULATION_DIR, + sizeof (S10_REQ_EMULATION_DIR) - 1) != 0) + continue; + if (*(basenamep - 1) != '/') + continue; + + /* + * Convert the file's basename into a bit index in + * the emulation bitmap. If the file's basename isn't + * integral, then skip the file. Otherwise, clear the + * corresponding bit in the bitmap. + */ + bit_index = basename_to_uint(basenamep); + if (bit_index == (unsigned int)-1) + continue; + if (bit_index < S10_NUM_EMUL_FEATURES) + bitmap[(bit_index >> 3)] &= + ~(1 << (bit_index & 0x7)); + } + if (ferror(delete_listp) != 0 || feof(delete_listp) == 0) + s10_err(gettext("The program encountered an error while" + " reading from %s" DELETE_LIST_PATH "."), zoneroot); + (void) fclose(delete_listp); + } else if (errno != ENOENT) { + /* + * The delete list exists but couldn't be opened. Warn the + * administrator. + */ + s10_err(gettext("Unable to open %s" DELETE_LIST_PATH ": %s"), + zoneroot, strerror(errno)); + } /* * We're done scanning files. Set the zone's emulation bitmap. */ - (void) closedir(req_emulation_dirp); if ((zoneid = getzoneidbyname(zonename)) < 0) s10_err(gettext("unable to get zoneid")); if (zone_setattr(zoneid, S10_EMUL_BITMAP, bitmap, sizeof (bitmap)) != 0) diff --git a/usr/src/lib/brand/solaris10/zone/p2v.ksh b/usr/src/lib/brand/solaris10/zone/p2v.ksh index 7fe25a6409..7797d1ea1f 100644 --- a/usr/src/lib/brand/solaris10/zone/p2v.ksh +++ b/usr/src/lib/brand/solaris10/zone/p2v.ksh @@ -19,8 +19,7 @@ # # CDDL HEADER END # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # NOTE: this script runs in the global zone and touches the non-global @@ -50,6 +49,12 @@ trap_cleanup() /usr/sbin/zoneadm -z $ZONENAME halt fi + # + # Delete temporary files created during the hollow package removal + # process. + # + rm -f $hollow_pkgs $hollow_file_list $hollow_dir_list + exit $EXIT_CODE } @@ -539,6 +544,9 @@ e_exitfail=$(gettext "Postprocessing failed.") # safe_dir /etc safe_dir /var +safe_dir /var/sadm +safe_dir /var/sadm/install +safe_dir /var/sadm/pkg safe_opt_dir /etc/dfs safe_opt_dir /etc/lu safe_opt_dir /etc/zones @@ -587,6 +595,88 @@ if (( $? != 0 )); then fatal "$e_exitfail" fi +# +# Remove all files and directories installed by hollow packages. Such files +# and directories shouldn't exist inside zones. +# +hollow_pkgs=$(mktemp -t .hollow.pkgs.XXXXXX) +hollow_file_list=$(mktemp $ZONEROOT/.hollow.pkgs.files.XXXXXX) +hollow_dir_list=$(mktemp $ZONEROOT/.hollow.pkgs.dirs.XXXXXX) +[ -f "$hollow_pkgs" -a -f "$hollow_file_list" -a -f "$hollow_dir_list" ] || { + error "$e_tmpfile" + rm -f $hollow_pkgs $hollow_file_list $hollow_dir_list + fatal "$e_exitfail" +} +for pkg_name in $ZONEROOT/var/sadm/pkg/*; do + grep 'SUNW_PKG_HOLLOW=true' $pkg_name/pkginfo >/dev/null 2>&1 && \ + basename $pkg_name >>$hollow_pkgs +done +/usr/bin/nawk -v hollowpkgs=$hollow_pkgs -v filelist=$hollow_file_list \ + -v dirlist=$hollow_dir_list ' + BEGIN { + while (getline p <hollowpkgs > 0) + pkgs[p] = 1; + close(hollowpkgs); + } + { + # fld is the field where the pkg names begin. + # nm is the file/dir entry name. + if ($2 == "f") { + fld=10; + nm=$1; + } else if ($2 == "d") { + fld=7; + nm=$1; + } else if ($2 == "s" || $2 == "l") { + fld=4; + split($1, a, "="); + nm=a[1]; + } else { + next; + } + + # Determine whether the file or directory is delivered by any + # non-hollow packages. Files and directories can be + # delivered by multiple pkgs. The file or directory should only + # be removed if it is only delivered by hollow packages. + for (i = fld; i <= NF; i++) { + if (pkgs[get_pkg_name($i)] != 1) { + # We encountered a non-hollow package. Skip + # this entry. + next; + } + } + + # The file or directory is only delivered by hollow packages. + # Mark it for removal. + if (fld != 7) + print nm >>filelist + else + print nm >>dirlist + } + + # 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) + } +' $ZONEROOT/var/sadm/install/contents +/usr/sbin/zlogin -S $ZONENAME "cat /$(basename $hollow_file_list) | xargs rm -f" +/usr/sbin/zlogin -S $ZONENAME "sort -r /$(basename $hollow_dir_list) | \ + xargs rmdir >/dev/null 2>&1" +rm -f $hollow_pkgs $hollow_file_list $hollow_dir_list + # cleanup SMF services fix_smf |
