9860 cpio_cleanup: $tarchive is already fully-qualified
[unleashed.git] / usr / src / cmd / boot / scripts / create_ramdisk.ksh
blob6301d107f44fa524cf9fa49ebc4f36d55d59724d
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.
30 # Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
33 ALT_ROOT=
34 EXTRACT_ARGS=
35 FORMAT=
36 format_set=0
37 compress=yes
38 dirsize=0
40 usage() {
41 cat <<- EOM
42 This utility is a component of the bootadm(1M) implementation and it is not
43 recommended for stand-alone use. Please use bootadm(1M) instead.
45 Usage: ${0##*/}: [-R <root>] [-p <platform>] [ -f <format> ] [--nocompress]
46 where <platform> is one of i86pc, sun4u or sun4v
47 and <format> is one of ufs, ufs-nocompress or cpio
48 EOM
49 exit
52 # default platform is what we're running on
53 PLATFORM=`uname -m`
55 export PATH=/usr/sbin:/usr/bin:/sbin
56 export GZIP_CMD=/usr/bin/gzip
57 export CPIO_CMD=/usr/bin/cpio
59 EXTRACT_FILELIST="/boot/solaris/bin/extract_boot_filelist"
62 # Parse options
64 while [ -n "$1" ]; do
65 case $1 in
66 -f) shift
67 FORMAT="$1"
68 format_set=1
70 -n|--nocompress) compress=no
72 -p) shift
73 PLATFORM="$1"
74 EXTRACT_ARGS="${EXTRACT_ARGS} -p ${PLATFORM}"
76 -R) shift
77 ALT_ROOT="$1"
78 if [ "$ALT_ROOT" != "/" ]; then
79 echo "Creating boot_archive for $ALT_ROOT"
80 EXTRACT_ARGS="${EXTRACT_ARGS} -R ${ALT_ROOT}"
81 EXTRACT_FILELIST="${ALT_ROOT}${EXTRACT_FILELIST}"
84 *) usage
86 esac
87 shift
88 done
90 shift `expr $OPTIND - 1`
92 if [ $# -eq 1 ]; then
93 ALT_ROOT="$1"
94 echo "Creating boot_archive for $ALT_ROOT"
97 if [ -z "$FORMAT" ]; then
98 if [ -n "$ALT_ROOT" ]; then
99 SVCCFG_DTD=/$ALT_ROOT/usr/share/lib/xml/dtd/service_bundle.dtd.1
100 SVCCFG_REPOSITORY=/$ALT_ROOT/etc/svc/repository.db
101 export SVCCFG_DTD SVCCFG_REPOSITORY
103 FORMAT=`svccfg -s system/boot-archive listprop config/format \
104 | awk '{print $3}'`
107 if [ $format_set -eq 0 -a "$FORMAT" = hsfs ]; then
108 if /sbin/bootadm update-archive -R ${ALT_ROOT:-/} -f -L -F hsfs; then
109 exit 0
110 else
111 echo "Failed to create HSFS archive, falling back."
115 [[ "$FORMAT" =~ ^(cpio|ufs|ufs-nocompress)$ ]] || FORMAT=ufs
117 case $PLATFORM in
118 i386|i86pc) PLATFORM=i86pc
119 ISA=i386
120 ARCH64=amd64
121 BOOT_ARCHIVE_SUFFIX=$ARCH64/boot_archive
123 sun4u|sun4v) ISA=sparc
124 ARCH64=sparcv9
125 BOOT_ARCHIVE_SUFFIX=boot_archive
126 compress=no
128 *) usage
130 esac
132 BOOT_ARCHIVE=platform/$PLATFORM/$BOOT_ARCHIVE_SUFFIX
134 function fatal_error
136 print -u2 $*
137 exit 1
140 [ -x $GZIP_CMD ] || compress=no
142 case $FORMAT in
143 cpio) [ -x $CPIO_CMD ] || FORMAT=ufs ;;
144 ufs-nocompress) FORMAT=ufs; compress=no ;;
145 ufs) ;;
146 esac
149 # Copies all desired files to a target directory. One argument should be
150 # passed: the file containing the list of files to copy. This function also
151 # depends on several variables that must be set before calling:
153 # $ALT_ROOT - the target directory
154 # $compress - whether or not the files in the archives should be compressed
155 # $rdmnt - the target directory
157 function copy_files
159 typeset listfile="$1"
162 # If compress is set, the files are gzip'd and put in the correct
163 # location in the loop. Nothing is printed, so the pipe and cpio
164 # at the end is a nop.
166 # If compress is not set, the file names are printed, which causes
167 # the cpio at the end to do the copy.
169 while read path; do
170 if [ $compress = yes ]; then
171 dir="${path%/*}"
172 [ -d "$rdmnt/$dir" ] || mkdir -p "$rdmnt/$dir"
173 $GZIP_CMD -c "$path" > "$rdmnt/$path"
174 else
175 print "$path"
177 done <"$listfile" | cpio -pdum "$rdmnt" 2>/dev/null
179 if [ $ISA = sparc ] ; then
180 # copy links
181 find $filelist -type l -print 2>/dev/null |\
182 cpio -pdum "$rdmnt" 2>/dev/null
183 if [ $compress = yes ] ; then
184 # always copy unix uncompressed
185 find $filelist -name unix -type f -print 2>/dev/null |\
186 cpio -pdum "$rdmnt" 2>/dev/null
192 function ufs_cleanup
194 umount -f "$rdmnt" 2>/dev/null
195 lofiadm -d "$rdfile" 2>/dev/null
196 [ -n "$rddir" ] && rm -fr "$rddir" 2> /dev/null
197 [ -n "$new_rddir" ] && rm -fr "$new_rddir" 2>/dev/null
200 function ufs_getsize
202 # Estimate image size and add 10% overhead for ufs stuff.
203 # Note, we can't use du here in case we're on a filesystem, e.g. zfs,
204 # in which the disk usage is less than the sum of the file sizes.
205 # The nawk code
207 # {t += ($5 % 1024) ? (int($5 / 1024) + 1) * 1024 : $5}
209 # below rounds up the size of a file/directory, in bytes, to the
210 # next multiple of 1024. This mimics the behavior of ufs especially
211 # with directories. This results in a total size that's slightly
212 # bigger than if du was called on a ufs directory.
213 size=$(cat "$list" | xargs -I {} ls -lLd "{}" 2> /dev/null |
214 nawk '{t += ($5 % 1024) ? (int($5 / 1024) + 1) * 1024 : $5}
215 END {print int(t * 1.10 / 1024)}')
216 (( size += dirsize ))
217 (( total_size = size ))
218 # If compression is enabled, then each file within the archive will
219 # be individually compressed. The compression ratio is around 60%
220 # across the archive so make the image smaller.
221 [ $compress = yes ] && (( total_size = total_size / 2 ))
224 function create_ufs_archive
226 typeset archive="$ALT_ROOT/$BOOT_ARCHIVE"
228 [ "$compress" = yes ] && \
229 echo "updating $archive (UFS)" || \
230 echo "updating $archive (UFS-nocompress)"
233 # We use /tmp/ for scratch space now. This will be changed later to
234 # $ALT_ROOT/var/tmp if there is insufficient space in /tmp/.
236 rddir="/tmp/create_ramdisk.$$.tmp"
237 new_rddir=
238 rm -rf "$rddir"
239 mkdir "$rddir" || fatal_error "Could not create directory $rddir"
241 # Clean up upon exit.
242 trap 'ufs_cleanup' EXIT
244 list="$rddir/filelist"
246 cd "/$ALT_ROOT" || fatal_error "Cannot chdir to $ALT_ROOT"
247 find $filelist -print 2>/dev/null | while read path; do
248 if [ -d "$path" ]; then
249 size=`ls -lLd "$path" | nawk '
250 {print ($5 % 1024) ? (int($5 / 1024) + 1) * 1024 : $5}'`
251 (( dirsize += size / 1024 ))
252 else
253 print "$path"
255 done >"$list"
257 # calculate image size
258 ufs_getsize
260 # check to see if there is sufficient space in tmpfs
262 tmp_free=`df -b /tmp | tail -1 | awk '{ print $2 }'`
263 (( tmp_free = tmp_free / 3 ))
265 if [ $total_size -gt $tmp_free ] ; then
266 echo "Insufficient space in /tmp, using $ALT_ROOT/var/tmp"
267 # assumes we have enough scratch space on $ALT_ROOT
268 new_rddir="/$ALT_ROOT/var/tmp/create_ramdisk.$$.tmp"
269 rm -rf "$new_rddir"
270 mkdir "$new_rddir" || fatal_error \
271 "Could not create temporary directory $new_rddir"
273 # Save the file lists
274 mv "$list" "$new_rddir"/
275 list="/$new_rddir/filelist"
277 # Remove the old $rddir and set the new value of rddir
278 rm -rf "$rddir"
279 rddir="$new_rddir"
280 new_rddir=
283 rdfile="$rddir/rd.file"
284 rdmnt="$rddir/rd.mount"
285 errlog="$rddir/rd.errlog"
286 lofidev=""
288 mkfile ${total_size}k "$rdfile" || \
289 fatal_error "Could not create backing file"
290 lofidev=`lofiadm -a "$rdfile"` || \
291 fatal_error "Could not create lofi device"
293 NOINUSE_CHECK=1 newfs -m 0 $lofidev < /dev/null 2> /dev/null
294 mkdir "$rdmnt"
295 mount -F mntfs mnttab /etc/mnttab > /dev/null 2>&1
296 mount -F ufs -o nologging $lofidev "$rdmnt"
297 rm -rf "$rdmnt/lost+found"
299 # do the actual copy
300 copy_files "$list"
301 umount -f "$rdmnt"
302 rmdir "$rdmnt"
304 if [ $ISA = sparc ] ; then
305 rlofidev="${lofidev/lofi/rlofi}"
306 bb="/$ALT_ROOT/platform/$PLATFORM/lib/fs/ufs/bootblk"
307 # installboot is not available on all platforms
308 dd if=$bb of=$rlofidev bs=1b oseek=1 count=15 conv=sync 2>&1
311 lofiadm -d "$rdfile"
314 # Check if gzip exists in /usr/bin, so we only try to run gzip
315 # on systems that have gzip. Then run gzip out of the patch to
316 # pick it up from bfubin or something like that if needed.
318 # If compress is set, the individual files in the archive are
319 # compressed, and the final compression will accomplish very
320 # little. To save time, we skip the gzip in this case.
322 if [ $ISA = i386 ] && [ $compress = no ] && [ -x $GZIP_CMD ] ; then
323 $GZIP_CMD -c "$rdfile" > "${archive}-new"
324 else
325 cat "$rdfile" > "${archive}-new"
328 if [ $? -ne 0 ] ; then
329 rm -f "${archive}-new"
332 # sanity check the archive before moving it into place
334 ARCHIVE_SIZE=`ls -l "${archive}-new" 2> /dev/null | nawk '{ print $5 }'`
335 if [ $compress = yes ] || [ $ISA = sparc ] ; then
337 # 'file' will report "English text" for uncompressed
338 # boot_archives. Checking for that doesn't seem stable,
339 # so we just check that the file exists.
341 ls "${archive}-new" >/dev/null 2>&1
342 else
344 # the file type check also establishes that the
345 # file exists at all
347 LC_MESSAGES=C file "${archive}-new" | grep gzip > /dev/null
350 if [ $? = 1 ] && [ -x $GZIP_CMD ] || [ "$ARCHIVE_SIZE" -lt 10000 ]
351 then
352 fatal_error "update of $archive failed"
353 else
354 lockfs -f "/$ALT_ROOT" 2>/dev/null
355 rm -f "$archive.hash"
356 mv "${archive}-new" "$archive"
357 digest -a sha1 "$rdfile" > "$archive.hash"
358 lockfs -f "/$ALT_ROOT" 2>/dev/null
360 [ -n "$rddir" ] && rm -rf "$rddir"
363 function cpio_cleanup
365 rm -f "$tarchive" "$tarchive.cpio" "$tarchive.hash"
368 function create_cpio_archive
370 typeset archive="$ALT_ROOT/$BOOT_ARCHIVE"
372 echo "updating $archive (CPIO)"
374 tarchive="$archive.$$.new"
376 # Clean up upon exit.
377 trap 'cpio_cleanup' EXIT
379 cd "/$ALT_ROOT" || fatal_error "Cannot chdir to $ALT_ROOT"
381 touch "$tarchive" \
382 || fatal_error "Cannot create temporary archive $tarchive"
384 find $filelist 2>/dev/null | cpio -qo -H odc > "$tarchive.cpio" \
385 || fatal_error "Problem creating archive"
387 [ -x /usr/bin/digest ] \
388 && /usr/bin/digest -a sha1 "$tarchive.cpio" \
389 > "$tarchive.hash"
391 if [ -x "$GZIP_CMD" ]; then
392 $GZIP_CMD -c "$tarchive.cpio" > "$tarchive"
393 rm -f "$tarchive.cpio"
394 else
395 mv "$tarchive.cpio" "$tarchive"
398 # Move new archive into place
399 [ -f "$archive.hash" ] && rm -f "$archive.hash"
400 mv "$tarchive" "$archive"
401 [ $? -eq 0 -a -f "$tarchive.hash" ] \
402 && mv "$tarchive.hash" "$archive.hash"
406 # get filelist
408 if [ ! -f "$ALT_ROOT/boot/solaris/filelist.ramdisk" ] &&
409 [ ! -f "$ALT_ROOT/etc/boot/solaris/filelist.ramdisk" ]
410 then
411 print -u2 "Can't find filelist.ramdisk"
412 exit 1
414 filelist=$($EXTRACT_FILELIST $EXTRACT_ARGS \
415 /boot/solaris/filelist.ramdisk \
416 /etc/boot/solaris/filelist.ramdisk \
417 2>/dev/null | sort -u)
419 # Now that we have the list of files, we can create the archive.
421 case "$FORMAT" in
422 cpio) create_cpio_archive ;;
423 ufs) create_ufs_archive ;;
424 *) print -u2 "Unknown boot archive format, $FORMAT"
425 exit 1
427 esac
430 # For the diskless case, hardlink archive to /boot to make it
431 # visible via tftp. /boot is lofs mounted under /tftpboot/<hostname>.
432 # NOTE: this script must work on both client and server.
434 grep "[ ]/[ ]*nfs[ ]" "$ALT_ROOT/etc/vfstab" > /dev/null
435 if [ $? = 0 ]; then
436 rm -f "$ALT_ROOT/boot/$BOOT_ARCHIVE_SUFFIX"
437 mkdir -p "$ALT_ROOT/boot/`dirname $BOOT_ARCHIVE_SUFFIX`"
438 ln "$ALT_ROOT/$BOOT_ARCHIVE" "$ALT_ROOT/boot/$BOOT_ARCHIVE_SUFFIX"