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