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