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