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