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