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 # Copyright 2014, Joyent, Inc. All rights reserved.
  23 #
  24 
  25 #
  26 # Send the error message to the screen and to the logfile.
  27 #
  28 error()
  29 {
  30         typeset fmt="$1"
  31         shift
  32 
  33         printf "${MSG_PREFIX}ERROR: ${fmt}\n" "$@"
  34         [[ -n $LOGFILE ]] && printf "[$(date)] ERROR: ${fmt}\n" "$@" >&2
  35 }
  36 
  37 fatal()
  38 {
  39         typeset fmt="$1"
  40         shift
  41 
  42         error "$fmt" "$@"
  43         exit $EXIT_CODE
  44 }
  45 
  46 fail_fatal() {
  47         typeset fmt="$1"
  48         shift
  49 
  50         error "$fmt" "$@"
  51         exit $ZONE_SUBPROC_FATAL
  52 }
  53 
  54 #
  55 # Send the provided printf()-style arguments to the screen and to the logfile.
  56 #
  57 log()
  58 {
  59         typeset fmt="$1"
  60         shift
  61 
  62         printf "${MSG_PREFIX}${fmt}\n" "$@"
  63         [[ -n $LOGFILE ]] && printf "[$(date)] ${MSG_PREFIX}${fmt}\n" "$@" >&2
  64 }
  65 
  66 #
  67 # Print provided text to the screen if the shell variable "OPT_V" is set.
  68 # The text is always sent to the logfile.
  69 #
  70 vlog()
  71 {
  72         typeset fmt="$1"
  73         shift
  74 
  75         [[ -n $OPT_V ]] && printf "${MSG_PREFIX}${fmt}\n" "$@"
  76         [[ -n $LOGFILE ]] && printf "[$(date)] ${MSG_PREFIX}${fmt}\n" "$@" >&2
  77 }
  78 
  79 #
  80 # Validate that the directory is safe.
  81 #
  82 # It is possible for a malicious zone root user to modify a zone's filesystem
  83 # so that modifications made to the zone's filesystem by administrators in the
  84 # global zone modify the global zone's filesystem.  We can prevent this by
  85 # ensuring that all components of paths accessed by scripts are real (i.e.,
  86 # non-symlink) directories.
  87 #
  88 # NOTE: The specified path should be an absolute path as would be seen from
  89 # within the zone.  Also, this function does not check parent directories.
  90 # If, for example, you need to ensure that every component of the path
  91 # '/foo/bar/baz' is a directory and not a symlink, then do the following:
  92 #
  93 #       safe_dir /foo
  94 #       safe_dir /foo/bar
  95 #       safe_dir /foo/bar/baz
  96 #
  97 safe_dir()
  98 {
  99         typeset dir="$1"
 100         typeset pwd_dir=""
 101 
 102         if [[ -d $ZONEROOT/$dir ]]; then
 103                 if [[ -h $ZONEROOT/$dir ]]; then
 104                         #
 105                         # When dir is a symlink to a directory, we 'cd' to that
 106                         # directory to ensure that's under $ZONEROOT. We use pwd
 107                         # from /usr/bin instead of built-in because they give
 108                         # different results.
 109                         #
 110                         pwd_dir=$(cd $ZONEROOT/$dir && /usr/bin/pwd)
 111                         if [[ $pwd_dir =~ "^$ZONEROOT" ]]; then
 112                                 return;
 113                         else
 114                                 fatal \
 115                                     "$e_baddir: symlink out of zoneroot" "$dir"
 116                         fi
 117                 else
 118                         # it's a dir and not a symlink, so that's ok.
 119                         return
 120                 fi
 121         fi
 122 }
 123 
 124 # Like safe_dir except the dir doesn't have to exist.
 125 safe_opt_dir()
 126 {
 127         typeset dir="$1"
 128 
 129         [[ ! -e $ZONEROOT/$dir ]] && return
 130 
 131         safe_dir $dir
 132 }
 133 
 134 # Only make a copy if we haven't already done so.
 135 safe_backup()
 136 {
 137         typeset src="$1"
 138         typeset dst="$2"
 139 
 140         if [[ ! -h $src && ! -h $dst && ! -d $dst && ! -f $dst ]]; then
 141                 /usr/bin/cp -p $src $dst || fatal "$e_badfile" "$src"
 142         fi
 143 }
 144 
 145 # Make a copy even if the destination already exists.
 146 safe_copy()
 147 {
 148         typeset src="$1"
 149         typeset dst="$2"
 150 
 151         if [[ ! -h $src && ! -h $dst && ! -d $dst ]]; then
 152                 /usr/bin/cp -p $src $dst || fatal "$e_badfile" "$src"
 153         fi
 154 }
 155 
 156 # Move a file
 157 safe_move()
 158 {
 159         typeset src="$1"
 160         typeset dst="$2"
 161 
 162         if [[ ! -h $src && ! -h $dst && ! -d $dst ]]; then
 163                 /usr/bin/mv $src $dst || fatal "$e_badfile" "$src"
 164         fi
 165 }
 166 
 167 safe_rm()
 168 {
 169         if [[ ! -h $ZONEROOT/$1 && -f $ZONEROOT/$1 ]]; then
 170                 rm -f "$ZONEROOT/$1"
 171         fi
 172 }
 173 
 174 #
 175 # Replace the file with a wrapper pointing to the native brand code.
 176 # However, we only do the replacement if the file hasn't already been
 177 # replaced with our wrapper.  This function expects the cwd to be the
 178 # location of the file we're replacing.
 179 #
 180 # Some of the files we're replacing are hardlinks to isaexec so we need to 'rm'
 181 # the file before we setup the wrapper while others are hardlinks to rc scripts
 182 # that we need to maintain.
 183 #
 184 safe_replace()
 185 {
 186         typeset filename="$1"
 187         typeset runname="$2"
 188         typeset mode="$3"
 189         typeset own="$4"
 190         typeset rem="$5"
 191 
 192         if [ -h $filename -o ! -f $filename ]; then
 193                 return
 194         fi
 195 
 196         egrep -s "Solaris Brand Replacement" $filename
 197         if [ $? -eq 0 ]; then
 198                 return
 199         fi
 200 
 201         safe_backup $filename $filename.pre_p2v
 202         if [ $rem = "remove" ]; then
 203                 rm -f $filename
 204         fi
 205 
 206         cat <<-END >$filename || exit 1
 207         #!/bin/sh
 208         #
 209         # Solaris Brand Replacement
 210         #
 211         # Attention.  This file has been replaced with a new version for
 212         # use in a virtualized environment.  Modification of this script is not
 213         # supported and all changes will be lost upon reboot.  The
 214         # {name}.pre_p2v version of this file is a backup copy of the
 215         # original and should not be deleted.
 216         #
 217         END
 218 
 219         echo ". $runname \"\$@\"" >>$filename || exit 1
 220 
 221         chmod $mode $filename
 222         chown $own $filename
 223 }
 224 
 225 safe_wrap()
 226 {
 227         typeset filename="$1"
 228         typeset runname="$2"
 229         typeset mode="$3"
 230         typeset own="$4"
 231 
 232         if [ -f $filename ]; then
 233                 log "$e_cannot_wrap" "$filename"
 234                 exit 1
 235         fi
 236 
 237         cat <<-END >$filename || exit 1
 238         #!/bin/sh
 239         #
 240         # Solaris Brand Wrapper
 241         #
 242         # Attention.  This file has been created for use in a
 243         # virtualized environment.  Modification of this script
 244         # is not supported and all changes will be lost upon reboot.
 245         #
 246         END
 247 
 248         echo ". $runname \"\$@\"" >>$filename || exit 1
 249 
 250         chmod $mode $filename
 251         chown $own $filename
 252 }
 253 
 254 #
 255 # Read zonecfg fs entries and save the relevant data, one entry per
 256 # line.
 257 # This assumes the properties from the zonecfg output, e.g.:
 258 #       fs:
 259 #               dir: /opt
 260 #               special: /opt
 261 #               raw not specified
 262 #               type: lofs
 263 #               options: [noexec,ro,noatime]
 264 #
 265 # and it assumes the order of the fs properties as above.
 266 #
 267 get_fs_info()
 268 {
 269         zonecfg -z $zonename info fs | nawk '{
 270                 if ($1 == "options:") {
 271                         # Remove brackets.
 272                         options=substr($2, 2, length($2) - 2);
 273                         printf("%s %s %s %s\n", dir, type, special, options);
 274                 } else if ($1 == "dir:") {
 275                         dir=$2;
 276                 } else if ($1 == "special:") {
 277                         special=$2;
 278                 } else if ($1 == "type:") {
 279                         type=$2
 280                 }
 281         }' >> $fstmpfile
 282 }
 283 
 284 #
 285 # Mount zonecfg fs entries into the zonepath.
 286 #
 287 mnt_fs()
 288 {
 289         if [ ! -s $fstmpfile ]; then
 290                 return;
 291         fi
 292 
 293         # Sort the fs entries so we can handle nested mounts.
 294         sort $fstmpfile | nawk -v zonepath=$zonepath '{
 295                 if (NF == 4)
 296                         options="-o " $4;
 297                 else
 298                         options=""
 299 
 300                 # Create the mount point.  Ignore errors since we might have
 301                 # a nested mount with a pre-existing mount point.
 302                 cmd="/usr/bin/mkdir -p " zonepath "/root" $1 " >/dev/null 2>&1"
 303                 system(cmd);
 304 
 305                 cmd="/usr/sbin/mount -F " $2 " " options " " $3 " " \
 306                     zonepath "/root" $1;
 307                 if (system(cmd) != 0) {
 308                         printf("command failed: %s\n", cmd);
 309                         exit 1;
 310                 }
 311         }' >>$LOGFILE
 312 }
 313 
 314 #
 315 # Unmount zonecfg fs entries from the zonepath.
 316 #
 317 umnt_fs()
 318 {
 319         if [ ! -s $fstmpfile ]; then
 320                 return;
 321         fi
 322 
 323         # Reverse sort the fs entries so we can handle nested unmounts.
 324         sort -r $fstmpfile | nawk -v zonepath=$zonepath '{
 325                 cmd="/usr/sbin/umount " zonepath "/root" $1
 326                 if (system(cmd) != 0) {
 327                         printf("command failed: %s\n", cmd);
 328                 }
 329         }' >>$LOGFILE
 330 }
 331 
 332 # Find the dataset mounted on the zonepath.
 333 get_zonepath_ds() {
 334         ZONEPATH_DS=`/usr/sbin/zfs list -H -t filesystem -o name,mountpoint | \
 335             /usr/bin/nawk -v zonepath=$1 '{
 336                 if ($2 == zonepath)
 337                         print $1
 338         }'`
 339 
 340         if [ -z "$ZONEPATH_DS" ]; then
 341                 fail_fatal "$f_no_ds"
 342         fi
 343 }
 344 
 345 #
 346 # Perform validation and cleanup in the zoneroot after unpacking the archive.
 347 #
 348 post_unpack()
 349 {
 350         #
 351         # Check if the image was created with a valid libc.so.1.
 352         #
 353         if [[ -f $ZONEROOT/lib/libc.so.1 ]]; then
 354                 hwcap=`moe -v -32 $ZONEROOT/lib/libc.so.1 2>&1`
 355                 if (( $? != 0 )); then
 356                         vlog "$f_hwcap_info" "$hwcap"
 357                         fail_fatal "$f_sanity_hwcap"
 358                 fi
 359         fi
 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 #
 368 get_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 #
 379 get_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 #
 399 install_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 $fspaxfile ]]; then
 505                         archiver_arguments="-r -p e -c \
 506                             $(/usr/bin/cat $fspaxfile)"
 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 $fscpiofile"
 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 #
 583 get_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 #
 655 install_cpio()
 656 {
 657         stage1=$1
 658         archive=$2
 659 
 660         get_archive_base "$stage1" "$archive" "cpio -it"
 661 
 662         cpioopts="-idmfE $fscpiofile"
 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 #
 678 install_pax()
 679 {
 680         archive=$1
 681 
 682         get_archive_base "cat" "$archive" "pax"
 683 
 684         if [[ -s $fspaxfile ]]; then
 685                 filtopt="-c $(/usr/bin/cat $fspaxfile)"
 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 #
 702 install_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         #
 712         ( cd "$ZONEROOT" && ufsrestore rf "$archive" < /dev/null )
 713         result=$?
 714 
 715         post_unpack
 716 
 717         return $result
 718 }
 719 
 720 #
 721 # Copy directory hierarchy into zoneroot.
 722 #
 723 install_dir()
 724 {
 725         source_dir=$1
 726 
 727         cpioopts="-pdm"
 728 
 729         first=1
 730         filt=$(for i in $(cat $fspaxfile)
 731                 do
 732                         echo $i | egrep -s "/" && continue
 733                         if [[ $first == 1 ]]; then
 734                                 printf "^%s" $i
 735                                 first=0
 736                         else
 737                                 printf "|^%s" $i
 738                         fi
 739                 done)
 740 
 741         list=$(cd "$source_dir" && ls -d * | egrep -v "$filt")
 742         flist=$(for i in $list
 743         do
 744                 printf "%s " "$i"
 745         done)
 746         findopts="-xdev ( -type d -o -type f -o -type l ) -print"
 747 
 748         vlog "cd \"$source_dir\" && find $flist $findopts | "
 749         vlog "cpio $cpioopts \"$ZONEROOT\""
 750 
 751         # Ignore errors from cpio since we expect some errors depending on
 752         # how the archive was made.
 753         ( cd "$source_dir" && find $flist $findopts | \
 754             cpio $cpioopts "$ZONEROOT" )
 755 
 756         post_unpack
 757 
 758         return 0
 759 }
 760 
 761 #
 762 # This is a common function for laying down a zone image from a variety of
 763 # different sources.  This can be used to either install a fresh zone or as
 764 # part of zone migration during attach.
 765 #
 766 # The first argument specifies the type of image: archive, directory or stdin.
 767 # The second argument specifies the image itself.  In the case of stdin, the
 768 # second argument specifies the format of the stream (cpio, flar, etc.).
 769 # Any validation or post-processing on the image is done elsewhere.
 770 #
 771 # This function calls a 'sanity_check' function which must be provided by
 772 # the script which includes this code.
 773 #
 774 install_image()
 775 {
 776         intype=$1
 777         insrc=$2
 778 
 779         if [[ -z "$intype" || -z "$insrc" ]]; then
 780                 return 1
 781         fi
 782 
 783         filetype="unknown"
 784         filetypename="unknown"
 785         stage1="cat"
 786 
 787         if [[ "$intype" == "directory" ]]; then
 788                 if [[ "$insrc" == "-" ]]; then
 789                         # Indicates that the existing zonepath is prepopulated.
 790                         filetype="existing"
 791                         filetypename="existing"
 792                 else
 793                         if [[ "$(echo $insrc | cut -c 1)" != "/" ]]; then
 794                                 fatal "$e_path_abs" "$insrc"
 795                         fi
 796 
 797                         if [[ ! -e "$insrc" ]]; then
 798                                 log "$e_not_found" "$insrc"
 799                                 fatal "$e_install_abort"
 800                         fi
 801 
 802                         if [[ ! -r "$insrc" ]]; then
 803                                 log "$e_not_readable" "$insrc"
 804                                 fatal "$e_install_abort"
 805                         fi
 806 
 807                         if [[ ! -d "$insrc" ]]; then
 808                                 log "$e_not_dir"
 809                                 fatal "$e_install_abort"
 810                         fi
 811 
 812                         sanity_check $insrc
 813 
 814                         filetype="directory"
 815                         filetypename="directory"
 816                 fi
 817 
 818         else
 819                 # Common code for both archive and stdin stream.
 820 
 821                 if [[ "$intype" == "archive" ]]; then
 822                         if [[ ! -f "$insrc" ]]; then
 823                                 log "$e_unknown_archive"
 824                                 fatal "$e_install_abort"
 825                         fi
 826                         ftype="$(LC_ALL=C file $insrc | cut -d: -f 2)"
 827                 else
 828                         # For intype == stdin, the insrc parameter specifies
 829                         # the stream format coming on stdin.
 830                         ftype="$insrc"
 831                         insrc="-"
 832                 fi
 833 
 834                 # Setup vars for the archive type we have.
 835                 case "$ftype" in
 836                 *cpio*)         filetype="cpio"
 837                                 filetypename="cpio archive"
 838                         ;;
 839                 *bzip2*)        filetype="bzip2"
 840                                 filetypename="bzipped cpio archive"
 841                         ;;
 842                 *gzip*)         filetype="gzip"
 843                                 filetypename="gzipped cpio archive"
 844                         ;;
 845                 *ufsdump*)      filetype="ufsdump"
 846                                 filetypename="ufsdump archive"
 847                         ;;
 848                 "flar")
 849                                 filetype="flar"
 850                                 filetypename="flash archive"
 851                         ;;
 852                 "flash")
 853                                 filetype="flar"
 854                                 filetypename="flash archive"
 855                         ;;
 856                 *Flash\ Archive*)
 857                                 filetype="flar"
 858                                 filetypename="flash archive"
 859                         ;;
 860                 "tar")
 861                                 filetype="tar"
 862                                 filetypename="tar archive"
 863                         ;;
 864                 *USTAR\ tar\ archive)
 865                                 filetype="tar"
 866                                 filetypename="tar archive"
 867                         ;;
 868                 "pax")
 869                                 filetype="xustar"
 870                                 filetypename="pax (xustar) archive"
 871                         ;;
 872                 *USTAR\ tar\ archive\ extended\ format*)
 873                                 filetype="xustar"
 874                                 filetypename="pax (xustar) archive"
 875                         ;;
 876                 "zfs")
 877                                 filetype="zfs"
 878                                 filetypename="ZFS send stream"
 879                         ;;
 880                 *ZFS\ snapshot\ stream*)
 881                                 filetype="zfs"
 882                                 filetypename="ZFS send stream"
 883                         ;;
 884                 *)              log "$e_unknown_archive"
 885                                 fatal "$e_install_abort"
 886                         ;;
 887                 esac
 888         fi
 889 
 890         vlog "$filetypename"
 891 
 892         # Check for a non-empty root if no '-d -' option. 
 893         if [[ "$filetype" != "existing" ]]; then
 894                 cnt=$(ls $ZONEROOT | wc -l)
 895                 if (( $cnt != 0 )); then
 896                         fatal "$e_root_full" "$ZONEROOT"
 897                 fi
 898         fi
 899 
 900         fstmpfile=$(/usr/bin/mktemp -t -p /var/tmp)
 901         if [[ -z "$fstmpfile" ]]; then
 902                 fatal "$e_tmpfile"
 903         fi
 904 
 905         # Make sure we always have the files holding the directories to filter
 906         # out when extracting from a CPIO or PAX archive.  We'll add the fs
 907         # entries to these files in get_fs_info()
 908         fscpiofile=$(/usr/bin/mktemp -t -p /var/tmp fs.cpio.XXXXXX)
 909         if [[ -z "$fscpiofile" ]]; then
 910                 rm -f $fstmpfile
 911                 fatal "$e_tmpfile"
 912         fi
 913 
 914         # Filter out these directories.
 915         echo 'dev/*' >>$fscpiofile
 916         echo 'devices/*' >>$fscpiofile
 917         echo 'devices' >>$fscpiofile
 918         echo 'proc/*' >>$fscpiofile
 919         echo 'tmp/*' >>$fscpiofile
 920         echo 'var/run/*' >>$fscpiofile
 921         echo 'system/contract/*' >>$fscpiofile
 922         echo 'system/object/*' >>$fscpiofile
 923 
 924         fspaxfile=$(/usr/bin/mktemp -t -p /var/tmp fs.pax.XXXXXX)
 925         if [[ -z "$fspaxfile" ]]; then
 926                 rm -f $fstmpfile $fscpiofile
 927                 fatal "$e_tmpfile"
 928         fi
 929 
 930         printf "%s " \
 931             "dev devices proc tmp var/run system/contract system/object" \
 932             >>$fspaxfile
 933 
 934         # Set up any fs mounts so the archive will install into the correct
 935         # locations.
 936         get_fs_info
 937         mnt_fs
 938         if (( $? != 0 )); then
 939                 umnt_fs >/dev/null 2>&1
 940                 rm -f $fstmpfile $fscpiofile $fspaxfile
 941                 fatal "$mount_failed"
 942         fi
 943 
 944         if [[ "$filetype" == "existing" ]]; then
 945                 log "$no_installing"
 946         else
 947                 log "$installing"
 948         fi
 949 
 950         #
 951         # Install the image into the zonepath.
 952         #
 953         unpack_result=0
 954         stage1="cat"
 955         if [[ "$filetype" == "gzip" ]]; then
 956                 stage1="gzcat"
 957                 filetype="cpio"
 958         elif [[ "$filetype" == "bzip2" ]]; then
 959                 stage1="bzcat"
 960                 filetype="cpio"
 961         fi
 962 
 963         if [[ "$filetype" == "cpio" ]]; then
 964                 install_cpio "$stage1" "$insrc"
 965                 unpack_result=$?
 966 
 967         elif [[ "$filetype" == "flar" ]]; then
 968                 ( cd "$ZONEROOT" && $stage1 $insrc | install_flar )
 969                 unpack_result=$?
 970 
 971         elif [[ "$filetype" == "xustar" ]]; then
 972                 install_pax "$insrc"
 973                 unpack_result=$?
 974 
 975         elif [[ "$filetype" = "tar" ]]; then
 976                 vlog "cd \"$ZONEROOT\" && tar -xf \"$insrc\""
 977                 # Ignore errors from tar since we expect some errors depending
 978                 # on how the archive was made.
 979                 ( cd "$ZONEROOT" && tar -xf "$insrc" )
 980                 unpack_result=0
 981                 post_unpack
 982 
 983         elif [[ "$filetype" == "ufsdump" ]]; then
 984                 install_ufsdump "$insrc"
 985                 unpack_result=$?
 986 
 987         elif [[ "$filetype" == "directory" ]]; then
 988                 install_dir "$insrc"
 989                 unpack_result=$?
 990 
 991         elif [[ "$filetype" == "zfs" ]]; then
 992                 #
 993                 # Given a 'zfs send' stream file, receive the snapshot into
 994                 # the zone's dataset.  We're getting the original system's
 995                 # zonepath dataset.  Destroy the existing dataset created
 996                 # above since this recreates it.
 997                 #
 998                 if [[ -z "$DATASET" ]]; then
 999                         fatal "$f_nodataset"
1000                 fi
1001                 /usr/sbin/zfs destroy "$DATASET"
1002                 if (( $? != 0 )); then
1003                         log "$f_zfsdestroy" "$DATASET"
1004                 fi
1005 
1006                 vlog "$stage1 $insrc | zfs receive -F $DATASET"
1007                 ( $stage1 $insrc | /usr/sbin/zfs receive -F $DATASET )
1008                 unpack_result=$?
1009         fi
1010 
1011         # Clean up any fs mounts used during unpacking.
1012         umnt_fs
1013         rm -f $fstmpfile $fscpiofile $fspaxfile
1014 
1015         chmod 700 $zonepath
1016 
1017         (( $unpack_result != 0 )) && fatal "$f_unpack_failed"
1018 
1019         # Verify this is a valid image.
1020         sanity_check $ZONEROOT
1021 
1022         return 0
1023 }
1024 
1025 e_cannot_wrap="%s: error: wrapper file already exists"
1026 e_baddir="Invalid '%s' directory within the zone"
1027 e_badfile="Invalid '%s' file within the zone"
1028 e_path_abs="Pathname specified to -a '%s' must be absolute."
1029 e_not_found="%s: error: file or directory not found."
1030 e_install_abort="Installation aborted."
1031 e_not_readable="Cannot read directory '%s'"
1032 e_not_dir="Error: must be a directory"
1033 e_unknown_archive="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."
1034 e_absolute_archive="Error: archive contains absolute paths instead of relative paths."
1035 e_mismatch_archive="Error: the archive top-level directory (%s) does not match the zonepath (%s)."
1036 e_tmpfile="Unable to create temporary file"
1037 e_root_full="Zonepath root %s exists and contains data; remove or move aside prior to install."
1038 f_mkdir="Unable to create directory %s."
1039 f_chmod="Unable to chmod directory %s."
1040 f_chown="Unable to chown directory %s."
1041 f_hwcap_info="HWCAP: %s\n"
1042 f_sanity_hwcap="The image was created with an incompatible libc.so.1 hwcap lofs mount.\n"\
1043 "       The zone will not boot on this platform.  See the zone's\n"\
1044 "       documentation for the recommended way to create the archive."
1045 
1046 m_analyse_archive="Analysing the archive"
1047 
1048 not_readable="Cannot read file '%s'"
1049 not_flar="Input is not a flash archive"
1050 bad_flar="Flash archive is a corrupt"
1051 bad_zfs_flar="Flash archive contains a ZFS send stream.\n\tRecreate the flar using the -L option with cpio or pax."
1052 f_unpack_failed="Unpacking the archive failed"
1053 unknown_archiver="Archiver %s is not supported"
1054 cmd_not_exec="Required command '%s' not executable!"
1055 
1056 #
1057 # Exit values used by the script, as #defined in <sys/zone.h>
1058 #
1059 #       ZONE_SUBPROC_OK
1060 #       ===============
1061 #       Installation was successful
1062 #
1063 #       ZONE_SUBPROC_USAGE
1064 #       ==================
1065 #       Improper arguments were passed, so print a usage message before exiting
1066 #
1067 #       ZONE_SUBPROC_NOTCOMPLETE
1068 #       ========================
1069 #       Installation did not complete, but another installation attempt can be
1070 #       made without an uninstall
1071 #
1072 #       ZONE_SUBPROC_FATAL
1073 #       ==================
1074 #       Installation failed and an uninstall will be required before another
1075 #       install can be attempted
1076 #
1077 ZONE_SUBPROC_OK=0
1078 ZONE_SUBPROC_USAGE=253
1079 ZONE_SUBPROC_NOTCOMPLETE=254
1080 ZONE_SUBPROC_FATAL=255
1081