1 #!/bin/ksh -p
   2 #
   3 # CDDL HEADER START
   4 #
   5 # The contents of this file are subject to the terms of the
   6 # Common Development and Distribution License (the "License").
   7 # You may not use this file except in compliance with the License.
   8 #
   9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10 # or http://www.opensolaris.org/os/licensing.
  11 # See the License for the specific language governing permissions
  12 # and limitations under the License.
  13 #
  14 # When distributing Covered Code, include this CDDL HEADER in each
  15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16 # If applicable, add the following below this CDDL HEADER, with the
  17 # fields enclosed by brackets "[]" replaced with your own identifying
  18 # information: Portions Copyright [yyyy] [name of copyright owner]
  19 #
  20 # CDDL HEADER END
  21 #
  22 
  23 #
  24 # Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
  25 # Copyright (c) 2015, OmniTI Computer Consulting, Inc. All rights reserved.
  26 # Copyright 2018 Nexenta Systems, Inc. All rights reserved.
  27 #
  28 
  29 #
  30 # Resetting GZ_IMAGE to something besides slash allows for simplified
  31 # debugging of various global zone image configurations-- simply make
  32 # an image somewhere with the appropriate interesting parameters.
  33 #
  34 GZ_IMAGE=${GZ_IMAGE:-/}
  35 PKG_IMAGE=$GZ_IMAGE
  36 export PKG_IMAGE
  37 
  38 . /usr/lib/brand/ipkg/common.ksh
  39 
  40 f_a_obs=$(gettext "-a publisher=uri option is obsolete, use -P instead.")
  41 f_pkg5_missing=$(gettext "pkg(5) does not seem to be present on this system.\n")
  42 f_img=$(gettext "failed to create image\n")
  43 f_pkg=$(gettext "failed to install package\n")
  44 f_interrupted=$(gettext "Installation cancelled due to interrupt.\n")
  45 f_bad_publisher=$(gettext "Syntax error in publisher information.")
  46 f_no_entire_in_pref=$(gettext "Unable to locate the incorporation '%s' in the preferred publisher '%s'.\nUse -P to supply a publisher which contains this package.\n")
  47 
  48 m_publisher=$(gettext   "   Publisher: Using %s (%s).")
  49 m_cache=$(gettext       "       Cache: Using %s.")
  50 m_image=$(gettext       "       Image: Preparing at %s.")
  51 m_incorp=$(gettext      "Sanity Check: Looking for 'entire' incorporation.")
  52 m_core=$(gettext        "  Installing: Packages (output follows)")
  53 m_smf=$(gettext         " Postinstall: Copying SMF seed repository ...")
  54 m_mannote=$(gettext     "        Note: Man pages can be obtained by installing pkg:/system/manual")
  55 
  56 m_usage=$(gettext "\n        install [-h]\n        install [-c certificate_file] [-k key_file] [-P publisher=uri]\n                [-e extrapkg [...]]\n        install {-a archive|-d path} {-p|-u} [-s|-v]")
  57 
  58 m_done=$(gettext      " done.")
  59 
  60 trap_cleanup() {
  61         print "$f_interrupted"
  62         exit $int_code
  63 }
  64 
  65 int_code=$ZONE_SUBPROC_NOTCOMPLETE
  66 trap trap_cleanup INT
  67 
  68 extra_packages=""
  69 ZONENAME=""
  70 ZONEPATH=""
  71 pub_and_origins=""
  72 
  73 # Setup i18n output
  74 TEXTDOMAIN="SUNW_OST_OSCMD"
  75 export TEXTDOMAIN
  76 
  77 KEYDIR=/var/pkg/ssl
  78 PKG=/usr/bin/pkg
  79 
  80 #
  81 # Just in case.  This should probably be removed later.
  82 #
  83 [[ ! -x $PKG ]] && fail_incomplete "$f_pkg5_missing"
  84 
  85 certfile="None"
  86 keyfile="None"
  87 unset install_archive
  88 unset source_dir
  89 unset msg
  90 unset silent_mode
  91 unset verbose_mode
  92 
  93 while getopts "a:c:d:e:hk:P:pR:suvz:" opt; do
  94         case $opt in
  95                 a)      # We're expecting a path to an archive
  96                         if [[ ! -f $OPTARG ]]; then
  97                                 # If old style 'pub=uri' parameter then error.
  98                                 echo $OPTARG | egrep -s =
  99                                 if (( $? == 0 )); then
 100                                         fail_usage "$f_a_obs"
 101                                 fi
 102                         fi
 103                         install_archive="-a $OPTARG";;
 104                 c)      certfile="$OPTARG" ;;
 105                 d)      source_dir="-d $OPTARG";;
 106                 e)      extra_packages="$extra_packages $OPTARG" ;;
 107                 h)      fail_usage "";;
 108                 k)      keyfile="$OPTARG" ;;
 109                 P)      pub_and_origins="$OPTARG" ;;
 110                 p)      preserve_zone="-p";;
 111                 R)      ZONEPATH="$OPTARG" ;;
 112                 s)      silent_mode=1;;
 113                 u)      unconfig_zone="-u";;
 114                 v)      verbose_mode="-v";;
 115                 z)      ZONENAME="$OPTARG" ;;
 116                 *)      fail_usage "";;
 117         esac
 118 done
 119 shift $((OPTIND-1))
 120 
 121 if [[ -z $ZONEPATH || -z $ZONENAME ]]; then
 122         print -u2 "Brand error: No zone path or name"
 123         exit $ZONE_SUBPROC_USAGE
 124 fi
 125 
 126 # XXX shared/common script currently uses lower case zonename & zonepath
 127 zonename="$ZONENAME"
 128 zonepath="$ZONEPATH"
 129 
 130 is_brand_labeled
 131 brand_labeled=$?
 132 
 133 ZONEROOT=$ZONEPATH/root
 134 secinfo=""
 135 
 136 # An image install can't use both -a AND -d...
 137 [[ -n "$install_archive" && -n "$source_dir" ]] &&
 138     fail_usage "$f_incompat_options" "-a" "-d"
 139 
 140 # The install can't be both verbose AND silent...
 141 [[ -n $silent_mode && -n $verbose_mode ]] && \
 142     fail_usage "$f_incompat_options" "-s" "-v"
 143 
 144 # The install can't both preserve and unconfigure
 145 [[ -n $unconfig_zone && -n $preserve_zone ]] && \
 146     fail_usage "$f_incompat_options" "-u" "-p"
 147 
 148 # IPS options aren't allowed when installing from a system image.
 149 if [[ -n "$install_archive" || -n "$source_dir" ]]; then
 150         [[ -n $pub_and_origins ]] && fail_usage "$f_incompat_options" \
 151             "-a|-d" "-P"
 152         [[ -n "$extra_packages" ]] && \
 153             fail_usage "$f_incompat_options" "-a|-d" "-e"
 154         [[ "$certfile" != "None" ]] && \
 155             fail_usage "$f_incompat_options" "-a|-d" "-c"
 156         [[ "$keyfile" != "None" ]] && \
 157             fail_usage "$f_incompat_options" "-a|-d" "-k"
 158 fi
 159 
 160 # p2v options aren't allowed when installing from a repo.
 161 if [[ -z $install_archive && -z $source_dir ]]; then
 162         [[ -n $preserve_zone || -n $unconfig_zone ]] && \
 163                 fail_usage "$f_incompat_options" "default" "-p|-u"
 164 fi
 165 
 166 #
 167 # Look for the 'entire' incorporation's FMRI in the current image; due to users
 168 # doing weird machinations with their publishers, we strip off the publisher
 169 # from the FMRI if it is present.
 170 # It's ok to not find entire in the current image, since this means the user
 171 # can install pre-release development bits for testing purposes.
 172 entire_fmri=$(get_entire_incorp)
 173 
 174 #
 175 # If we found an "entire" incorporation in the current image, then
 176 # check to see if the user's choice of preferred publisher contains the
 177 # version of the 'entire' incorporation needed.  This helps us to prevent
 178 # mishaps in the event the user selected some weirdo publisher as their
 179 # preferred one, or passed a preferred pub on the command line which doesn't
 180 # have a suitable 'entire' in it.
 181 #
 182 if [[ -n $entire_fmri ]]; then
 183         # If we have a user-specified publisher and origin from -P, consult
 184         # only that one; otherwise any origin from the first publisher will do.
 185         list_origin=
 186         if [[ -n "$pub_and_origins" ]]; then
 187                 #
 188                 # Crack pub=url into two pieces.
 189                 #
 190                 echo $pub_and_origins | IFS="=" read publisher pub_origins
 191                 if [[ -z $publisher || -z $pub_origins ]]; then
 192                         fail_usage "$f_bad_publisher"
 193                 fi
 194                 list_origin="-g $pub_origins"
 195         else
 196                 $PKG publisher -HPn -F tsv | cut -f1 | read publisher
 197         fi
 198         printf "$m_incorp\n"
 199         LC_ALL=C $PKG list $list_origin -af pkg://$publisher/$entire_fmri \
 200                 > /dev/null 2>&1
 201         if [[ $? -ne 0 ]]; then
 202                 fail_fatal "$f_no_entire_in_pref" $entire_fmri $publisher
 203         fi
 204 fi
 205 
 206 #
 207 # Before installing the zone, set up ZFS dataset hierarchy for the zone root
 208 # dataset.
 209 #
 210 create_active_ds
 211 
 212 #
 213 # If we're installing from an image, branch off to that installer.
 214 #
 215 if [[ -n $install_archive || -n $source_dir ]]; then
 216         /usr/lib/brand/ipkg/image_install $ZONENAME $ZONEPATH \
 217             $install_archive $source_dir $verbose_mode $silent_mode \
 218             $unconfig_zone $preserve_zone
 219         ii_result=$?
 220 
 221         if (( $ii_result != 0 )); then
 222                 exit $ZONE_SUBPROC_NOTCOMPLETE
 223         fi
 224         exit $ZONE_SUBPROC_OK
 225 fi
 226 
 227 printf "$m_image\n" $ZONEROOT
 228 
 229 # If we have a publisher specified by -P, pass it to image-create and use no
 230 # other publishers. Otherwise, use all of the publishers from the GZ.
 231 if [[ -n $pub_and_origins ]]; then
 232         LC_ALL=C $PKG image-create --zone --full -p $pub_and_origins \
 233             $ZONEROOT || fail_incomplete "$f_img"
 234 else
 235         LC_ALL=C $PKG image-create --zone --full $ZONEROOT \
 236             || fail_incomplete "$f_img"
 237         LC_ALL=C $PKG -R $ZONEROOT copy-publishers-from $GZ_IMAGE \
 238             || fail_incomplete "$f_img"
 239 fi
 240 
 241 # Change the value of PKG_IMAGE so that future PKG operation will work
 242 # on the newly created zone rather than the global zone
 243 
 244 PKG_IMAGE="$ZONEROOT"
 245 export PKG_IMAGE
 246 
 247 LC_ALL=C $PKG publisher -Hn -F tsv | cut -f1,7 | while read pub url; do
 248         printf "$m_publisher\n" $pub $url
 249 done
 250 
 251 if [[ -f /var/pkg/pkg5.image && -d /var/pkg/publisher ]]; then
 252         PKG_CACHEROOT=/var/pkg/publisher
 253         export PKG_CACHEROOT
 254         printf "$m_cache\n" $PKG_CACHEROOT
 255 fi
 256 
 257 printf "$m_core\n"
 258 pkglist=""
 259 if [[ -n $entire_fmri ]]; then
 260         pkglist="$pkglist $entire_fmri"
 261 fi
 262 
 263 pkglist="$pkglist
 264         pkg:///SUNWcs
 265         pkg:///SUNWcsd
 266         pkg:///system/network
 267         pkg:///service/file-system/nfs
 268         pkg:///network/ipfilter
 269         pkg:///system/extended-system-utilities
 270         pkg:///compress/bzip2
 271         pkg:///compress/gzip
 272         pkg:///compress/zip
 273         pkg:///compress/unzip
 274         pkg:///package/pkg"
 275 
 276 #
 277 # Get some diagnostic tools, truss, dtrace, etc.
 278 #
 279 pkglist="$pkglist
 280         pkg:/developer/linker
 281         pkg:/developer/dtrace"
 282 
 283 #
 284 # Needed for 'whois', 'snoop' I think; also provides rup, rmt, rsh etc.
 285 #
 286 pkglist="$pkglist
 287         pkg:/service/network/network-clients
 288         pkg:/network/ftp"
 289 
 290 #
 291 # Get at least one sensible shell, vim, openssh.
 292 #
 293 pkglist="$pkglist
 294         pkg:///shell/bash
 295         pkg:///shell/zsh
 296         pkg:///editor/vim
 297         pkg:///network/openssh
 298         pkg:///network/openssh-server"
 299 
 300 #
 301 # Get some name services and DNS.
 302 #
 303 pkglist="$pkglist
 304         pkg:/system/network/nis
 305         pkg:/network/dns/bind
 306         pkg:/naming/ldap"
 307 
 308 #
 309 # Get nfs client and autofs; it's a pain not to have them.
 310 #
 311 pkglist="$pkglist
 312         pkg:/system/file-system/autofs
 313         pkg:/system/file-system/nfs"
 314 
 315 #
 316 # Get routing daemons.  They're required for useful exclusive stack zones.
 317 #
 318 pkglist="$pkglist
 319         pkg:/system/network/routing"
 320 
 321 #
 322 # Get packages for TX zones if appropriate.
 323 #
 324 (( $brand_labeled == 1 )) && pkglist="$pkglist pkg:/system/trusted/trusted-nonglobal"
 325 
 326 #
 327 # Get man(1) but not the man pages
 328 #
 329 pkglist="$pkglist
 330         pkg:/text/doctools"
 331 
 332 #
 333 # Add in any extra packages requested by the user.
 334 #
 335 pkglist="$pkglist $extra_packages"
 336 
 337 #
 338 # Do the install; we just refreshed after image-create, so skip that.  We
 339 # also skip indexing here, as that is also what the LiveCD does.
 340 #
 341 LC_ALL=C $PKG install --accept --no-index --no-refresh $pkglist || \
 342     pkg_err_check "$f_pkg"
 343 
 344 printf "\n$m_mannote\n"
 345 
 346 printf "$m_smf"
 347 PROFILEDIR=etc/svc/profile
 348 ln -s ns_files.xml $ZONEROOT/$PROFILEDIR/name_service.xml
 349 ln -s generic_limited_net.xml $ZONEROOT/$PROFILEDIR/generic.xml
 350 ln -s inetd_generic.xml $ZONEROOT/$PROFILEDIR/inetd_services.xml
 351 ln -s platform_none.xml $ZONEROOT/$PROFILEDIR/platform.xml
 352 
 353 # This was formerly done in i.manifest
 354 repfile=$ZONEROOT/etc/svc/repository.db
 355 cp $ZONEROOT/lib/svc/seed/nonglobal.db $repfile
 356 chmod 0600 $repfile
 357 chown root:sys $repfile
 358 
 359 printf "$m_done\n"
 360 
 361 # Clean up root as a role and jack if needed
 362 if grep "^root::::type=role;" $ZONEROOT/etc/user_attr >/dev/null 2>&1; then
 363         printf "$m_brokenness\n"
 364         #
 365         # Remove "jack" user.
 366         #
 367         print "/^jack:/d\nw" | ed -s $ZONEROOT/etc/passwd
 368         chmod u+w $ZONEROOT/etc/shadow
 369         print "/^jack:/d\nw" | ed -s $ZONEROOT/etc/shadow
 370         chmod u-w $ZONEROOT/etc/shadow
 371 
 372         #
 373         # Set root from a role back to... not a role.  Grr.
 374         #
 375         print "s/^root::::type=role;/root::::/\nw" |
 376             ed -s $ZONEROOT/etc/user_attr
 377 fi
 378 
 379 # If no password has been set, you'd have to log in with zlogin -S
 380 # This is obtuse and highly undesireable.  A blank password is much
 381 # better as it can only be used to zlogin the first time anyway
 382 # and if someone were to turn on ssh (with PermitRootLogin yes)
 383 # it would still prevent a remote login
 384 sed -i -e 's%^root::%root:$5$kr1VgdIt$OUiUAyZCDogH/uaxH71rMeQxvpDEY2yX.x0ZQRnmeb9:%' $ZONEROOT/etc/shadow
 385 
 386 #
 387 # Labeled zones need to be able to modify /etc/gconf files, when gnome
 388 # packages are installed in the zone.  Set up links in the zone to the
 389 # global zone files -- this will provide default versions from the global
 390 # zone, which can be modified by the zone, breaking the link.
 391 if (( $brand_labeled == 1 )); then
 392         cd /etc/gconf
 393         for i in $(find .); do
 394                 if [ ! -e $ZONEROOT/etc/gconf/$i ]; then
 395                         if [ -d $i ]; then
 396                                 mkdir $ZONEROOT/etc/gconf/$i
 397                         else
 398                                 ln -s /etc/gconf-global/$i \
 399                                     $ZONEROOT/etc/gconf/$i
 400                         fi
 401                 fi
 402         done
 403 fi
 404 
 405 printf "$m_complete\n\n" ${SECONDS}
 406 if (( $brand_labeled == 0 )); then
 407         printf "$m_postnote\n"
 408         printf "$m_postnote2\n"
 409 else
 410         # Umount the dataset on the root.
 411         umount $ZONEROOT || printf "$f_zfs_unmount" "$ZONEPATH/root"
 412 fi
 413 
 414 exit $ZONE_SUBPROC_OK