xref: /onnv-gate/usr/src/cmd/itutools/pkg2du.ksh (revision 10661:789e162d8de6)
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
32readonly PROG=$0
33readonly ORIGPWD=$PWD
34readonly TMP_DIR=${TMPDIR:-/tmp}/${PROG##*/}.$$
35
36# Must-have utilities
37readonly CPIO=/usr/bin/cpio
38readonly GZIP=/usr/bin/gzip
39readonly MKISOFS=/usr/bin/mkisofs
40readonly PATCHADD=/usr/sbin/patchadd
41readonly PKGTRANS=/usr/bin/pkgtrans
42readonly ROOT_ARCHIVE=/usr/sbin/root_archive
43readonly LOFIADM=/usr/sbin/lofiadm
44readonly MKDIR=/usr/bin/mkdir
45readonly RM=/usr/bin/rm
46readonly CP=/usr/bin/cp
47readonly HEAD=/usr/bin/head
48readonly SORT=/usr/bin/sort
49readonly MKBOOTMEDIA=/usr/bin/mkbootmedia
50readonly PKG2DU=/usr/bin/pkg2du
51readonly TOUCH=/usr/bin/touch
52readonly NAWK=/usr/bin/nawk
53readonly CHMOD=/usr/bin/chmod
54readonly GREP=/usr/bin/grep
55readonly LS=/usr/bin/ls
56readonly LN=/usr/bin/ln
57readonly SED=/usr/bin/sed
58readonly CAT=/usr/bin/cat
59readonly FIND=/usr/bin/find
60readonly UNAME=/usr/bin/uname
61readonly MACH=`$UNAME -p`
62
63# for gettext
64TEXTDOMAIN=SUNW_OST_OSCMD
65export TEXTDOMAIN
66
67
68function 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
81function 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
97function cleanup
98{
99	$RM -rf "$TMP_DIR"
100}
101
102
103function 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
123function 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
142function 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"
197mail=
198instance=unique
199partial=nocheck
200runlevel=nocheck
201idepend=nocheck
202rdepend=nocheck
203space=nocheck
204setuid=nocheck
205conflict=nocheck
206action=nocheck
207EOF
208
209	# Create install.sh
210	$CAT > "$distdir/Tools/install.sh" <<"EOF"
211#!/sbin/sh
212# install.sh -R <basedir> - install packages to basedir
213basedir=/
214toolsdir=`dirname $0`
215tmpfile=/tmp/`basename $0`.$$
216while getopts "R:" arg
217do
218        case "$arg" in
219                R) basedir=$OPTARG;;
220        esac
221done
222/usr/bin/gzip -c -d "$toolsdir/../Product/pkgs.gz" > $tmpfile &&
223	/usr/sbin/pkgadd -R "$basedir" -d "$tmpfile" -a "$toolsdir/admin" all
224status=$?
225/bin/rm -f "$tmpfile"
226exit $status
227EOF
228	$CHMOD a+rx "$distdir/Tools/install.sh"
229}
230
231
232function 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#
287trap cleanup EXIT
288
289FORCE=
290ISO=
291LABEL=
292RELEASE=
293ROOTDIR=
294VERBOSE_LEVEL=0
295
296while getopts ':d:fo:l:r:v' opt
297do
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
325done
326shift 'OPTIND - 1'
327
328# Release number must be specified.
329if [[ -z "$RELEASE" ]]
330then
331	gettext "Solaris release number must be specified (-r option).\n"
332	usage
333	exit 1
334fi
335
336# Verify release number.  Allow major.minor or major.minor.micro format.
337if [[ $RELEASE != +([0-9]).+([0-9])?(.+([0-9])) ]]
338then
339	gettext "Invalid release number: $RELEASE\n"
340	exit 1
341fi
342VERSION=$(echo $RELEASE | $SED 's/5\./2/')
343
344# Either or both of -d or -o option must be specified.
345if [[ -z "$ROOTDIR" && -z "$ISO" ]]
346then
347	gettext "Either -d or -o option (or both) must be specified.\n"
348	usage
349	exit 1
350fi
351
352# There must be at least one package.
353if (( $# == 0 ))
354then
355	gettext "No package was specified.\n"
356	usage
357	exit 1
358fi
359
360# Check and collect packages
361unset PACKAGES
362collect_objs "$@" || exit 1
363
364# Default label for ISO image
365LABEL=${LABEL:-DU sol_$VERSION}
366
367check_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.
371unset ISODIR
372if [[ -n "$ISO" ]]
373then
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
385fi
386
387# If user specified a media root directory, verify it exists, else use
388# a temporary directory.
389if [[ -n "$ROOTDIR" ]]
390then
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
410else
411	ROOTDIR=$TMP_DIR/root
412fi
413
414# If DU directory already exists, ask user permission to remove it unless -f
415# option was specified.
416if [[ -d "$ROOTDIR/DU" ]]
417then
418	is_overwrite "$ROOTDIR/DU" || exit 0
419	$RM -rf "$ROOTDIR/DU"
420fi
421
422# If ISO image already exists, ask user permission to remove it unless -f
423# option was specified.
424if [[ -f "$ISO" ]]
425then
426	is_overwrite "$ISO" || exit 0
427	$RM -f "$ISO"
428fi
429
430# Create DU directory and the ISO image (if requested).
431mkdu && mkiso
432if (( $? ))
433then
434	$RM -rf "$ROOTDIR/DU"
435	[[ -n "$ISO" ]] && $RM -f "$ISO"
436	exit 1
437fi
438exit 0
439