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