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 # Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 # Use is subject to license terms.
24 #
25 # ident "%Z%%M% %I% %E% SMI"
26 #
27
28 #
29 # This script contains various routines used to post-process a zone for use
30 # with BrandZ after it has been installed from RPM media or a tar image.
31 #
32 # Briefly, there are three main jobs we need to do:
33 #
34 # 1) Create any needed directories and symlinks BrandZ needs but that the
35 # Linux install may not create
36 #
37 # 2) Modify rc scripts to shut off services that don't apply to a zone
38 # or that wish to access hardware directly
39 #
40 # 3) Modify various Linux system files for use within a zone environment
41 #
42
43 #
44 # Restrict executables to /bin and /usr/bin
45 #
46 PATH=/bin:/usr/bin
47 export PATH
48
49 #
50 # Sends output to a log file via redirection of stderr.
51 #
52 # This script assumes its caller has already performed the redirection to the
53 # logfile.
54 #
55 log()
56 {
57 echo "$@" >&2
58 }
59
60 #
61 # Setup i18n output
62 #
63 TEXTDOMAIN="SUNW_OST_OSCMD"
64 export TEXTDOMAIN
65
66 cmd_failed=$(gettext "%s failed! Aborting installation...")
67 cmd2_failed=$(gettext "%s of '%s' to '%s' failed!")
68 create_failed=$(gettext "Could not create new file '%s'!")
69 disable_failed=$(gettext "Attempt to disable entries in '%s' failed!")
70 install_aborted=$(gettext "Aborting installation...")
71 install_noroot=$(gettext "Installation root directory '%s' does not exist.")
72 ln_fail=$(gettext "Unable to symlink '%s' to '%s'!")
73 mkdir_fail=$(gettext "Unable to create the directory '%s'")
74 mod_failed=$(gettext -n "Attempt to modify entries in '%s' failed!")
75
76 usage=$(gettext "usage: %s <install_root> [mini]")
77
78 #
79 # Output an internationalized string followed by a carriage return
80 #
81 i18n_echo()
82 {
83 typeset fmt="$1"
84 shift
85
86 printf "$fmt\n" "$@"
87 }
88
89 #
90 # Routine to make a full path out of a supplied path
91 #
92 fullpath()
93 {
94 typeset path="$1"
95
96 echo $path | egrep -s "^/" || path="${PWD:=$(pwd)}/$path"
97 echo $path
98 }
99
100 #
101 # Routine to create directories and handle errors
102 #
103 makedir()
104 {
105 typeset dirname=$(fullpath "$1")
106 typeset mode=""
107
108 [[ $# -eq 2 ]] && mode="-m $2"
109
110 [[ -d "$dirname" ]] && return
111
112 if ! mkdir $mode -p "$dirname"; then
113 log "Unable to create the directory \"$dirname\"!"
114 i18n_echo "$mkdir_fail" "$dirname"
115 echo $(gettext "Aborting installation...")
116 exit 1
117 fi
118 }
119
120 #
121 # Routine to create initial symlinks and handle errors
122 #
123 symlink()
124 {
125 typeset src="$1"
126 typeset dst=$(fullpath "$2")
127
128 [[ -e "$dst" || -h "$dst" ]] && rm -f "$dst"
129
130 if ! ln -s "$src" "$dst"; then
131 log "Unable to symlink \"$src\" to \"$dst\"!"
132 i18n_echo "$ln_fail" "$src" "$dst"
133 echo $(gettext "Aborting installation...")
134 exit 1
135 fi
136 }
137
138 #
139 # Install a file using "ln -s"
140 #
141 # Returns 0 on success, 1 on failure.
142 #
143 install_ln()
144 {
145 typeset source="$1"
146 typeset target=$(fullpath "$2")
147
148 log " Installing \"$target\""
149
150 mv -f "$target" "$target.$tag" 2>/dev/null
151
152 if ! ln -s "$source" "$target"; then
153 log ""
154 log "Attempt to install $target FAILED."
155 return 1
156 fi
157
158 return 0
159 }
160
161
162 #
163 # Enable NFS servers and the NFS lock daemon for a particular zone.
164 #
165 enable_nfs_services()
166 {
167 log "Non-miniroot install; enabing NFS servers and NFS lock daemon"
168
169 #
170 # Setup files required for NFS:
171 #
172 # /native/etc/netconfig
173 # /native/etc/default/nfs
174 #
175 # These two files are treated as read-only in lx branded zones.
176 # To enfore this restriction we will read-only lofs mount them
177 # into the zone from the global zone. For these lofs mounts to
178 # work we'll need to create empty directories now that will serve
179 # as mount points later.
180 #
181 # /sbin/rpc.statd
182 # /sbin/rpc.lockd
183 #
184 # These files are symlinks to scripts supplied by the lx brand
185 # that will start up the solaris nfs daemons.
186 #
187 if { ! makedir native/etc/netconfig ||
188 ! makedir native/etc/default/nfs ; }; then
189 log "Aborting NFS setup..."
190 log ""
191 return
192 fi
193
194 if { ! install_ln ../native/usr/lib/brand/lx/lx_lockd sbin/rpc.lockd ||
195 ! install_ln ../native/usr/lib/brand/lx/lx_statd \
196 sbin/rpc.statd ; }; then
197 log "Aborting NFS setup..."
198 log ""
199 return
200 fi
201
202 #
203 # update /etc/services for NFS
204 #
205 log ""
206 log "Adding lockd entry to \"$install_root/etc/services\"..."
207
208 cp -p $install_root/etc/services $install_root/etc/services.$tag
209
210 #
211 # Brackets in the sed script below contain a space followed by a tab
212 #
213 cat $install_root/etc/services.$tag |
214 sed 's:\(111\/..p[ ][ ]*\):\1rpcbind :' |
215 cat > $install_root/etc/services
216
217 cat >> $install_root/etc/services <<-EOF
218 lockd 4045/udp # NFS lock daemon/manager
219 lockd 4045/tcp # NFS lock daemon/manager
220 EOF
221
222 #
223 # Modify /etc/init.d/nfslock to enable the USERLAND_LOCKD option and to
224 # find some commands in alternate locations.
225 #
226 log ""
227 log "Modifying \"$install_root/etc/init.d/nfslock\"..."
228 cp -p etc/init.d/nfslock etc/init.d/nfslock.$tag
229 cat etc/init.d/nfslock.$tag |
230 sed '
231 s/USERLAND_LOCKD=$/USERLAND_LOCKD="yes"/
232 s/killproc rpc.statd/killproc statd/
233 s/status rpc.statd/status statd/
234 s/pidof rpc.statd/pidof statd/
235 ' |
236 cat > etc/init.d/nfslock
237 }
238
239 #
240 # The main script starts here.
241 #
242 # The syntax is:
243 #
244 # lx_init_zone <rootdir> [mini]
245 #
246 # Where:
247 # <rootdir> is the root of the zone directory to be modified
248 #
249 # [mini] is an optional second argument that signifies whether this is
250 # to be a miniroot install; if it is, NFS services are not enabled
251 # in the processed zone
252 #
253 unset is_miniroot
254 unset install_root
255
256 install_root="$1"
257
258 tag="lxsave_$(date +%m.%d.%Y@%T)"
259
260 if (($# < 1 || $# > 2)); then
261 i18n_echo "$usage" "$0"
262 exit 1
263 fi
264
265 (($# == 2)) && is_miniroot=1
266
267 if [[ ! -d "$install_root" ]]; then
268 i18n_echo "$install_noroot" "$install_root"
269 echo $(gettext "** Installation aborted **")
270 exit 1
271 fi
272
273 cd "$install_root"
274
275 log ""
276 log "Initial lx_brand environment modification started `date`"
277 log "Making needed directories in \"$install_root\"."
278 echo $(gettext "Setting up the initial lx brand environment.")
279
280 #
281 # Make various directories in /native that are needed to boot an lx branded
282 # zone.
283 #
284 makedir native/dev
285 makedir native/etc/default
286 makedir native/etc/svc/volatile
287 makedir native/lib
288 makedir native/proc
289 makedir native/tmp 1777
290 makedir native/usr
291 makedir native/var
292
293 #
294 # Make various other directories needed for the lx brand
295 #
296 makedir mnt
297 makedir opt
298 makedir usr/local/bin
299 makedir usr/local/include
300 makedir usr/local/lib
301 makedir usr/local/sbin
302 makedir usr/local/share
303 makedir usr/local/src
304
305 makedir dev 0755
306 makedir tmp 1777
307 makedir proc 0555
308 makedir boot 0755
309
310 #
311 # zlogin requires that these utilities live in places other than their
312 # Linux defaults, so create appropriate links for them here.
313 #
314 # XX - The need for these links may go away in the future if zlogin is
315 # appropriately modified
316 #
317 symlink /bin/sh sbin/sh
318 symlink /bin/su usr/bin/su
319 symlink /native/usr/lib/ld.so.1 usr/lib/ld.so.1
320
321 libpam_so="$(echo lib/libpam.so.0.*)"
322 libpam_misc="$(echo lib/libpam_misc.so.0.*)"
323 libpamc_so="$(echo lib/libpamc.so.0.*)"
324
325 symlink "/$libpam_so" lib/libpam.so.0
326 symlink "/$libpam_misc" lib/libpam_misc.so.0
327 symlink "/$libpamc_so" lib/libpamc.so.0
328
329 log ""
330 log "Modifying system configuration in \"$install_root\""
331
332 #
333 # Create a /var/ld/ld.config that will point to /native/lib for our Solaris
334 # libraries.
335 #
336 log "Creating \"$install_root/var/ld/ld.config\"..."
337
338 makedir var/ld
339
340 if ! crle -c var/ld/ld.config -l /native/lib:/native/usr/lib \
341 -s /native/lib/secure:/native/usr/lib/secure; then
342 log "\tCreation of \"$install_root/var/ld/ld.config\" failed!"
343 i18n_echo "$cmd_failed" "crle"
344 exit 1
345 fi
346
347 log ""
348 log "Modifying \"$install_root/etc/fstab\"..."
349
350 mv -f etc/fstab etc/fstab.$tag 2>/dev/null
351
352 cat > etc/fstab <<- EOF
353 none / ufs defaults 1 1
354 none /proc proc defaults 0 0
355 EOF
356
357 if [[ $? -ne 0 ]]; then
358 log "Could not create new \"$install_root/etc/fstab\"!"
359 i18n_echo "$create_failed" "$install_root/etc/fstab"
360 exit 1
361 fi
362
363 #
364 # The default /etc/inittab spawns mingetty on each of the virtual consoles
365 # as well as xdm on the X console. Since we don't have virtual consoles nor
366 # an X console, spawn a single mingetty on /dev/console instead.
367 #
368 # Don't bother changing the file if it looks like we already did.
369 #
370 if ! egrep -s "Disabled by lx brand" etc/inittab; then
371 log "Modifying: \"$install_root/etc/inittab\"..."
372
373 tmpfile=/tmp/inittab.$$
374
375 sed 's/^[1-6]:/# Disabled by lx brand: &/
376 s/^id:5:initdefault:/id:3:initdefault: # Modified by lx brand: &/' \
377 etc/inittab > $tmpfile
378
379 #
380 # Don't bother with further alterations if the sed above failed...
381 #
382 if [[ $? -eq 0 ]]; then
383 egrep -s "console login for lx brand" etc/inittab
384 if [[ $? -ne 0 ]]; then
385 cat >> $tmpfile <<- EOF
386
387 #
388 # console login for lx brand
389 #
390 1:2345:respawn:/sbin/mingetty console
391 EOF
392
393 #
394 # Only install the new inittab if the append
395 # above succeeded.
396 #
397 if [[ $? -eq 0 ]]; then
398 #
399 # Attempt to save off the original inittab
400 # before moving over the modified version.
401 #
402 mv -f etc/inittab etc/inittab.$tag 2>/dev/null
403
404 mv -f $tmpfile etc/inittab
405
406 if [[ $? -ne 0 ]]; then
407 log "mv of \"$tmpfile\" to" \
408 "\"$installroot/etc/inittab\"" \
409 "failed!"
410 i18n_echo "$cmd2_failed" "mv" \
411 "$tmpfile" \
412 "$installroot/etc/inittab"
413 i18n_echo "$install_aborted"
414 exit 1
415 else
416 chmod 644 etc/inittab
417 fi
418 fi
419 fi
420
421 else
422 log "Attempt to disable entries in" \
423 "\"$install_root/etc/inittab\" failed!"
424 i18n_echo "$disable_failed" "$install_root/etc/inittab"
425 i18n_echo "$install_aborted"
426 exit 1
427 fi
428 fi
429
430 if [[ ! -e "$install_root/etc/hosts" ]]; then
431 log ""
432 log "Creating: \"$install_root/etc/hosts\"..."
433
434 cat > "$install_root/etc/hosts" <<-_EOF_
435 127.0.0.1 localhost
436 _EOF_
437 fi
438
439 #
440 # User must configure various brand-specific items to enable networking, so
441 # boot the system non-networked.
442 #
443 log ""
444 log "Modifying: \"$install_root/etc/sysconfig/network\"..."
445
446 mv -f etc/sysconfig/network etc/sysconfig/network.$tag 2>/dev/null
447
448 cat > etc/sysconfig/network <<- EOF
449 NETWORKING="no"
450 #
451 # To enable networking, change the "no" above to "yes" and
452 # uncomment and fill in the following parameters.
453 #
454 # If you are specifying a hostname by name rather than by IP address,
455 # be sure the system can resolve the name properly via the use of a
456 # name service and/or the proper name files, as specified by
457 # nsswitch.conf. See nsswitch.conf(5) for further details.
458 #
459 # HOSTNAME=your_hostname_here
460 #
461 EOF
462
463 if [[ $? -ne 0 ]]; then
464 log "Could not create new \"$install_root/etc/sysconfig/network\"!"
465 i18n_echo "$create_failed" "$install_root/etc/sysconfig/network"
466 i18n_echo "$install_aborted"
467 exit 1
468 fi
469
470 if [[ -a etc/sysconfig/syslog ]]; then
471 #
472 # By default, syslogd will attempt to create a socket in /dev/log, but
473 # /dev is not be writable. Instead, modify /etc/sysconfig/syslog to
474 # tell it to use /var/run/syslog instead, and make /dev/log a symlink
475 # to /var/run/syslog.
476 #
477 log ""
478 log "Modifying: \"$install_root/etc/sysconfig/syslog\"..."
479
480 tmpfile=/tmp/lx_sc.syslog.$$
481
482 sed 's@\(SYSLOGD_OPTIONS="-m 0\)"@\1 -p /var/run/syslog"@' \
483 etc/sysconfig/syslog > $tmpfile
484
485 #
486 # Only install the new sysconfig/syslog if the edit above succeeded.
487 #
488 if [[ $? -eq 0 ]]; then
489 #
490 # Attempt to save off the original syslog before moving over
491 # the modified version.
492 #
493 mv -f etc/sysconfig/syslog etc/sysconfig/syslog.$tag 2>/dev/null
494
495 if ! mv -f $tmpfile etc/sysconfig/syslog; then
496 log "mv of \"$tmpfile\" to" \
497 "\"$installroot/etc/sysconfig/syslog\" failed!"
498 i18n_echo "$cmd2_failed" "mv" "$tmpfile" \
499 "$installroot/etc/sysconfig/syslog"
500 i18n_echo "$install_aborted"
501 exit 1
502 else
503 chmod 755 etc/sysconfig/syslog
504 fi
505 else
506 log "Attempt to modify entries in" \
507 "\"$install_root/sysconfig/syslog\" failed!"
508 i18n_echo "$mod_failed" "$install_root/sysconfig/syslog"
509 i18n_echo "$install_aborted"
510 exit 1
511 fi
512 fi
513
514 if [[ $? -ne 0 ]]; then
515 log "Could not create new \"$install_root/etc/sysconfig/syslog\"!"
516 i18n_echo "$create_failed" "$install_root/etc/sysconfig/syslog"
517 i18n_echo "$install_aborted"
518 exit 1
519 fi
520
521 #
522 # /etc/rc.d/init.d/keytable tries to load a physical keyboard map, which won't
523 # work in a zone. If we remove etc/sysconfig/keyboard, it won't try this at all.
524 #
525 mv -f etc/sysconfig/keyboard etc/sysconfig/keyboard.$tag 2>/dev/null
526
527 #
528 # /etc/rc.d/init.d/gpm tries to configure the console mouse for cut-and-paste
529 # text operations, which we don't support. Removing this file disables the
530 # mouse configuration.
531 #
532 mv -f etc/sysconfig/mouse etc/sysconfig/mouse.$tag 2>/dev/null
533
534 #
535 # The following scripts attempt to start services or otherwise configure
536 # the system in ways incompatible with zones, so don't execute them at boot
537 # time.
538 #
539 log ""
540 log "Modifying \"$install_root/etc/rc.d/init.d\" to disable any"
541 log " services not supported by BrandZ:"
542 unsupported_services="
543 kudzu
544 microcode_ctl
545 network
546 random
547 pcmcia
548 isdn
549 iptables
550 ip6tables
551 iscsi
552 psacct
553 gpm
554 irda
555 smartd
556 rawdevices
557 netdump
558 hpoj
559 mdmonitor
560 mdmpd
561 irqbalance
562 "
563
564 for file in $unsupported_services; do
565 if [[ -a "etc/rc.d/init.d/$file" ]]; then
566
567 if mv -f "etc/rc.d/init.d/$file" "etc/rc.d/init.d/$file.$tag"; then
568 log " + Moved script \"etc/rc.d/init.d/$file\" to"
569 log " \"etc/rc.d/init.d/$file.$tag\""
570 fi
571 fi
572
573 rc_files="$(echo etc/rc.d/rc[0-6].d/[SK]+([0-9])$file)"
574
575 if [[ "$rc_files" != "etc/rc.d/rc[0-6].d/[SK]+([0-9])$file" ]]; then
576 for file in $rc_files; do
577 if [[ -h "$file" ]]; then
578 rm -f "$file" &&
579 log " + Removed symbolic link \"$file\""
580 else
581 rm -f "$file" &&
582 log " + Removed script \"$file\""
583 fi
584 done
585 fi
586 done
587
588 #
589 # There is a lot of stuff in the standard halt and reboot scripts that we
590 # have no business running in a zone. Fortunately, the stuff we want to
591 # skip is all in one contiguous chunk.
592 #
593 # Don't bother to modify the file if it looks like we already did.
594 #
595 if ! egrep -s "Disabled by lx brand" etc/rc.d/init.d/halt; then
596 log ""
597 log "Modifying \"$install_root/etc/rc.d/init.d/halt\" for operation"
598 log " within a zone..."
599 awk 'BEGIN {skip = ""}
600 /^# Save mixer/ {skip = "# Disabled by lx brand: "}
601 /halt.local/ {skip = ""}
602 /./ {print skip $0}' etc/rc.d/init.d/halt > /tmp/halt.$$
603
604 if [[ $? -eq 0 ]]; then
605 mv -f etc/rc.d/init.d/halt etc/rc.d/init.d/halt.$tag 2>/dev/null
606 mv -f /tmp/halt.$$ etc/rc.d/init.d/halt
607 chmod 755 etc/rc.d/init.d/halt
608 else
609 log "Attempt to modify \"$install_root/etc/rc.d/init.d/halt\"" \
610 "FAILED"
611 log "Continuing with balance of zone setup..."
612 fi
613 fi
614
615 #
616 # Fix up /etc/rc.d/rc.sysinit:
617 #
618 # 1) /sbin/hwclock requires the iopl() system call, which BrandZ won't support.
619 # Since the hardware clock cannot be set from within a zone, we comment out
620 # the line.
621 #
622 # 2) Disable dmesg commands, since we don't implement klogctl
623 #
624 # 3) Disable initlog and the mount of /dev/pts
625 #
626 # 4) Don't touch /dev/tty* in order to start virtual terminals, as that won't
627 # work from within a zone.
628 #
629 # 5) Don't try to check the root filesystem (/) as there is no associated
630 # physical device, and any attempt to run fsck will fail.
631 #
632 # Don't modify the rc.sysinit file if it looks like we already did.
633 #
634 if ! egrep -s "Disabled by lx brand" etc/rc.d/rc.sysinit; then
635 log ""
636 log "Modifying: \"$install_root/etc/rc.d/rc.sysinit\"..."
637 log ""
638
639 tmpfile=/tmp/lx_rc.sysinit.$$
640
641 sed 's@^/sbin/hwclock@# Disabled by lx brand: &@
642 s@^HOSTTYPE=@HOSTTYPE=\"s390\" # Spoofed for lx brand: &@
643 s@/bin/dmesg -n@: # Disabled by lx brand: &@
644 s@^dmesg -s@# Disabled by lx brand: &@
645 s@initlog -c \"fsck@: # Disabled by lx brand: &@
646 s@^.*mount .* /dev/pts$@# Disabled by lx brand: &@' \
647 etc/rc.d/rc.sysinit > $tmpfile
648
649 #
650 # Only install the new rc.sysinit if the edit above succeeded.
651 #
652 if [[ $? -eq 0 ]]; then
653 #
654 # Attempt to save off the original rc.sysinit
655 # before moving over the modified version.
656 #
657 mv -f etc/rc.d/rc.sysinit etc/rc.d/rc.sysinit.$tag 2>/dev/null
658
659 if ! mv -f $tmpfile etc/rc.d/rc.sysinit; then
660 log "mv of \"$tmpfile\" to" \
661 "\"$installroot/etc/rc.d/rc.sysinit\" failed!"
662 i18n_echo "$cmd2_failed" "mv" "$tmpfile" \
663 "$installroot/etc/rc.d/rc.sysinit"
664 i18n_echo "$install_aborted"
665 exit 1
666 else
667 chmod 755 etc/rc.d/rc.sysinit
668 fi
669 else
670 log "Attempt to modify entries in" \
671 "\"$install_root/rc.d/rc.sysinit\" failed!"
672 i18n_echo "$mod_failed" "$install_root/rc.d/rc.sysinit"
673 i18n_echo "$install_aborted"
674 exit 1
675 fi
676 fi
677
678 if [[ -z $is_miniroot ]]; then
679 enable_nfs_services || log "NFS services were not properly enabled."
680 fi
681
682 log ""
683 log "System configuration modifications complete `date`"
684 log ""
685 i18n_echo "System configuration modifications complete."
686 exit 0