xref: /illumos-gate/usr/src/cmd/boot/scripts/root_archive.ksh (revision c65ebfc7045424bd04a6c7719a27b0ad3399ad54)
1#!/bin/ksh -p
2#
3# CDDL HEADER START
4#
5# The contents of this file are subject to the terms of the
6# Common Development and Distribution License (the "License").
7# You may not use this file except in compliance with the License.
8#
9# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10# or http://www.opensolaris.org/os/licensing.
11# See the License for the specific language governing permissions
12# and limitations under the License.
13#
14# When distributing Covered Code, include this CDDL HEADER in each
15# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16# If applicable, add the following below this CDDL HEADER, with the
17# fields enclosed by brackets "[]" replaced with your own identifying
18# information: Portions Copyright [yyyy] [name of copyright owner]
19#
20# CDDL HEADER END
21#
22
23# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24# Use is subject to license terms.
25#
26# Copyright 2012 Nexenta Systems, Inc. All rights reserved.
27
28# utility to pack and unpack a boot/root archive
29# both ufs and hsfs (iso9660) format archives are unpacked
30# only ufs archives are generated
31#
32# usage: pack   <archive> <root>
33#        unpack <archive> <root>
34#
35#   Where <root> is the directory to unpack to and will be cleaned out
36#   if it exists.
37#
38
39usage()
40{
41	printf "usage: root_archive pack <archive> <root>\n"
42	printf "       root_archive unpack <archive> <root>\n"
43	exit 1
44}
45
46cleanup()
47{
48	if [ -d $MNT ] ; then
49		umount $MNT 2> /dev/null
50		rmdir $MNT
51	fi
52
53	lofiadm -d "$TMR" 2>/dev/null
54        if [ "$REALTHING" != true ] ; then
55		rm -f "$TMR"
56	fi
57	rm -f "$TMR.gz"
58	rm -f /tmp/flist$$
59}
60
61do_unpack()
62{
63	(
64		cd $MNT
65		find . -print | cpio -pdum "$UNPACKED_ROOT" 2> /dev/null
66	)
67	# increase the chances the unmount will succeed
68	umount -f $MNT
69}
70
71unpack()
72{
73	MR=$1
74	if [ ! -f "$MR" ] ; then
75		printf "$MR: not found\n"
76		usage
77	fi
78
79	if [ `uname -i` = i86pc ] ; then
80		gzcat "$MR" > $TMR
81	else
82		REALTHING=true ; export REALTHING
83		TMR="$MR"
84	fi
85
86	LOFIDEV=`/usr/sbin/lofiadm -a $TMR`
87	if [ $? != 0 ] ; then
88		echo lofi plumb failed
89		exit 2
90	fi
91
92	mkdir -p $MNT
93
94	FSTYP=`fstyp $LOFIDEV`
95
96	if [ "$FSTYP" = ufs ] ; then
97		/usr/sbin/mount -o ro,nologging $LOFIDEV $MNT
98		do_unpack
99	elif [ "$FSTYP" = hsfs ] ; then
100		/usr/sbin/mount -F hsfs -o ro $LOFIDEV $MNT
101		do_unpack
102	else
103		printf "invalid root archive\n"
104	fi
105
106
107	rmdir $MNT
108	lofiadm -d $TMR ; LOFIDEV=
109	if [ "$REALTHING" != true ] ; then
110		rm $TMR
111	fi
112}
113
114compress()
115{
116	SRC=$1
117	DST=$2
118
119	(
120		cd $SRC
121		filelist=`find .`
122
123		for file in $filelist ; do
124
125			file=`echo $file | sed s#^./##`
126
127			# copy all files over to preserve hard links
128			#
129			echo $file | cpio -pdum $DST 2> /dev/null
130
131			if [ -f $file ] && [ -s $file ] && [ ! -h $file ] ; then
132				fiocompress -mc $file $DST/$file &
133			fi
134
135		done
136
137		wait `pgrep fiocompress`
138
139		# now re-copy a couple of uncompressed files
140
141		if [ -d "$SRC/platform/i86pc" ] ; then
142			find `cat boot/solaris/filelist.ramdisk` -type file \
143			    -print 2> /dev/null > /tmp/flist$$
144			find usr/kernel -type file -print 2> /dev/null \
145			    >> /tmp/flist$$
146			# some of the files are replaced with links into
147			# tmp/root on the miniroot, so find the backing files
148			# from there as well and add them to the list ti
149			# be copied uncompressed
150			(
151				cd $SRC/tmp/root
152				find `cat ../../boot/solaris/filelist.ramdisk` \
153				    -type file -print 2> /dev/null | \
154				    sed 's#^#tmp/root/#' >> /tmp/flist$$
155			)
156			flist=`cat /tmp/flist$$`
157			(
158				cd $DST
159				rm -f $flist
160			)
161			for file in $flist ; do
162				echo $file | cpio -pdum $DST 2> /dev/null
163			done
164		else
165			find kernel platform -name unix | \
166			    cpio -pdum $DST 2> /dev/null
167			find kernel platform -name genunix | cpio -pdum $DST \
168			    2> /dev/null
169			find kernel platform -name platmod | cpio -pdum $DST \
170			    2> /dev/null
171			find `find kernel platform -name cpu` | \
172			    cpio -pdum $DST 2> /dev/null
173			find `find kernel platform -name kmdb\*` | \
174				cpio -pdum $DST 2> /dev/null
175			find kernel/misc/sparcv9/ctf kernel/fs/sparcv9/dcfs \
176			    etc/system etc/name_to_major etc/path_to_inst \
177			    etc/name_to_sysnum  etc/driver_aliases \
178			    etc/driver_classes etc/minor_perm | \
179			    cpio -pdum $DST 2> /dev/null
180		fi
181	)
182}
183
184root_is_ramdisk()
185{
186	grep -v "set root_is_ramdisk=" "$UNPACKED_ROOT"/etc/system | \
187	    grep -v "set ramdisk_size=" > /tmp/system.$$
188	cat /tmp/system.$$ > "$UNPACKED_ROOT"/etc/system
189	rm /tmp/system.$$
190
191	echo set root_is_ramdisk=1 >> "$UNPACKED_ROOT"/etc/system
192	echo set ramdisk_size=$1 >> "$UNPACKED_ROOT"/etc/system
193}
194
195pack()
196{
197	MR="$1"
198	[ -d "$UNPACKED_ROOT" ] || usage
199
200	# always compress if fiocompress exists
201	#
202	if [ -x /usr/sbin/fiocompress ] ; then
203		COMPRESS=true
204	fi
205
206	# Estimate image size and add %10 overhead for ufs stuff.
207	# Note, we can't use du here in case $UNPACKED_ROOT is on a filesystem,
208	# e.g. zfs, in which the disk usage is less than the sum of the file
209	# sizes.  The nawk code
210	#
211	#	{t += ($7 % 1024) ? (int($7 / 1024) + 1) * 1024 : $7}
212	#
213	# below rounds up the size of a file/directory, in bytes, to the
214	# next multiple of 1024.  This mimics the behavior of ufs especially
215	# with directories.  This results in a total size that's slightly
216	# bigger than if du was called on a ufs directory.
217	#
218	# if the operation in turn is compressing the files the amount
219	# of typical shrinkage is used to come up with a useful archive
220	# size
221	size=$(find "$UNPACKED_ROOT" -ls | nawk '
222	    {t += ($7 % 1024) ? (int($7 / 1024) + 1) * 1024 : $7}
223	    END {print int(t * 1.10 / 1024)}')
224	if [ "$COMPRESS" = true ] ; then
225		size=`echo $size | nawk '{s = $1} END {print int(s * 0.6)}'`
226	fi
227
228	/usr/sbin/mkfile ${size}k "$TMR"
229
230	LOFIDEV=`/usr/sbin/lofiadm -a "$TMR"`
231	if [ $? != 0 ] ; then
232		echo lofi plumb failed
233		exit 2
234	fi
235
236	RLOFIDEV=`echo $LOFIDEV | sed s/lofi/rlofi/`
237	newfs $RLOFIDEV < /dev/null 2> /dev/null
238	mkdir -p $MNT
239	mount -o nologging $LOFIDEV $MNT
240	rmdir $MNT/lost+found
241
242	if [ -d "$UNPACKED_ROOT/kernel/drv/sparcv9" ] ; then
243		root_is_ramdisk $size
244	fi
245
246	(
247		cd "$UNPACKED_ROOT"
248		if [ "$COMPRESS" = true ] ; then
249			compress . $MNT
250		else
251			find . -print | cpio -pdum $MNT 2> /dev/null
252		fi
253	)
254	lockfs -f $MNT
255	umount $MNT
256	rmdir $MNT
257
258	if [ -d "$UNPACKED_ROOT/kernel/drv/sparcv9" ] ; then
259		"$UNPACKED_ROOT/usr/sbin/installboot" \
260		    "$UNPACKED_ROOT/platform/sun4u/lib/fs/ufs/bootblk" \
261		    $RLOFIDEV
262	fi
263
264	lofiadm -d $LOFIDEV
265	LOFIDEV=
266
267	rm -f "$TMR.gz"
268
269	if [ -d "$UNPACKED_ROOT/kernel/drv/sparcv9" ] ; then
270		mv "$TMR" "$MR"
271	else
272		gzip -f "$TMR"
273		mv "$TMR.gz" "$MR"
274	fi
275
276	chmod a+r "$MR"
277}
278
279strip_amd64()
280{
281	find "$UNPACKED_ROOT" -name amd64 -type directory | xargs rm -rf
282}
283
284# main
285#
286
287EXTRA_SPACE=0
288STRIP_AMD64=
289COMPRESS=
290
291PATH=/usr/sbin:/usr/bin:/opt/sfw/bin ; export PATH
292
293while getopts s:6c opt ; do
294	case $opt in
295	s)	EXTRA_SPACE="$OPTARG"
296		;;
297	6)	STRIP_AMD64=false
298		;;
299	c)	COMPRESS=true
300		;;
301	*)	usage
302		;;
303	esac
304done
305shift `expr $OPTIND - 1`
306
307[ $# == 3 ] || usage
308
309UNPACKED_ROOT="$3"
310BASE="`pwd`"
311MNT=/tmp/mnt$$
312TMR=/tmp/mr$$
313LOFIDEV=
314MR="$2"
315
316# sanity check
317[ "$UNPACKED_ROOT" != "/" ] || usage
318
319if [ "`dirname $MR`" = . ] ; then
320	MR="$BASE/$MR"
321fi
322if [ "`dirname $UNPACKED_ROOT`" = . ] ; then
323	UNPACKED_ROOT="$BASE/$UNPACKED_ROOT"
324fi
325
326trap cleanup EXIT
327
328# always unpack into a fresh root
329case $1 in
330	unpack)
331		rm -rf "$UNPACKED_ROOT"
332		mkdir -p "$UNPACKED_ROOT"
333		;;
334esac
335[ -d "$UNPACKED_ROOT" ] || usage
336
337case $1 in
338	pack)	pack "$MR"
339		;;
340	unpack)	unpack "$MR"
341		;;
342	*)	usage
343		;;
344esac
345