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