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