#!/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. # # # pkg2du - convert driver packages to Driver Update (DU) format # readonly PROG=$0 readonly ORIGPWD=$PWD readonly TMP_DIR=${TMPDIR:-/tmp}/${PROG##*/}.$$ # 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 ROOT_ARCHIVE=/usr/sbin/root_archive 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` # for gettext TEXTDOMAIN=SUNW_OST_OSCMD export TEXTDOMAIN function usage { gettext "Usage:\n${PROG##*/} -r <release> [-f] [-v] [-d <dir>] [-o <iso>] [-l <label>]\n <pkg> [<pkg> ...]\n" gettext "Options:\n -d <dir>\n Directory where the Driver Update directory should be created.\n" gettext " -o <iso>\n Create a Solaris ISO image of the Driver Update directory.\n" gettext " -f\n If <dir>/DU or <iso> exists, remove it without asking first.\n" gettext " -l <label>\n Label/volume name of the ISO image (if -o option is specified).\n" gettext " -r <release>\n Solaris release number to use. It takes the form of 5.10.\n This option must be specified.\n" gettext " -v\n Verbose. Multiple -v options increase verbosity.\n" echo; } function check_prereqs { typeset f # We must have these utilities. for f in $GZIP ${ISO:+$MKISOFS} $PKGTRANS do if [[ ! -x "$f" ]] then gettext "Cannot find required utilty $f" exit 1 fi done } function cleanup { $RM -rf "$TMP_DIR" } function is_overwrite { typeset arg=$1 typeset -l ans [[ $FORCE == yes ]] && 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 echo; } function collect_objs # <pkg> ... { typeset obj fail=0 for obj do if [[ -f "$obj"/pkginfo ]] then PACKAGES[ ${#PACKAGES[*]} ]=$obj else gettext "$obj is not in package format\n" (( fail += 1 )) fi done (( fail )) && return 1 return 0 } function mkdu { typeset distdir tmpdudir pkgs obj statusfile trap '/bin/rm -rf $statusfile $tmpdudir' EXIT # Create DU directory first. distdir=$ROOTDIR/DU/sol_$VERSION/$MACH $MKDIR -p "$distdir/Tools" "$distdir/Product" # to the other UltraSPARC architecture if [[ "$MACH" != "i386" ]] then cd $ROOTDIR/DU/sol_$VERSION $LN -s sparc sun4v $LN -s sparc sun4u else cd $ROOTDIR/DU/sol_$VERSION $LN -s i386 i86pc fi # 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>. tmpdudir=$TMP_DIR/mkdu $MKDIR -p "$tmpdudir" for obj in "${PACKAGES[@]}" 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" "$tmpdudir" || exit 1 # Remember just the file component. pkgs[ ${#pkgs[*]} ]=${obj##*/} done # Package up packages as compressed data stream. statusfile=$TMP_DIR/.pkgtrans.status { $PKGTRANS -s "$tmpdudir" /dev/stdout "${pkgs[@]}" 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=unique 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 <basedir> - install packages to basedir basedir=/ toolsdir=`dirname $0` tmpfile=/tmp/`basename $0`.$$ while getopts "R:" arg do case "$arg" in R) basedir=$OPTARG;; esac done /usr/bin/gzip -c -d "$toolsdir/../Product/pkgs.gz" > $tmpfile && /usr/sbin/pkgadd -R "$basedir" -d "$tmpfile" -a "$toolsdir/admin" all status=$? /bin/rm -f "$tmpfile" exit $status EOF $CHMOD a+rx "$distdir/Tools/install.sh" } function mkiso { typeset vflag # 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 (( VERBOSE_LEVEL )) && gettext "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 ISOARGS_sparc="-B ... -joliet-long -R -U" ISOARGS_i386="-d -N -r -relaxed-filenames" if [[ "$MACH" = "i386" ]] then ISOARGS=$ISOARGS_i386 else ISOARGS=$ISOARGS_sparc fi $MKISOFS -o "$ISO" \ -allow-leading-dots \ $ISOARGS \ -ldots -full-iso9660-filenames \ -R -J \ -V "$ISOLABEL" \ $vflag \ -log-file >($CAT -u >&2) \ "$ROOTDIR" 2>/dev/null } # # Main # trap cleanup EXIT FORCE= ISO= LABEL= RELEASE= ROOTDIR= VERBOSE_LEVEL=0 while getopts ':d:fo:l:r:v' opt do case $opt in d) ROOTDIR=$OPTARG ;; f) FORCE=yes ;; 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 ;; l) LABEL=$OPTARG ;; r) RELEASE=$OPTARG ;; v) (( VERBOSE_LEVEL += 1 )) ;; :) gettext "Option -$OPTARG missing argument." usage exit 1 ;; *) gettext "Option -$OPTARG invalid.\n" usage exit 2 ;; esac done shift 'OPTIND - 1' # Release number must be specified. if [[ -z "$RELEASE" ]] then gettext "Solaris release number must be specified (-r option).\n" usage exit 1 fi # Verify release number. Allow major.minor or major.minor.micro format. if [[ $RELEASE != +([0-9]).+([0-9])?(.+([0-9])) ]] then gettext "Invalid release number: $RELEASE\n" exit 1 fi VERSION=$(echo $RELEASE | $SED 's/5\./2/') # Either or both of -d or -o option must be specified. if [[ -z "$ROOTDIR" && -z "$ISO" ]] then gettext "Either -d or -o option (or both) must be specified.\n" usage exit 1 fi # There must be at least one package. if (( $# == 0 )) then gettext "No package was specified.\n" usage exit 1 fi # Check and collect packages unset PACKAGES collect_objs "$@" || exit 1 # Default label for ISO image LABEL=${LABEL:-DU sol_$VERSION} check_prereqs # must be called after $ISO is possibly set # If an ISO image was specified, check its parent directory and get its # full pathname. unset ISODIR if [[ -n "$ISO" ]] then if [[ "$ISO" = */* ]] then ISODIR=$(cd "${ISO%/*}" 2>/dev/null && pwd -P) if (( $? )) then gettext "Can't access parent directory of ISO image\n" exit 1 fi else ISODIR=$(pwd -P) fi fi # If user specified a media root directory, verify it exists, else use # a temporary directory. if [[ -n "$ROOTDIR" ]] then $MKDIR -p "$ROOTDIR"; if [ $? != 0 ]; then gettext "$ROOTDIR is not a directory.\n" exit 1 elif [[ ! -w "$ROOTDIR" ]] then gettext "Directory $ROOTDIR is not writable.\n" exit 1 fi # If an ISO image path is also specified, make sure it's not under # $ROOTDIR since we're going to take the ISO image of $ROOTDIR. if [[ -n "$ISODIR" ]] then realroot=$(cd "$ROOTDIR" 2>/dev/null && pwd -P) if [[ "$ISODIR" = "$realroot"?(/*) ]] then gettext "ISO image must not be under Driver Update's parent directory ($realroot)\n" exit 1 fi fi else ROOTDIR=$TMP_DIR/root fi # If DU directory already exists, ask user permission to remove it unless -f # option was specified. if [[ -d "$ROOTDIR/DU" ]] then is_overwrite "$ROOTDIR/DU" || exit 0 $RM -rf "$ROOTDIR/DU" fi # If ISO image already exists, ask user permission to remove it unless -f # option was specified. if [[ -f "$ISO" ]] then is_overwrite "$ISO" || exit 0 $RM -f "$ISO" fi # Create DU directory and the ISO image (if requested). mkdu && mkiso if (( $? )) then $RM -rf "$ROOTDIR/DU" [[ -n "$ISO" ]] && $RM -f "$ISO" exit 1 fi exit 0