1# 2# CDDL HEADER START 3# 4# The contents of this file are subject to the terms of the 5# Common Development and Distribution License (the "License"). 6# You may not use this file except in compliance with the License. 7# 8# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9# or http://www.opensolaris.org/os/licensing. 10# See the License for the specific language governing permissions 11# and limitations under the License. 12# 13# When distributing Covered Code, include this CDDL HEADER in each 14# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15# If applicable, add the following below this CDDL HEADER, with the 16# fields enclosed by brackets "[]" replaced with your own identifying 17# information: Portions Copyright [yyyy] [name of copyright owner] 18# 19# CDDL HEADER END 20# 21# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 22# 23 24# 25# Send the error message to the screen and to the logfile. 26# 27error() 28{ 29 typeset fmt="$1" 30 shift 31 32 printf "${MSG_PREFIX}ERROR: ${fmt}\n" "$@" 33 [[ -n $LOGFILE ]] && printf "[$(date)] ERROR: ${fmt}\n" "$@" >&2 34} 35 36fatal() 37{ 38 typeset fmt="$1" 39 shift 40 41 error "$fmt" "$@" 42 exit $EXIT_CODE 43} 44 45fail_fatal() { 46 typeset fmt="$1" 47 shift 48 49 error "$fmt" "$@" 50 exit $ZONE_SUBPROC_FATAL 51} 52 53# 54# Send the provided printf()-style arguments to the screen and to the logfile. 55# 56log() 57{ 58 typeset fmt="$1" 59 shift 60 61 printf "${MSG_PREFIX}${fmt}\n" "$@" 62 [[ -n $LOGFILE ]] && printf "[$(date)] ${MSG_PREFIX}${fmt}\n" "$@" >&2 63} 64 65# 66# Print provided text to the screen if the shell variable "OPT_V" is set. 67# The text is always sent to the logfile. 68# 69vlog() 70{ 71 typeset fmt="$1" 72 shift 73 74 [[ -n $OPT_V ]] && printf "${MSG_PREFIX}${fmt}\n" "$@" 75 [[ -n $LOGFILE ]] && printf "[$(date)] ${MSG_PREFIX}${fmt}\n" "$@" >&2 76} 77 78# 79# Validate that the directory is safe. 80# 81# It is possible for a malicious zone root user to modify a zone's filesystem 82# so that modifications made to the zone's filesystem by administrators in the 83# global zone modify the global zone's filesystem. We can prevent this by 84# ensuring that all components of paths accessed by scripts are real (i.e., 85# non-symlink) directories. 86# 87# NOTE: The specified path should be an absolute path as would be seen from 88# within the zone. Also, this function does not check parent directories. 89# If, for example, you need to ensure that every component of the path 90# '/foo/bar/baz' is a directory and not a symlink, then do the following: 91# 92# safe_dir /foo 93# safe_dir /foo/bar 94# safe_dir /foo/bar/baz 95# 96safe_dir() 97{ 98 typeset dir="$1" 99 100 if [[ -h $ZONEROOT/$dir || ! -d $ZONEROOT/$dir ]]; then 101 fatal "$e_baddir" "$dir" 102 fi 103} 104 105# Like safe_dir except the dir doesn't have to exist. 106safe_opt_dir() 107{ 108 typeset dir="$1" 109 110 [[ ! -e $ZONEROOT/$dir ]] && return 111 112 if [[ -h $ZONEROOT/$dir || ! -d $ZONEROOT/$dir ]]; then 113 fatal "$e_baddir" "$dir" 114 fi 115} 116 117# Only make a copy if we haven't already done so. 118safe_backup() 119{ 120 typeset src="$1" 121 typeset dst="$2" 122 123 if [[ ! -h $src && ! -h $dst && ! -d $dst && ! -f $dst ]]; then 124 /usr/bin/cp -p $src $dst || fatal "$e_badfile" "$src" 125 fi 126} 127 128# Make a copy even if the destination already exists. 129safe_copy() 130{ 131 typeset src="$1" 132 typeset dst="$2" 133 134 if [[ ! -h $src && ! -h $dst && ! -d $dst ]]; then 135 /usr/bin/cp -p $src $dst || fatal "$e_badfile" "$src" 136 fi 137} 138 139# Move a file 140safe_move() 141{ 142 typeset src="$1" 143 typeset dst="$2" 144 145 if [[ ! -h $src && ! -h $dst && ! -d $dst ]]; then 146 /usr/bin/mv $src $dst || fatal "$e_badfile" "$src" 147 fi 148} 149 150safe_rm() 151{ 152 if [[ ! -h $ZONEROOT/$1 && -f $ZONEROOT/$1 ]]; then 153 rm -f "$ZONEROOT/$1" 154 fi 155} 156 157# 158# Replace the file with a wrapper pointing to the native brand code. 159# However, we only do the replacement if the file hasn't already been 160# replaced with our wrapper. This function expects the cwd to be the 161# location of the file we're replacing. 162# 163# Some of the files we're replacing are hardlinks to isaexec so we need to 'rm' 164# the file before we setup the wrapper while others are hardlinks to rc scripts 165# that we need to maintain. 166# 167safe_replace() 168{ 169 typeset filename="$1" 170 typeset runname="$2" 171 typeset mode="$3" 172 typeset own="$4" 173 typeset rem="$5" 174 175 if [ -h $filename -o ! -f $filename ]; then 176 return 177 fi 178 179 egrep -s "Solaris Brand Replacement" $filename 180 if [ $? -eq 0 ]; then 181 return 182 fi 183 184 safe_backup $filename $filename.pre_p2v 185 if [ $rem = "remove" ]; then 186 rm -f $filename 187 fi 188 189 cat <<-END >$filename || exit 1 190 #!/bin/sh -p 191 # 192 # Solaris Brand Replacement 193 # 194 # Attention. This file has been replaced with a new version for 195 # use in a virtualized environment. Modification of this script is not 196 # supported and all changes will be lost upon reboot. The 197 # {name}.pre_p2v version of this file is a backup copy of the 198 # original and should not be deleted. 199 # 200 END 201 202 echo ". $runname \"\$@\"" >>$filename || exit 1 203 204 chmod $mode $filename 205 chown $own $filename 206} 207 208safe_wrap() 209{ 210 typeset filename="$1" 211 typeset runname="$2" 212 typeset mode="$3" 213 typeset own="$4" 214 215 if [ -f $filename ]; then 216 log "$e_cannot_wrap" "$filename" 217 exit 1 218 fi 219 220 cat <<-END >$filename || exit 1 221 #!/bin/sh 222 # 223 # Solaris Brand Wrapper 224 # 225 # Attention. This file has been created for use in a 226 # virtualized environment. Modification of this script 227 # is not supported and all changes will be lost upon reboot. 228 # 229 END 230 231 echo ". $runname \"\$@\"" >>$filename || exit 1 232 233 chmod $mode $filename 234 chown $own $filename 235} 236 237# 238# Read zonecfg fs entries and save the relevant data, one entry per 239# line. 240# This assumes the properties from the zonecfg output, e.g.: 241# fs: 242# dir: /opt 243# special: /opt 244# raw not specified 245# type: lofs 246# options: [noexec,ro,noatime] 247# 248# and it assumes the order of the fs properties as above. 249# 250get_fs_info() 251{ 252 zonecfg -z $zonename info fs | nawk '{ 253 if ($1 == "options:") { 254 # Remove brackets. 255 options=substr($2, 2, length($2) - 2); 256 printf("%s %s %s %s\n", dir, type, special, options); 257 } else if ($1 == "dir:") { 258 dir=$2; 259 } else if ($1 == "special:") { 260 special=$2; 261 } else if ($1 == "type:") { 262 type=$2 263 } 264 }' >> $fstmpfile 265} 266 267# 268# Mount zonecfg fs entries into the zonepath. 269# 270mnt_fs() 271{ 272 if [ ! -s $fstmpfile ]; then 273 return; 274 fi 275 276 # Sort the fs entries so we can handle nested mounts. 277 sort $fstmpfile | nawk -v zonepath=$zonepath '{ 278 if (NF == 4) 279 options="-o " $4; 280 else 281 options="" 282 283 # Create the mount point. Ignore errors since we might have 284 # a nested mount with a pre-existing mount point. 285 cmd="/usr/bin/mkdir -p " zonepath "/root" $1 " >/dev/null 2>&1" 286 system(cmd); 287 288 cmd="/usr/sbin/mount -F " $2 " " options " " $3 " " \ 289 zonepath "/root" $1; 290 if (system(cmd) != 0) { 291 printf("command failed: %s\n", cmd); 292 exit 1; 293 } 294 }' >>$LOGFILE 295} 296 297# 298# Unmount zonecfg fs entries from the zonepath. 299# 300umnt_fs() 301{ 302 if [ ! -s $fstmpfile ]; then 303 return; 304 fi 305 306 # Reverse sort the fs entries so we can handle nested unmounts. 307 sort -r $fstmpfile | nawk -v zonepath=$zonepath '{ 308 cmd="/usr/sbin/umount " zonepath "/root" $1 309 if (system(cmd) != 0) { 310 printf("command failed: %s\n", cmd); 311 } 312 }' >>$LOGFILE 313} 314 315# Find the dataset mounted on the zonepath. 316get_zonepath_ds() { 317 ZONEPATH_DS=`/usr/sbin/zfs list -H -t filesystem -o name,mountpoint | \ 318 /usr/bin/nawk -v zonepath=$1 '{ 319 if ($2 == zonepath) 320 print $1 321 }'` 322 323 if [ -z "$ZONEPATH_DS" ]; then 324 fail_fatal "$f_no_ds" 325 fi 326} 327 328# 329# Perform validation and cleanup in the zoneroot after unpacking the archive. 330# 331post_unpack() 332{ 333 # 334 # Check if the image was created with a valid libc.so.1. 335 # 336 hwcap=`moe -v -32 $ZONEROOT/lib/libc.so.1 2>&1` 337 if (( $? != 0 )); then 338 vlog "$f_hwcap_info" "$hwcap" 339 fail_fatal "$f_sanity_hwcap" 340 fi 341 342 ( cd "$ZONEROOT" && \ 343 find . \( -type b -o -type c \) -exec rm -f "{}" \; ) 344} 345 346# 347# Determine flar compression style from identification file. 348# 349get_compression() 350{ 351 typeset ident=$1 352 typeset line=$(grep "^files_compressed_method=" $ident) 353 354 print ${line##*=} 355} 356 357# 358# Determine flar archive style from identification file. 359# 360get_archiver() 361{ 362 typeset ident=$1 363 typeset line=$(grep "^files_archived_method=" $ident) 364 365 print ${line##*=} 366} 367 368# 369# Unpack flar into current directory (which should be zoneroot). The flash 370# archive is standard input. See flash_archive(4) man page. 371# 372# We can't use "flar split" since it will only unpack into a directory called 373# "archive". We need to unpack in place in order to properly handle nested 374# fs mounts within the zone root. This function does the unpacking into the 375# current directory. 376# 377# This code is derived from the gen_split() function in /usr/sbin/flar so 378# we keep the same style as the original. 379# 380install_flar() 381{ 382 typeset result 383 typeset archiver_command 384 typeset archiver_arguments 385 386 vlog "cd $ZONEROOT && $stage1 "$insrc" | install_flar" 387 388 # Read cookie 389 read -r input_line 390 if (( $? != 0 )); then 391 log "$not_readable" "$install_media" 392 return 1 393 fi 394 # The cookie has format FlAsH-aRcHiVe-m.n where m and n are integers. 395 if [[ ${input_line%%-[0-9]*.[0-9]*} != "FlAsH-aRcHiVe" ]]; then 396 log "$not_flar" 397 return 1 398 fi 399 400 while [ true ] 401 do 402 # We should always be at the start of a section here 403 read -r input_line 404 if [[ ${input_line%%=*} != "section_begin" ]]; then 405 log "$bad_flar" 406 return 1 407 fi 408 section_name=${input_line##*=} 409 410 # If we're at the archive, we're done skipping sections. 411 if [[ "$section_name" == "archive" ]]; then 412 break 413 fi 414 415 # 416 # Save identification section to a file so we can determine 417 # how to unpack the archive. 418 # 419 if [[ "$section_name" == "identification" ]]; then 420 /usr/bin/rm -f identification 421 while read -r input_line 422 do 423 if [[ ${input_line%%=*} == \ 424 "section_begin" ]]; then 425 /usr/bin/rm -f identification 426 log "$bad_flar" 427 return 1 428 fi 429 430 if [[ $input_line == \ 431 "section_end=$section_name" ]]; then 432 break; 433 fi 434 echo $input_line >> identification 435 done 436 437 continue 438 fi 439 440 # 441 # Otherwise skip past this section; read lines until detecting 442 # section_end. According to flash_archive(4) we can have 443 # an arbitrary number of sections but the archive section 444 # must be last. 445 # 446 success=0 447 while read -r input_line 448 do 449 if [[ $input_line == "section_end=$section_name" ]]; 450 then 451 success=1 452 break 453 fi 454 # Fail if we miss the end of the section 455 if [[ ${input_line%%=*} == "section_begin" ]]; then 456 /usr/bin/rm -f identification 457 log "$bad_flar" 458 return 1 459 fi 460 done 461 if (( $success == 0 )); then 462 # 463 # If we get here we read to the end of the file before 464 # seeing the end of the section we were reading. 465 # 466 /usr/bin/rm -f identification 467 log "$bad_flar" 468 return 1 469 fi 470 done 471 472 # Check for an archive made from a ZFS root pool. 473 egrep -s "^rootpool=" identification 474 if (( $? == 0 )); then 475 /usr/bin/rm -f identification 476 log "$bad_zfs_flar" 477 return 1 478 fi 479 480 # Get the information needed to unpack the archive. 481 archiver=$(get_archiver identification) 482 if [[ $archiver == "pax" ]]; then 483 # pax archiver specified 484 archiver_command="/usr/bin/pax" 485 if [[ -s $fspaxfile ]]; then 486 archiver_arguments="-r -p e -c \ 487 $(/usr/bin/cat $fspaxfile)" 488 else 489 archiver_arguments="-r -p e" 490 fi 491 elif [[ $archiver == "cpio" || -z $archiver ]]; then 492 # cpio archived specified OR no archiver specified - use default 493 archiver_command="/usr/bin/cpio" 494 archiver_arguments="-icdumfE $fscpiofile" 495 else 496 # unknown archiver specified 497 log "$unknown_archiver" $archiver 498 return 1 499 fi 500 501 if [[ ! -x $archiver_command ]]; then 502 /usr/bin/rm -f identification 503 log "$cmd_not_exec" $archiver_command 504 return 1 505 fi 506 507 compression=$(get_compression identification) 508 509 # We're done with the identification file 510 /usr/bin/rm -f identification 511 512 # Extract archive 513 if [[ $compression == "compress" ]]; then 514 /usr/bin/zcat | \ 515 $archiver_command $archiver_arguments 2>/dev/null 516 else 517 $archiver_command $archiver_arguments 2>/dev/null 518 fi 519 result=$? 520 521 post_unpack 522 523 (( $result != 0 )) && return 1 524 525 return 0 526} 527 528# 529# Get the archive base. 530# 531# We must unpack the archive in the right place within the zonepath so 532# that files are installed into the various mounted filesystems that are set 533# up in the zone's configuration. These are already mounted for us by the 534# mntfs function. 535# 536# Archives can be made of either a physical host's root file system or a 537# zone's zonepath. For a physical system, if the archive is made using an 538# absolute path (/...) we can't use it. For a zone the admin can make the 539# archive from a variety of locations; 540# 541# a) zonepath itself: This will be a single dir, probably named with the 542# zone name, it will contain a root dir and under the root we'll see all 543# the top level dirs; etc, var, usr... We must be above the ZONEPATH 544# when we unpack the archive but this will only work if the the archive's 545# top-level dir name matches the ZONEPATH base-level dir name. If not, 546# this is an error. 547# 548# b) inside the zonepath: We'll see root and it will contain all the top 549# level dirs; etc, var, usr.... We must be in the ZONEPATH when we unpack 550# the archive. 551# 552# c) inside the zonepath root: We'll see all the top level dirs, ./etc, 553# ./var, ./usr.... This is also the case we see when we get an archive 554# of a physical system. We must be in ZONEROOT when we unpack the archive. 555# 556# Note that there can be a directory named "root" under the ZONEPATH/root 557# directory. 558# 559# This function handles the above possibilities so that we reject absolute 560# path archives and figure out where in the file system we need to be to 561# properly unpack the archive into the zone. It sets the ARCHIVE_BASE 562# variable to the location where the achive should be unpacked. 563# 564get_archive_base() 565{ 566 stage1=$1 567 archive=$2 568 stage2=$3 569 570 vlog "$m_analyse_archive" 571 572 base=`$stage1 $archive | $stage2 2>/dev/null | nawk -F/ '{ 573 # Check for an absolute path archive 574 if (substr($0, 1, 1) == "/") 575 exit 1 576 577 if ($1 != ".") 578 dirs[$1] = 1 579 else 580 dirs[$2] = 1 581 } 582 END { 583 for (d in dirs) { 584 cnt++ 585 if (d == "bin") sawbin = 1 586 if (d == "etc") sawetc = 1 587 if (d == "root") sawroot = 1 588 if (d == "var") sawvar = 1 589 } 590 591 if (cnt == 1) { 592 # If only one top-level dir named root, we are in the 593 # zonepath, otherwise this must be an archive *of* 594 # the zonepath so print the top-level dir name. 595 if (sawroot) 596 print "*zonepath*" 597 else 598 for (d in dirs) print d 599 } else { 600 # We are either in the zonepath or in the zonepath/root 601 # (or at the top level of a full system archive which 602 # looks like the zonepath/root case). Figure out which 603 # one. 604 if (sawroot && !sawbin && !sawetc && !sawvar) 605 print "*zonepath*" 606 else 607 print "*zoneroot*" 608 } 609 }'` 610 611 if (( $? != 0 )); then 612 umnt_fs 613 fatal "$e_absolute_archive" 614 fi 615 616 if [[ "$base" == "*zoneroot*" ]]; then 617 ARCHIVE_BASE=$ZONEROOT 618 elif [[ "$base" == "*zonepath*" ]]; then 619 ARCHIVE_BASE=$ZONEPATH 620 else 621 # We need to be in the dir above the ZONEPATH but we need to 622 # validate that $base matches the final component of ZONEPATH. 623 bname=`basename $ZONEPATH` 624 625 if [[ "$bname" != "$base" ]]; then 626 umnt_fs 627 fatal "$e_mismatch_archive" "$base" "$bname" 628 fi 629 ARCHIVE_BASE=`dirname $ZONEPATH` 630 fi 631} 632 633# 634# Unpack cpio archive into zoneroot. 635# 636install_cpio() 637{ 638 stage1=$1 639 archive=$2 640 641 get_archive_base "$stage1" "$archive" "cpio -it" 642 643 cpioopts="-idmfE $fscpiofile" 644 645 vlog "cd \"$ARCHIVE_BASE\" && $stage1 \"$archive\" | cpio $cpioopts" 646 647 # Ignore errors from cpio since we expect some errors depending on 648 # how the archive was made. 649 ( cd "$ARCHIVE_BASE" && $stage1 "$archive" | cpio $cpioopts ) 650 651 post_unpack 652 653 return 0 654} 655 656# 657# Unpack pax archive into zoneroot. 658# 659install_pax() 660{ 661 archive=$1 662 663 get_archive_base "cat" "$archive" "pax" 664 665 if [[ -s $fspaxfile ]]; then 666 filtopt="-c $(/usr/bin/cat $fspaxfile)" 667 fi 668 669 vlog "cd \"$ARCHIVE_BASE\" && pax -r -f \"$archive\" $filtopt" 670 671 # Ignore errors from pax since we expect some errors depending on 672 # how the archive was made. 673 ( cd "$ARCHIVE_BASE" && pax -r -f "$archive" $filtopt ) 674 675 post_unpack 676 677 return 0 678} 679 680# 681# Unpack UFS dump into zoneroot. 682# 683install_ufsdump() 684{ 685 archive=$1 686 687 vlog "cd \"$ZONEROOT\" && ufsrestore rf \"$archive\"" 688 689 # 690 # ufsrestore goes interactive if you ^C it. To prevent that, 691 # we make sure its stdin is not a terminal. 692 # 693 ( cd "$ZONEROOT" && ufsrestore rf "$archive" < /dev/null ) 694 result=$? 695 696 post_unpack 697 698 return $result 699} 700 701# 702# Copy directory hierarchy into zoneroot. 703# 704install_dir() 705{ 706 source_dir=$1 707 708 cpioopts="-pdm" 709 710 first=1 711 filt=$(for i in $(cat $fspaxfile) 712 do 713 echo $i | egrep -s "/" && continue 714 if [[ $first == 1 ]]; then 715 printf "^%s" $i 716 first=0 717 else 718 printf "|^%s" $i 719 fi 720 done) 721 722 list=$(cd "$source_dir" && ls -d * | egrep -v "$filt") 723 flist=$(for i in $list 724 do 725 printf "%s " "$i" 726 done) 727 findopts="-xdev ( -type d -o -type f -o -type l ) -print" 728 729 vlog "cd \"$source_dir\" && find $flist $findopts | " 730 vlog "cpio $cpioopts \"$ZONEROOT\"" 731 732 # Ignore errors from cpio since we expect some errors depending on 733 # how the archive was made. 734 ( cd "$source_dir" && find $flist $findopts | \ 735 cpio $cpioopts "$ZONEROOT" ) 736 737 post_unpack 738 739 return 0 740} 741 742# 743# This is a common function for laying down a zone image from a variety of 744# different sources. This can be used to either install a fresh zone or as 745# part of zone migration during attach. 746# 747# The first argument specifies the type of image: archive, directory or stdin. 748# The second argument specifies the image itself. In the case of stdin, the 749# second argument specifies the format of the stream (cpio, flar, etc.). 750# Any validation or post-processing on the image is done elsewhere. 751# 752# This function calls a 'sanity_check' function which must be provided by 753# the script which includes this code. 754# 755install_image() 756{ 757 intype=$1 758 insrc=$2 759 760 if [[ -z "$intype" || -z "$insrc" ]]; then 761 return 1 762 fi 763 764 filetype="unknown" 765 filetypename="unknown" 766 stage1="cat" 767 768 if [[ "$intype" == "directory" ]]; then 769 if [[ "$insrc" == "-" ]]; then 770 # Indicates that the existing zonepath is prepopulated. 771 filetype="existing" 772 filetypename="existing" 773 else 774 if [[ "$(echo $insrc | cut -c 1)" != "/" ]]; then 775 fatal "$e_path_abs" "$insrc" 776 fi 777 778 if [[ ! -e "$insrc" ]]; then 779 log "$e_not_found" "$insrc" 780 fatal "$e_install_abort" 781 fi 782 783 if [[ ! -r "$insrc" ]]; then 784 log "$e_not_readable" "$insrc" 785 fatal "$e_install_abort" 786 fi 787 788 if [[ ! -d "$insrc" ]]; then 789 log "$e_not_dir" 790 fatal "$e_install_abort" 791 fi 792 793 sanity_check $insrc 794 795 filetype="directory" 796 filetypename="directory" 797 fi 798 799 else 800 # Common code for both archive and stdin stream. 801 802 if [[ "$intype" == "archive" ]]; then 803 if [[ ! -f "$insrc" ]]; then 804 log "$e_unknown_archive" 805 fatal "$e_install_abort" 806 fi 807 ftype="$(LC_ALL=C file $insrc | cut -d: -f 2)" 808 else 809 # For intype == stdin, the insrc parameter specifies 810 # the stream format coming on stdin. 811 ftype="$insrc" 812 insrc="-" 813 fi 814 815 # Setup vars for the archive type we have. 816 case "$ftype" in 817 *cpio*) filetype="cpio" 818 filetypename="cpio archive" 819 ;; 820 *bzip2*) filetype="bzip2" 821 filetypename="bzipped cpio archive" 822 ;; 823 *gzip*) filetype="gzip" 824 filetypename="gzipped cpio archive" 825 ;; 826 *ufsdump*) filetype="ufsdump" 827 filetypename="ufsdump archive" 828 ;; 829 "flar") 830 filetype="flar" 831 filetypename="flash archive" 832 ;; 833 "flash") 834 filetype="flar" 835 filetypename="flash archive" 836 ;; 837 *Flash\ Archive*) 838 filetype="flar" 839 filetypename="flash archive" 840 ;; 841 "tar") 842 filetype="tar" 843 filetypename="tar archive" 844 ;; 845 *USTAR\ tar\ archive) 846 filetype="tar" 847 filetypename="tar archive" 848 ;; 849 "pax") 850 filetype="xustar" 851 filetypename="pax (xustar) archive" 852 ;; 853 *USTAR\ tar\ archive\ extended\ format*) 854 filetype="xustar" 855 filetypename="pax (xustar) archive" 856 ;; 857 "zfs") 858 filetype="zfs" 859 filetypename="ZFS send stream" 860 ;; 861 *ZFS\ snapshot\ stream*) 862 filetype="zfs" 863 filetypename="ZFS send stream" 864 ;; 865 *) log "$e_unknown_archive" 866 fatal "$e_install_abort" 867 ;; 868 esac 869 fi 870 871 vlog "$filetypename" 872 873 # Check for a non-empty root if no '-d -' option. 874 if [[ "$filetype" != "existing" ]]; then 875 cnt=$(ls $ZONEROOT | wc -l) 876 if (( $cnt != 0 )); then 877 fatal "$e_root_full" "$ZONEROOT" 878 fi 879 fi 880 881 fstmpfile=$(/usr/bin/mktemp -t -p /var/tmp) 882 if [[ -z "$fstmpfile" ]]; then 883 fatal "$e_tmpfile" 884 fi 885 886 # Make sure we always have the files holding the directories to filter 887 # out when extracting from a CPIO or PAX archive. We'll add the fs 888 # entries to these files in get_fs_info() 889 fscpiofile=$(/usr/bin/mktemp -t -p /var/tmp fs.cpio.XXXXXX) 890 if [[ -z "$fscpiofile" ]]; then 891 rm -f $fstmpfile 892 fatal "$e_tmpfile" 893 fi 894 895 # Filter out these directories. 896 echo 'dev/*' >>$fscpiofile 897 echo 'devices/*' >>$fscpiofile 898 echo 'devices' >>$fscpiofile 899 echo 'proc/*' >>$fscpiofile 900 echo 'tmp/*' >>$fscpiofile 901 echo 'var/run/*' >>$fscpiofile 902 echo 'system/contract/*' >>$fscpiofile 903 echo 'system/object/*' >>$fscpiofile 904 905 fspaxfile=$(/usr/bin/mktemp -t -p /var/tmp fs.pax.XXXXXX) 906 if [[ -z "$fspaxfile" ]]; then 907 rm -f $fstmpfile $fscpiofile 908 fatal "$e_tmpfile" 909 fi 910 911 printf "%s " \ 912 "dev devices proc tmp var/run system/contract system/object" \ 913 >>$fspaxfile 914 915 # Set up any fs mounts so the archive will install into the correct 916 # locations. 917 get_fs_info 918 mnt_fs 919 if (( $? != 0 )); then 920 umnt_fs >/dev/null 2>&1 921 rm -f $fstmpfile $fscpiofile $fspaxfile 922 fatal "$mount_failed" 923 fi 924 925 if [[ "$filetype" == "existing" ]]; then 926 log "$no_installing" 927 else 928 log "$installing" 929 fi 930 931 # 932 # Install the image into the zonepath. 933 # 934 unpack_result=0 935 stage1="cat" 936 if [[ "$filetype" == "gzip" ]]; then 937 stage1="gzcat" 938 filetype="cpio" 939 elif [[ "$filetype" == "bzip2" ]]; then 940 stage1="bzcat" 941 filetype="cpio" 942 fi 943 944 if [[ "$filetype" == "cpio" ]]; then 945 install_cpio "$stage1" "$insrc" 946 unpack_result=$? 947 948 elif [[ "$filetype" == "flar" ]]; then 949 ( cd "$ZONEROOT" && $stage1 $insrc | install_flar ) 950 unpack_result=$? 951 952 elif [[ "$filetype" == "xustar" ]]; then 953 install_pax "$insrc" 954 unpack_result=$? 955 956 elif [[ "$filetype" = "tar" ]]; then 957 vlog "cd \"$ZONEROOT\" && tar -xf \"$insrc\"" 958 # Ignore errors from tar since we expect some errors depending 959 # on how the archive was made. 960 ( cd "$ZONEROOT" && tar -xf "$insrc" ) 961 unpack_result=0 962 post_unpack 963 964 elif [[ "$filetype" == "ufsdump" ]]; then 965 install_ufsdump "$insrc" 966 unpack_result=$? 967 968 elif [[ "$filetype" == "directory" ]]; then 969 install_dir "$insrc" 970 unpack_result=$? 971 972 elif [[ "$filetype" == "zfs" ]]; then 973 # 974 # Given a 'zfs send' stream file, receive the snapshot into 975 # the zone's dataset. We're getting the original system's 976 # zonepath dataset. Destroy the existing dataset created 977 # above since this recreates it. 978 # 979 if [[ -z "$DATASET" ]]; then 980 fatal "$f_nodataset" 981 fi 982 /usr/sbin/zfs destroy "$DATASET" 983 if (( $? != 0 )); then 984 log "$f_zfsdestroy" "$DATASET" 985 fi 986 987 vlog "$stage1 $insrc | zfs receive -F $DATASET" 988 ( $stage1 $insrc | /usr/sbin/zfs receive -F $DATASET ) 989 unpack_result=$? 990 fi 991 992 # Clean up any fs mounts used during unpacking. 993 umnt_fs 994 rm -f $fstmpfile $fscpiofile $fspaxfile 995 996 chmod 700 $zonepath 997 998 (( $unpack_result != 0 )) && fatal "$f_unpack_failed" 999 1000 # Verify this is a valid image. 1001 sanity_check $ZONEROOT 1002 1003 return 0 1004} 1005 1006# Setup i18n output 1007TEXTDOMAIN="SUNW_OST_OSCMD" 1008export TEXTDOMAIN 1009 1010e_cannot_wrap=$(gettext "%s: error: wrapper file already exists") 1011e_baddir=$(gettext "Invalid '%s' directory within the zone") 1012e_badfile=$(gettext "Invalid '%s' file within the zone") 1013e_path_abs=$(gettext "Pathname specified to -a '%s' must be absolute.") 1014e_not_found=$(gettext "%s: error: file or directory not found.") 1015e_install_abort=$(gettext "Installation aborted.") 1016e_not_readable=$(gettext "Cannot read directory '%s'") 1017e_not_dir=$(gettext "Error: must be a directory") 1018e_unknown_archive=$(gettext "Error: Unknown archive format. Must be a flash archive, a cpio archive (can also be gzipped or bzipped), a pax XUSTAR archive, or a level 0 ufsdump archive.") 1019e_absolute_archive=$(gettext "Error: archive contains absolute paths instead of relative paths.") 1020e_mismatch_archive=$(gettext "Error: the archive top-level directory (%s) does not match the zonepath (%s).") 1021e_tmpfile=$(gettext "Unable to create temporary file") 1022e_root_full=$(gettext "Zonepath root %s exists and contains data; remove or move aside prior to install.") 1023f_mkdir=$(gettext "Unable to create directory %s.") 1024f_chmod=$(gettext "Unable to chmod directory %s.") 1025f_chown=$(gettext "Unable to chown directory %s.") 1026f_hwcap_info=$(gettext "HWCAP: %s\n") 1027f_sanity_hwcap=$(gettext \ 1028"The image was created with an incompatible libc.so.1 hwcap lofs mount.\n"\ 1029" The zone will not boot on this platform. See the zone's\n"\ 1030" documentation for the recommended way to create the archive.") 1031 1032m_analyse_archive=$(gettext "Analysing the archive") 1033 1034not_readable=$(gettext "Cannot read file '%s'") 1035not_flar=$(gettext "Input is not a flash archive") 1036bad_flar=$(gettext "Flash archive is a corrupt") 1037bad_zfs_flar=$(gettext "Flash archive contains a ZFS send stream.\n\tRecreate the flar using the -L option with cpio or pax.") 1038f_unpack_failed=$(gettext "Unpacking the archive failed") 1039unknown_archiver=$(gettext "Archiver %s is not supported") 1040cmd_not_exec=$(gettext "Required command '%s' not executable!") 1041 1042# 1043# Exit values used by the script, as #defined in <sys/zone.h> 1044# 1045# ZONE_SUBPROC_OK 1046# =============== 1047# Installation was successful 1048# 1049# ZONE_SUBPROC_USAGE 1050# ================== 1051# Improper arguments were passed, so print a usage message before exiting 1052# 1053# ZONE_SUBPROC_NOTCOMPLETE 1054# ======================== 1055# Installation did not complete, but another installation attempt can be 1056# made without an uninstall 1057# 1058# ZONE_SUBPROC_FATAL 1059# ================== 1060# Installation failed and an uninstall will be required before another 1061# install can be attempted 1062# 1063ZONE_SUBPROC_OK=0 1064ZONE_SUBPROC_USAGE=253 1065ZONE_SUBPROC_NOTCOMPLETE=254 1066ZONE_SUBPROC_FATAL=255 1067 1068