itu.ksh revision 4f10d6de4eaf8568195df6a921d12810040e03d9
#
# 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
# 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.
#
#
# itu - converts packages to Driver Update format and patches Solaris install
# media for Install Time Update (ITU).
#
readonly PROG=$0
# Must-have utilities
# Relative to a Solaris media root.
# Paths we need.
# for gettext
export TEXTDOMAIN
function cleanup
{
}
function usage_long
{
print -u2
}
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 " -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 # <arg> ...
{
esac
do
;;
f) FORCE=1
;;
;;
gettext "ISO images will not be created on /tmp.\n"
gettext "Please choose a different output location.\n"
exit 3
fi
;;
;;
;;
;;
return 1
;;
*) gettext "Option -$OPTARG invalid for $SUBCOMMAND.\n"
return 1
;;
esac
done
return 0
}
#
# Check some prerequisites
#
function check_prereqs
{
typeset utils f
# List of must-have utilities depends on subcommand.
;;
;;
;;
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
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 # <arg> ...
{
typeset obj
do
then
return 1
then
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 # <arg> ...
{
typeset obj
do
then
# Collect patches.
PATCHES[ ${#PATCHES[*]} ]=$obj
then
# Collect packages.
PACKAGES[ ${#PACKAGES[*]} ]=$obj
then
return 1
else
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
while true
do
read ans
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.
then
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.
}
#
# 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
{
then
if (( $? ))
then
gettext "Can't access parent directory of ISO image.\n"
return 1
fi
else
ISODIR=$(pwd -P)
fi
then
fi
return 0
}
#
# If specified, check the Driver Update output directory $DU_OUTDIR (-d option).
# already exists, ask user whether to overwrite it, unless -f option was given.
#
function check_dudir
{
typeset realpath
then
return 0
fi
# Verify user-specified DU output directory.
then
gettext "$DU_OUTDIR is not a directory.\n"
return 1
fi
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.
then
then
return 1
fi
fi
# If the DU directory already exists, ask user permission to
# remove it unless -f option was given.
then
fi
return 0
}
#
# Verify $MEDIA_ROOT is indeed a Solaris install media.
#
function check_media_root
{
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
{
then
return 1
fi
return 0
}
#
# Create a non-bootable ISO image of the given directory.
#
function create_nonboot_iso # <dir>
{
if (( $# != 1 ))
then
gettext "create_nonboot_iso missing argument.\n"
return 1
fi
dir=$1
# Skip if no ISO image was specified.
# Determine mkisofs' verbose flag depending on $VERBOSE_LEVEL.
case $VERBOSE_LEVEL in
;;
1) vflag= # mkisofs' default verboseness
;;
*) vflag=
while ((i > 0))
do
(( i -= 1 ))
done
;;
esac
print "Creating ISO image ..."
# trick to filter out mkisofs's warning message about being
# non-conforming to ISO-9660.
-N -l -d -D -r \
-R -J \
$vflag \
}
#
# Create a bootable Solaris ISO image of the given Solaris install directory.
#
function create_bootable_iso # <dir>
{
if (( $# != 1 ))
then
gettext "create_bootable_iso missing argument.\n"
return 1
fi
dir=$1
# Skip if no ISO image was specified.
# Determine mkisofs' verbose flag depending on $VERBOSE_LEVEL.
case $VERBOSE_LEVEL in
;;
1) vflag= # mkisofs' default verboseness
;;
*) vflag=
while ((i > 0))
do
(( i -= 1 ))
done
;;
esac
# Verify the El Torito file exists under media root. And if so,
# verify it's writable since it will be modified with some boot
# information by mkisofs' -boot-info-table option.
then
return 1
then
return 1
fi
gettext "Creating bootable ISO image ..."
# Since mkisofs below will modify the file $ELTORITO in-place, save
# a copy of it first.
# trick to filter out mkisofs's warning message about being
# non-conforming to ISO-9660.
-c .catalog \
-N -l -d -D -r \
-R -J \
$vflag \
i=$?
# Restore saved El Torito file
return $i
}
#
# Create a Driver Update (DU) format directory from packages
#
function create_du
{
typeset distdir tmpdudir pkgs obj statusfile
# Create DU directory first.
# Unfortunately pkgtrans insists that all packages must be in
# <device1> (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 <device1>.
do
# Get rid of trailing /'s, if any.
# Make sure it's full pathname.
# Remember just the file component.
pkgs[ ${#pkgs[*]} ]=${obj##*/}
done
# Package up packages as compressed data stream.
(
# 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
{
echo $? > $statusfile
$TOUCH $statusfile # make sure file is created
)
# Create admin file for pkgadd
mail=
# Create install.sh
# install.sh -R <basedir> - install packages to basedir
basedir=/
do
esac
done
status=$?
exit $status
$CHMOD a+rx "$distdir/Tools/install.sh"
}
#
# 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 ... "
if [ $? != 0 -a ! -d $MEDIA_ROOT/Solaris_10 ]; then
# we _do_ care, because we're not patching a Solaris 10
# update media instance
gettext "There was an error unpacking the media from $MEDIA_ROOT\n"
exit 1
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
# 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
fi
if [ $? != 0 -a ! -d $MEDIA_ROOT/Solaris_10 ]; then
# we _do_ care, because we're not patching a Solaris 10
# update media instance
gettext "There was an error unpacking the media from $MEDIA_ROOT\n"
exit 1
fi
}
#
# Add packages to a Solaris install media. Also install these packages
# onto the miniroot.
#
function add_pkgs
{
typeset icmd statusfile i
(( ${#PACKAGES[*]} == 0 )) && 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"
then
# This shouldn't happen, but just in case.
return 1
fi
$RM -f "$statusfile"
{
if (( i=$? ))
then
echo $i > "$statusfile"
fi
# If not verbose, print certain lines from patchadd.
(vlevel == 0) && /^Installing/ {print}
(vlevel == 0) && /^Installation.*successful/ {print}
# If verbose, print every line to stderr.
# Save every line to logfile.
{print >> logfile}
' || return
return 0
}
#
# Add patches to a Solaris install media. Also patch the miniroot with
# these patches
#
function add_patches
{
(( ${#PATCHES[*]} == 0 )) && return
#
# Add packages onto media root
#
echo;
gettext "Adding patch(es) to media root.\n"
do
# Get rid of trailing /'s, if any.
# Make sure it's a full pathname.
# 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"
do
if (( i=$? ))
then
echo $i > "$statusfile"
return $i
fi
) || return
# Create install.sh
# install.sh -R <basedir> - install patches to basedir
basedir=/
do
esac
done
cd "$patchdir"
$CHMOD a+rx "$distdir/Tools/install.sh"
#
# 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"
fi
# If not verbose, print certain lines from patchadd.
(vlevel == 0) && /^Patch.*successful/ {print}
# If verbose, print every line to stderr.
# Save every line to logfile.
{print >> logfile}
' || return
# Remove patch log files to save space when miniroot is repacked.
}
#
# Starting point for makedu subcommand:
#
# Convert packages into Driver Update (DU) directory format.
#
function makedu # <arg> ...
{
typeset i
shift 'MYOPTIND - 1'
if (( $# == 0 ))
then
gettext "Please specify one or more packages.\n"
return 1
fi
# Release number must be specified.
then
gettext "Please specify Solaris release number (-r option).\n"
return 1
fi
check_release || return
# Either -d or -o option, or both, must be specified.
then
gettext "Please specify either -d or -o option (or both).\n"
return 1
fi
then
check_iso || return
fi
check_dudir || return # should be called after check_iso
# Rest of arguments must be packages.
check_prereqs || return
# Create DU and the (non-bootable) ISO image (if requested).
if (( i=$? ))
then
$RM -rf "$DU_OUTDIR/DU"
fi
return $i
}
#
# Starting point for patchmedia subcommand:
#
# Patch a Solaris install image with the given packages and patches.
#
function patchmedia # <arg> ...
{
typeset soldir
shift 'MYOPTIND - 1'
if (( $# == 0 ))
then
gettext "Please specify one or more packages or patches.\n"
return 1
fi
# -R option must be specified
then
gettext "Please specify Solaris media root (-R option).\n"
return 1
fi
check_media_root || return
# Get the Solaris directory under $MEDIA_ROOT.
then
gettext "Can't find Solaris directory in $MEDIA_ROOT.\n"
return 1
fi
# Extract the Solaris release number from the Solaris_* directory.
check_release || return
# If user specifies an ISO image to create.
then
check_iso || return
fi
# Rest of arguments must be packages or patches.
# 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
# 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.
then
else
fi
unpack_media || return
then
echo;
gettext "A package or patch installation has failed.\n"
return $status
else
fi
print
repack_media || return
}
#
# Starting point for makeiso subcommand:
#
# Create a bootable ISO image of a Solaris install image.
#
function makeiso # <arg> ..
{
shift 'MYOPTIND - 1'
if (( $# == 0 ))
then
gettext "Please specify the Solaris media root.\n"
return 1
elif (( $# > 1 ))
then
gettext "Too many arguments supplied.\n"
return 1
fi
MEDIA_ROOT=$1
check_media_root || return
# ISO image must be specified.
then
gettext "Please specify ISO image file (-o option).\n"
return 1
fi
check_iso || return
# If user doesn't specify ISO label, use the Solaris_* directory name
# under $MEDIA_ROOT.
then
fi
check_prereqs || return
}
#
# Main
#
# Numbered subdirectories under ITU directory $ITUDIR.
typeset -Z3 ITU_COUNTDIR=0
# Where to unpack a miniroot.
# Reset arrays.
FORCE=0
ISO=
if (( $# == 0 ))
then
return 1
fi
typeset -l SUBCOMMAND=$1 # ignore case
shift
then
# Be nice: allow some subcommands that cry out "help".
return 0
;;
*)
gettext "Invalid subcommand: $SUBCOMMAND.\n"
return 1
;;
esac
fi
# Run the subcommand.
$SUBCOMMAND "$@"