6005 bootadm update-archive should create/update archive sha-1 hash Reviewed by:...
[unleashed.git] / usr / src / cmd / boot / scripts / create_ramdisk.ksh
blob4fec8809a22c6772216f568791d9e2cfaf5660d2
1 #!/bin/ksh -p
3 # CDDL HEADER START
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.
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.
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]
20 # CDDL HEADER END
23 # Copyright 2016 Toomas Soome <tsoome@me.com>
24 # Copyright 2009 Sun Microsystems, Inc. All rights reserved.
25 # Use is subject to license terms.
29 # Copyright (c) 2014 by Delphix. All rights reserved.
32 format=ufs
33 ALT_ROOT=
34 EXTRACT_ARGS=
35 compress=yes
36 SPLIT=unknown
37 ERROR=0
38 dirsize32=0
39 dirsize64=0
41 usage() {
42 echo "This utility is a component of the bootadm(1M) implementation"
43 echo "and it is not recommended for stand-alone use."
44 echo "Please use bootadm(1M) instead."
45 echo ""
46 echo "Usage: ${0##*/}: [-R \<root\>] [-p \<platform\>] [--nocompress]"
47 echo "where \<platform\> is one of i86pc, sun4u or sun4v"
48 exit
51 # default platform is what we're running on
52 PLATFORM=`uname -m`
55 # set path, but inherit /tmp/bfubin if owned by
56 # same uid executing this process, which must be root.
58 if [ "`echo $PATH | cut -f 1 -d :`" = /tmp/bfubin ] && \
59 [ -O /tmp/bfubin ] ; then
60 export PATH=/tmp/bfubin
61 export GZIP_CMD=/tmp/bfubin/gzip
62 else
63 export PATH=/usr/sbin:/usr/bin:/sbin
64 export GZIP_CMD=/usr/bin/gzip
67 EXTRACT_FILELIST="/boot/solaris/bin/extract_boot_filelist"
70 # Parse options
72 while [ "$1" != "" ]
74 case $1 in
75 -R) shift
76 ALT_ROOT="$1"
77 if [ "$ALT_ROOT" != "/" ]; then
78 echo "Creating boot_archive for $ALT_ROOT"
79 EXTRACT_ARGS="${EXTRACT_ARGS} -R ${ALT_ROOT}"
80 EXTRACT_FILELIST="${ALT_ROOT}${EXTRACT_FILELIST}"
83 -n|--nocompress) compress=no
85 -p) shift
86 PLATFORM="$1"
87 EXTRACT_ARGS="${EXTRACT_ARGS} -p ${PLATFORM}"
89 *) usage
91 esac
92 shift
93 done
95 if [ -x /usr/bin/mkisofs -o -x /tmp/bfubin/mkisofs ] ; then
96 format=isofs
100 # mkisofs on s8 doesn't support functionality used by GRUB boot.
101 # Use ufs format for boot archive instead.
103 release=`uname -r`
104 if [ "$release" = "5.8" ]; then
105 format=ufs
108 shift `expr $OPTIND - 1`
110 if [ $# -eq 1 ]; then
111 ALT_ROOT="$1"
112 echo "Creating boot_archive for $ALT_ROOT"
115 case $PLATFORM in
116 i386) PLATFORM=i86pc
117 ISA=i386
118 ARCH64=amd64
120 i86pc) ISA=i386
121 ARCH64=amd64
123 sun4u) ISA=sparc
124 ARCH64=sparcv9
126 sun4v) ISA=sparc
127 ARCH64=sparcv9
129 *) usage
131 esac
133 BOOT_ARCHIVE=platform/$PLATFORM/boot_archive
134 BOOT_ARCHIVE_64=platform/$PLATFORM/$ARCH64/boot_archive
136 if [ $PLATFORM = i86pc ] ; then
137 if [ ! -x "$ALT_ROOT"/boot/solaris/bin/symdef ]; then
138 # no dboot implies combined archives for example
139 # live-upgrade from s9 to s10u6 is multiboot-only
140 echo "Creating single archive at $ALT_ROOT/$BOOT_ARCHIVE"
141 SPLIT=no
142 compress=no
143 else
144 SPLIT=yes
146 else # must be sparc
147 SPLIT=no # there's only 64-bit (sparcv9), so don't split
148 compress=no
151 [ -x $GZIP_CMD ] || compress=no
153 function cleanup
155 umount -f "$rdmnt32" 2>/dev/null
156 umount -f "$rdmnt64" 2>/dev/null
157 lofiadm -d "$rdfile32" 2>/dev/null
158 lofiadm -d "$rdfile64" 2>/dev/null
159 [ -n "$rddir" ] && rm -fr "$rddir" 2> /dev/null
160 [ -n "$new_rddir" ] && rm -fr "$new_rddir" 2>/dev/null
163 function getsize
165 # Estimate image size and add 10% overhead for ufs stuff.
166 # Note, we can't use du here in case we're on a filesystem, e.g. zfs,
167 # in which the disk usage is less than the sum of the file sizes.
168 # The nawk code
170 # {t += ($5 % 1024) ? (int($5 / 1024) + 1) * 1024 : $5}
172 # below rounds up the size of a file/directory, in bytes, to the
173 # next multiple of 1024. This mimics the behavior of ufs especially
174 # with directories. This results in a total size that's slightly
175 # bigger than if du was called on a ufs directory.
176 size32=$(cat "$list32" | xargs -I {} ls -lLd "{}" 2> /dev/null |
177 nawk '{t += ($5 % 1024) ? (int($5 / 1024) + 1) * 1024 : $5}
178 END {print int(t * 1.10 / 1024)}')
179 (( size32 += dirsize32 ))
180 size64=$(cat "$list64" | xargs -I {} ls -lLd "{}" 2> /dev/null |
181 nawk '{t += ($5 % 1024) ? (int($5 / 1024) + 1) * 1024 : $5}
182 END {print int(t * 1.10 / 1024)}')
183 (( size64 += dirsize64 ))
184 (( total_size = size32 + size64 ))
186 if [ $compress = yes ] ; then
187 total_size=`echo $total_size | nawk '{print int($1 / 2)}'`
192 # Copies all desired files to a target directory. One argument should be
193 # passed: the file containing the list of files to copy. This function also
194 # depends on several variables that must be set before calling:
196 # $ALT_ROOT - the target directory
197 # $compress - whether or not the files in the archives should be compressed
198 # $rdmnt - the target directory
200 function copy_files
202 list="$1"
205 # If compress is set, the files are gzip'd and put in the correct
206 # location in the loop. Nothing is printed, so the pipe and cpio
207 # at the end is a nop.
209 # If compress is not set, the file names are printed, which causes
210 # the cpio at the end to do the copy.
212 while read path
214 if [ $compress = yes ]; then
215 dir="${path%/*}"
216 [ -d "$rdmnt/$dir" ] || mkdir -p "$rdmnt/$dir"
217 $GZIP_CMD -c "$path" > "$rdmnt/$path"
218 else
219 print "$path"
221 done <"$list" | cpio -pdum "$rdmnt" 2>/dev/null
223 if [ $ISA = sparc ] ; then
224 # copy links
225 find $filelist -type l -print 2>/dev/null |\
226 cpio -pdum "$rdmnt" 2>/dev/null
227 if [ $compress = yes ] ; then
228 # always copy unix uncompressed
229 find $filelist -name unix -type f -print 2>/dev/null |\
230 cpio -pdum "$rdmnt" 2>/dev/null
237 # The first argument can be:
239 # "both" - create an archive with both 32-bit and 64-bit binaries
240 # "32-bit" - create an archive with only 32-bit binaries
241 # "64-bit" - create an archive with only 64-bit binaries
243 function create_ufs
245 which=$1
246 archive=$2
247 lofidev=$3
249 # should we exclude amd64 binaries?
250 if [ "$which" = "32-bit" ]; then
251 rdfile="$rdfile32"
252 rdmnt="$rdmnt32"
253 list="$list32"
254 elif [ "$which" = "64-bit" ]; then
255 rdfile="$rdfile64"
256 rdmnt="$rdmnt64"
257 list="$list64"
258 else
259 rdfile="$rdfile32"
260 rdmnt="$rdmnt32"
261 list="$list32"
264 NOINUSE_CHECK=1 newfs $lofidev < /dev/null 2> /dev/null
265 mkdir "$rdmnt"
266 mount -F mntfs mnttab /etc/mnttab > /dev/null 2>&1
267 mount -F ufs -o nologging $lofidev "$rdmnt"
268 files=
270 # do the actual copy
271 copy_files "$list"
272 umount -f "$rdmnt"
273 rmdir "$rdmnt"
275 if [ $ISA = sparc ] ; then
276 rlofidev=`echo "$lofidev" | sed -e "s/dev\/lofi/dev\/rlofi/"`
277 bb="$ALT_ROOT/platform/$PLATFORM/lib/fs/ufs/bootblk"
278 # installboot is not available on all platforms
279 dd if=$bb of=$rlofidev bs=1b oseek=1 count=15 conv=sync 2>&1
283 # Check if gzip exists in /usr/bin, so we only try to run gzip
284 # on systems that have gzip. Then run gzip out of the patch to
285 # pick it up from bfubin or something like that if needed.
287 # If compress is set, the individual files in the archive are
288 # compressed, and the final compression will accomplish very
289 # little. To save time, we skip the gzip in this case.
291 if [ $ISA = i386 ] && [ $compress = no ] && \
292 [ -x $GZIP_CMD ] ; then
293 gzip -c "$rdfile" > "${archive}-new"
294 else
295 cat "$rdfile" > "${archive}-new"
298 if [ $? -ne 0 ] ; then
299 rm -f "${archive}-new"
304 # The first argument can be:
306 # "both" - create an archive with both 32-bit and 64-bit binaries
307 # "32-bit" - create an archive with only 32-bit binaries
308 # "64-bit" - create an archive with only 64-bit binaries
310 function create_isofs
312 which=$1
313 archive=$2
315 # should we exclude amd64 binaries?
316 if [ "$which" = "32-bit" ]; then
317 rdmnt="$rdmnt32"
318 errlog="$errlog32"
319 list="$list32"
320 elif [ "$which" = "64-bit" ]; then
321 rdmnt="$rdmnt64"
322 errlog="$errlog64"
323 list="$list64"
324 else
325 rdmnt="$rdmnt32"
326 errlog="$errlog32"
327 list="$list32"
330 # create image directory seed with graft points
331 mkdir "$rdmnt"
332 files=
333 isocmd="mkisofs -quiet -graft-points -dlrDJN -relaxed-filenames"
335 if [ $ISA = sparc ] ; then
336 bb="$ALT_ROOT/platform/$PLATFORM/lib/fs/hsfs/bootblk"
337 isocmd="$isocmd -G \"$bb\""
340 copy_files "$list"
341 isocmd="$isocmd \"$rdmnt\""
342 rm -f "$errlog"
345 # Check if gzip exists in /usr/bin, so we only try to run gzip
346 # on systems that have gzip. Then run gzip out of the patch to
347 # pick it up from bfubin or something like that if needed.
349 # If compress is set, the individual files in the archive are
350 # compressed, and the final compression will accomplish very
351 # little. To save time, we skip the gzip in this case.
353 mkiso_ret=0
355 if [ $ISA = i386 ] &&[ $compress = no ] && [ -x $GZIP_CMD ]
356 then
357 ksh -c "$isocmd" 2> "$errlog" | \
358 gzip > "${archive}-new"
359 else
360 ksh -c "$isocmd" 2> "$errlog" > "${archive}-new"
363 if [ $? -ne 0 ]; then
364 cat "$errlog"
365 rm -f "${archive}-new" 2> /dev/null
366 rm -f "$errlog" 2> /dev/null
367 return
370 dd_ret=0
371 if [ $ISA = sparc ] ; then
372 bb="$ALT_ROOT/platform/$PLATFORM/lib/fs/hsfs/bootblk"
373 dd if="$bb" of="${archive}-new" bs=1b oseek=1 count=15 \
374 conv=notrunc conv=sync >> "$errlog" 2>&1
375 dd_ret=$?
378 if [ -s "$errlog" ] || [ $dd_ret -ne 0 ] ; then
379 grep Error: "$errlog" >/dev/null 2>&1
380 if [ $? -eq 0 ] || [ $dd_ret -ne 0 ] ; then
381 cat "$errlog"
382 rm -f "${archive}-new"
385 rm -f "$errlog"
388 function create_archive
390 which=$1
391 archive=$2
392 lofidev=$3
394 echo "updating $archive"
396 if [ "$format" = "ufs" ]; then
397 create_ufs "$which" "$archive" "$lofidev"
398 else
399 create_isofs "$which" "$archive"
402 # sanity check the archive before moving it into place
404 ARCHIVE_SIZE=`ls -l "${archive}-new" 2> /dev/null | nawk '{ print $5 }'`
405 if [ $compress = yes ] || [ $ISA = sparc ] ; then
407 # 'file' will report "English text" for uncompressed
408 # boot_archives. Checking for that doesn't seem stable,
409 # so we just check that the file exists.
411 ls "${archive}-new" >/dev/null 2>&1
412 else
414 # the file type check also establishes that the
415 # file exists at all
417 LC_MESSAGES=C file "${archive}-new" | grep gzip > /dev/null
420 if [ $? = 1 ] && [ -x $GZIP_CMD ] || [ "$ARCHIVE_SIZE" -lt 10000 ]
421 then
423 # Two of these functions may be run in parallel. We
424 # need to allow the other to clean up, so we can't
425 # exit immediately. Instead, we set a flag.
427 echo "update of $archive failed"
428 ERROR=1
429 else
430 lockfs -f "/$ALT_ROOT" 2>/dev/null
431 mv "${archive}-new" "$archive"
432 rm -f "$archive.hash"
433 digest -a sha1 "$archive" > "$archive.hash"
434 lockfs -f "/$ALT_ROOT" 2>/dev/null
439 function fatal_error
441 print -u2 $*
442 exit 1
446 # get filelist
448 if [ ! -f "$ALT_ROOT/boot/solaris/filelist.ramdisk" ] &&
449 [ ! -f "$ALT_ROOT/etc/boot/solaris/filelist.ramdisk" ]
450 then
451 print -u2 "Can't find filelist.ramdisk"
452 exit 1
454 filelist=$($EXTRACT_FILELIST $EXTRACT_ARGS \
455 /boot/solaris/filelist.ramdisk \
456 /etc/boot/solaris/filelist.ramdisk \
457 2>/dev/null | sort -u)
460 # We use /tmp/ for scratch space now. This may be changed later if there
461 # is insufficient space in /tmp/.
463 rddir="/tmp/create_ramdisk.$$.tmp"
464 new_rddir=
465 rm -rf "$rddir"
466 mkdir "$rddir" || fatal_error "Could not create temporary directory $rddir"
468 # Clean up upon exit.
469 trap 'cleanup' EXIT
471 list32="$rddir/filelist.32"
472 list64="$rddir/filelist.64"
474 touch $list32 $list64
477 # This loop creates the 32-bit and 64-bit lists of files. The 32-bit list
478 # is written to stdout, which is redirected at the end of the loop. The
479 # 64-bit list is appended with each write.
481 cd "/$ALT_ROOT"
482 find $filelist -print 2>/dev/null | while read path
484 if [ $SPLIT = no ]; then
485 print "$path"
486 elif [ -d "$path" ]; then
487 if [ $format = ufs ]; then
488 size=`ls -lLd "$path" | nawk '
489 {print ($5 % 1024) ? (int($5 / 1024) + 1) * 1024 : $5}'`
490 if [ `basename "$path"` != "amd64" ]; then
491 (( dirsize32 += size ))
493 (( dirsize64 += size ))
495 else
496 case `LC_MESSAGES=C /usr/bin/file -m /dev/null "$path" 2>/dev/null` in
497 *ELF\ 64-bit*)
498 print "$path" >> "$list64"
500 *ELF\ 32-bit*)
501 print "$path"
504 # put in both lists
505 print "$path"
506 print "$path" >> "$list64"
507 esac
509 done >"$list32"
511 if [ $format = ufs ] ; then
512 # calculate image size
513 getsize
515 # check to see if there is sufficient space in tmpfs
517 tmp_free=`df -b /tmp | tail -1 | awk '{ printf ($2) }'`
518 (( tmp_free = tmp_free / 3 ))
519 if [ $SPLIT = yes ]; then
520 (( tmp_free = tmp_free / 2 ))
523 if [ $total_size -gt $tmp_free ] ; then
524 # assumes we have enough scratch space on $ALT_ROOT
525 new_rddir="/$ALT_ROOT/var/tmp/create_ramdisk.$$.tmp"
526 rm -rf "$new_rddir"
527 mkdir "$new_rddir" || fatal_error \
528 "Could not create temporary directory $new_rddir"
530 # Save the file lists
531 mv "$list32" "$new_rddir"/
532 mv "$list64" "$new_rddir"/
533 list32="/$new_rddir/filelist.32"
534 list64="/$new_rddir/filelist.64"
536 # Remove the old $rddir and set the new value of rddir
537 rm -rf "$rddir"
538 rddir="$new_rddir"
539 new_rddir=
543 rdfile32="$rddir/rd.file.32"
544 rdfile64="$rddir/rd.file.64"
545 rdmnt32="$rddir/rd.mount.32"
546 rdmnt64="$rddir/rd.mount.64"
547 errlog32="$rddir/rd.errlog.32"
548 errlog64="$rddir/rd.errlog.64"
549 lofidev32=""
550 lofidev64=""
552 if [ $SPLIT = yes ]; then
554 # We can't run lofiadm commands in parallel, so we have to do
555 # them here.
557 if [ "$format" = "ufs" ]; then
558 mkfile ${size32}k "$rdfile32"
559 lofidev32=`lofiadm -a "$rdfile32"`
560 mkfile ${size64}k "$rdfile64"
561 lofidev64=`lofiadm -a "$rdfile64"`
563 create_archive "32-bit" "$ALT_ROOT/$BOOT_ARCHIVE" $lofidev32 &
564 create_archive "64-bit" "$ALT_ROOT/$BOOT_ARCHIVE_64" $lofidev64
565 wait
566 if [ "$format" = "ufs" ]; then
567 lofiadm -d "$rdfile32"
568 lofiadm -d "$rdfile64"
570 else
571 if [ "$format" = "ufs" ]; then
572 mkfile ${total_size}k "$rdfile32"
573 lofidev32=`lofiadm -a "$rdfile32"`
575 create_archive "both" "$ALT_ROOT/$BOOT_ARCHIVE" $lofidev32
576 [ "$format" = "ufs" ] && lofiadm -d "$rdfile32"
578 if [ $ERROR = 1 ]; then
579 cleanup
580 exit 1
584 # For the diskless case, hardlink archive to /boot to make it
585 # visible via tftp. /boot is lofs mounted under /tftpboot/<hostname>.
586 # NOTE: this script must work on both client and server.
588 grep "[ ]/[ ]*nfs[ ]" "$ALT_ROOT/etc/vfstab" > /dev/null
589 if [ $? = 0 ]; then
590 rm -f "$ALT_ROOT/boot/boot_archive" "$ALT_ROOT/boot/amd64/boot_archive"
591 ln "$ALT_ROOT/$BOOT_ARCHIVE" "$ALT_ROOT/boot/boot_archive"
592 if [ $SPLIT = yes ]; then
593 ln "$ALT_ROOT/$BOOT_ARCHIVE_64" \
594 "$ALT_ROOT/boot/amd64/boot_archive"
597 [ -n "$rddir" ] && rm -rf "$rddir"