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 # 27 error() 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 36 fatal() 37 { 38 typeset fmt="$1" 39 shift 40 41 error "$fmt" "$@" 42 exit $EXIT_CODE 43 } 44 45 fail_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 # 56 log() 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 # 69 vlog() 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 # 96 safe_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. 106 safe_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. 118 safe_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. 129 safe_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 140 safe_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 150 safe_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 # 167 safe_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 208 safe_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 # 250 get_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 # 270 mnt_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 # 300 umnt_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. 316 get_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 # 331 post_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 # 349 get_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 # 360 get_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 # 380 install_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 sytem. 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 # 564 get_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 # 636 install_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 # 659 install_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 # 683 install_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 # 704 install_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 # 755 install_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 1007 TEXTDOMAIN="SUNW_OST_OSCMD" 1008 export TEXTDOMAIN 1009 1010 e_cannot_wrap=$(gettext "%s: error: wrapper file already exists") 1011 e_baddir=$(gettext "Invalid '%s' directory within the zone") 1012 e_badfile=$(gettext "Invalid '%s' file within the zone") 1013 e_path_abs=$(gettext "Pathname specified to -a '%s' must be absolute.") 1014 e_not_found=$(gettext "%s: error: file or directory not found.") 1015 e_install_abort=$(gettext "Installation aborted.") 1016 e_not_readable=$(gettext "Cannot read directory '%s'") 1017 e_not_dir=$(gettext "Error: must be a directory") 1018 e_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.") 1019 e_absolute_archive=$(gettext "Error: archive contains absolute paths instead of relative paths.") 1020 e_mismatch_archive=$(gettext "Error: the archive top-level directory (%s) does not match the zonepath (%s).") 1021 e_tmpfile=$(gettext "Unable to create temporary file") 1022 e_root_full=$(gettext "Zonepath root %s exists and contains data; remove or move aside prior to install.") 1023 f_mkdir=$(gettext "Unable to create directory %s.") 1024 f_chmod=$(gettext "Unable to chmod directory %s.") 1025 f_chown=$(gettext "Unable to chown directory %s.") 1026 f_hwcap_info=$(gettext "HWCAP: %s\n") 1027 f_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 1032 m_analyse_archive=$(gettext "Analysing the archive") 1033 1034 not_readable=$(gettext "Cannot read file '%s'") 1035 not_flar=$(gettext "Input is not a flash archive") 1036 bad_flar=$(gettext "Flash archive is a corrupt") 1037 bad_zfs_flar=$(gettext "Flash archive contains a ZFS send stream.\n\tRecreate the flar using the -L option with cpio or pax.") 1038 f_unpack_failed=$(gettext "Unpacking the archive failed") 1039 unknown_archiver=$(gettext "Archiver %s is not supported") 1040 cmd_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 # 1063 ZONE_SUBPROC_OK=0 1064 ZONE_SUBPROC_USAGE=253 1065 ZONE_SUBPROC_NOTCOMPLETE=254 1066 ZONE_SUBPROC_FATAL=255 1067