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 awk 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 | /usr/xpg4/bin/awk ' 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 | /usr/xpg4/bin/awk '{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