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