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