Home | History | Annotate | Download | only in itutools
      1 #!/bin/ksh93 -p
      2 #
      3 #
      4 # CDDL HEADER START
      5 #
      6 # The contents of this file are subject to the terms of the
      7 # Common Development and Distribution License (the "License").
      8 # You may not use this file except in compliance with the License.
      9 #
     10 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     11 # or http://www.opensolaris.org/os/licensing.
     12 # See the License for the specific language governing permissions
     13 # and limitations under the License.
     14 #
     15 # When distributing Covered Code, include this CDDL HEADER in each
     16 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     17 # If applicable, add the following below this CDDL HEADER, with the
     18 # fields enclosed by brackets "[]" replaced with your own identifying
     19 # information: Portions Copyright [yyyy] [name of copyright owner]
     20 #
     21 # CDDL HEADER END
     22 #
     23 #
     24 # Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     25 # Use is subject to license terms.
     26 #
     27 
     28 #
     29 # pkg2du - convert driver packages to Driver Update (DU) format
     30 #
     31 
     32 readonly PROG=$0
     33 readonly ORIGPWD=$PWD
     34 readonly TMP_DIR=${TMPDIR:-/tmp}/${PROG##*/}.$$
     35 
     36 # Must-have utilities
     37 readonly CPIO=/usr/bin/cpio
     38 readonly GZIP=/usr/bin/gzip
     39 readonly MKISOFS=/usr/bin/mkisofs
     40 readonly PATCHADD=/usr/sbin/patchadd
     41 readonly PKGTRANS=/usr/bin/pkgtrans
     42 readonly ROOT_ARCHIVE=/usr/sbin/root_archive
     43 readonly LOFIADM=/usr/sbin/lofiadm
     44 readonly MKDIR=/usr/bin/mkdir
     45 readonly RM=/usr/bin/rm
     46 readonly CP=/usr/bin/cp
     47 readonly HEAD=/usr/bin/head
     48 readonly SORT=/usr/bin/sort
     49 readonly MKBOOTMEDIA=/usr/bin/mkbootmedia
     50 readonly PKG2DU=/usr/bin/pkg2du
     51 readonly TOUCH=/usr/bin/touch
     52 readonly NAWK=/usr/bin/nawk
     53 readonly CHMOD=/usr/bin/chmod
     54 readonly GREP=/usr/bin/grep
     55 readonly LS=/usr/bin/ls
     56 readonly LN=/usr/bin/ln
     57 readonly SED=/usr/bin/sed
     58 readonly CAT=/usr/bin/cat
     59 readonly FIND=/usr/bin/find
     60 readonly UNAME=/usr/bin/uname
     61 readonly MACH=`$UNAME -p`
     62 
     63 # for gettext
     64 TEXTDOMAIN=SUNW_OST_OSCMD
     65 export TEXTDOMAIN
     66 
     67 
     68 function usage
     69 {
     70 	gettext "Usage:\n${PROG##*/} -r <release> [-f] [-v] [-d <dir>] [-o <iso>] [-l <label>]\n        <pkg> [<pkg> ...]\n"
     71 	gettext "Options:\n  -d <dir>\n        Directory where the Driver Update directory should be created.\n"
     72 	gettext "  -o <iso>\n        Create a Solaris ISO image of the Driver Update directory.\n"
     73 	gettext "  -f\n        If <dir>/DU or <iso> exists, remove it without asking first.\n"
     74 	gettext "  -l <label>\n        Label/volume name of the ISO image (if -o option is specified).\n"
     75 	gettext "  -r <release>\n        Solaris release number to use.  It takes the form of 5.10.\n        This option must be specified.\n"
     76 	gettext "  -v\n        Verbose.  Multiple -v options increase verbosity.\n"
     77 	echo;
     78 }
     79 
     80 
     81 function check_prereqs
     82 {
     83 	typeset f
     84 
     85 	# We must have these utilities.
     86 	for f in $GZIP ${ISO:+$MKISOFS} $PKGTRANS
     87 	do 
     88 		if [[ ! -x "$f" ]]
     89 		then
     90 			gettext "Cannot find required utilty $f"
     91 			exit 1
     92 		fi
     93 	done
     94 }
     95 
     96 
     97 function cleanup
     98 {
     99 	$RM -rf "$TMP_DIR"
    100 }
    101 
    102 
    103 function is_overwrite
    104 {
    105 	typeset arg=$1
    106 	typeset -l ans
    107 
    108 	[[ $FORCE == yes ]] && return 0
    109 
    110 	while true
    111 	do
    112 		gettext "$arg already exists. Overwrite it? (y/n) "
    113 		read ans
    114 		case $ans in
    115 		y*|Y*) return 0 ;;		# go ahead overwrite
    116 		n*|N*) return 1 ;;		# don't overwrite
    117 		esac
    118 	done
    119 	echo;
    120 }
    121 
    122 
    123 function collect_objs # <pkg> ...
    124 {
    125 	typeset obj fail=0
    126 
    127 	for obj
    128 	do
    129 		if [[ -f "$obj"/pkginfo ]]
    130 		then
    131 			PACKAGES[ ${#PACKAGES[*]} ]=$obj
    132 		else
    133 			gettext "$obj is not in package format\n"
    134 			(( fail += 1 ))
    135 		fi
    136 	done
    137 	(( fail )) && return 1
    138 	return 0
    139 }
    140 
    141 
    142 function mkdu
    143 {
    144 	typeset distdir tmpdudir pkgs obj statusfile
    145 
    146 	trap '/bin/rm -rf $statusfile $tmpdudir' EXIT
    147 
    148 	# Create DU directory first.
    149 	distdir=$ROOTDIR/DU/sol_$VERSION/$MACH
    150 	$MKDIR -p "$distdir/Tools" "$distdir/Product"
    151 
    152 	# to the other UltraSPARC architecture
    153 	if [[ "$MACH" != "i386" ]]
    154 	then
    155 		cd $ROOTDIR/DU/sol_$VERSION
    156 		$LN -s sparc sun4v
    157 		$LN -s sparc sun4u
    158 	else
    159 		cd $ROOTDIR/DU/sol_$VERSION
    160 		$LN -s i386 i86pc
    161 	fi	
    162 
    163 	# Unfortunately pkgtrans insists that all packages must be in
    164 	# <device1> (see pkgtrans(1)).  The packages can't have any path
    165 	# components.  So we'll create a temporary directory first and then
    166 	# symlinks to the specified packages.  Then run pkgtrans with
    167 	# the temporary directory as <device1>.
    168 	tmpdudir=$TMP_DIR/mkdu
    169 	$MKDIR -p "$tmpdudir"
    170 
    171 	for obj in "${PACKAGES[@]}"
    172 	do
    173 		# Get rid of trailing /'s, if any.
    174 		[[ "$obj" == */ ]] && obj=${obj%%+(/)}
    175 
    176 		# Make sure it's a full pathname.
    177 		[[ "$obj" != /* ]] && obj=$ORIGPWD/$obj
    178 
    179 		$LN -s "$obj" "$tmpdudir" || exit 1
    180 
    181 		# Remember just the file component.
    182 		pkgs[ ${#pkgs[*]} ]=${obj##*/}
    183 	done
    184 
    185 	# Package up packages as compressed data stream.
    186 	statusfile=$TMP_DIR/.pkgtrans.status
    187 	{
    188 		$PKGTRANS -s "$tmpdudir" /dev/stdout "${pkgs[@]}"
    189 		echo $? > $statusfile
    190 		$TOUCH $statusfile	# make sure file is created
    191 	} | $GZIP -9 > "$distdir/Product/pkgs.gz"
    192 
    193 	[[ -s $statusfile && $(<$statusfile) != 0 ]] && return 1
    194 
    195 	# Create admin file for pkgadd
    196 	$CAT > "$distdir/Tools/admin" <<"EOF"
    197 mail=
    198 instance=unique
    199 partial=nocheck
    200 runlevel=nocheck
    201 idepend=nocheck
    202 rdepend=nocheck
    203 space=nocheck
    204 setuid=nocheck
    205 conflict=nocheck
    206 action=nocheck
    207 EOF
    208 
    209 	# Create install.sh
    210 	$CAT > "$distdir/Tools/install.sh" <<"EOF"
    211 #!/sbin/sh
    212 # install.sh -R <basedir> - install packages to basedir
    213 basedir=/
    214 toolsdir=`dirname $0`
    215 tmpfile=/tmp/`basename $0`.$$
    216 while getopts "R:" arg
    217 do
    218         case "$arg" in
    219                 R) basedir=$OPTARG;;
    220         esac
    221 done
    222 /usr/bin/gzip -c -d "$toolsdir/../Product/pkgs.gz" > $tmpfile &&
    223 	/usr/sbin/pkgadd -R "$basedir" -d "$tmpfile" -a "$toolsdir/admin" all
    224 status=$?
    225 /bin/rm -f "$tmpfile"
    226 exit $status
    227 EOF
    228 	$CHMOD a+rx "$distdir/Tools/install.sh"
    229 }
    230 
    231 
    232 function mkiso
    233 {
    234 	typeset vflag
    235 
    236 	# Skip if no ISO image was specified.
    237 	[[ -z "$ISO" ]] && return 0
    238 
    239 	# Determine mkisofs' verbose flag depending on $VERBOSE_LEVEL.
    240 	case $VERBOSE_LEVEL in
    241 	0)	vflag=-quiet
    242 		;;
    243 	1)	vflag=				# mkisofs' default verboseness
    244 		;;
    245 	*)	vflag=
    246 		i=$VERBOSE_LEVEL
    247 		while ((i > 0))
    248 		do
    249 			vflag="-v $vflag"
    250 			(( i -= 1 ))
    251 		done
    252 		;;
    253 	esac
    254 
    255 	(( VERBOSE_LEVEL )) && gettext "Creating ISO image ..."
    256 
    257 	# Note: the "-log-file >(cat -u >&2)" and "2>/dev/null" below is a
    258 	#	trick to filter out mkisofs's warning message about being
    259 	#	non-conforming to ISO-9660.
    260 	# We do some funky architecture-specific stuff here so that we can
    261 	# actually create a bootable media image for UltraSPARC systems
    262 	
    263 	ISOARGS_sparc="-B ... -joliet-long -R -U"
    264 	ISOARGS_i386="-d -N -r -relaxed-filenames"	
    265 	if [[ "$MACH" = "i386" ]]
    266 	then
    267 		ISOARGS=$ISOARGS_i386
    268 	else
    269 		ISOARGS=$ISOARGS_sparc
    270 	fi
    271 
    272 	$MKISOFS -o "$ISO" \
    273 		-allow-leading-dots \
    274 		$ISOARGS \
    275 		-ldots -full-iso9660-filenames \
    276 		-R -J \
    277 		-V "$ISOLABEL" \
    278 		$vflag \
    279 		-log-file >($CAT -u >&2) \
    280 		"$ROOTDIR" 2>/dev/null
    281 }
    282 
    283 
    284 #
    285 # Main
    286 #
    287 trap cleanup EXIT
    288 
    289 FORCE=
    290 ISO=
    291 LABEL=
    292 RELEASE=
    293 ROOTDIR=
    294 VERBOSE_LEVEL=0
    295 
    296 while getopts ':d:fo:l:r:v' opt
    297 do
    298 	case $opt in
    299 	d)	ROOTDIR=$OPTARG
    300 		;;
    301 	f)	FORCE=yes
    302 		;;
    303 	o)	ISO=$OPTARG
    304 		if [ ! -z `echo $ISO | $GREP "^/tmp"` ]; then
    305 		        gettext "ISO images will not be created on /tmp.\n"
    306 			gettext "Please choose a different output location.\n"
    307 			exit 3
    308 		fi
    309 		;;
    310 	l)	LABEL=$OPTARG
    311 		;;
    312 	r)	RELEASE=$OPTARG
    313 		;;
    314 	v)	(( VERBOSE_LEVEL += 1 ))
    315 		;;
    316 	:)	gettext "Option -$OPTARG missing argument."
    317 		usage
    318 		exit 1
    319 		;;
    320 	*)	gettext "Option -$OPTARG invalid.\n"
    321 		usage
    322 		exit 2
    323 		;;
    324 	esac
    325 done
    326 shift 'OPTIND - 1'
    327 
    328 # Release number must be specified.
    329 if [[ -z "$RELEASE" ]]
    330 then
    331 	gettext "Solaris release number must be specified (-r option).\n"
    332 	usage
    333 	exit 1
    334 fi
    335 
    336 # Verify release number.  Allow major.minor or major.minor.micro format.
    337 if [[ $RELEASE != +([0-9]).+([0-9])?(.+([0-9])) ]]
    338 then
    339 	gettext "Invalid release number: $RELEASE\n"
    340 	exit 1
    341 fi
    342 VERSION=$(echo $RELEASE | $SED 's/5\./2/')
    343 
    344 # Either or both of -d or -o option must be specified.
    345 if [[ -z "$ROOTDIR" && -z "$ISO" ]]
    346 then
    347 	gettext "Either -d or -o option (or both) must be specified.\n"
    348 	usage
    349 	exit 1
    350 fi
    351 
    352 # There must be at least one package.
    353 if (( $# == 0 ))
    354 then
    355 	gettext "No package was specified.\n"
    356 	usage
    357 	exit 1
    358 fi
    359 
    360 # Check and collect packages
    361 unset PACKAGES
    362 collect_objs "$@" || exit 1
    363 
    364 # Default label for ISO image
    365 LABEL=${LABEL:-DU sol_$VERSION}
    366 
    367 check_prereqs		# must be called after $ISO is possibly set
    368 
    369 # If an ISO image was specified, check its parent directory and get its
    370 # full pathname.
    371 unset ISODIR
    372 if [[ -n "$ISO" ]]
    373 then
    374 	if [[ "$ISO" = */* ]]
    375 	then
    376 		ISODIR=$(cd "${ISO%/*}" 2>/dev/null && pwd -P)
    377 		if (( $? ))
    378 		then
    379 			gettext "Can't access parent directory of ISO image\n"
    380 			exit 1
    381 		fi
    382 	else
    383 		ISODIR=$(pwd -P)
    384 	fi
    385 fi
    386 
    387 # If user specified a media root directory, verify it exists, else use
    388 # a temporary directory.
    389 if [[ -n "$ROOTDIR" ]]
    390 then
    391 	$MKDIR -p "$ROOTDIR";
    392 	if [ $? != 0 ]; then
    393 		gettext "$ROOTDIR is not a directory.\n"
    394 		exit 1
    395 	elif [[ ! -w "$ROOTDIR" ]] then
    396 		gettext "Directory $ROOTDIR is not writable.\n"
    397 		exit 1
    398 	fi
    399 	# If an ISO image path is also specified, make sure it's not under
    400 	# $ROOTDIR since we're going to take the ISO image of $ROOTDIR.
    401 	if [[ -n "$ISODIR" ]]
    402 	then
    403 		realroot=$(cd "$ROOTDIR" 2>/dev/null && pwd -P)
    404 		if [[ "$ISODIR" = "$realroot"?(/*) ]]
    405 		then
    406 			gettext "ISO image must not be under Driver Update's parent directory ($realroot)\n"
    407 			exit 1
    408 		fi
    409 	fi
    410 else
    411 	ROOTDIR=$TMP_DIR/root
    412 fi
    413 
    414 # If DU directory already exists, ask user permission to remove it unless -f
    415 # option was specified.
    416 if [[ -d "$ROOTDIR/DU" ]]
    417 then
    418 	is_overwrite "$ROOTDIR/DU" || exit 0
    419 	$RM -rf "$ROOTDIR/DU"
    420 fi
    421 
    422 # If ISO image already exists, ask user permission to remove it unless -f
    423 # option was specified.
    424 if [[ -f "$ISO" ]]
    425 then
    426 	is_overwrite "$ISO" || exit 0
    427 	$RM -f "$ISO"
    428 fi
    429 
    430 # Create DU directory and the ISO image (if requested).
    431 mkdu && mkiso
    432 if (( $? ))
    433 then
    434 	$RM -rf "$ROOTDIR/DU"
    435 	[[ -n "$ISO" ]] && $RM -f "$ISO"
    436 	exit 1
    437 fi
    438 exit 0
    439