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