1 #!/bin/bash
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 2009 Sun Microsystems, Inc. All rights reserved.
25 # Use is subject to license terms.
26 #
27 # ident "%Z%%M% %I% %E% SMI"
28 #
29
30 #
31 # Known issue: if you clone an ipkg zone but choose a different locale
32 # from the cloned zone, the locale package may not be installed in the
33 # new zone.
34 #
35
36 ipkg_packages=""
37 #Old definition...
38 #ipkg_dash_o="SUNWftp SUNWrcmds SUNWsshd"
39 #New definition, note no FTP server, as it was obsoleted.
40 ipkg_dash_o="network-servers service/network/ssh"
41 def_ufs_zone_path=/export/home/zones
42 def_zfs_zone_path=/zones
43 # Source zone for ZFS cloning, empty means do not clone
44 clone_src=""
45 zone_base=""
46 zone_add_cfg=""
47 zone_ns=NONE
48 zone_blank=""
49 # Last index assigned
50 vnic_last=""
51 # Index for vnic auto name generation
52 vnic_auto=""
53 vnic_cnt=0
54 ip_type="none"
55 intf_cnt=0
56 wait_confirm=0
57 # Additional arguments for the
58 zone_inst_args=""
59 bar=\
60 "------------------------------------------------------------------------------"
61
62 usage () {
63 cmd=`basename $0`
64 cat <<-EOF
65 Usage: $cmd -z <zone_name> [options]
66
67 Options supported:
68 -B Create the zone with the specified brand
69 -C <zone> Create the new zone by cloning the specified zone.
70 -b Start with a blank zone config
71 -c <config> Add a line to the zone configuration
72 -e <pkgs> Comma separated list of packages to install (ipkg zone only)
73 -h Prints this usage message
74 -l <locale> Sets the locale for the zone (defaults to \$LANG)
75 -i <ifspec> Configure an ip-type shared interface (OBSOLETE)
76 -n Name service, one of NIS, DNS, NONE (default)
77 -o Open the zone up for testing *NOT SECURE*
78 -p <path> Base path for zones
79 -w Prompt for confirmation before installing zone
80 -v <vnspec> Create a VNIC on the specified device
81 -x <ifspec> Configure an ip-type exclusive interface
82
83 Specifying interfaces:
84 <ifspec> is a comma separated lists of assignments or keywords:
85 dev=<interface name, ex. e1000g1>
86 dhcp (-x only)
87 ip=<IP address>[/<mask>]
88 ipv6
89 ipv6=<IPv6 address>/<mask> (-i only)
90 name=<hostname> (-x only)
91 route=<default route ip> (-x only)
92 No whitespace is permitted between arguments.
93 Since both flags set ip-type, -i and -x are mutually exclusive.
94 The special value "VNIC" for dev uses the last vnic created via -v.
95 Keyword ipv6 automatically generates a link-local address.
96
97 Specifying VNICs:
98 <vnspec> is a comma separated lists of assignments:
99 name=<name, defaults to vnic#>
100 dev=<interface name, ex. e1000g1>
101 mac=<hardware address>
102 No whitespace is permitted between arguments.
103 MAC address is optional; by default, a random MAC is generated.
104 EOF
105 }
106
107 lindex () {
108 typeset -a arr=($1)
109 echo ${arr[$2]}
110 }
111
112 log_err () {
113 echo "ERROR: $*" >&2
114 }
115
116 log_warn () {
117 echo "WARNING: $*" >&2
118 }
119
120 new_interface () {
121 for setting in ${1//,/ }; do
122 case $setting in
123 dev=*)
124 intf_devs[$intf_cnt]=${setting/dev=/}
125 ;;
126 dhcp)
127 intf_ips[$intf_cnt]=DHCP
128 ;;
129 ip=*)
130 setting=${setting/ip=/}
131 intf_ips[$intf_cnt]=${setting%%/*}
132 if [[ "${setting%%/*}" != "${setting##*/}" ]]; \
133 then
134 intf_masks[$intf_cnt]=${setting##*/}
135 fi
136 ;;
137 ipv6=*)
138 intf_ipv6s[$intf_cnt]=${setting/ipv6=/}
139 ;;
140 ipv6)
141 #
142 # Set a special case for just the link-local
143 # address.
144 #
145 if [[ ${intf_ipv6s[$intf_cnt]} == "" ]]; then
146 intf_ipv6s[$intf_cnt]="-"
147 fi
148 ;;
149 name=*)
150 intf_names[$intf_cnt]=${setting/name=/}
151 ;;
152 route=*)
153 intf_routes[$intf_cnt]=${setting/route=/}
154 ;;
155 esac
156 done
157
158 #
159 # VNIC is a special case to use the last vnic configured via -v.
160 #
161 if [[ "${intf_devs[$intf_cnt]}" == "VNIC" ]]; then
162 if [[ -z "$vnic_last" ]]; then
163 log_err "for intf <$1>, dev=VNIC but no prior -v option"
164 exit 1
165 fi
166 intf_devs[$intf_cnt]=${vnic_names[$vnic_last]}
167 fi
168
169 #
170 # Name defaults to the zone name for the first interface.
171 #
172 if [[ $intf_cnt -eq 0 ]] && [[ "${intf_names[$intf_cnt]}" == "" ]]; then
173 intf_names[$intf_cnt]=$zone_name
174 fi
175
176 #
177 # If a name was specified, but no IP was given, try looking up the name.
178 #
179 if [[ "${intf_ips[$intf_cnt]}" == "" ]] && \
180 [[ "${intf_names[$intf_cnt]}" != "" ]] ; then
181 temp=`getent hosts ${intf_names[$intf_cnt]}`
182 if [[ $? -eq 0 ]] && [[ "$temp" != "" ]]; then
183 intf_ips[$intf_cnt]=`lindex "$temp" 0`
184 fi
185 fi
186
187 #
188 # Special case: if no device is supplied for the first interface,
189 # use the outgoing interface for the system's default route.
190 #
191 if [[ "${intf_devs[$intf_cnt]}" == "" ]]; then
192 if [[ $intf_cnt -eq 0 ]] && [[ "$ip_type" == "shared" ]]; then
193 temp=`route -n get default | grep interface`
194 temp=`lindex "$temp" 1`
195 intf_devs[0]=$temp
196 else
197 log_err "Interface <$1>: missing device"
198 exit 1
199 fi
200 fi
201 ((intf_cnt++))
202 }
203
204 new_vnic () {
205 for setting in ${1//,/ }; do
206 case $setting in
207 name=*)
208 vnic_names[$vnic_cnt]=${setting/name=/}
209 ;;
210 dev=*)
211 vnic_devs[$vnic_cnt]=${setting/dev=/}
212 ;;
213 mac=*)
214 vnic_macs[$vnic_cnt]=${setting/mac=/}
215 ;;
216 esac
217 done
218
219 # If no name was given for the VNIC, generate one automatically.
220 if [[ "${vnic_names[$vnic_cnt]}" == "" ]]; then
221 # Find the first available vnic# name
222 if [[ -z "$vnic_auto" ]]; then
223 vnic_auto=`dladm show-vnic | tail -1 | sed \
224 's/vnic\([0-9][0-9]*\).*$/\1/g'`
225 if [[ "$vnic_auto" == "" ]]; then
226 vnic_auto=0
227 else
228 ((vnic_auto++))
229 fi
230 fi
231 vnic_names[$vnic_cnt]=vnic$vnic_auto
232 ((vnic_auto++))
233 fi
234
235 if [[ "${vnic_devs[$vnic_cnt]}" == "" ]]; then
236 log_err "VNIC <$1>: missing device"
237 exit 1
238 fi
239
240 if [[ "${vnic_macs[$vnic_cnt]}" == "" ]]; then
241 vnic_macs[$vnic_cnt]=auto
242 fi
243
244 vnic_last=$vnic_cnt
245 ((vnic_cnt++))
246 }
247
248 #
249 # Enable or disable a service within the zone. This function sets the
250 # state and then checks to see if it worked, trying for up to 10 minutes
251 # to make the change stick.
252 #
253 # The first argument is the service, and the second is action, which can
254 # be either enable or disable.
255 #
256 change_zone_service () {
257 local service=$1
258 local action=$2
259 local i=0
260
261 case $action in
262 enable)
263 local good_state=online
264 ;;
265 disable)
266 local good_state=disabled
267 ;;
268 *)
269 log_err "invalid action for change_zone_service"
270 exit 1
271 ;;
272 esac
273
274 while [[ $i -lt 120 ]]; do
275 zlogin $zone_name svcadm $action $service > /dev/null 2>&1
276 zlogin $zone_name svcs $service 2>/dev/null | \
277 grep -w $good_state > /dev/null
278 if [[ $? -eq 0 ]]; then
279 break
280 fi
281 ((i++))
282 sleep 5
283 done
284 }
285
286 open_for_testing () {
287 echo " ** WARNING: Opening zone for rsh, ssh, and ftp as root."
288 echo " This may take a few minutes."
289 local temp_file=/tmp/open_for_testing.$$
290 local zone_root=$zone_base/$zone_name/root
291 cat $zone_root/etc/default/login | sed "s/^CONSOLE/#CONSOLE/" > \
292 $temp_file
293 cp $temp_file $zone_root/etc/default/login
294 cat $zone_root/etc/ftpd/ftpusers | sed "s/^root/#root/" > \
295 $temp_file
296 cp $temp_file $zone_root/etc/ftpd/ftpusers
297 cat $zone_root/etc/ssh/sshd_config | \
298 sed "s/^PermitRootLogin no/PermitRootLogin yes/" > \
299 $temp_file
300 cp $temp_file $zone_root/etc/ssh/sshd_config
301 # Assumes ~root is the same frament in global and created zone.
302 local rhosts_file=~root/.rhosts
303 echo "+ +" > ${zone_root}${rhosts_file}
304 rm -f $temp_file
305
306 change_zone_service svc:/network/login:rlogin enable
307 }
308
309 #
310 # Two arguments, index of the interface and the file to write to.
311 # Uses global interface arrays, ip_type and zone_name.
312 #
313 ip_into_rc3 () {
314 local idx=$1
315 local filename=$2
316
317 if [[ "${intf_ips[$idx]}" == "DHCP" ]]; then
318 echo "ipadm create-addr -T dhcp ${intf_devs[$idx]}/v4"
319 else
320 if [[ "${intf_names[$idx]}" != "" && ${intf_ips[$idx]} != "" ]]; then
321 echo "echo '${intf_ips[$idx]} ${intf_names[$idx]}' >> /etc/hosts" \
322 >> $filename
323 fi
324 mask=24
325 if [[ "${intf_masks[$idx]}" != "" ]]; then
326 mask=${intf_masks[$idx]}
327 fi
328 echo "ipadm create-addr -T static -a local=${intf_ips[$idx]}/$mask" \
329 " ${intf_devs[$idx]}/v4" >> $filename
330 if [[ "${intf_routes[$idx]}" != "" ]]; then
331 #echo " default_route=${intf_routes[$idx]}" >> $filename
332 echo "route add -p default $intf_routes[$idx]" >> $filename
333 fi
334 fi
335 }
336
337 expand_mask () {
338 local mask=$((0xffffffff << (32 - $1)))
339 printf "%u.%u.%u.%u\n" $((($mask >> 24) & 0xff)) \
340 $((($mask >> 16) & 0xff)) \
341 $((($mask >> 8) & 0xff)) \
342 $(($mask & 0xff))
343 }
344
345 #
346 # Two arguments, index of the interface and the file to write to.
347 # Uses global interface arrays and ip_type.
348 #
349 #ipv6_into_syscfg () {
350 ipv6_into_rc3 () {
351 local idx=$1
352 local filename=$2
353
354 if [[ "${intf_ipv6s[$idx]}" != "" ]]; then
355 echo "ipadm create-addr -T addrconf -p stateless=yes "\
356 "${intf_devs[$idx]}/v6" >> $filename
357 fi
358 }
359
360 get_nfsmapid_domain () {
361 local temp=""
362
363 if [[ -f /etc/default/nfs ]]; then
364 temp=`grep NFSMAPID_DOMAIN /etc/default/nfs | grep -v "#"`
365 temp=${temp##*NFSMAPID_DOMAIN=}
366 if [[ ! -z "$temp" ]]; then
367 echo $temp
368 return
369 fi
370 fi
371 echo "dynamic"
372 }
373
374 map_locale_to_pkgs() {
375 local pkg
376
377 pkg search -l /usr/lib/locale/$1 | tail +2 | while read line
378 do
379 pkg=`lindex "$line" 3`
380 pkg=${pkg#pkg:/}
381 pkg=${pkg%@*}
382 echo -n "$pkg "
383 done
384 echo ""
385 }
386
387 #
388 # Add the brand specific arguments for "zone install" for ipkg
389 #
390 add_ipkg_args() {
391 local locale_pkg=""
392
393 if [[ "$zone_locale" != C ]]; then
394 ipkg_packages="$ipkg_packages `map_locale_to_pkgs $zone_locale`"
395 fi
396 #
397 # Work arround the issue that causes excessive messages like:
398 # en_US.UTF-8: unknown locale
399 # from zlogin due to the system local being missing from the zone.
400 #
401 if [[ "$LANG" != C ]]; then
402 ipkg_packages="$ipkg_packages `map_locale_to_pkgs $LANG`"
403 fi
404
405 # Clean up an duplicates and sort the package list for easy review
406 ipkg_packages=`for pkg in $ipkg_packages; do echo $pkg; done | sort -u`
407
408 echo "These addition packages will be installed into the ipkg zone:"
409 echo "$ipkg_packages"
410 echo $bar
411
412 for pkg in $ipkg_packages; do
413 zone_inst_args="$zone_inst_args -e $pkg"
414 done
415 }
416
417 get_random_v6token () {
418 for i in 0 1 2 3 4; do
419 b[$i]=`get_random`
420 done
421 echo "00${b[0]}:${b[1]}ff:fe${b[2]}:${b[3]}${b[4]}"
422 }
423
424 get_random () {
425 local res=`dd if=/dev/urandom bs=1 count=1 2>/dev/null | \
426 od -tx1 | head -1 | cut -d' ' -f2-`
427 res=${res/ /}
428 echo $res
429 }
430
431 get_zonestate () {
432 echo `(zoneadm -z $1 list -p 2>/dev/null || echo ::noexist) | \
433 cut -d: -f3 `
434 }
435
436 while getopts "B:C:bc:e:hi:l:n:op:rv:wx:z:" opt; do
437 case $opt in
438 B)
439 zone_brand="set brand=$OPTARG"
440 ;;
441 C)
442 clone_src=$OPTARG
443 zoneadm -z $clone_src list > /dev/null 2>&1
444 if [[ $? -ne 0 ]]; then
445 log_err "clone source $clone_src does not exist"
446 exit 1
447 fi
448 ;;
449 b)
450 zone_blank=-b
451 ;;
452 c)
453 zone_add_cfg="$zone_add_cfg
454 $OPTARG"
455 ;;
456 e)
457 ipkg_packages="$ipkg_packages ${OPTARG//,/ }"
458 ;;
459 h)
460 usage
461 exit 0
462 ;;
463 i)
464 log_err "-i no longer supported."
465 exit 1
466 ;;
467 l)
468 zone_locale=$OPTARG
469 ;;
470 n)
471 zone_ns=$OPTARG
472 if [ "$zone_ns" != "NIS" ] && \
473 [ "$zone_ns" != "DNS" ] && \
474 [ "$zone_ns" != "NONE" ] && \
475 [ "$zone_ns" != "PARENT" ]; then
476 log_err "bad argument for -n: $zone_ns"
477 exit 1
478 fi
479 ;;
480 N)
481 zone_nfs4=$OPTARG
482 ;;
483 o)
484 zone_open=1;
485 # -o implies these network services are desired
486 ipkg_packages="$ipkg_packages $ipkg_dash_o"
487 ;;
488 p)
489 zone_base=$OPTARG
490 ;;
491 r)
492 blank_root=1
493 ;;
494 v)
495 new_vnic $OPTARG
496 ;;
497 w)
498 wait_confirm=1
499 ;;
500 x)
501 if [[ "$ip_type" == "shared" ]]; then
502 log_err "-i and -x are mutually exclusive"
503 exit 1
504 fi
505 ip_type=exclusive
506 new_interface $OPTARG
507 ;;
508 z)
509 zone_name=$OPTARG
510 ;;
511 ?)
512 log_err "invalid argument: $opt"
513 log_err "try `basename $0` -h for help"
514 exit 1
515 ;;
516 esac
517 done
518
519 if [ -z $zone_name ]; then
520 log_err "missing required -z option"
521 log_err "try `basename $0` -h for help"
522 exit 1
523 fi
524
525 #
526 # Determine the zone path to use. If -p was supplied, there's nothing to do.
527 # Otherwise, zfs and ufs root systems require different handling. For
528 # UFS, we use the default path, creating it if needed. For ZFS, we may need
529 # to create a new files system for the zones default path if it doesn't
530 # already exist. This will only be done if the pool rpool exists.
531 #
532 if [[ -z "$zone_base" ]]; then
533 zfs list / > /dev/null 2>&1
534 if [[ $? -ne 0 ]]; then
535 # System root is not ZFS
536 zone_base=$def_ufs_zone_path
537 mkdir -p $zone_base
538 if [[ ! -d "$zone_base" ]]; then
539 log_err "failed to create default zone path: $zone_base"
540 exit 1
541 fi
542 else
543 # System root is ZFS
544 zone_base=$def_zfs_zone_path
545
546 if [[ ! -d "$zone_base" ]]; then
547 zpool list rpool > /dev/null 2>&1
548 if [[ "$?" -ne 0 ]]; then
549 log_err "non-default zfs configuration detected"
550 log_err "the -p option is required"
551 exit 1
552 fi
553 echo "Creating ZFS pool rpool$zone_base"
554 echo $bar
555 zfs create -o mountpoint=$zone_base rpool$zone_base
556 if [[ "$?" -ne 0 ]]; then
557 log_err "failed to create ZFS filesystem"
558 log_err "cannot install zone at $zone_base"
559 exit 1
560 fi
561 else
562 echo "Using existing default ZFS zone path: $zone_base"
563 echo $bar
564 fi
565 fi
566 fi
567
568 #
569 # Network Interface Configuration
570 #
571 if [[ "$ip_type" == "shared" ]]; then
572 #
573 # Shared IP Instance
574 #
575 for ((i=0 ; $i < $intf_cnt; i++)); do
576 if [[ "${intf_ips[$i]}" == "" ]] && \
577 [[ "${intf_ipv6s[$i]}" == "" ]]; then
578 if [[ $i -eq 0 ]]; then
579 temp=`getent hosts $zone_name`
580 zone_ips[$i]=`lindex "$temp" 0`
581 fi
582 if [[ "${intf_ips[$i]}" == "" ]]; then
583 log_err "missing IP address for interface $i"
584 exit 1
585 fi
586 fi
587 if [[ "${intf_ips[$i]}" != "" ]]; then
588 mask=24
589 if [[ "${intf_masks[$i]}" != "" ]]; then
590 mask=${intf_masks[$i]}
591 fi
592 IP="${IP}
593 add net
594 set physical=${intf_devs[$i]}
595 set address=${intf_ips[$i]}/$mask
596 end"
597 fi
598 if [[ "${intf_ipv6s[$i]}" == "-" ]]; then
599 if [[ "${intf_ips[$i]}" != "" ]]; then
600 ipv6_ll=fe80::${intf_ips[$i]//./:}
601 else
602 token=`get_random_v6token`
603 ipv6_ll=fe80::$token
604 fi
605 IP="${IP}
606 add net
607 set physical=${intf_devs[$i]}
608 set address=$ipv6_ll/16
609 end"
610 fi
611 if [[ "${intf_ipv6s[$i]}" != "" ]] && \
612 [[ "${intf_ipv6s[$i]}" != "-" ]]; then
613 IP="${IP}
614 add net
615 set physical=${intf_devs[$i]}
616 set address=${intf_ipv6s[$i]}
617 end"
618 fi
619 done
620 fi
621 if [[ "$ip_type" == "exclusive" ]]; then
622 #
623 # Exclusive IP Instance
624 #
625 IP="set ip-type=exclusive"
626 for ((i=0 ; $i < $intf_cnt; i++)); do
627 IP="${IP}
628 add net
629 set physical=${intf_devs[$i]}
630 end"
631 done
632 fi
633
634 #
635 # Determine the root password to use in the zone.
636 #
637 # zone_rootpasswd=`cat /etc/shadow | grep -w root | cut -f2 -d:`
638 #
639 # emtpy root password to work around the security hash changes breaking
640 # the sysidcfg ability to set the root password
641 zone_rootpasswd=""
642
643 #
644 # Make sure this zone isn't already configured.
645 #
646 zoneadm -z $zone_name list -c > /dev/null 2>&1
647 if [ $? -ne 1 ]; then
648 log_err "configuration for zone $zone_name already exists!"
649 exit 1
650 fi
651
652 zonecfg_tmpfile=/tmp/zonecfg_temp.$$
653
654 #
655 # Create the zone configuration in a temporary file.
656 #
657 cat <<-EOF > $zonecfg_tmpfile
658 create $zone_blank
659 set zonepath=$zone_base/$zone_name
660 set autoboot=true
661 $zone_brand
662 $IP
663 $zone_add_cfg
664 commit
665 exit
666 EOF
667
668 zonecfg -z $zone_name -f $zonecfg_tmpfile > /tmp/${zone_name}-config.log 2>&1
669
670 if [[ $? -ne 0 ]]; then
671 log_err "failed to configure zone: $zone_name"
672 log_err " zonecfg output logged in: /tmp/${zone_name}-config.log"
673 log_err " attempted configuration left in: $zonecfg_tmpfile"
674 exit 1
675 fi
676
677 rm -f $zonecfg_tmpfile
678
679 zone_brand=`zonecfg -z $zone_name info brand | cut -d' ' -f2`
680
681 if [[ "$zone_brand" == "ipkg" ]]; then
682 add_ipkg_args
683 fi
684
685 ##
686 ## OmniOS removed sysidcfg. To configure a zone with networking up front
687 ## one either needs to set the config files in the zone's root, OR set up
688 ## an rc3 script that runs once, runs the commands, and deletes itself.
689 ##
690 ## I will do a bit of both, because ipadm(1M) is the way forward for
691 ## configuration.
692 ##
693
694 rc3_tmpfile=/tmp/rc3_temp.$$
695
696 #
697 # We now need to do cleanup should the script end early.
698 #
699 cleanup_zonecfg () {
700 zonecfg -z $zone_name delete -F
701 rm -f $sysid_tmpfile
702 exit 1
703 }
704
705 trap cleanup_zonecfg SIGINT
706
707 echo " ** Configuration created for zone $zone_name:"
708 zonecfg -z $zone_name info
709 echo " ** Configuration output logged in /tmp/${zone_name}-config.log"
710 echo $bar
711 #
712 # Common configuration
713 #
714 if [[ -L /etc/TIMEZONE ]]; then
715 zone_tz=`grep -v "#" /etc/TIMEZONE | grep TZ=`
716 zone_tz=${zone_tz/TZ=/}
717 else
718 zone_tz=US/Pacific
719 fi
720
721 #
722 # NFSv4 Domain
723 #
724 #zone_nfsmapid_domain=`get_nfsmapid_domain`
725 #if [[ -z $zone_nfsmapid_domain ]]; then
726 # log_warn "unknown NFSMAPID_DOMAIN"
727 # log_warn "you will be prompted at first zone boot"
728 #fi
729
730 #
731 # Set the locale based on what $LANG is set to in the caller's environment.
732 #
733 #if [[ -z "$zone_locale" ]]; then
734 # zone_locale=$LANG
735 # if [[ -z "$zone_locale" ]]; then
736 # zone_locale=C
737 # fi
738 #fi
739
740 #if [[ ! -d /usr/lib/locale/$zone_locale ]]; then
741 # log_err "zone locale $zone_locale not found, aborting"
742 # exit 1
743 #fi
744
745 #cat > $sysid_tmpfile <<-EOF
746 #system_locale=$zone_locale
747 #terminal=xterms
748 #security_policy=NONE
749 #timezone=$zone_tz
750 #nfs4_domain=$zone_nfsmapid_domain
751 #root_password="$zone_rootpasswd"
752 #EOF
753
754 #
755 # Interface configuration
756 #
757 case $ip_type in
758 shared)
759 cat >> $sysid_tmpfile <<-EOF
760 network_interface=primary {
761 hostname=$zone_name
762 }
763 EOF
764 ;;
765 exclusive)
766 for ((i=0 ; $i < $intf_cnt; i++)); do
767 echo "ipadm create-if ${intf_devs[$i]}" >> $rc3_tmpfile
768 ip_into_rc3 $i $rc3_tmpfile
769 ipv6_into_rc3 $i $rc3_tmpfile
770 done
771 ;;
772 none)
773 cat >> $sysid_tmpfile <<-EOF
774 network_interface=NONE {
775 hostname=$zone_name
776 }
777 EOF
778 ;;
779 esac
780
781 #
782 # Name service configuration
783 #
784 case $zone_ns in
785 NIS)
786 zone_domainname=`domainname`
787 nis_server=`ypwhich`
788 nis_server_ip=`getent ipnodes $nis_server | cut -f 1`
789
790 if [[ -z "$zone_domainname" ]] || \
791 [[ -z "$nis_server" ]] || \
792 [[ -z "$nis_server_ip" ]]; then
793 log_err "could not gather enough info to configure NIS:"
794 log_err " domain_name=$zone_domainname"
795 log_err " name_server=$nis_server"
796 log_err " name_server_ip=$nis_server_ip"
797 log_err "NIS must be configured in the global zone"
798 cleanup_zonecfg
799 # Above command exits
800 fi
801
802 cat >> $sysid_tmpfile <<-EOF
803 name_service=NIS {
804 domain_name=$zone_domainname
805 name_server=$nis_server($nis_server_ip)
806 }
807 EOF
808 ;;
809 DNS)
810 zone_dnsdomain=`grep domain /etc/resolv.conf | grep -v "#"`
811 zone_dnsdomain=`lindex "$zone_dnsdomain" 1`
812 zone_dnssvrs=`grep nameserver /etc/resolv.conf | grep -v "#"`
813 zone_dnssvrs=${zone_dnssvrs/nameserver}
814 zone_dnssvrs=${zone_dnssvrs//nameserver/,}
815 zone_dnssvrs=`echo $zone_dnssvrs | tr -d '[:space:]'`
816 zone_search=`grep search /etc/resolv.conf | grep -v "#"`
817 zone_search=${zone_search/search}
818 zone_search=${zone_search//search/,}
819 zone_search=`echo $zone_search | tr -d '[:space:]'`
820
821 if [[ -z "$zone_dnsdomain" ]] || \
822 [[ -z "$zone_dnssvrs" ]]; then
823 log_err "could not gather enough info to configure DNS:"
824 log_err " domain_name=$zone_dnsdomain"
825 log_err " name_servers=$zone_dnssvers"
826 log_err "please ensure a usable /etc/resolv.conf"
827 cleanup_zonecfg
828 # Above command exits
829 fi
830
831 cat >> $sysid_tmpfile <<-EOF
832 name_service=DNS {
833 domain_name=$zone_dnsdomain
834 name_server=$zone_dnssvrs
835 EOF
836 if [[ ! -z "$zone_search" ]]; then
837 echo " search=$zone_search" >> $sysid_tmpfile
838 fi
839 echo "}" >> $sysid_tmpfile
840 ;;
841 NONE|PARENT)
842 echo "name_service=NONE" >> $sysid_tmpfile
843 ;;
844 esac
845
846 #echo " ** /etc/sysidcfg created for zone $zone_name:"
847 #cat $sysid_tmpfile
848 echo $bar
849
850 if [[ ! -z "$clone_src" ]]; then
851 echo "Zone will be cloned from $clone_src"
852 echo $bar
853 fi
854
855 if [[ $vnic_cnt -gt 0 ]]; then
856 echo "The following VNICs will be created:"
857 for ((i=0 ; $i < $vnic_cnt; i++)); do
858 dev=${vnic_devs[$i]}
859 mac=${vnic_macs[$i]}
860 name=${vnic_names[$i]}
861 echo " ${name} on $dev with hardware address $mac"
862 done
863 echo $bar
864 fi
865
866 #
867 # Install the zone.
868 #
869 if [[ "$wait_confirm" -eq 1 ]]; then
870 echo ""
871 echo " ** Press enter to install zone, or CTRL-C to abort"
872 read
873 fi
874
875 if [[ "$do_update_sysidtools" -eq 1 ]]; then
876 update_sysidtools
877 fi
878
879 if [[ "$vnic_cnt" -gt 0 ]]; then
880 echo "Creating VNICs ..."
881 for ((i=0 ; $i < $vnic_cnt; i++)); do
882 dladm create-vnic -l ${vnic_devs[$i]} -m ${vnic_macs[$i]} \
883 ${vnic_names[$i]}
884 if [[ "$?" -ne 0 ]]; then
885 log_err "failed to create vnic ${vnic_names[$i]}"
886 exit 1
887 fi
888 done
889 fi
890
891 if [[ -z "$clone_src" ]]; then
892 zoneadm -z $zone_name install $zone_inst_args
893 if [[ "$?" -ne 0 ]]; then
894 log_err "non-zero return from zoneadm install"
895 cleanup_zonecfg
896 # Above command exits
897 fi
898 else
899 case `get_zonestate $clone_src` in
900 installed)
901 zoneadm -z $zone_name clone $clone_src
902 ;;
903 running)
904 zoneadm -z $clone_src halt
905 zoneadm -z $zone_name clone $clone_src
906 zoneadm -z $clone_src boot
907 ;;
908 *)
909 log_error "clone source zone in unexpected state"
910 cleanup_zonecfg
911 ;;
912 esac
913 fi
914
915 #
916 # We're now past the point where cleaning up makes sense.
917 #
918 trap - SIGINT
919
920 zoneadm -z $zone_name mount
921 if [[ "$?" -eq 0 ]]; then
922 #
923 # Move over the sysidcfg file created earlier
924 #
925 # mv $sysid_tmpfile $zone_base/$zone_name/root/etc/sysidcfg
926 # Clean up and install the one-time rc3 file.
927 echo "/bin/rm -f /etc/rc3.d/S99hacky-addrconf" >>$rc3_tmpfile
928 mv $rc3_tmpfile $zone_base/$zone_name/root/etc/rc3.d/S99hacky-addrconf
929 echo "Here's the file: (press RETURN) to continue"
930 echo "-------"
931 cat $zone_base/$zone_name/root/etc/rc3.d/S99hacky-addrconf
932 echo "-------"
933 read
934
935 #
936 # We'll want a hosts file entry for the zone name.
937 #
938 if [ ! -z "${intf_ips[0]}" ]; then
939 if [[ -z "${intf_names[0]}" ]]; then
940 echo "${intf_ips[0]} $zone_name" >> \
941 $zone_base/$zone_name/root/etc/hosts
942 else
943 echo "${intf_ips[0]} ${intf_names[0]}" >> \
944 $zone_base/$zone_name/root/etc/hosts
945 fi
946 fi
947
948 #
949 # Setup NFSv4 mapid domain in the zone
950 #
951 if [[ ! -z "$zone_nfsmapid_domain" ]]; then
952 echo "NFSMAPID_DOMAIN=$zone_nfsmapid_domain" >> \
953 $zone_base/$zone_name/root/etc/default/nfs
954 touch $zone_base/$zone_name/root/etc/.NFS4inst_state.domain
955 fi
956 zoneadm -z $zone_name unmount
957 else
958 log_warn "zoneadm -z $zone_name mount: failed"
959 log_warn "some zone pre-configuration will be incomplete"
960 fi
961
962 echo $bar
963
964 #
965 # Boot the zone.
966 #
967 #echo "Booting zone $zone_name"
968 zoneadm -z $zone_name boot
969
970 if [[ "$zone_open" -eq 1 ]]; then
971 open_for_testing
972 fi
973
974 zoneadm -z $zone_name reboot
975 # In OmniOS, these aren't needed. They might be in other IPS-running distros.
976 #rm $zone_base/$zone_name/root/etc/sysidcfg
977 #rm $zone_base/$zone_name/root/etc/.UNCONFIGURED
978
979 #
980 # Allow empty passwords for user login.
981 #
982 login_file=$zone_base/$zone_name/root/etc/default/login
983 sed 's/PASSREQ=.*/PASSREQ=NO/' ${login_file} > ${login_file}.tmp
984 mv ${login_file}.tmp ${login_file}
985
986 echo "`basename $0` completed successfully."