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 hwcap=`moe -v -32 $ZONEROOT/lib/libc.so.1 2>&1`
354 if (( $? != 0 )); then
355 vlog "$f_hwcap_info" "$hwcap"
356 fail_fatal "$f_sanity_hwcap"
357 fi
358
359 ( cd "$ZONEROOT" && \
360 find . \( -type b -o -type c \) -exec rm -f "{}" \; )
361 }
362
363 #
364 # Determine flar compression style from identification file.
365 #
366 get_compression()
367 {
368 typeset ident=$1
369 typeset line=$(grep "^files_compressed_method=" $ident)
370
371 print ${line##*=}
372 }
373
374 #
375 # Determine flar archive style from identification file.
376 #
377 get_archiver()
378 {
379 typeset ident=$1
380 typeset line=$(grep "^files_archived_method=" $ident)
381
382 print ${line##*=}
383 }
384
385 #
386 # Unpack flar into current directory (which should be zoneroot). The flash
387 # archive is standard input. See flash_archive(4) man page.
388 #
389 # We can't use "flar split" since it will only unpack into a directory called
390 # "archive". We need to unpack in place in order to properly handle nested
391 # fs mounts within the zone root. This function does the unpacking into the
392 # current directory.
393 #
394 # This code is derived from the gen_split() function in /usr/sbin/flar so
395 # we keep the same style as the original.
396 #
397 install_flar()
398 {
399 typeset result
400 typeset archiver_command
401 typeset archiver_arguments
402
403 vlog "cd $ZONEROOT && $stage1 "$insrc" | install_flar"
404
405 # Read cookie
406 read -r input_line
407 if (( $? != 0 )); then
408 log "$not_readable" "$install_media"
409 return 1
410 fi
411 # The cookie has format FlAsH-aRcHiVe-m.n where m and n are integers.
412 if [[ ${input_line%%-[0-9]*.[0-9]*} != "FlAsH-aRcHiVe" ]]; then
413 log "$not_flar"
414 return 1
415 fi
416
417 while [ true ]
418 do
419 # We should always be at the start of a section here
420 read -r input_line
421 if [[ ${input_line%%=*} != "section_begin" ]]; then
422 log "$bad_flar"
423 return 1
424 fi
425 section_name=${input_line##*=}
426
427 # If we're at the archive, we're done skipping sections.
428 if [[ "$section_name" == "archive" ]]; then
429 break
430 fi
431
432 #
433 # Save identification section to a file so we can determine
434 # how to unpack the archive.
435 #
436 if [[ "$section_name" == "identification" ]]; then
437 /usr/bin/rm -f identification
438 while read -r input_line
439 do
440 if [[ ${input_line%%=*} == \
441 "section_begin" ]]; then
442 /usr/bin/rm -f identification
443 log "$bad_flar"
444 return 1
445 fi
446
447 if [[ $input_line == \
448 "section_end=$section_name" ]]; then
449 break;
450 fi
451 echo $input_line >> identification
452 done
453
454 continue
455 fi
456
457 #
458 # Otherwise skip past this section; read lines until detecting
459 # section_end. According to flash_archive(4) we can have
460 # an arbitrary number of sections but the archive section
461 # must be last.
462 #
463 success=0
464 while read -r input_line
465 do
466 if [[ $input_line == "section_end=$section_name" ]];
467 then
468 success=1
469 break
470 fi
471 # Fail if we miss the end of the section
472 if [[ ${input_line%%=*} == "section_begin" ]]; then
473 /usr/bin/rm -f identification
474 log "$bad_flar"
475 return 1
476 fi
477 done
478 if (( $success == 0 )); then
479 #
480 # If we get here we read to the end of the file before
481 # seeing the end of the section we were reading.
482 #
483 /usr/bin/rm -f identification
484 log "$bad_flar"
485 return 1
486 fi
487 done
488
489 # Check for an archive made from a ZFS root pool.
490 egrep -s "^rootpool=" identification
491 if (( $? == 0 )); then
492 /usr/bin/rm -f identification
493 log "$bad_zfs_flar"
494 return 1
495 fi
496
497 # Get the information needed to unpack the archive.
498 archiver=$(get_archiver identification)
499 if [[ $archiver == "pax" ]]; then
500 # pax archiver specified
501 archiver_command="/usr/bin/pax"
502 if [[ -s $fspaxfile ]]; then
503 archiver_arguments="-r -p e -c \
504 $(/usr/bin/cat $fspaxfile)"
505 else
506 archiver_arguments="-r -p e"
507 fi
508 elif [[ $archiver == "cpio" || -z $archiver ]]; then
509 # cpio archived specified OR no archiver specified - use default
510 archiver_command="/usr/bin/cpio"
511 archiver_arguments="-icdumfE $fscpiofile"
512 else
513 # unknown archiver specified
514 log "$unknown_archiver" $archiver
515 return 1
516 fi
517
518 if [[ ! -x $archiver_command ]]; then
519 /usr/bin/rm -f identification
520 log "$cmd_not_exec" $archiver_command
521 return 1
522 fi
523
524 compression=$(get_compression identification)
525
526 # We're done with the identification file
527 /usr/bin/rm -f identification
528
529 # Extract archive
530 if [[ $compression == "compress" ]]; then
531 /usr/bin/zcat | \
532 $archiver_command $archiver_arguments 2>/dev/null
533 else
534 $archiver_command $archiver_arguments 2>/dev/null
535 fi
536 result=$?
537
538 post_unpack
539
540 (( $result != 0 )) && return 1
541
542 return 0
543 }
544
545 #
546 # Get the archive base.
547 #
548 # We must unpack the archive in the right place within the zonepath so
549 # that files are installed into the various mounted filesystems that are set
550 # up in the zone's configuration. These are already mounted for us by the
551 # mntfs function.
552 #
553 # Archives can be made of either a physical host's root file system or a
554 # zone's zonepath. For a physical system, if the archive is made using an
555 # absolute path (/...) we can't use it. For a zone the admin can make the
556 # archive from a variety of locations;
557 #
558 # a) zonepath itself: This will be a single dir, probably named with the
559 # zone name, it will contain a root dir and under the root we'll see all
560 # the top level dirs; etc, var, usr... We must be above the ZONEPATH
561 # when we unpack the archive but this will only work if the the archive's
562 # top-level dir name matches the ZONEPATH base-level dir name. If not,
563 # this is an error.
564 #
565 # b) inside the zonepath: We'll see root and it will contain all the top
566 # level dirs; etc, var, usr.... We must be in the ZONEPATH when we unpack
567 # the archive.
568 #
569 # c) inside the zonepath root: We'll see all the top level dirs, ./etc,
570 # ./var, ./usr.... This is also the case we see when we get an archive
571 # of a physical sytem. We must be in ZONEROOT when we unpack the archive.
572 #
573 # Note that there can be a directory named "root" under the ZONEPATH/root
574 # directory.
575 #
576 # This function handles the above possibilities so that we reject absolute
577 # path archives and figure out where in the file system we need to be to
578 # properly unpack the archive into the zone. It sets the ARCHIVE_BASE
579 # variable to the location where the achive should be unpacked.
580 #
581 get_archive_base()
582 {
583 stage1=$1
584 archive=$2
585 stage2=$3
586
587 vlog "$m_analyse_archive"
588
589 base=`$stage1 $archive | $stage2 2>/dev/null | nawk -F/ '{
590 # Check for an absolute path archive
591 if (substr($0, 1, 1) == "/")
592 exit 1
593
594 if ($1 != ".")
595 dirs[$1] = 1
596 else
597 dirs[$2] = 1
598 }
599 END {
600 for (d in dirs) {
601 cnt++
602 if (d == "bin") sawbin = 1
603 if (d == "etc") sawetc = 1
604 if (d == "root") sawroot = 1
605 if (d == "var") sawvar = 1
606 }
607
608 if (cnt == 1) {
609 # If only one top-level dir named root, we are in the
610 # zonepath, otherwise this must be an archive *of*
611 # the zonepath so print the top-level dir name.
612 if (sawroot)
613 print "*zonepath*"
614 else
615 for (d in dirs) print d
616 } else {
617 # We are either in the zonepath or in the zonepath/root
618 # (or at the top level of a full system archive which
619 # looks like the zonepath/root case). Figure out which
620 # one.
621 if (sawroot && !sawbin && !sawetc && !sawvar)
622 print "*zonepath*"
623 else
624 print "*zoneroot*"
625 }
626 }'`
627
628 if (( $? != 0 )); then
629 umnt_fs
630 fatal "$e_absolute_archive"
631 fi
632
633 if [[ "$base" == "*zoneroot*" ]]; then
634 ARCHIVE_BASE=$ZONEROOT
635 elif [[ "$base" == "*zonepath*" ]]; then
636 ARCHIVE_BASE=$ZONEPATH
637 else
638 # We need to be in the dir above the ZONEPATH but we need to
639 # validate that $base matches the final component of ZONEPATH.
640 bname=`basename $ZONEPATH`
641
642 if [[ "$bname" != "$base" ]]; then
643 umnt_fs
644 fatal "$e_mismatch_archive" "$base" "$bname"
645 fi
646 ARCHIVE_BASE=`dirname $ZONEPATH`
647 fi
648 }
649
650 #
651 # Unpack cpio archive into zoneroot.
652 #
653 install_cpio()
654 {
655 stage1=$1
656 archive=$2
657
658 get_archive_base "$stage1" "$archive" "cpio -it"
659
660 cpioopts="-idmfE $fscpiofile"
661
662 vlog "cd \"$ARCHIVE_BASE\" && $stage1 \"$archive\" | cpio $cpioopts"
663
664 # Ignore errors from cpio since we expect some errors depending on
665 # how the archive was made.
666 ( cd "$ARCHIVE_BASE" && $stage1 "$archive" | cpio $cpioopts )
667
668 post_unpack
669
670 return 0
671 }
672
673 #
674 # Unpack pax archive into zoneroot.
675 #
676 install_pax()
677 {
678 archive=$1
679
680 get_archive_base "cat" "$archive" "pax"
681
682 if [[ -s $fspaxfile ]]; then
683 filtopt="-c $(/usr/bin/cat $fspaxfile)"
684 fi
685
686 vlog "cd \"$ARCHIVE_BASE\" && pax -r -f \"$archive\" $filtopt"
687
688 # Ignore errors from pax since we expect some errors depending on
689 # how the archive was made.
690 ( cd "$ARCHIVE_BASE" && pax -r -f "$archive" $filtopt )
691
692 post_unpack
693
694 return 0
695 }
696
697 #
698 # Unpack UFS dump into zoneroot.
699 #
700 install_ufsdump()
701 {
702 archive=$1
703
704 vlog "cd \"$ZONEROOT\" && ufsrestore rf \"$archive\""
705
706 #
707 # ufsrestore goes interactive if you ^C it. To prevent that,
708 # we make sure its stdin is not a terminal.
709 #
710 ( cd "$ZONEROOT" && ufsrestore rf "$archive" < /dev/null )
711 result=$?
712
713 post_unpack
714
715 return $result
716 }
717
718 #
719 # Copy directory hierarchy into zoneroot.
720 #
721 install_dir()
722 {
723 source_dir=$1
724
725 cpioopts="-pdm"
726
727 first=1
728 filt=$(for i in $(cat $fspaxfile)
729 do
730 echo $i | egrep -s "/" && continue
731 if [[ $first == 1 ]]; then
732 printf "^%s" $i
733 first=0
734 else
735 printf "|^%s" $i
736 fi
737 done)
738
739 list=$(cd "$source_dir" && ls -d * | egrep -v "$filt")
740 flist=$(for i in $list
741 do
742 printf "%s " "$i"
743 done)
744 findopts="-xdev ( -type d -o -type f -o -type l ) -print"
745
746 vlog "cd \"$source_dir\" && find $flist $findopts | "
747 vlog "cpio $cpioopts \"$ZONEROOT\""
748
749 # Ignore errors from cpio since we expect some errors depending on
750 # how the archive was made.
751 ( cd "$source_dir" && find $flist $findopts | \
752 cpio $cpioopts "$ZONEROOT" )
753
754 post_unpack
755
756 return 0
757 }
758
759 #
760 # This is a common function for laying down a zone image from a variety of
761 # different sources. This can be used to either install a fresh zone or as
762 # part of zone migration during attach.
763 #
764 # The first argument specifies the type of image: archive, directory or stdin.
765 # The second argument specifies the image itself. In the case of stdin, the
766 # second argument specifies the format of the stream (cpio, flar, etc.).
767 # Any validation or post-processing on the image is done elsewhere.
768 #
769 # This function calls a 'sanity_check' function which must be provided by
770 # the script which includes this code.
771 #
772 install_image()
773 {
774 intype=$1
775 insrc=$2
776
777 if [[ -z "$intype" || -z "$insrc" ]]; then
778 return 1
779 fi
780
781 filetype="unknown"
782 filetypename="unknown"
783 stage1="cat"
784
785 if [[ "$intype" == "directory" ]]; then
786 if [[ "$insrc" == "-" ]]; then
787 # Indicates that the existing zonepath is prepopulated.
788 filetype="existing"
789 filetypename="existing"
790 else
791 if [[ "$(echo $insrc | cut -c 1)" != "/" ]]; then
792 fatal "$e_path_abs" "$insrc"
793 fi
794
795 if [[ ! -e "$insrc" ]]; then
796 log "$e_not_found" "$insrc"
797 fatal "$e_install_abort"
798 fi
799
800 if [[ ! -r "$insrc" ]]; then
801 log "$e_not_readable" "$insrc"
802 fatal "$e_install_abort"
803 fi
804
805 if [[ ! -d "$insrc" ]]; then
806 log "$e_not_dir"
807 fatal "$e_install_abort"
808 fi
809
810 sanity_check $insrc
811
812 filetype="directory"
813 filetypename="directory"
814 fi
815
816 else
817 # Common code for both archive and stdin stream.
818
819 if [[ "$intype" == "archive" ]]; then
820 if [[ ! -f "$insrc" ]]; then
821 log "$e_unknown_archive"
822 fatal "$e_install_abort"
823 fi
824 ftype="$(LC_ALL=C file $insrc | cut -d: -f 2)"
825 else
826 # For intype == stdin, the insrc parameter specifies
827 # the stream format coming on stdin.
828 ftype="$insrc"
829 insrc="-"
830 fi
831
832 # Setup vars for the archive type we have.
833 case "$ftype" in
834 *cpio*) filetype="cpio"
835 filetypename="cpio archive"
836 ;;
837 *bzip2*) filetype="bzip2"
838 filetypename="bzipped cpio archive"
839 ;;
840 *gzip*) filetype="gzip"
841 filetypename="gzipped cpio archive"
842 ;;
843 *ufsdump*) filetype="ufsdump"
844 filetypename="ufsdump archive"
845 ;;
846 "flar")
847 filetype="flar"
848 filetypename="flash archive"
849 ;;
850 "flash")
851 filetype="flar"
852 filetypename="flash archive"
853 ;;
854 *Flash\ Archive*)
855 filetype="flar"
856 filetypename="flash archive"
857 ;;
858 "tar")
859 filetype="tar"
860 filetypename="tar archive"
861 ;;
862 *USTAR\ tar\ archive)
863 filetype="tar"
864 filetypename="tar archive"
865 ;;
866 "pax")
867 filetype="xustar"
868 filetypename="pax (xustar) archive"
869 ;;
870 *USTAR\ tar\ archive\ extended\ format*)
871 filetype="xustar"
872 filetypename="pax (xustar) archive"
873 ;;
874 "zfs")
875 filetype="zfs"
876 filetypename="ZFS send stream"
877 ;;
878 *ZFS\ snapshot\ stream*)
879 filetype="zfs"
880 filetypename="ZFS send stream"
881 ;;
882 *) log "$e_unknown_archive"
883 fatal "$e_install_abort"
884 ;;
885 esac
886 fi
887
888 vlog "$filetypename"
889
890 # Check for a non-empty root if no '-d -' option.
891 if [[ "$filetype" != "existing" ]]; then
892 cnt=$(ls $ZONEROOT | wc -l)
893 if (( $cnt != 0 )); then
894 fatal "$e_root_full" "$ZONEROOT"
895 fi
896 fi
897
898 fstmpfile=$(/usr/bin/mktemp -t -p /var/tmp)
899 if [[ -z "$fstmpfile" ]]; then
900 fatal "$e_tmpfile"
901 fi
902
903 # Make sure we always have the files holding the directories to filter
904 # out when extracting from a CPIO or PAX archive. We'll add the fs
905 # entries to these files in get_fs_info()
906 fscpiofile=$(/usr/bin/mktemp -t -p /var/tmp fs.cpio.XXXXXX)
907 if [[ -z "$fscpiofile" ]]; then
908 rm -f $fstmpfile
909 fatal "$e_tmpfile"
910 fi
911
912 # Filter out these directories.
913 echo 'dev/*' >>$fscpiofile
914 echo 'devices/*' >>$fscpiofile
915 echo 'devices' >>$fscpiofile
916 echo 'proc/*' >>$fscpiofile
917 echo 'tmp/*' >>$fscpiofile
918 echo 'var/run/*' >>$fscpiofile
919 echo 'system/contract/*' >>$fscpiofile
920 echo 'system/object/*' >>$fscpiofile
921
922 fspaxfile=$(/usr/bin/mktemp -t -p /var/tmp fs.pax.XXXXXX)
923 if [[ -z "$fspaxfile" ]]; then
924 rm -f $fstmpfile $fscpiofile
925 fatal "$e_tmpfile"
926 fi
927
928 printf "%s " \
929 "dev devices proc tmp var/run system/contract system/object" \
930 >>$fspaxfile
931
932 # Set up any fs mounts so the archive will install into the correct
933 # locations.
934 get_fs_info
935 mnt_fs
936 if (( $? != 0 )); then
937 umnt_fs >/dev/null 2>&1
938 rm -f $fstmpfile $fscpiofile $fspaxfile
939 fatal "$mount_failed"
940 fi
941
942 if [[ "$filetype" == "existing" ]]; then
943 log "$no_installing"
944 else
945 log "$installing"
946 fi
947
948 #
949 # Install the image into the zonepath.
950 #
951 unpack_result=0
952 stage1="cat"
953 if [[ "$filetype" == "gzip" ]]; then
954 stage1="gzcat"
955 filetype="cpio"
956 elif [[ "$filetype" == "bzip2" ]]; then
957 stage1="bzcat"
958 filetype="cpio"
959 fi
960
961 if [[ "$filetype" == "cpio" ]]; then
962 install_cpio "$stage1" "$insrc"
963 unpack_result=$?
964
965 elif [[ "$filetype" == "flar" ]]; then
966 ( cd "$ZONEROOT" && $stage1 $insrc | install_flar )
967 unpack_result=$?
968
969 elif [[ "$filetype" == "xustar" ]]; then
970 install_pax "$insrc"
971 unpack_result=$?
972
973 elif [[ "$filetype" = "tar" ]]; then
974 vlog "cd \"$ZONEROOT\" && tar -xf \"$insrc\""
975 # Ignore errors from tar since we expect some errors depending
976 # on how the archive was made.
977 ( cd "$ZONEROOT" && tar -xf "$insrc" )
978 unpack_result=0
979 post_unpack
980
981 elif [[ "$filetype" == "ufsdump" ]]; then
982 install_ufsdump "$insrc"
983 unpack_result=$?
984
985 elif [[ "$filetype" == "directory" ]]; then
986 install_dir "$insrc"
987 unpack_result=$?
988
989 elif [[ "$filetype" == "zfs" ]]; then
990 #
991 # Given a 'zfs send' stream file, receive the snapshot into
992 # the zone's dataset. We're getting the original system's
993 # zonepath dataset. Destroy the existing dataset created
994 # above since this recreates it.
995 #
996 if [[ -z "$DATASET" ]]; then
997 fatal "$f_nodataset"
998 fi
999 /usr/sbin/zfs destroy "$DATASET"
1000 if (( $? != 0 )); then
1001 log "$f_zfsdestroy" "$DATASET"
1002 fi
1003
1004 vlog "$stage1 $insrc | zfs receive -F $DATASET"
1005 ( $stage1 $insrc | /usr/sbin/zfs receive -F $DATASET )
1006 unpack_result=$?
1007 fi
1008
1009 # Clean up any fs mounts used during unpacking.
1010 umnt_fs
1011 rm -f $fstmpfile $fscpiofile $fspaxfile
1012
1013 chmod 700 $zonepath
1014
1015 (( $unpack_result != 0 )) && fatal "$f_unpack_failed"
1016
1017 # Verify this is a valid image.
1018 sanity_check $ZONEROOT
1019
1020 return 0
1021 }
1022
1023 # Setup i18n output
1024 TEXTDOMAIN="SUNW_OST_OSCMD"
1025 export TEXTDOMAIN
1026
1027 e_cannot_wrap=$(gettext "%s: error: wrapper file already exists")
1028 e_baddir=$(gettext "Invalid '%s' directory within the zone")
1029 e_badfile=$(gettext "Invalid '%s' file within the zone")
1030 e_path_abs=$(gettext "Pathname specified to -a '%s' must be absolute.")
1031 e_not_found=$(gettext "%s: error: file or directory not found.")
1032 e_install_abort=$(gettext "Installation aborted.")
1033 e_not_readable=$(gettext "Cannot read directory '%s'")
1034 e_not_dir=$(gettext "Error: must be a directory")
1035 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.")
1036 e_absolute_archive=$(gettext "Error: archive contains absolute paths instead of relative paths.")
1037 e_mismatch_archive=$(gettext "Error: the archive top-level directory (%s) does not match the zonepath (%s).")
1038 e_tmpfile=$(gettext "Unable to create temporary file")
1039 e_root_full=$(gettext "Zonepath root %s exists and contains data; remove or move aside prior to install.")
1040 f_mkdir=$(gettext "Unable to create directory %s.")
1041 f_chmod=$(gettext "Unable to chmod directory %s.")
1042 f_chown=$(gettext "Unable to chown directory %s.")
1043 f_hwcap_info=$(gettext "HWCAP: %s\n")
1044 f_sanity_hwcap=$(gettext \
1045 "The image was created with an incompatible libc.so.1 hwcap lofs mount.\n"\
1046 " The zone will not boot on this platform. See the zone's\n"\
1047 " documentation for the recommended way to create the archive.")
1048
1049 m_analyse_archive=$(gettext "Analysing the archive")
1050
1051 not_readable=$(gettext "Cannot read file '%s'")
1052 not_flar=$(gettext "Input is not a flash archive")
1053 bad_flar=$(gettext "Flash archive is a corrupt")
1054 bad_zfs_flar=$(gettext "Flash archive contains a ZFS send stream.\n\tRecreate the flar using the -L option with cpio or pax.")
1055 f_unpack_failed=$(gettext "Unpacking the archive failed")
1056 unknown_archiver=$(gettext "Archiver %s is not supported")
1057 cmd_not_exec=$(gettext "Required command '%s' not executable!")
1058
1059 #
1060 # Exit values used by the script, as #defined in <sys/zone.h>
1061 #
1062 # ZONE_SUBPROC_OK
1063 # ===============
1064 # Installation was successful
1065 #
1066 # ZONE_SUBPROC_USAGE
1067 # ==================
1068 # Improper arguments were passed, so print a usage message before exiting
1069 #
1070 # ZONE_SUBPROC_NOTCOMPLETE
1071 # ========================
1072 # Installation did not complete, but another installation attempt can be
1073 # made without an uninstall
1074 #
1075 # ZONE_SUBPROC_FATAL
1076 # ==================
1077 # Installation failed and an uninstall will be required before another
1078 # install can be attempted
1079 #
1080 ZONE_SUBPROC_OK=0
1081 ZONE_SUBPROC_USAGE=253
1082 ZONE_SUBPROC_NOTCOMPLETE=254
1083 ZONE_SUBPROC_FATAL=255
1084