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
39 usage()
40 {
41 printf "usage: root_archive pack <archive> <root>\n"
42 printf " root_archive unpack <archive> <root>\n"
43 exit 1
44 }
45
46 cleanup()
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
61 do_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
71 unpack()
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
114 compress()
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
184 root_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
195 pack()
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
279 strip_amd64()
280 {
281 find "$UNPACKED_ROOT" -name amd64 -type directory | xargs rm -rf
282 }
283
284 # main
285 #
286
287 EXTRA_SPACE=0
288 STRIP_AMD64=
289 COMPRESS=
290
291 PATH=/usr/sbin:/usr/bin:/opt/sfw/bin ; export PATH
292
293 while 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
304 done
305 shift `expr $OPTIND - 1`
306
307 [ $# == 3 ] || usage
308
309 UNPACKED_ROOT="$3"
310 BASE="`pwd`"
311 MNT=/tmp/mnt$$
312 TMR=/tmp/mr$$
313 LOFIDEV=
314 MR="$2"
315
316 # sanity check
317 [ "$UNPACKED_ROOT" != "/" ] || usage
318
319 if [ "`dirname $MR`" = . ] ; then
320 MR="$BASE/$MR"
321 fi
322 if [ "`dirname $UNPACKED_ROOT`" = . ] ; then
323 UNPACKED_ROOT="$BASE/$UNPACKED_ROOT"
324 fi
325
326 trap cleanup EXIT
327
328 # always unpack into a fresh root
329 case $1 in
330 unpack)
331 rm -rf "$UNPACKED_ROOT"
332 mkdir -p "$UNPACKED_ROOT"
333 ;;
334 esac
335 [ -d "$UNPACKED_ROOT" ] || usage
336
337 case $1 in
338 pack) pack "$MR"
339 ;;
340 unpack) unpack "$MR"
341 ;;
342 *) usage
343 ;;
344 esac