#!/bin/ksh93 -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 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # # itu - converts packages to Driver Update format and patches Solaris install # media for Install Time Update (ITU). # readonly PROG=$0 readonly ORIGPWD=$PWD # Must-have utilities readonly CPIO=/usr/bin/cpio readonly GZIP=/usr/bin/gzip readonly MKISOFS=/usr/bin/mkisofs readonly PATCHADD=/usr/sbin/patchadd readonly PKGTRANS=/usr/bin/pkgtrans readonly PKGADD=/usr/sbin/pkgadd readonly LOFIADM=/usr/sbin/lofiadm readonly MKDIR=/usr/bin/mkdir readonly RM=/usr/bin/rm readonly CP=/usr/bin/cp readonly HEAD=/usr/bin/head readonly SORT=/usr/bin/sort readonly MKBOOTMEDIA=/usr/bin/mkbootmedia readonly PKG2DU=/usr/bin/pkg2du readonly TOUCH=/usr/bin/touch readonly NAWK=/usr/bin/nawk readonly CHMOD=/usr/bin/chmod readonly GREP=/usr/bin/grep readonly LS=/usr/bin/ls readonly LN=/usr/bin/ln readonly SED=/usr/bin/sed readonly CAT=/usr/bin/cat readonly FIND=/usr/bin/find readonly UNAME=/usr/bin/uname readonly MACH=`$UNAME -p` ROOT_ARCHIVE=/usr/sbin/root_archive BOOTBLOCK= MINIROOT= # Relative to a Solaris media root. if [ "$MACH" = "sparc" ]; then BOOTBLOCK=boot/hsfs.bootblock MINIROOT=$MEDIA_ROOT/boot/sparc.miniroot else # x86/x64 BOOTBLOCK=boot/grub/stage2_eltorito MINIROOT=$MEDIA_ROOT/boot/x86.miniroot fi readonly TMP_DIR=${TMPDIR:-/tmp}/${PROG##*/}.$$ readonly LOGFILE=${TMPDIR:-/tmp}/${PROG##*/}-log.$$ # Paths we need. export PATH=/usr/bin:/usr/sbin:/sbin:/boot/solaris/bin:$PATH # for gettext TEXTDOMAIN=SUNW_OST_OSCMD export TEXTDOMAIN function cleanup { $RM -rf "$TMP_DIR" } function usage_long { usage_short print -u2 usage_options } function usage_short { gettext "Usage:\n" gettext "${PROG##*/} makedu -r solaris_release [-v] [-f] [-d output_dir]\n [-o iso_file] [-l iso_label] package [package ...]\n" gettext "${PROG##*/} patchmedia -R media_root [-v] [-f]\n [-o iso_file] [-l iso_label] pkg_or_patch [pkg_or_patch ...]\n" gettext "${PROG##*/} makeiso -o iso_file [-v] [-f] [-l iso_label] media_root\n" } function usage_options { gettext "Options:\n" gettext " -d output_dir\n Directory where the Driver Update directory should be created.\n" gettext " -f\n If output_dir/DU or iso_file already exists, remove it without\n asking first.\n" gettext " -l iso_label\n Label/volume name of the ISO image (if -o option is specified).\n" gettext " -o iso_file\n Path of ISO image file to create. For subcommands patchmedia and\n makeiso this will be a bootable ISO image.\n This option must be specified for subcommand makeiso.\n" gettext " -R media_root\n Top-level directory of on-disk image of Solaris installation media.\n This option must be specified for subcommand patchmedia.\n" gettext " -r solaris_release\n Solaris release number for which the Driver Update is intended.\n It takes the form of 5.10.\n This option must be specified for subcommand makedu.\n" gettext " -v\n Verbose. Multiple -v options increase verbosity.\n" echo; } # # Process command line options. # Note: since $OPTIND is a local variable inside functions, upon return # from this function global variable $MYOPTIND is set to this value. # function process_options # ... { typeset opt optlist case "$SUBCOMMAND" in makedu) optlist='d:fl:o:r:v' ;; patchmedia) optlist='fl:o:R:v' ;; makeiso) optlist='fl:o:v' ;; esac while getopts ":$optlist" opt do case $opt in d) DU_OUTDIR=$OPTARG ;; f) FORCE=1 ;; l) ISOLABEL=$OPTARG ;; o) ISO=$OPTARG if [ ! -z `echo $ISO | $GREP "^/tmp"` ]; then gettext "ISO images will not be created on /tmp.\n" gettext "Please choose a different output location.\n" exit 3 fi ;; R) MEDIA_ROOT=$OPTARG ;; r) RELEASE=$OPTARG ;; v) (( VERBOSE_LEVEL += 1 )) VERBOSE_OPTS="${VERBOSE_OPTS:--}$opt" # collect options ;; :) gettext "Option -$OPTARG missing argument.\n" usage_short return 1 ;; *) gettext "Option -$OPTARG invalid for $SUBCOMMAND.\n" usage_short return 1 ;; esac done MYOPTIND=$OPTIND return 0 } # # Check some prerequisites # function check_prereqs { typeset utils f # List of must-have utilities depends on subcommand. case "$SUBCOMMAND" in makedu) set -A utils $GZIP ${ISO:+$MKISOFS} $PKGTRANS ;; patchmedia) set -A utils $CPIO $GZIP ${ISO:+$MKISOFS} $PATCHADD \ $ROOT_ARCHIVE ;; makeiso) set -A utils $MKISOFS ;; esac for f in "${utils[@]}" do if [[ ! -x "$f" ]] then gettext "Can't find required utility $f.\n" return 1 fi done # Subcommand packmedia uses the "root_archive unpack_media" command # which calls lofiadm -a, which requires write access as # determined by /dev/lofictl. See lofiadm(1m). if [[ $SUBCOMMAND = patchmedia && ! -w /dev/lofictl ]] then gettext "You don't have enough privileges to run lofiadm -a.\n" gettext "See lofiadm(1m) for more information.\n" return 1 fi return 0 } # # Verifies the given packages and collects them in the PACKAGES array. # function collect_packages # ... { typeset obj for obj in "$@" do if [[ ! -e "$obj" ]] then gettext "Can't find package $obj.\n" return 1 elif [[ ! -f "$obj/pkginfo" ]] then gettext "$obj is not a package.\n" return 1 fi PACKAGES[ ${#PACKAGES[*]} ]=$obj done return 0 } # # Verifies the given packages and patches. Packages are then collected in # the array PACKAGES. Patches are stored in the PATCHES array. # function collect_packages_patches # ... { typeset obj for obj in "$@" do if [[ -f "$obj/patchinfo" ]] then # Collect patches. PATCHES[ ${#PATCHES[*]} ]=$obj elif [[ -f "$obj/pkginfo" ]] then # Collect packages. PACKAGES[ ${#PACKAGES[*]} ]=$obj elif [[ -e "$obj" ]] then gettext "$obj is not a package or patch.\n" return 1 else gettext "$obj does not exist.\n" return 1 fi done return 0 } # # Ask user whether to overwrite an object, unless -f option was given. # function is_overwrite { typeset arg=$1 typeset -l ans (( FORCE )) && return 0 while true do gettext "$arg already exists. Overwrite it? (y/n) " read ans case $ans in y*|Y*) return 0 ;; # go ahead, overwrite n*|N*) return 1 ;; # don't overwrite esac done } # # Check the format of the Solaris release number $RELEASE. # Also set $VERSION (for DU format) based on $RELEASE. # function check_release { # Allow Major.Minor or Major.Minor.Micro format. if [[ $RELEASE != +([0-9]).+([0-9])?(.+([0-9])) ]] then gettext "Invalid release number specified: $RELEASE.\n" return 1 fi # As defined by the ITU spec, a Solaris release number 5.x corresponds # to version number 2x (e.g. 5.10 -> 210). Hopefully, by the time we # do a 6.x Release we won't need ITUs any more. VERSION=$(echo $RELEASE | $SED 's/5\./2/') } # # If an ISO file was specified, get realpath of its parent directory ($ISODIR). # If the ISO file already exists, ask user to overwrite it, unless -f option # was specified. # function check_iso { if [[ "$ISO" = */* ]] then ISODIR=$(cd "${ISO%/*}" 2>/dev/null && pwd -P) if (( $? )) then gettext "Can't access parent directory of ISO image.\n" return 1 fi else ISODIR=$(pwd -P) fi if [[ -f "$ISO" ]] then is_overwrite "$ISO" || return 2 $RM -f "$ISO" fi return 0 } # # If specified, check the Driver Update output directory $DU_OUTDIR (-d option). # Else set $DU_OUTDIR to a temporary directory. Also if $DU_OUTDIR/DU # already exists, ask user whether to overwrite it, unless -f option was given. # function check_dudir { typeset realpath if [[ -z "$DU_OUTDIR" ]] then DU_OUTDIR=$TMP_DIR/dudir return 0 fi # Verify user-specified DU output directory. if [[ ! -d "$DU_OUTDIR" ]] then if [ `$MKDIR -p $DU_OUTDIR` ]; then gettext "$DU_OUTDIR is not a directory.\n" return 1 fi elif [[ ! -w "$DU_OUTDIR" ]] then gettext "Directory $DU_OUTDIR is not writable.\n" return 1 fi # If an ISO image path is also specified, make sure it's not under # $DU_OUTDIR since we might take the ISO image of $DU_OUTDIR. if [[ -n "$ISODIR" ]] then realpath=$(cd "$DU_OUTDIR" 2>/dev/null && pwd -P) if [[ "$ISODIR" = "$realpath"?(/*) ]] then gettext "ISO image must not be under Driver Update's output directory ($realpath).\n" return 1 fi fi # If the DU directory already exists, ask user permission to # remove it unless -f option was given. if [[ -d "$DU_OUTDIR/DU" ]] then is_overwrite "$DU_OUTDIR/DU" || return 2 $RM -rf "$DU_OUTDIR/DU" || return 1 fi return 0 } # # Verify $MEDIA_ROOT is indeed a Solaris install media. # function check_media_root { if [[ ! -d $(echo "$MEDIA_ROOT"/Solaris*/Tools/Boot) ]] then gettext "$MEDIA_ROOT is not a Solaris install media.\n" return 1 fi return 0 } # # Verify there's a miniroot file under $MEDIA_ROOT. Also set $MINIROOT # to the path of the miniroot. # function check_miniroot { MINIROOT=$MEDIA_ROOT/boot/x86.miniroot if [[ ! -f "$MINIROOT" ]] then return 0 fi MINIROOT=$MEDIA_ROOT/boot/sparc.miniroot if [[ ! -f "$MINIROOT" ]] then return 0 fi gettext "Can't find $MEDIA_ROOT/boot/x86.miniroot or $MEDIA_ROOT/boot/sparc.miniroot.\n" return 1 } # # Create a non-bootable ISO image of the given directory. # function create_nonboot_iso # { typeset dir vflag i if (( $# != 1 )) then gettext "create_nonboot_iso missing argument.\n" return 1 fi dir=$1 # Skip if no ISO image was specified. [[ -z "$ISO" ]] && return 0 # Determine mkisofs' verbose flag depending on $VERBOSE_LEVEL. case $VERBOSE_LEVEL in 0) vflag=-quiet ;; 1) vflag= # mkisofs' default verboseness ;; *) vflag= i=$VERBOSE_LEVEL while ((i > 0)) do vflag="-v $vflag" (( i -= 1 )) done ;; esac print "Creating ISO image ..." # Note: the "-log-file >(cat -u >&2)" and "2>/dev/null" below is a # trick to filter out mkisofs's warning message about being # non-conforming to ISO-9660. # We do some funky architecture-specific stuff here so that we can # actually create a bootable media image for UltraSPARC systems sparc_ISOARGS="-B ... -joliet-long -U" i386_ISOARGS="-d -N -r -relaxed-filenames" if [[ "$MACH" = "i386" ]] then ISOARGS=$i386_ISOARGS else ISOARGS=$sparc_ISOARGS fi $MKISOFS -o "$ISO" \ -allow-leading-dots \ $ISOARGS \ -l -ldots \ -R -J \ -V "$ISOLABEL" \ $vflag \ -log-file >(cat -u >&2) \ "$dir" 2>/dev/null } # # Create a bootable Solaris ISO image of the given Solaris install directory. # function create_bootable_iso # { typeset dir vflag saved i if (( $# != 1 )) then gettext "create_bootable_iso missing argument.\n" return 1 fi dir=$1 # Skip if no ISO image was specified. [[ -z "$ISO" ]] && return 0 # Determine mkisofs' verbose flag depending on $VERBOSE_LEVEL. case $VERBOSE_LEVEL in 0) vflag=-quiet ;; 1) vflag= # mkisofs' default verboseness ;; *) vflag= i=$VERBOSE_LEVEL while ((i > 0)) do vflag="-v $vflag" (( i -= 1 )) done ;; esac # Verify the boot block exists under media root. If it does, # verify it's writable since it will be modified with some boot # information by mkisofs' -boot-info-table option. if [[ ! -f "$dir/$BOOTBLOCK" ]] then gettext "Can't find $dir/$BOOTBLOCK.\n" return 1 elif [[ ! -w "$dir/$BOOTBLOCK" ]] then gettext "$dir/$BOOTBLOCK is not writable.\n" return 1 fi gettext "Creating bootable ISO image ..." # Since mkisofs below will modify the file $BOOTBLOCK in-place, save # a copy of it first. saved=$TMP_DIR/${BOOTBLOCK##*/} $CP -f "$dir/$BOOTBLOCK" "$saved" || return # Note: the "-log-file >(cat -u >&2)" and "2>/dev/null" below is a # trick to filter out mkisofs's warning message about being # non-conforming to ISO-9660. # We do some funky architecture-specific stuff here so that we can # actually create a bootable media image for UltraSPARC systems sparc_ISOARGS="-G $BOOTBLOCK -B ... -joliet-long -U" i386_ISOARGS="-b boot/grub/stage2_eltorito -boot-info-table " i386_ISOARGS="$i386_ISOARGS -boot-load-size 4 -c .catalog -d -N " i386_ISOARGS="$i386_ISOARGS -no-emul-boot -r -relaxed-filenames" if [[ "$MACH" = "i386" ]] then ISOARGS=$i386_ISOARGS else ISOARGS=$sparc_ISOARGS fi cd $dir $MKISOFS -o "$ISO" \ -allow-leading-dots \ $ISOARGS \ -l -ldots \ -R -J \ -V "$ISOLABEL" \ $vflag \ -log-file >(cat -u >&2) \ "$dir" 2>/dev/null i=$? # Restore saved El Torito file $CP -f "$saved" "$dir/$ELTORITO" 2>/dev/null return $i } # # Create a Driver Update (DU) format directory from packages # function create_du { typeset distdir tmpdudir pkgs obj statusfile # Create DU directory first. distdir=$DU_OUTDIR/DU/sol_$VERSION/$MACH $MKDIR -p "$distdir/Tools" "$distdir/Product" echo "start create DU with MACH $MACH" # If we're running this script on sun4[vu], then create a symlink # to the other UltraSPARC architecture if [[ "$MACH" != "i386" ]] then cd $DU_OUTDIR/DU/sol_$VERSION $LN -s sparc sun4v $LN -s sparc sun4u else cd $DU_OUTDIR/DU/sol_$VERSION $LN -s i386 i86pc fi # Unfortunately pkgtrans insists that all packages must be in # (see pkgtrans(1)). The packages can't have any path # components. So we'll create a temporary directory first and then # symlinks to the specified packages. Then run pkgtrans with # the temporary directory as . tmpdudir=$TMP_DIR/create_du $RM -rf "$tmpdudir" $MKDIR -p "$tmpdudir" for obj in "${PACKAGES[@]}" do # Get rid of trailing /'s, if any. [[ "$obj" == */ ]] && obj=${obj%%+(/)} # Make sure it's full pathname. [[ "$obj" != /* ]] && obj=$ORIGPWD/$obj ln -s "$obj" "$tmpdudir" || return # Remember just the file component. pkgs[ ${#pkgs[*]} ]=${obj##*/} done # Package up packages as compressed data stream. statusfile=$TMP_DIR/.pkgtrans.status ( # Use fd 9 for redirecting pkgtrans' "Transferring..." # messages which normally go to stderr to current stdout # (not the following pipeline's stdout). exec 9>&1 { $PKGTRANS -s "$tmpdudir" /dev/stdout "${pkgs[@]}" 2>&9 echo $? > $statusfile $TOUCH $statusfile # make sure file is created } | $GZIP -9 > "$distdir/Product/pkgs.gz" ) [[ -s $statusfile && $(<$statusfile) != 0 ]] && return 1 # Create admin file for pkgadd $CAT > "$distdir/Tools/admin" <<"EOF" mail= instance=overwrite partial=nocheck runlevel=nocheck idepend=nocheck rdepend=nocheck space=nocheck setuid=nocheck conflict=nocheck action=nocheck EOF # Create install.sh $CAT > "$distdir/Tools/install.sh" <<"EOF" #!/sbin/sh # install.sh -R - install packages to basedir basedir=/ toolsdir=`dirname $0` tmpfile=/tmp/`basename $0`.$$ gzip=/usr/bin/gzip while getopts "R:" arg do case "$arg" in R) basedir=$OPTARG;; esac done # /etc/driver_aliases ,/etc/driver_classes # /etc/name_to_major /etc/minor_perm # The four file can't append due to ACL defect. # workaround this by mv and cp /usr/bin/touch /etc/driver_aliases if [ $? -ne 0 ] ; then /bin/cp /etc/driver_aliases /tmp/driver_aliases /bin/mv /etc/driver_aliases /tmp/driver_aliases.bak /bin/mv /tmp/driver_aliases /etc fi /usr/bin/touch /etc/driver_classes if [ $? -ne 0 ] ; then /bin/cp /etc/driver_classes /tmp/driver_classes /bin/mv /etc/driver_classes /tmp/driver_classes.bak /bin/mv /tmp/driver_classes /etc fi /usr/bin/touch /etc/name_to_major if [ $? -ne 0 ] ; then /bin/cp /etc/name_to_major /tmp/name_to_major /bin/mv /etc/name_to_major /tmp/name_to_major.bak /bin/mv /tmp/name_to_major /etc fi /usr/bin/touch /etc/minor_perm if [ $? -ne 0 ] ; then /bin/cp /etc/minor_perm /tmp/minor_perm /bin/mv /etc/minor_perm /tmp/minor_perm.bak /bin/mv /tmp/minor_perm /etc fi # Make sure that we've got our own copy of /usr/bin/gzip # in the tools directory if [ ! -f $gzip ] ; then gzip=$toolsdir/gzip /usr/bin/chmod a+x "$toolsdir/gzip" 2>/dev/null fi $gzip -c -d "$toolsdir/../Product/pkgs.gz" > $tmpfile && /usr/sbin/pkgadd -R "$basedir" -d "$tmpfile" -a "$toolsdir/admin" all status=$? rm -f "$tmpfile" exit $status EOF $CHMOD a+rx "$distdir/Tools/install.sh" $CP -f /usr/bin/gzip "$distdir/Tools" 2>/dev/null } # # Unpack the miniroot of a Solaris install media. # function unpack_media { # Create temp directory to unpack the miniroot. $MKDIR -p "$UNPACKED_ROOT" # We need to use the unpackmedia option to correctly apply patches gettext "Unpacking media ... " $ROOT_ARCHIVE unpackmedia "$MEDIA_ROOT" "$UNPACKED_ROOT" > /dev/null 2>&1 if [ $? != 0 ]; then if [ -d $MEDIA_ROOT/Solaris_10 -a -d $MEDIA_ROOT/Solaris_11 ]; then # we _do_ care, because we're not patching a Solaris # update media instance gettext "There was an error unpacking the media from $MEDIA_ROOT\n" exit 1 fi fi } # # Pack an unpacked miniroot onto a Solaris install media. # function repack_media { gettext "Repacking media ..." # We need to ensure that we're using the appropriate version # of root_archive for the media that we're packing/unpacking. # The onnv version of root_archive differs from the S10 version, # and this will cause problems on re-packing. So we sneakily # use the version that we've just unpacked if [ -d $MEDIA_ROOT/Solaris_10 ]; then ROOT_ARCHIVE=$UNPACKED_ROOT/boot/solaris/bin/root_archive fi $ROOT_ARCHIVE packmedia "$MEDIA_ROOT" "$UNPACKED_ROOT" > /dev/null 2>&1 if [ $? != 0 ]; then if [ -d $MEDIA_ROOT/Solaris_10 -a -d $MEDIA_ROOT/Solaris_11 ]; then # we _do_ care, because we're not patching a Solaris # update media instance gettext "There was an error packing the media from $MEDIA_ROOT\n" exit 1 fi fi gettext "Done.\n" } # # Add packages to a Solaris install media. Also install these packages # onto the miniroot. # function add_pkgs { typeset icmd statusfile i (( ${#PACKAGES[*]} == 0 )) && return statusfile=$TMP_DIR/.add_pkgs.status DU_OUTDIR=$ITUDIR/$ITU_COUNTDIR (( ITU_COUNTDIR += 1 )) $MKDIR "$DU_OUTDIR" || return # # Add a Driver Update directory on the media # echo; gettext "Adding package(s) to media root.\n" create_du || return # # Using the Driver Update above install the packages onto the miniroot. # echo; gettext "Installing package(s) onto miniroot.\n" icmd=$DU_OUTDIR/DU/sol_$VERSION/$MACH/Tools/install.sh if [[ ! -f "$icmd" ]] then # This shouldn't happen, but just in case. gettext "Cannot find $icmd.\n" return 1 fi [[ ! -x "$icmd" ]] && chmod a+x "$icmd" $RM -f "$statusfile" { "$icmd" -R "$UNPACKED_ROOT" if (( i=$? )) then echo $i > "$statusfile" $TOUCH "$statusfile" # make sure file is created fi } 2>&1 | $NAWK -v logfile="$LOGFILE" -v vlevel=$VERBOSE_LEVEL ' # If not verbose, print certain lines from patchadd. (vlevel == 0) && /^Installing/ {print} (vlevel == 0) && /^Installation.*successful/ {print} # If verbose, print every line to stderr. (vlevel > 0) {print > "/dev/stderr"} # Save every line to logfile. {print >> logfile} ' || return [[ -s "$statusfile" ]] && return $(<$statusfile) return 0 } # # Add patches to a Solaris install media. Also patch the miniroot with # these patches # function add_patches { typeset distdir tmpdir icmd obj patches statusfile (( ${#PATCHES[*]} == 0 )) && return tmpdir=$TMP_DIR/patches statusfile=$TMP_DIR/.add_patches.status $RM -rf "$tmpdir" distdir=$ITUDIR/$ITU_COUNTDIR/DU/sol_$VERSION/$MACH (( ITU_COUNTDIR += 1 )) $MKDIR -p "$distdir/Tools" "$distdir/Product" "$tmpdir" || return # If we're running this script on sun4[vu], then create a symlink # to the other UltraSPARC architecture if [[ "$MACH" != "i386" ]] then cd $ITUDIR/$ITU_COUNTDIR/DU/sol_$VERSION $LN -s sparc sun4v $LN -s sparc sun4u else cd $ITUDIR/$ITU_COUNTDIR/DU/sol_$VERSION $LN -s i386 i86pc fi # # Add packages onto media root # echo; gettext "Adding patch(es) to media root.\n" # Symlink each patch in a temp dir so a single cpio/gzip can work. for obj in "${PATCHES[@]}" do # Get rid of trailing /'s, if any. [[ "$obj" == */ ]] && obj=${obj%%+(/)} # Make sure it's a full pathname. [[ "$obj" != /* ]] && obj=$ORIGPWD/$obj $LN -s "$obj" "$tmpdir" || return # Remember just the file component. patches[ ${#patches[*]} ]=${obj##*/} done # Package up patches as compressed cpio archive. $RM -f "$statusfile" ( # Save current stdout as fd 8. This doesn't point to the # gzip pipeline below. exec 8>&1 { # Fd 9 is used later on for filtering out cpio's # reporting total blocks to stderr but yet still # print other error messages. fd 9 refers to the # pipeline to gzip. exec 9>&1 cd "$tmpdir" for obj in "${patches[@]}" do print -u8 "Transferring patch $obj." $FIND "$obj/." -follow -print if (( i=$? )) then echo $i > "$statusfile" $TOUCH "$statusfile" return $i fi done | $CPIO -oc 2>&1 >&9 | $GREP -v '^[0-9]* blocks' >&2 } | $GZIP -9 > "$distdir/Product/patches.gz" ) || return [[ -s "$statusfile" ]] && return $(<$statusfile) # Create install.sh $CAT > "$distdir/Tools/install.sh" <<"EOF" #!/sbin/sh # install.sh -R - install patches to basedir basedir=/ toolsdir=`dirname $0` tmpdir=/tmp/`basename $0`.$$ gzip=/usr/bin/gzip trap "/bin/rm -rf $tmpdir" 0 while getopts "R:" arg do case "$arg" in R) basedir=$OPTARG;; esac done /bin/mkdir -p "$tmpdir" || exit tmpfile=$tmpdir/patches patchdir=$tmpdir/patchdir /bin/mkdir "$patchdir" || exit # Make sure that we've got our own copy of /usr/bin/gzip # in the tools directory if [ ! -f $gzip ] ; then gzip=$toolsdir/gzip /usr/bin/chmod a+x "$toolsdir/gzip" 2>/dev/null fi $gzip -c -d "$toolsdir/../Product/patches.gz" > $tmpfile || exit cd "$patchdir" /bin/cpio -idum < "$tmpfile" || exit patchadd -R "$basedir" -nu * EOF $CHMOD a+rx "$distdir/Tools/install.sh" $CP -f /usr/bin/gzip "$distdir/Tools" 2>/dev/null # # Patch the miniroot # echo; gettext "Installing patch(es) onto miniroot.\n" $RM -f "$statusfile" { $PATCHADD -udn -C "$UNPACKED_ROOT" "${PATCHES[@]}" if (( i=$? )) then echo $i > "$statusfile" $TOUCH "$statusfile" # make sure file is created fi } 2>&1 | $NAWK -v logfile="$LOGFILE" -v vlevel=$VERBOSE_LEVEL ' # If not verbose, print certain lines from patchadd. (vlevel == 0) && /^Patch.*successful/ {print} # If verbose, print every line to stderr. (vlevel > 0) {print > "/dev/stderr"} # Save every line to logfile. {print >> logfile} ' || return [[ -s "$statusfile" ]] && return $(<$statusfile) # Remove patch log files to save space when miniroot is repacked. $RM -rf "$UNPACKED_ROOT"/var/sadm/patch } # # Starting point for makedu subcommand: # # Convert packages into Driver Update (DU) directory format. # function makedu # ... { typeset i process_options "$@" || return shift 'MYOPTIND - 1' if (( $# == 0 )) then gettext "Please specify one or more packages.\n" usage_short return 1 fi # Release number must be specified. if [[ -z "$RELEASE" ]] then gettext "Please specify Solaris release number (-r option).\n" usage_short return 1 fi check_release || return # Either -d or -o option, or both, must be specified. if [[ -z "$DU_OUTDIR" && -z "$ISO" ]] then gettext "Please specify either -d or -o option (or both).\n" usage_short return 1 fi if [[ -n "$ISO" ]] then check_iso || return ${ISOLABEL:=DU sol_$VERSION} 2>/dev/null # default ISO label fi check_dudir || return # should be called after check_iso # Rest of arguments must be packages. collect_packages "$@" || return check_prereqs || return # Create DU and the (non-bootable) ISO image (if requested). create_du && create_nonboot_iso "$DU_OUTDIR" if (( i=$? )) then $RM -rf "$DU_OUTDIR/DU" [[ -n "$ISO" ]] && rm -f "$ISO" else if [[ "$MACH" != "i386" ]] then echo "This DU must be written as either an ISO (hsfs)" echo "or a *ufs* filesystem. DO NOT USE pcfs!" fi fi return $i } # # Starting point for patchmedia subcommand: # # Patch a Solaris install image with the given packages and patches. # function patchmedia # ... { typeset soldir process_options "$@" || return shift 'MYOPTIND - 1' if (( $# == 0 )) then gettext "Please specify one or more packages or patches.\n" usage_short return 1 fi # -R option must be specified if [[ -z "$MEDIA_ROOT" ]] then gettext "Please specify Solaris media root (-R option).\n" usage_short return 1 fi check_media_root || return # Get the Solaris directory under $MEDIA_ROOT. soldir=$($LS -d $MEDIA_ROOT/Solaris* 2>/dev/null) if [[ -z "$soldir" ]] then gettext "Can't find Solaris directory in $MEDIA_ROOT.\n" return 1 fi # Extract the Solaris release number from the Solaris_* directory. RELEASE=5.${soldir##*Solaris_} check_release || return # If user specifies an ISO image to create. if [[ -n "$ISO" ]] then check_iso || return ${ISOLABEL:=${soldir##*/}} # default ISO label fi # Rest of arguments must be packages or patches. collect_packages_patches "$@" || return # Verify we have some important utilities we need. check_prereqs || return # Verify there's miniroot file in $MEDIA_ROOT. check_miniroot || return # Create the ITU directory on the media root, if necessary ITUDIR=$MEDIA_ROOT/ITUs $MKDIR -p "$ITUDIR" || return # The ITU directory might contain multiple driver updates already, # each in a separate numbered subdirectory. So look for the # subdirectory with the highest number and we'll add the packages # and patches on the next one. ITU_COUNTDIR=$($LS -d "$ITUDIR"/+([0-9]) 2>/dev/null | $SED 's;.*/;;' | $SORT -rn | $HEAD -1) if [[ $ITU_COUNTDIR == *( ) ]] # ITU_COUNTDIR is a typeset -Zn var then ITU_COUNTDIR=0 else (( ITU_COUNTDIR += 1 )) fi unpack_media || return add_pkgs && add_patches if (( status=$? )) && [[ -s "$LOGFILE" ]] then echo; gettext "A package or patch installation has failed.\n" gettext "Messages from pkgadd and patchadd have been saved in $LOGFILE\n" return $status else rm -f "$LOGFILE" fi print repack_media || return create_bootable_iso "$MEDIA_ROOT" gettext "$MEDIA_ROOT has been successfully patched\n" } # # Starting point for makeiso subcommand: # # Create a bootable ISO image of a Solaris install image. # function makeiso # .. { process_options "$@" || return shift 'MYOPTIND - 1' if (( $# == 0 )) then gettext "Please specify the Solaris media root.\n" usage_short return 1 elif (( $# > 1 )) then gettext "Too many arguments supplied.\n" usage_short return 1 fi MEDIA_ROOT=$1 check_media_root || return # ISO image must be specified. if [[ -z "$ISO" ]] then gettext "Please specify ISO image file (-o option).\n" usage_short return 1 fi check_iso || return # If user doesn't specify ISO label, use the Solaris_* directory name # under $MEDIA_ROOT. if [[ -z "$ISOLABEL" ]] then ISOLABEL=$(echo "$MEDIA_ROOT"/Solaris*) ISOLABEL=${ISOLABEL##*/} fi check_prereqs || return create_bootable_iso "$MEDIA_ROOT" } # # Main # trap cleanup EXIT # Numbered subdirectories under ITU directory $ITUDIR. typeset -Z3 ITU_COUNTDIR=0 # Where to unpack a miniroot. UNPACKED_ROOT=${TMP_DIR}/miniroot # Reset arrays. unset PACKAGES PATCHES DU_OUTDIR= FORCE=0 ISO= ISOLABEL= MEDIA_ROOT= RELEASE= SUBCOMMAND= VERBOSE_LEVEL=0 VERBOSE_OPTS= if (( $# == 0 )) then usage_long return 1 fi typeset -l SUBCOMMAND=$1 # ignore case shift if [[ $SUBCOMMAND != @(makedu|patchmedia|makeiso) ]] then # Be nice: allow some subcommands that cry out "help". case "$SUBCOMMAND" in *(-)help|*(-)usage|-h|-\?) usage_long return 0 ;; *) gettext "Invalid subcommand: $SUBCOMMAND.\n" usage_short return 1 ;; esac fi $MKDIR -p "$TMP_DIR" || return $RM -f "$LOGFILE" # Run the subcommand. $SUBCOMMAND "$@"