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