install.sub revision 1.33 1 #!/bin/sh
2 # $NetBSD: install.sub,v 1.33 2000/02/20 00:23:10 mrg Exp $
3 #
4 # Copyright (c) 1996 The NetBSD Foundation, Inc.
5 # All rights reserved.
6 #
7 # This code is derived from software contributed to The NetBSD Foundation
8 # by Jason R. Thorpe.
9 #
10 # Redistribution and use in source and binary forms, with or without
11 # modification, are permitted provided that the following conditions
12 # are met:
13 # 1. Redistributions of source code must retain the above copyright
14 # notice, this list of conditions and the following disclaimer.
15 # 2. Redistributions in binary form must reproduce the above copyright
16 # notice, this list of conditions and the following disclaimer in the
17 # documentation and/or other materials provided with the distribution.
18 # 3. All advertising materials mentioning features or use of this software
19 # must display the following acknowledgement:
20 # This product includes software developed by the NetBSD
21 # Foundation, Inc. and its contributors.
22 # 4. Neither the name of The NetBSD Foundation nor the names of its
23 # contributors may be used to endorse or promote products derived
24 # from this software without specific prior written permission.
25 #
26 # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 # POSSIBILITY OF SUCH DAMAGE.
37 #
38
39 # NetBSD installation/upgrade script - common subroutines.
40
41 ROOTDISK="" # filled in below
42 VERSION= # filled in automatically (see list)
43 export VERSION
44
45 ALLSETS="base comp etc games man misc text" # default install sets
46 UPGRSETS="base comp games man misc text" # default upgrade sets
47 THESETS= # one of the above
48
49 local_sets_dir="" # Path searched for sets by install_sets
50 # on the local filesystems
51
52 # decide upon an editor
53 if [ X$EDITOR = X ]; then
54 if [ -x /usr/bin/vi ]; then
55 EDITOR=vi
56 else
57 EDITOR=ed
58 fi
59 fi
60
61 getresp() {
62 read resp
63 if [ "X$resp" = "X" ]; then
64 resp=$1
65 fi
66 }
67
68 isin() {
69 # test the first argument against the remaining ones, return succes on a match
70 _a=$1; shift
71 while [ $# != 0 ]; do
72 if [ "$_a" = "$1" ]; then return 0; fi
73 shift
74 done
75 return 1
76 }
77
78 rmel() {
79 # remove first argument from list formed by the remaining arguments
80 local _a
81
82 _a=$1; shift
83 while [ $# != 0 ]; do
84 if [ "$_a" != "$1" ]; then
85 echo "$1";
86 fi
87 shift
88 done
89 }
90
91 cutword () {
92 # read a line of data, return Nth element.
93 local _a
94 local _n
95 local _oifs
96
97 # optional field separator
98 _oifs="$IFS"
99 case "$1" in
100 -t?*) IFS=${1#-t}; shift;;
101 esac
102
103 _n=$1
104 read _a; set -- $_a
105 IFS="$_oifs"
106 if [ "$1" = "" ]; then return; fi
107 eval echo \$$_n
108 }
109
110 cutlast () {
111 # read a line of data, return last element. Equiv. of awk '{print $NF}'.
112 local _a
113 local _oifs
114
115 # optional field separator
116 _oifs="$IFS"
117 case "$1" in
118 -t?*) IFS=${1#-t}; shift;;
119 esac
120
121 read _a; set -- $_a
122 IFS="$_oifs"
123 if [ "$1" = "" ]; then return; fi
124 while [ "$#" -gt 10 ]; do shift 10; done
125 eval echo \$$#
126 }
127
128 firstchar () {
129 # return first character of argument
130 local _a
131 _a=$1
132 while [ ${#_a} != 1 ]; do
133 _a=${_a%?}
134 done
135 echo $_a
136 }
137
138 basename () {
139 local _oifs
140 if [ "$1" = "" ]; then return; fi
141 _oifs="$IFS"
142 IFS="/"
143 set -- $1
144 IFS="$_oifs"
145 while [ "$#" -gt 10 ]; do shift 10; done
146 eval echo \$$#
147 }
148
149 dir_has_sets() {
150 # return true when the directory $1 contains a set for $2...$n
151 local _dir
152 local _file
153
154 _dir=$1; shift
155 for _file in $*
156 do
157 if [ -f $_dir/${_file}.tar.gz ]; then
158 return 0
159 fi
160 # Try for stupid msdos convention
161 if [ -f $_dir/${_file}.tgz ]; then
162 return 0
163 fi
164 # Try for split files
165 if [ -f $_dir/${_file}${VERSION}.aa ]; then
166 return 0
167 fi
168 done
169 return 1
170 }
171
172 twiddle() {
173 # spin the propeller so we don't get bored
174 while : ; do
175 sleep 1; echo -n "/";
176 sleep 1; echo -n "-";
177 sleep 1; echo -n "\\";
178 sleep 1; echo -n "|";
179 done > /dev/tty & echo $!
180 }
181
182 get_localdir() {
183 # $1 is relative mountpoint
184 local _mp
185 local _dir
186
187 _mp=$1
188 _dir=
189 while : ; do
190 if [ X$_mp != X ]; then
191 cat << __get_localdir_1
192 Note: your filesystems are mounted under the temporary mount point \"$_mp\".
193 The pathname you are requested to enter below should NOT include the \"$_mp\"
194 prefix.
195 __get_localdir_1
196 fi
197 echo -n "Enter the pathname where the sets are stored [$_dir] "
198 getresp "$_dir"
199 _dir=$resp
200
201 # Allow break-out with empty response
202 if [ -z "$_dir" ]; then
203 echo -n "Are you sure you don't want to set the pathname? [n] "
204 getresp "n"
205 case "$resp" in
206 y*|Y*)
207 break
208 ;;
209 *)
210 continue
211 ;;
212 esac
213 fi
214
215 if dir_has_sets "$_mp/$_dir" $THESETS
216 then
217 local_sets_dir="$_mp/$_dir"
218 break
219 else
220 cat << __get_localdir_2
221 The directory \"$_mp/$_dir\" does not exist, or does not hold any of the
222 upgrade sets.
223 __get_localdir_2
224 echo -n "Re-enter pathname? [y] "
225 getresp "y"
226 case "$resp" in
227 y*|Y*)
228 ;;
229 *)
230 local_sets_dir=""
231 break
232 ;;
233 esac
234 fi
235 done
236 }
237
238 getrootdisk() {
239 cat << \__getrootdisk_1
240
241 The installation program needs to know which disk to consider
242 the root disk. Note the unit number may be different than
243 the unit number you used in the standalone installation
244 program.
245
246 Available disks are:
247
248 __getrootdisk_1
249 _DKDEVS=`md_get_diskdevs`
250 echo "$_DKDEVS"
251 echo ""
252 echo -n "Which disk is the root disk? "
253 getresp ""
254 if isin $resp $_DKDEVS ; then
255 ROOTDISK="$resp"
256 else
257 echo ""
258 echo "The disk $resp does not exist."
259 ROOTDISK=""
260 fi
261 }
262
263 labelmoredisks() {
264 cat << \__labelmoredisks_1
265
266 You may label the following disks:
267
268 __labelmoredisks_1
269 echo "$_DKDEVS"
270 echo ""
271 echo -n "Label which disk? [done] "
272 getresp "done"
273 case "$resp" in
274 "done")
275 ;;
276
277 *)
278 if isin $resp $_DKDEVS ; then
279 md_labeldisk $resp
280 else
281 echo ""
282 echo "The disk $resp does not exist."
283 fi
284 ;;
285 esac
286 }
287
288 addhostent() {
289 # $1 - IP address
290 # $2 - symbolic name
291
292 # Create an entry in the hosts table. If no host table
293 # exists, create one. If the IP address already exists,
294 # replace it's entry.
295 if [ ! -f /tmp/hosts ]; then
296 echo "127.0.0.1 localhost" > /tmp/hosts
297 fi
298
299 sed "/^$1 /d" < /tmp/hosts > /tmp/hosts.new
300 mv /tmp/hosts.new /tmp/hosts
301
302 echo "$1 $2 $2.$FQDN" >> /tmp/hosts
303 }
304
305 addifconfig() {
306 # $1 - interface name
307 # $2 - interface symbolic name
308 # $3 - interface IP address
309 # $4 - interface netmask
310 # $5 - (optional) interface link-layer medium
311 # $6 - (optional) interface link-layer directives
312 local _m
313
314 _m=""
315 if [ "$5" != "" ]; then
316 _m="media $5"
317 fi
318 # Create a ifconfig.* file for the interface.
319 echo "inet $2 netmask $4 $_m $6" > /tmp/ifconfig.$1
320
321 addhostent $3 $2
322 }
323
324 configurenetwork() {
325 local _ifsdone
326 local _ifs
327
328 # _IFS=`md_get_ifdevs`
329 _IFS=`ifconfig -l | sed '
330 s/lo0//
331 s/ppp[0-9]//g
332 s/sl[0-9]//g
333 s/tun[0-9]//g'`
334
335 _ifsdone=""
336 resp="" # force at least one iteration
337 while [ "X${resp}" != X"done" ]; do
338 cat << \__configurenetwork_1
339
340 You may configure the following network interfaces (the interfaces
341 marked with [X] have been succesfully configured):
342
343 __configurenetwork_1
344
345 for _ifs in $_IFS; do
346 if isin $_ifs $_ifsdone ; then
347 echo -n "[X] "
348 else
349 echo -n " "
350 fi
351 echo $_ifs
352 done
353 echo ""
354 echo -n "Configure which interface? [done] "
355 getresp "done"
356 case "$resp" in
357 "done")
358 ;;
359 *)
360 _ifs=$resp
361 if isin $_ifs $_IFS ; then
362 if configure_ifs $_ifs ; then
363 _ifsdone="$_ifs $_ifsdone"
364 fi
365 else
366 echo "Invalid response: \"$resp\" is not in list"
367 fi
368 ;;
369 esac
370 done
371 }
372
373 configure_ifs() {
374
375 local _up
376 local _interface_name
377 local _interface_ip
378 local _interface_mask
379 local _interface_symname
380 local _interface_extra
381 local _interface_mediumtype
382 local _interface_supported_media
383 local _m
384 local _t
385
386 _interface_name=$1
387 _up=DOWN
388 if isin $_interface_name `ifconfig -l -u` ; then
389 _up=UP
390 fi
391
392 _interface_supported_media=`ifconfig -m $_interface_name | sed -n '
393 /^[ ]*media autoselect/d
394 4,$s/[ ]*media //p'`
395
396 # get current "media" "ip" and "netmask" ("broadcast")
397 _t=`ifconfig $_interface_name | sed -n '
398 s/^[ ]*media: [^ ]* \([^ ][^ ]*\).*/\1/p'`
399
400 if [ "$_t" != "manual" -a "$_t" != "media:" -a "$_t" != "autoselect" ];
401 then
402 _interface_mediumtype=$1
403 fi
404
405 set -- `ifconfig $_interface_name | sed -n '
406 /^[ ]*inet/{
407 s/inet//
408 s/--> [0-9.][0-9.]*//
409 s/netmask//
410 s/broadcast//
411 p;}'`
412
413 _interface_ip=$1
414 _interface_mask=$2
415
416 # Get IP address
417 resp="" # force one iteration
418 while [ "X${resp}" = X"" ]; do
419 echo -n "IP address? [$_interface_ip] "
420 getresp "$_interface_ip"
421 _interface_ip=$resp
422 done
423
424 # Get symbolic name
425 resp="" # force one iteration
426 while [ "X${resp}" = X"" ]; do
427 echo -n "Symbolic (host) name? "
428 getresp ""
429 _interface_symname=$resp
430 done
431
432 # Get netmask
433 resp="" # force one iteration
434 while [ "X${resp}" = X"" ]; do
435 echo -n "Netmask? [$_interface_mask] "
436 getresp "$_interface_mask"
437 _interface_mask=$resp
438 done
439
440 echo "Your network interface might require explicit selection"
441 echo "of the type of network medium attached. Supported media:"
442 echo "$_interface_supported_media"
443 echo -n "Additional media type arguments (none)? [$_interface_mediumtype] "
444 getresp "$_interface_mediumtype"
445 _m=""
446 if [ "X${resp}" != X"" -a "X${resp}" != Xnone ]; then
447 _interface_mediumtype=$resp
448 _m="media ${resp}"
449 fi
450
451
452 echo "Your network interface might require additional link-layer"
453 echo "directives (like \`link0'). If this is the case you can enter"
454 echo "these at the next prompt."
455 echo ""
456 echo -n "Additional link-layer arguments (none)? [$_interface_extra] "
457 getresp "$_interface_extra"
458 if [ "X${resp}" != X"" -a "X${resp}" != Xnone ]; then
459 _interface_extra=$resp
460 fi
461
462 # Configure the interface. If it
463 # succeeds, add it to the permanent
464 # network configuration info.
465 if [ $_up != "UP" ]; then
466 ifconfig ${_interface_name} down
467 if ifconfig ${_interface_name} inet \
468 ${_interface_ip} \
469 netmask ${_interface_mask} \
470 ${_interface_extra} ${_m} up ; then
471 addifconfig \
472 "${_interface_name}" \
473 "${_interface_symname}" \
474 "${_interface_ip}" \
475 "${_interface_mask}" \
476 "${_interface_mediumtype}" \
477 "${_interface_extra}"
478 return 0
479 fi
480 else
481 echo "Interface ${_interface_name} is already active."
482 echo "Just saving configuration on new root filesystem."
483 addifconfig \
484 "${_interface_name}" \
485 "${_interface_symname}" \
486 "${_interface_ip}" \
487 "${_interface_mask}" \
488 "${_interface_mediumtype}" \
489 "${_interface_extra}"
490 fi
491 return 1
492 }
493
494 # Much of this is gratuitously stolen from /etc/netstart.
495 enable_network() {
496
497 # Set up the hostname.
498 if [ ! -f /mnt/etc/myname ]; then
499 echo "ERROR: no /etc/myname!"
500 return 1
501 fi
502 hostname=`cat /mnt/etc/myname`
503 hostname $hostname
504
505 # configure all the interfaces which we know about.
506 if [ -f /mnt/etc/rc.conf ]; then
507 (
508 # assume network interface configuration style 1.2D and up
509 . /mnt/etc/rc.conf
510
511 if [ "$net_interfaces" != NO ]; then
512 if [ "$auto_ifconfig" = YES ]; then
513 tmp="`ifconfig -l`"
514 else
515 tmp="$net_interfaces"
516 fi
517 echo -n "configuring network interfaces:"
518 for i in $tmp; do
519 eval `echo 'args=$ifconfig_'$i`
520 if [ ! -z "$args" ]; then
521 echo -n " $i"
522 ifconfig $i $args
523 elif [ -f /mnt/etc/ifconfig.$i ]; then
524 echo -n " $i"
525 (while read args; do
526 ifconfig $i $args
527 done) < /mnt/etc/ifconfig.$i
528 elif [ "$auto_ifconfig" != YES ]; then
529 echo
530 echo -n "/mnt/etc/ifconfig.$i missing"
531 echo -n "& ifconfig_$i not set"
532 echo "; interface $i can't be configured"
533 fi
534 done
535 echo "."
536 fi
537 )
538 else
539 (
540 tmp="$IFS"
541 IFS="$IFS."
542 set -- `echo /mnt/etc/hostname*`
543 IFS=$tmp
544 unset tmp
545
546 while [ $# -ge 2 ] ; do
547 shift # get rid of "hostname"
548 (
549 read af name mask bcaddr extras
550 read dt dtaddr
551
552 if [ ! -n "$name" ]; then
553 echo "/etc/hostname.$1: invalid network configuration file"
554 exit
555 fi
556
557 cmd="ifconfig $1 $af $name "
558 if [ "${dt}" = "dest" ]; then cmd="$cmd $dtaddr"; fi
559 if [ -n "$mask" ]; then cmd="$cmd netmask $mask"; fi
560 if [ -n "$bcaddr" -a "X$bcaddr" != "XNONE" ]; then
561 cmd="$cmd broadcast $bcaddr";
562 fi
563 cmd="$cmd $extras"
564
565 $cmd
566 ) < /mnt/etc/hostname.$1
567 shift
568 done
569 )
570 fi
571
572 # set the address for the loopback interface
573 ifconfig lo0 inet localhost
574
575 # use loopback, not the wire
576 route add $hostname localhost
577
578 # /etc/mygate, if it exists, contains the name of my gateway host
579 # that name must be in /etc/hosts.
580 if [ -f /mnt/etc/mygate ]; then
581 route delete default > /dev/null 2>&1
582 route add default `cat /mnt/etc/mygate`
583 fi
584
585 # enable the resolver, if appropriate.
586 if [ -f /mnt/etc/resolv.conf ]; then
587 _resolver_enabled="TRUE"
588 cp /mnt/etc/resolv.conf /tmp/resolv.conf.shadow
589 fi
590
591 # Display results...
592 echo "Network interface configuration:"
593 ifconfig -a
594
595 echo ""
596
597 if [ "X${_resolver_enabled}" = X"TRUE" ]; then
598 netstat -r
599 echo ""
600 echo "Resolver enabled."
601 else
602 netstat -rn
603 echo ""
604 echo "Resolver not enabled."
605 fi
606
607 return 0
608 }
609
610 install_ftp() {
611 local _f
612 local _sets
613 local _next
614
615 # Build a script to extract valid files from a list
616 # of filenames on stdin.
617 # XXX : Can we use this on more places? Leo.
618
619 echo "#!/bin/sh" > /tmp/fname_filter.sh
620 echo "while read line; do" >> /tmp/fname_filter.sh
621 echo " case \$line in" >> /tmp/fname_filter.sh
622 for _f in $THESETS; do
623 echo " $_f.tar.gz|$_f.tgz|$_f.${VERSION}.aa)" \
624 >> /tmp/fname_filter.sh
625 echo ' echo -n "$line ";;' \
626 >> /tmp/fname_filter.sh
627 done
628 echo " *) ;;" >> /tmp/fname_filter.sh
629 echo " esac" >> /tmp/fname_filter.sh
630 echo "done" >> /tmp/fname_filter.sh
631
632 # Get several parameters from the user, and create
633 # a shell script that directs the appropriate
634 # commands into ftp.
635 cat << \__install_ftp_1
636
637 This is an automated ftp-based installation process. You will be asked
638 several questions. The correct set of commands will be placed in a script
639 that will be fed to ftp(1).
640
641 __install_ftp_1
642 # Get server IP address
643 resp="" # force one iteration
644 while [ "X${resp}" = X"" ]; do
645 echo -n "Server IP? [${_ftp_server_ip}] "
646 getresp "${_ftp_server_ip}"
647 _ftp_server_ip=$resp
648 done
649
650 # Get login name
651 resp="" # force one iteration
652 while [ "X${resp}" = X"" ]; do
653 echo -n "Login? [${_ftp_server_login}] "
654 getresp "${_ftp_server_login}"
655 _ftp_server_login=$resp
656 done
657
658 # Get password
659 resp="" # force one iteration
660 while [ "X${resp}" = X"" ]; do
661 echo -n "Password? "
662 stty -echo
663 getresp ""
664 echo ""
665 stty echo
666 _ftp_server_password=$resp
667 done
668
669 cat << \__install_ftp_2
670
671 You will be asked to enter the name of the directory that contains the
672 installation sets. When you enter a '?' you will see a listing of the
673 current directory on the server.
674 __install_ftp_2
675 _sets=""
676 while [ -z "$_sets" ]
677 do
678 resp="" # force one iteration
679 while [ "X${resp}" = X"" ]; do
680 echo -n "Server directory? [${_ftp_server_dir}] "
681 getresp "${_ftp_server_dir}"
682 if [ "X$resp" = 'X?' -a -z "$_ftp_server_dir" ]; then
683 resp=""
684 fi
685 done
686 if [ $resp != '?' ]; then
687 _ftp_server_dir=$resp
688 fi
689
690 # Build the basics of an ftp-script...
691 echo "#!/bin/sh" > /tmp/ftp-script.sh
692 echo "cd /mnt" >> /tmp/ftp-script.sh
693 echo "ftp -e -i -n $_ftp_server_ip << \__end_commands" >> \
694 /tmp/ftp-script.sh
695 echo "user $_ftp_server_login $_ftp_server_password" >> \
696 /tmp/ftp-script.sh
697 echo "bin" >> /tmp/ftp-script.sh
698 echo "cd $_ftp_server_dir" >> /tmp/ftp-script.sh
699
700 # Make a copy of this script that lists the directory
701 # contents, and use that to determine the files to get.
702 cat /tmp/ftp-script.sh > /tmp/ftp-dir.sh
703 echo "ls" >> /tmp/ftp-dir.sh
704 echo "quit" >> /tmp/ftp-dir.sh
705 echo "__end_commands" >> /tmp/ftp-dir.sh
706
707 if [ $resp = '?' ]; then
708 sh /tmp/ftp-dir.sh
709 else
710 _sets=`sh /tmp/ftp-dir.sh | sh /tmp/fname_filter.sh`
711 fi
712 done
713 rm -f /tmp/ftp-dir.sh /tmp/fname_filter.sh
714
715 while : ; do
716 echo "The following sets are available for extraction:"
717 echo "(marked sets are already on the extraction list)"
718 echo ""
719
720 _next=""
721 for _f in $_sets ; do
722 if isin $_f $_setsdone; then
723 echo -n "[X] "
724 _next=""
725 else
726 echo -n " "
727 if [ -z "$_next" ]; then _next=$_f; fi
728 fi
729 echo $_f
730 done
731 echo ""
732
733 # Get name of the file and add extraction command
734 # to the ftp-script.
735 if [ "X$_next" = "X" ]; then resp=n; else resp=y; fi
736 echo -n "Continue to add filenames [$resp]? "
737 getresp "$resp"
738 if [ "$resp" = "n" ]; then
739 break
740 fi
741
742 echo -n "File name [$_next]? "
743 getresp "$_next"
744 if isin $resp $_sets; then
745 echo "get $resp |\"pax -zr${verbose_flag}pe\"" >> \
746 /tmp/ftp-script.sh
747 _setsdone="$resp $_setsdone"
748 else
749 echo "You entered an invalid filename."
750 echo ""
751 fi
752 done
753
754 echo "quit" >> /tmp/ftp-script.sh
755 echo "__end_commands" >> /tmp/ftp-script.sh
756
757 sh /tmp/ftp-script.sh
758 rm -f /tmp/ftp-script.sh
759 echo "Extraction complete."
760 }
761
762 install_from_mounted_fs() {
763 # $1 - directory containing installation sets
764 local _filename
765 local _sets
766 local _next
767 local _all
768 local _f
769 local _dirname
770
771 _dirname=$1
772 _sets=""
773
774 if ! dir_has_sets ${_dirname} $THESETS
775 then
776
777 echo ""
778 echo "The directory at the mount point, \"${_dirname}\", contains: "
779 echo ""
780 ls -F ${_dirname}
781 echo ""
782 echo "Enter the subdirectory relative to the mountpoint, that"
783 echo -n "contains the savesets: [try this directory] "
784 getresp ""
785 if [ "X${resp}" != "X" ]; then
786 _dirname=${_dirname}/$resp
787 fi
788
789 while ! dir_has_sets ${_dirname} $THESETS; do
790 echo ""
791 echo -n "There are no NetBSD install sets available in "
792 echo "\"${_dirname}\"."
793 echo "\"${_dirname}\" contains: "
794 echo ""
795 ls -F ${_dirname}
796 echo ""
797 echo -n "Enter subdirectory: [try other install media] "
798 getresp ""
799 if [ "X${resp}" = "X" ]; then
800 return
801 fi
802 if [ ! -d ${_dirname}/${resp} ]; then
803 echo "\"${resp}\" is no directory; try again."
804 else
805 _dirname=${_dirname}/$resp
806 fi
807 done
808 fi
809
810 for _f in $THESETS ; do
811 if [ -f ${_dirname}/${_f}.tar.gz ]; then
812 _sets="$_sets ${_f}.tar.gz"
813 elif [ -f ${_dirname}/${_f}.tgz ]; then
814 _sets="$_sets ${_f}.tgz"
815 elif [ -f ${_dirname}/${_f}${VERSION}.aa ]; then
816 _sets="$_sets ${_f}${VERSION}"
817 fi
818 done
819
820 while : ; do
821 echo "The following sets are available for extraction:"
822 echo "(marked sets have already been extracted)"
823 echo ""
824
825 _next=""
826 _all=""
827 for _f in $_sets ; do
828 if isin $_f $_setsdone; then
829 echo -n "[X] "
830 _next=""
831 else
832 echo -n " "
833 if [ -z "$_next" ]; then
834 _next=$_f;
835 fi
836 _all="$_all $_f"
837 fi
838 echo $_f
839 done
840 echo ""
841
842 # Get the name of the file.
843 if [ "X$_next" = "X" ]; then
844 resp=n
845 else
846 resp=y
847 fi
848 echo -n "Continue extraction [$resp]?"
849 getresp "$resp"
850 if [ "$resp" = "n" ]; then
851 break
852 fi
853
854 echo -n "File name(s) (or "all") [$_next]? "
855 getresp "$_next"
856 if [ "x$resp" = xall ]; then
857 resp="$_all"
858 fi
859
860 for _f in $resp; do
861 _filename="/${_dirname}/$_f"
862
863 # Ensure file exists
864 if [ ! -f $_filename ]; then
865 if [ -f ${_filename}.aa ]; then
866 _filename=${_filename}.\?\?
867 else
868 echo "File $_filename does not exist. Check to make"
869 echo "sure you entered the information properly."
870 continue 2
871 fi
872 fi
873
874 # Extract file
875 echo "Extracting the $_f set:"
876 cat $_filename | (cd /mnt; pax -zr${verbose_flag}pe)
877 echo "Extraction complete."
878 _setsdone="$_f $_setsdone"
879 done
880
881 done
882 }
883
884 install_cdrom() {
885 local _drive
886 local _partition_range
887 local _partition
888 local _fstype
889 local _directory
890
891 # Get the cdrom device info
892 cat << \__install_cdrom_1
893
894 The following CD-ROM devices are installed on your system; please select
895 the CD-ROM device containing the partition with the installation sets:
896
897 __install_cdrom_1
898 _CDDEVS=`md_get_cddevs`
899 echo "$_CDDEVS"
900 echo ""
901 echo -n "Which is the CD-ROM with the installation media? [abort] "
902 getresp "abort"
903 case "$resp" in
904 abort)
905 echo "Aborting."
906 return
907 ;;
908
909 *)
910 if isin $resp $_CDDEVS ; then
911 _drive=$resp
912 else
913 echo ""
914 echo "The CD-ROM $resp does not exist."
915 echo "Aborting."
916 return
917 fi
918 ;;
919 esac
920
921 # Get partition
922 _partition_range=`md_get_partition_range`
923 resp="" # force one iteration
924 while [ "X${resp}" = X"" ]; do
925 echo -n "Partition? [a] "
926 getresp "a"
927 case "$resp" in
928 $_partition_range)
929 _partition=$resp
930 ;;
931
932 *)
933 echo "Invalid response: $resp"
934 resp="" # force loop to repeat
935 ;;
936 esac
937 done
938
939 # Ask for filesystem type
940 cat << \__install_cdrom_2
941
942 There are two CD-ROM filesystem types currently supported by this program:
943 1) ISO-9660 (cd9660)
944 2) Berkeley Fast Filesystem (ffs)
945
946 __install_cdrom_2
947 resp="" # force one iteration
948 while [ "X${resp}" = X"" ]; do
949 echo -n "Which filesystem type? [cd9660] "
950 getresp "cd9660"
951 case "$resp" in
952 cd9660|ffs)
953 _fstype=$resp
954 ;;
955
956 *)
957 echo "Invalid response: $resp"
958 resp="" # force loop to repeat
959 ;;
960 esac
961 done
962
963 # Mount the CD-ROM
964 if ! mount -t ${_fstype} -o ro \
965 /dev/${_drive}${_partition} /mnt2 ; then
966 echo "Cannot mount CD-ROM drive. Aborting."
967 return
968 fi
969
970 install_from_mounted_fs /mnt2
971 umount -f /mnt2 > /dev/null 2>&1
972 }
973
974 mount_a_disk() {
975 # Mount a disk on /mnt2. The set of disk devices to choose from
976 # is $_DKDEVS.
977 # returns 0 on failure.
978
979 local _drive
980 local _partition_range
981 local _partition
982 local _fstype
983 local _fsopts
984 local _directory
985 local _md_fstype
986 local _md_fsopts
987
988 getresp "abort"
989 case "$resp" in
990 abort)
991 echo "Aborting."
992 return 0
993 ;;
994
995 *)
996 if isin $resp $_DKDEVS ; then
997 _drive=$resp
998 else
999 echo ""
1000 echo "The disk $resp does not exist."
1001 echo "Aborting."
1002 return 0
1003 fi
1004 ;;
1005 esac
1006
1007 # Get partition
1008 _partition_range=`md_get_partition_range`
1009 resp="" # force one iteration
1010 while [ "X${resp}" = X"" ]; do
1011 echo -n "Partition? [d] "
1012 getresp "d"
1013 case "$resp" in
1014 $_partition_range)
1015 _partition=$resp
1016 ;;
1017
1018 *)
1019 echo "Invalid response: $resp"
1020 resp="" # force loop to repeat
1021 ;;
1022 esac
1023 done
1024
1025 # Ask for filesystem type
1026 cat << \__mount_a_disk_2
1027
1028 The following filesystem types are supported:
1029 1) ffs
1030 __mount_a_disk_2
1031 _md_fstype=`md_native_fstype`
1032 _md_fsopts=`md_native_fsopts`
1033 if [ ! -z "$_md_fstype" ]; then
1034 echo " 2) $_md_fstype"
1035 else
1036 _md_fstype="_undefined_"
1037 fi
1038 resp="" # force one iteration
1039 while [ "X${resp}" = X"" ]; do
1040 echo -n "Which filesystem type? [ffs] "
1041 getresp "ffs"
1042 case "$resp" in
1043 ffs)
1044 _fstype=$resp
1045 _fsopts="ro"
1046 ;;
1047 $_md_fstype)
1048 _fstype=$resp
1049 _fsopts=$_md_fsopts
1050 ;;
1051 *)
1052 echo "Invalid response: $resp"
1053 resp="" # force loop to repeat
1054 ;;
1055 esac
1056 done
1057
1058 # Mount the disk
1059 if ! mount -t ${_fstype} -o $_fsopts \
1060 /dev/${_drive}${_partition} /mnt2 ; then
1061 echo "Cannot mount disk. Aborting."
1062 return 0
1063 fi
1064 return 1
1065 }
1066
1067 install_disk() {
1068 local _directory
1069
1070 cat << \__install_disk_1
1071
1072 Ok, lets install from a disk. The file-system the install sets on may
1073 already mounted, or we might have to mount the filesystem to get to it.
1074
1075 __install_disk_1
1076
1077 echo -n "Is the file-system with the install sets already mounted? [n] "
1078 getresp "n"
1079 case $resp in
1080 y*|Y*)
1081 echo "What mount point are the sets located in? [] "
1082 getresp ""
1083 if [ -d "$resp" ]; then
1084 install_from_mounted_fs $resp
1085 else
1086 echo "$resp: Not a directory, aborting..."
1087 fi
1088 return
1089 ;;
1090 *)
1091 ;;
1092 esac
1093
1094 cat << \__install_disk_2
1095
1096 The following disk devices are installed on your system; please select
1097 the disk device containing the partition with the installation sets:
1098
1099 __install_disk_2
1100 _DKDEVS=`md_get_diskdevs`
1101 echo "$_DKDEVS"
1102 echo ""
1103 echo -n "Which is the disk with the installation sets? [abort] "
1104
1105 if mount_a_disk ; then
1106 return
1107 fi
1108
1109 install_from_mounted_fs /mnt2
1110 umount -f /mnt2 > /dev/null 2>&1
1111 }
1112
1113 install_nfs() {
1114 # Get the IP address of the server
1115 resp="" # force one iteration
1116 while [ "X${resp}" = X"" ]; do
1117 echo -n "Server IP address? [${_nfs_server_ip}] "
1118 getresp "${_nfs_server_ip}"
1119 done
1120 _nfs_server_ip=$resp
1121
1122 # Get server path to mount
1123 resp="" # force one iteration
1124 while [ "X${resp}" = X"" ]; do
1125 echo -n "Filesystem on server to mount? [${_nfs_server_path}] "
1126 getresp "${_nfs_server_path}"
1127 done
1128 _nfs_server_path=$resp
1129
1130 # Determine use of TCP
1131 echo -n "Use TCP transport (only works with capable NFS server)? [n] "
1132 getresp "n"
1133 case "$resp" in
1134 y*|Y*)
1135 _nfs_tcp="-T"
1136 ;;
1137
1138 *)
1139 _nfs_tcp=""
1140 ;;
1141 esac
1142
1143 # Mount the server
1144 mkdir /mnt2 > /dev/null 2>&1
1145 if ! mount_nfs $_nfs_tcp ${_nfs_server_ip}:${_nfs_server_path} \
1146 /mnt2 ; then
1147 echo "Cannot mount NFS server. Aborting."
1148 return
1149 fi
1150
1151 install_from_mounted_fs /mnt2
1152 umount -f /mnt2 > /dev/null 2>&1
1153 }
1154
1155 install_tape() {
1156 local _xcmd
1157
1158 # Get the name of the tape from the user.
1159 cat << \__install_tape_1
1160
1161 The installation program needs to know which tape device to use. Make
1162 sure you use a "no rewind on close" device.
1163
1164 __install_tape_1
1165 _tape=`basename $TAPE`
1166 resp="" # force one iteration
1167 while [ "X${resp}" = X"" ]; do
1168 echo -n "Name of tape device? [${_tape}]"
1169 getresp "${_tape}"
1170 done
1171 _tape=`basename $resp`
1172 TAPE="/dev/${_tape}"
1173 if [ ! -c $TAPE ]; then
1174 echo "$TAPE does not exist or is not a character special file."
1175 echo "Aborting."
1176 return
1177 fi
1178 export TAPE
1179
1180 # Rewind the tape device
1181 echo -n "Rewinding tape..."
1182 if ! mt rewind ; then
1183 echo "$TAPE may not be attached to the system or may not be"
1184 echo "a tape device. Aborting."
1185 return
1186 fi
1187 echo "done."
1188
1189 # Get the file number
1190 resp="" # force one iteration
1191 while [ "X${resp}" = X"" ]; do
1192 echo -n "File number? "
1193 getresp ""
1194 case "$resp" in
1195 [1-9]*)
1196 _nskip=`expr $resp - 1`
1197 ;;
1198
1199 *)
1200 echo "Invalid file number ${resp}."
1201 resp="" # fore loop to repeat
1202 ;;
1203 esac
1204 done
1205
1206 # Skip to correct file.
1207 echo -n "Skipping to source file..."
1208 if [ "X${_nskip}" != X"0" ]; then
1209 if ! mt fsf $_nskip ; then
1210 echo "Could not skip $_nskip files. Aborting."
1211 return
1212 fi
1213 fi
1214 echo "done."
1215
1216 cat << \__install_tape_2
1217
1218 There are 2 different ways the file can be stored on tape:
1219
1220 1) an image of a gzipped tar file
1221 2) a standard tar image
1222
1223 __install_tape_2
1224 resp="" # force one iteration
1225 while [ "X${resp}" = X"" ]; do
1226 echo -n "Which way is it? [1] "
1227 getresp "1"
1228 case "$resp" in
1229 1)
1230 _xcmd="pax -zr${verbose_flag}pe"
1231 ;;
1232
1233 2)
1234 _xcmd="pax -r${verbose_flag}pe"
1235 ;;
1236
1237 *)
1238 echo "Invalid response: $resp."
1239 resp="" # force loop to repeat
1240 ;;
1241 esac
1242 ( cd /mnt; dd if=$TAPE | $_xcmd )
1243 done
1244 echo "Extraction complete."
1245 }
1246
1247 get_timezone() {
1248 local _a
1249 local _zonepath
1250
1251 #
1252 # If the zoneinfo is not on the installation medium or on the
1253 # installed filesystem, set TZ to GMT and return immediatly.
1254 #
1255 if [ ! -e /usr/share/zoneinfo -a ! -e /mnt/usr/share/zoneinfo ]; then
1256 TZ=GMT
1257 return
1258 fi
1259 if [ ! -d /usr/share/zoneinfo ]; then
1260 _zonepath=/mnt
1261 else
1262 _zonepath=""
1263 fi
1264
1265 cat << \__get_timezone_1
1266
1267 Select a time zone for your location. Timezones are represented on the
1268 system by a directory structure rooted in "/usr/share/timezone". Most
1269 timezones can be selected by entering a token like "MET" or "GMT-6".
1270 Other zones are grouped by continent, with detailed zone information
1271 separated by a slash ("/"), e.g. "US/Pacific".
1272
1273 To get a listing of what's available in /usr/share/zoneinfo, enter "?"
1274 at the prompts below.
1275
1276 __get_timezone_1
1277 if [ X$TZ = X ]; then
1278 TZ=`ls -l /mnt/etc/localtime 2>/dev/null | cutlast`
1279 TZ=${TZ#/usr/share/zoneinfo/}
1280 fi
1281 while :; do
1282 echo -n "What timezone are you in [\`?' for list] [$TZ]? "
1283 getresp "$TZ"
1284 case "$resp" in
1285 "")
1286 echo "Timezone defaults to GMT"
1287 TZ="GMT"
1288 break;
1289 ;;
1290 "?")
1291 ls ${_zonepath}/usr/share/zoneinfo
1292 ;;
1293 *)
1294 _a=$resp
1295 while [ -d ${_zonepath}/usr/share/zoneinfo/$_a ]; do
1296 echo -n "There are several timezones available"
1297 echo " within zone '$_a'"
1298 echo -n "Select a sub-timezone [\`?' for list]: "
1299 getresp ""
1300 case "$resp" in
1301 "?") ls ${_zonepath}/usr/share/zoneinfo/$_a ;;
1302 *) _a=${_a}/${resp}
1303 if [ -f ${_zonepath}/usr/share/zoneinfo/$_a ]; then
1304 break;
1305 fi
1306 ;;
1307 esac
1308 done
1309 if [ -f ${_zonepath}/usr/share/zoneinfo/$_a ]; then
1310 TZ="$_a"
1311 echo "You have selected timezone \"$_a\"".
1312 break 2
1313 fi
1314 echo "'/usr/share/zoneinfo/$_a' is not a valid timezone on this system."
1315 ;;
1316 esac
1317 done
1318 }
1319
1320 install_sets()
1321 {
1322 local _yup
1323 _yup="FALSE"
1324
1325 # Ask the user which media to load the distribution from.
1326 # Ask the user if they want verbose extraction. They might not want
1327 # it on, eg, SPARC frame buffer console.
1328 cat << \__install_sets_1
1329
1330 It is now time to extract the installation sets onto the hard disk.
1331 Make sure the sets are either on a local device (i.e. tape, CD-ROM) or on a
1332 network server.
1333
1334 Would you like to see each file listed during extraction (verbose) mode?
1335 On some console hardware, such as serial consoles and Sun frame buffers,
1336 this can extend the total extraction time.
1337 __install_sets_1
1338 echo -n "Use verbose listing for extractions? [y] "
1339 getresp "y"
1340 case "$resp" in
1341 y*|Y*)
1342 verbose_flag=v
1343 ;;
1344 *)
1345 echo "Not using verbose listing.."
1346 verbose_flag=""
1347 ;;
1348 esac
1349
1350 if [ -d ${Default_sets_dir:-/dev/null} ]; then
1351 if dir_has_sets $Default_sets_dir $THESETS; then
1352 local_sets_dir=$Default_sets_dir
1353 fi
1354 fi
1355 if [ "X$local_sets_dir" != "X" ]; then
1356 install_from_mounted_fs ${local_sets_dir}
1357 if [ X"$_setsdone" != X ]; then
1358 _yup="TRUE"
1359 fi
1360 fi
1361
1362 # Go on prodding for alternate locations
1363 resp="" # force at least one iteration
1364 while [ X"${resp}" = X ]; do
1365 # If _yup is not FALSE, it means that we extracted sets above.
1366 # If that's the case, bypass the menu the first time.
1367 if [ X"$_yup" = X"FALSE" ]; then
1368 echo -n "Install from (f)tp, (t)ape, (C)D-ROM, (N)FS"
1369 echo -n " or local (d)isk? "
1370 getresp ""
1371 case "$resp" in
1372 d*|D*)
1373 install_disk
1374 ;;
1375 f*|F*)
1376 install_ftp
1377 ;;
1378 t*|T*)
1379 install_tape
1380 ;;
1381 c*|C*)
1382 install_cdrom
1383 ;;
1384 n*|N*)
1385 install_nfs
1386 ;;
1387 *)
1388 echo "Invalid response: $resp"
1389 resp=""
1390 ;;
1391 esac
1392 else
1393 _yup="FALSE" # So we'll ask next time
1394 fi
1395
1396 # Give the user the opportunity to extract more sets. They
1397 # don't necessarily have to come from the same media.
1398 echo ""
1399 echo -n "Extract more sets? [n] "
1400 getresp "n"
1401 case "$resp" in
1402 y*|Y*)
1403 # Force loop to repeat
1404 resp=""
1405 ;;
1406
1407 *)
1408 ;;
1409 esac
1410 done
1411 }
1412
1413 munge_fstab()
1414 {
1415 local _fstab
1416 local _fstab_shadow
1417 local _dev
1418 local _mp
1419 local _fstype
1420 local _rest
1421
1422 # Now that the 'real' fstab is configured, we munge it into a 'shadow'
1423 # fstab which we'll use for mounting and unmounting all of the target
1424 # filesystems relative to /mnt. Mount all filesystems.
1425 _fstab=$1
1426 _fstab_shadow=$2
1427 ( while read _dev _mp _fstype _rest; do
1428 # Skip comment lines
1429 case "$_dev" in
1430 \#*) continue;;
1431 *) ;;
1432 esac
1433 # and some filesystem types (like there are swap,kernfs,...)
1434 case "$_fstype" in
1435 ffs|ufs|nfs) ;;
1436 *) continue;;
1437 esac
1438 if [ "$_mp" = "/" ]; then
1439 echo $_dev /mnt $_fstype $_rest
1440 else
1441 echo $_dev /mnt$_mp $_fstype $_rest
1442 fi
1443 done ) < $_fstab > $_fstab_shadow
1444 }
1445
1446 mount_fs()
1447 {
1448 # Must mount filesystems manually, one at a time, so we can make
1449 # sure the mount points exist.
1450 # $1 is a file in fstab format
1451 local _fstab
1452
1453 _fstab=$1
1454
1455 ( while read line; do
1456 set -- $line
1457 _dev=$1
1458 _mp=$2
1459 _fstype=$3
1460 _opt=$4
1461
1462 # If not the root filesystem, make sure the mount
1463 # point is present.
1464 if [ "X{$_mp}" != X"/mnt" ]; then
1465 mkdir -p $_mp
1466 fi
1467
1468 # Mount the filesystem. If the mount fails, exit
1469 # with an error condition to tell the outer
1470 # later to bail.
1471 if ! mount -v -t $_fstype -o async -o $_opt $_dev $_mp ; then
1472 # error message displated by mount
1473 exit 1
1474 fi
1475 done ) < $_fstab
1476
1477 if [ "X${?}" != X"0" ]; then
1478 cat << \__mount_filesystems_1
1479
1480 FATAL ERROR: Cannot mount filesystems. Double-check your configuration
1481 and restart the installation process.
1482 __mount_filesystems_1
1483 exit
1484 fi
1485 }
1486
1487 unmount_fs()
1488 {
1489 # Unmount all filesystems and check their integrity.
1490 # Usage: [-fast] <fstab file>
1491 local _fast
1492 local _fstab
1493 local _pid
1494
1495 if [ "$1" = "-fast" ]; then
1496 _fast=1
1497 _fstab=$2
1498 else
1499 _fast=0
1500 _fstab=$1
1501 fi
1502
1503 if [ ! \( -f $_fstab -a -s $_fstab \) ]; then
1504 echo "fstab empty" > /dev/tty
1505 return
1506 fi
1507
1508 if [ $_fast = 0 ]; then
1509 echo -n "Syncing disks..."
1510 _pid=`twiddle`
1511 sync; sleep 4; sync; sleep 2; sync; sleep 2
1512 kill $_pid
1513 echo "done."
1514 fi
1515
1516 (
1517 _devs=""
1518 _mps=""
1519 # maintain reverse order
1520 while read line; do
1521 set -- $line
1522 _devs="$1 ${_devs}"
1523 _mps="$2 ${_mps}"
1524 done
1525 echo -n "Umounting filesystems... "
1526 for _mp in ${_mps}; do
1527 echo -n "${_mp} "
1528 umount ${_mp}
1529 done
1530 echo "Done."
1531
1532 if [ $_fast = 0 ]; then
1533 exit
1534 fi
1535 echo "Checking filesystem integrity..."
1536 for _dev in ${_devs}; do
1537 echo "${_dev}"
1538 fsck -f ${_dev}
1539 done
1540 echo "Done."
1541 ) < $_fstab
1542 }
1543
1544 check_fs()
1545 {
1546 # Check filesystem integrity.
1547 # $1 is a file in fstab format
1548 local _fstab
1549
1550 _fstab=$1
1551
1552 (
1553 _devs=""
1554 _mps=""
1555 while read line; do
1556 set -- $line
1557 _devs="$1 ${_devs}"
1558 _mps="$2 ${_mps}"
1559 done
1560
1561 echo "Checking filesystem integrity..."
1562 for _dev in ${_devs}; do
1563 echo "${_dev}"
1564 fsck -f ${_dev}
1565 done
1566 echo "Done."
1567 ) < $_fstab
1568 }
1569