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