install.sub revision 1.59 1 #!/bin/sh
2 # $NetBSD: install.sub,v 1.59 2020/12/12 05:23: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 rm -f /tmp/ftp-script.sh
729
730 # Prepare ftp-fetch script to fetch binary sets
731 _download_dir=INSTALL
732 _ftp_opts=""
733 _ftp_url="ftp://$_ftp_server_login:$_ftp_server_password@$_ftp_server_ip$_ftp_server_dir/"
734 echo "#!/bin/sh" > /tmp/ftp-fetch.sh
735 echo "cd /mnt" >> /tmp/ftp-fetch.sh
736 echo "mkdir -p $_download_dir" >> /tmp/ftp-fetch.sh
737
738 while : ; do
739 echo "The following sets are available for extraction:"
740 echo "(marked sets are already on the extraction list)"
741 echo ""
742
743 _next=""
744 for _f in $_sets ; do
745 if isin $_f $_setsdone; then
746 echo -n "[X] "
747 _next=""
748 else
749 echo -n " "
750 if [ -z "$_next" ]; then _next=$_f; fi
751 fi
752 echo $_f
753 done
754 echo ""
755
756 # Get name of the file and add extraction command
757 # to the ftp-fetch script.
758 if [ -z "$_next" ]; then resp=n; else resp=y; fi
759 echo -n "Continue to add filenames [$resp]? "
760 getresp "$resp"
761 if [ "$resp" = "n" ]; then
762 break
763 fi
764
765 echo -n "File name [$_next]? "
766 getresp "$_next"
767 if isin $resp $_sets; then
768 echo "echo Fetching $resp:" >> \
769 /tmp/ftp-fetch.sh
770 echo "ftp ${_ftp_opts} -o $_download_dir/$resp ${_ftp_url}$resp" >> \
771 /tmp/ftp-fetch.sh
772 echo "echo Extracting $resp:" >> \
773 /tmp/ftp-fetch.sh
774 echo "pax -zr${verbose_flag}pe -f $_download_dir/$resp" >> \
775 /tmp/ftp-fetch.sh
776 echo "rm -f $_download_dir/$resp" >> \
777 /tmp/ftp-fetch.sh
778 _setsdone="$resp $_setsdone"
779 else
780 echo "You entered an invalid filename."
781 echo ""
782 fi
783 done
784
785 sh /tmp/ftp-fetch.sh
786 rm -f /tmp/ftp-fetch.sh
787 echo "Extraction complete."
788 }
789
790 install_from_mounted_fs() {
791 # $1 - directory containing installation sets
792 local _filename
793 local _sets
794 local _next
795 local _all
796 local _f
797 local _dirname
798
799 _dirname=$1
800 _sets=""
801
802 if ! dir_has_sets ${_dirname} $THESETS
803 then
804
805 echo ""
806 echo "The directory at the mount point, \"${_dirname}\", contains: "
807 echo ""
808 ls -F ${_dirname}
809 echo ""
810 echo "Enter the subdirectory relative to the mountpoint, that"
811 echo -n "contains the savesets: [try this directory] "
812 getresp ""
813 if [ -n "${resp}" ]; then
814 _dirname=${_dirname}/$resp
815 fi
816
817 while ! dir_has_sets ${_dirname} $THESETS; do
818 echo ""
819 echo -n "There are no NetBSD install sets available in "
820 echo "\"${_dirname}\"."
821 echo "\"${_dirname}\" contains: "
822 echo ""
823 ls -F ${_dirname}
824 echo ""
825 echo -n "Enter subdirectory: [try other install media] "
826 getresp ""
827 if [ -z "${resp}" ]; then
828 return
829 fi
830 if [ ! -d ${_dirname}/${resp} ]; then
831 echo "\"${resp}\" is no directory; try again."
832 else
833 _dirname=${_dirname}/$resp
834 fi
835 done
836 fi
837
838 for _f in $THESETS ; do
839 if [ -f ${_dirname}/${_f}.tar.gz ]; then
840 _sets="$_sets ${_f}.tar.gz"
841 elif [ -f ${_dirname}/${_f}.tgz ]; then
842 _sets="$_sets ${_f}.tgz"
843 elif [ -f ${_dirname}/${_f}.tar ]; then
844 _sets="$_sets ${_f}.tar"
845 elif [ -f ${_dirname}/${_f}${VERSION}.aa ]; then
846 _sets="$_sets ${_f}${VERSION}"
847 fi
848 done
849
850 while : ; do
851 echo "The following sets are available for extraction:"
852 echo "(marked sets have already been extracted)"
853 echo ""
854
855 _next=""
856 _all=""
857 for _f in $_sets ; do
858 if isin $_f $_setsdone; then
859 echo -n "[X] "
860 _next=""
861 else
862 echo -n " "
863 if [ -z "$_next" ]; then
864 _next=$_f;
865 fi
866 _all="$_all $_f"
867 fi
868 echo $_f
869 done
870 echo ""
871
872 # Get the name of the file.
873 if [ -z "$_next" ]; then
874 resp=n
875 else
876 resp=y
877 fi
878 echo -n "Continue extraction [$resp]?"
879 getresp "$resp"
880 if [ "$resp" = "n" ]; then
881 break
882 fi
883
884 echo -n "File name(s) (or "all") [$_next]? "
885 getresp "$_next"
886 if [ "x$resp" = xall ]; then
887 resp="$_all"
888 fi
889
890 for _f in $resp; do
891 _filename="/${_dirname}/$_f"
892
893 # Ensure file exists
894 if [ ! -f $_filename ]; then
895 if [ -f ${_filename}.aa ]; then
896 _filename=${_filename}.\?\?
897 else
898 echo "File $_filename does not exist. Check to make"
899 echo "sure you entered the information properly."
900 continue 2
901 fi
902 fi
903
904 # Extract file
905 echo "Extracting the $_f set:"
906 case "$_filename" in
907 *.tar)
908 (cd /mnt; pax -r${verbose_flag}pe < $_filename)
909 ;;
910 *)
911 cat $_filename | \
912 (cd /mnt; pax -zr${verbose_flag}pe)
913 ;;
914 esac
915 echo "Extraction complete."
916 _setsdone="$_f $_setsdone"
917 done
918
919 done
920 }
921
922 install_cdrom() {
923 local _drive
924 local _partition_range
925 local _partition
926 local _fstype
927 local _directory
928
929 # Get the cdrom device info
930 cat << \__install_cdrom_1
931
932 The following CD-ROM devices are installed on your system; please select
933 the CD-ROM device containing the partition with the installation sets:
934
935 __install_cdrom_1
936 _CDDEVS=$(md_get_cddevs)
937 echo "$_CDDEVS"
938 echo ""
939 echo -n "Which is the CD-ROM with the installation media? [abort] "
940 getresp "abort"
941 case "$resp" in
942 abort)
943 echo "Aborting."
944 return
945 ;;
946
947 *)
948 if isin $resp $_CDDEVS ; then
949 _drive=$resp
950 else
951 echo ""
952 echo "The CD-ROM $resp does not exist."
953 echo "Aborting."
954 return
955 fi
956 ;;
957 esac
958
959 # Get partition
960 _partition_range=$(md_get_partition_range)
961 resp="" # force one iteration
962 while [ -z "${resp}" ]; do
963 echo -n "Partition? [a] "
964 getresp "a"
965 case "$resp" in
966 $_partition_range)
967 _partition=$resp
968 ;;
969
970 *)
971 echo "Invalid response: $resp"
972 resp="" # force loop to repeat
973 ;;
974 esac
975 done
976
977 # Ask for filesystem type
978 cat << \__install_cdrom_2
979
980 There are two CD-ROM filesystem types currently supported by this program:
981 1) ISO-9660 (cd9660)
982 2) Berkeley Fast Filesystem (ffs)
983
984 __install_cdrom_2
985 resp="" # force one iteration
986 while [ -z "${resp}" ]; do
987 echo -n "Which filesystem type? [cd9660] "
988 getresp "cd9660"
989 case "$resp" in
990 cd9660|ffs)
991 _fstype=$resp
992 ;;
993
994 *)
995 echo "Invalid response: $resp"
996 resp="" # force loop to repeat
997 ;;
998 esac
999 done
1000
1001 # Mount the CD-ROM
1002 if ! mount -t ${_fstype} -o ro \
1003 /dev/${_drive}${_partition} /mnt2 ; then
1004 echo "Cannot mount CD-ROM drive. Aborting."
1005 return
1006 fi
1007
1008 install_from_mounted_fs /mnt2
1009 umount -f /mnt2 > /dev/null 2>&1
1010 }
1011
1012 mount_a_disk() {
1013 # Mount a disk on /mnt2. The set of disk devices to choose from
1014 # is $_DKDEVS.
1015 # returns 0 on failure.
1016
1017 local _drive
1018 local _partition_range
1019 local _partition
1020 local _fstype
1021 local _fsopts
1022 local _directory
1023 local _md_fstype
1024 local _md_fsopts
1025
1026 getresp "abort"
1027 case "$resp" in
1028 abort)
1029 echo "Aborting."
1030 return 0
1031 ;;
1032
1033 *)
1034 if isin $resp $_DKDEVS ; then
1035 _drive=$resp
1036 else
1037 echo ""
1038 echo "The disk $resp does not exist."
1039 echo "Aborting."
1040 return 0
1041 fi
1042 ;;
1043 esac
1044
1045 # Get partition
1046 _partition_range=$(md_get_partition_range)
1047 resp="" # force one iteration
1048 while [ -z "${resp}" ]; do
1049 echo -n "Partition? [d] "
1050 getresp "d"
1051 case "$resp" in
1052 $_partition_range)
1053 _partition=$resp
1054 ;;
1055
1056 *)
1057 echo "Invalid response: $resp"
1058 resp="" # force loop to repeat
1059 ;;
1060 esac
1061 done
1062
1063 # Ask for filesystem type
1064 cat << \__mount_a_disk_2
1065
1066 The following filesystem types are supported:
1067 1) ffs
1068 2) cd9660
1069 __mount_a_disk_2
1070 _md_fstype=$(md_native_fstype)
1071 _md_fsopts=$(md_native_fsopts)
1072 if [ -n "$_md_fstype" ]; then
1073 echo " 3) $_md_fstype"
1074 else
1075 _md_fstype="_undefined_"
1076 fi
1077 resp="" # force one iteration
1078 while [ -z "${resp}" ]; do
1079 echo -n "Which filesystem type? [ffs] "
1080 getresp "ffs"
1081 case "$resp" in
1082 ffs|cd9660)
1083 _fstype=$resp
1084 _fsopts="ro"
1085 ;;
1086 $_md_fstype)
1087 _fstype=$resp
1088 _fsopts=$_md_fsopts
1089 ;;
1090 *)
1091 echo "Invalid response: $resp"
1092 resp="" # force loop to repeat
1093 ;;
1094 esac
1095 done
1096
1097 # Mount the disk
1098 if ! mount -t ${_fstype} -o $_fsopts \
1099 /dev/${_drive}${_partition} /mnt2 ; then
1100 echo "Cannot mount disk. Aborting."
1101 return 0
1102 fi
1103 return 1
1104 }
1105
1106 install_disk() {
1107 local _directory
1108
1109 cat << \__install_disk_1
1110
1111 Ok, lets install from a disk. The file-system the install sets on may
1112 already mounted, or we might have to mount the filesystem to get to it.
1113
1114 __install_disk_1
1115
1116 echo -n "Is the file-system with the install sets already mounted? [n] "
1117 getresp "n"
1118 case $resp in
1119 y*|Y*)
1120 echo "What mount point are the sets located in? [] "
1121 getresp ""
1122 if [ -d "$resp" ]; then
1123 install_from_mounted_fs $resp
1124 else
1125 echo "$resp: Not a directory, aborting..."
1126 fi
1127 return
1128 ;;
1129 *)
1130 ;;
1131 esac
1132
1133 cat << \__install_disk_2
1134
1135 The following disk devices are installed on your system; please select
1136 the disk device containing the partition with the installation sets:
1137
1138 __install_disk_2
1139 _DKDEVS=$(md_get_diskdevs)
1140 echo "$_DKDEVS"
1141 echo ""
1142 echo -n "Which is the disk with the installation sets? [abort] "
1143
1144 if mount_a_disk ; then
1145 return
1146 fi
1147
1148 install_from_mounted_fs /mnt2
1149 umount -f /mnt2 > /dev/null 2>&1
1150 }
1151
1152 install_nfs() {
1153 # Get the IP address of the server
1154 resp="" # force one iteration
1155 while [ -z "${resp}" ]; do
1156 echo -n "Server IP address? [${_nfs_server_ip}] "
1157 getresp "${_nfs_server_ip}"
1158 done
1159 _nfs_server_ip=$resp
1160
1161 # Get server path to mount
1162 resp="" # force one iteration
1163 while [ -z "${resp}" ]; do
1164 echo -n "Filesystem on server to mount? [${_nfs_server_path}] "
1165 getresp "${_nfs_server_path}"
1166 done
1167 _nfs_server_path=$resp
1168
1169 # Determine use of TCP
1170 echo -n "Use TCP transport (only works with capable NFS server)? [n] "
1171 getresp "n"
1172 case "$resp" in
1173 y*|Y*)
1174 _nfs_tcp="-T"
1175 ;;
1176
1177 *)
1178 echo -n "Use small NFS transfers (needed when server "
1179 echo "or client"
1180 echo -n "has a slow network card)? [n] "
1181 getresp "n"
1182 case "$resp" in
1183 y*|Y*)
1184 _nfs_tcp="-r 1024 -w 1024"
1185 ;;
1186
1187 *)
1188 _nfs_tcp=""
1189 ;;
1190 esac
1191 ;;
1192 esac
1193
1194 # Mount the server
1195 mkdir /mnt2 > /dev/null 2>&1
1196 if ! mount_nfs $_nfs_tcp ${_nfs_server_ip}:${_nfs_server_path} \
1197 /mnt2 ; then
1198 echo "Cannot mount NFS server. Aborting."
1199 return
1200 fi
1201
1202 install_from_mounted_fs /mnt2
1203 umount -f /mnt2 > /dev/null 2>&1
1204 }
1205
1206 install_tape() {
1207 local _xcmd
1208
1209 # Get the name of the tape from the user.
1210 cat << \__install_tape_1
1211
1212 The installation program needs to know which tape device to use. Make
1213 sure you use a "no rewind on close" device.
1214
1215 __install_tape_1
1216 _tape=$(basename $TAPE)
1217 resp="" # force one iteration
1218 while [ -z "${resp}" ]; do
1219 echo -n "Name of tape device? [${_tape}]"
1220 getresp "${_tape}"
1221 done
1222 _tape=$(basename $resp)
1223 TAPE="/dev/${_tape}"
1224 if [ ! -c $TAPE ]; then
1225 echo "$TAPE does not exist or is not a character special file."
1226 echo "Aborting."
1227 return
1228 fi
1229 export TAPE
1230
1231 # Rewind the tape device
1232 echo -n "Rewinding tape..."
1233 if ! mt rewind ; then
1234 echo "$TAPE may not be attached to the system or may not be"
1235 echo "a tape device. Aborting."
1236 return
1237 fi
1238 echo "done."
1239
1240 # Get the file number
1241 resp="" # force one iteration
1242 while [ -z "${resp}" ]; do
1243 echo -n "File number? "
1244 getresp ""
1245 case "$resp" in
1246 [1-9]*)
1247 _nskip=$(expr $resp - 1)
1248 ;;
1249
1250 *)
1251 echo "Invalid file number ${resp}."
1252 resp="" # fore loop to repeat
1253 ;;
1254 esac
1255 done
1256
1257 # Skip to correct file.
1258 echo -n "Skipping to source file..."
1259 if [ "${_nskip}" != "0" ]; then
1260 if ! mt fsf $_nskip ; then
1261 echo "Could not skip $_nskip files. Aborting."
1262 return
1263 fi
1264 fi
1265 echo "done."
1266
1267 cat << \__install_tape_2
1268
1269 There are 2 different ways the file can be stored on tape:
1270
1271 1) an image of a gzipped tar file
1272 2) a standard tar image
1273
1274 __install_tape_2
1275 resp="" # force one iteration
1276 while [ -z "${resp}" ]; do
1277 echo -n "Which way is it? [1] "
1278 getresp "1"
1279 case "$resp" in
1280 1)
1281 _xcmd="pax -zr${verbose_flag}pe"
1282 ;;
1283
1284 2)
1285 _xcmd="pax -r${verbose_flag}pe"
1286 ;;
1287
1288 *)
1289 echo "Invalid response: $resp."
1290 resp="" # force loop to repeat
1291 ;;
1292 esac
1293 ( cd /mnt; dd if=$TAPE | $_xcmd )
1294 done
1295 echo "Extraction complete."
1296 }
1297
1298 get_timezone() {
1299 local _a
1300 local _zonepath
1301
1302 #
1303 # If the zoneinfo is not on the installation medium or on the
1304 # installed filesystem, set TZ to GMT and return immediatly.
1305 #
1306 if [ ! -e /usr/share/zoneinfo ] && [ ! -e /mnt/usr/share/zoneinfo ]; then
1307 TZ=GMT
1308 return
1309 fi
1310 if [ ! -d /usr/share/zoneinfo ]; then
1311 _zonepath=/mnt
1312 else
1313 _zonepath=""
1314 fi
1315
1316 cat << \__get_timezone_1
1317
1318 Select a time zone for your location. Timezones are represented on the
1319 system by a directory structure rooted in "/usr/share/zoneinfo". Most
1320 timezones can be selected by entering a token like "MET" or "GMT-6".
1321 Other zones are grouped by continent, with detailed zone information
1322 separated by a slash ("/"), e.g. "US/Pacific".
1323
1324 To get a listing of what's available in /usr/share/zoneinfo, enter "?"
1325 at the prompts below.
1326
1327 __get_timezone_1
1328 if [ -z "$TZ" ]; then
1329 TZ=$(ls -l /mnt/etc/localtime 2>/dev/null | cutlast)
1330 TZ=${TZ#/usr/share/zoneinfo/}
1331 fi
1332 while :; do
1333 echo -n "What timezone are you in ['?' for list] [$TZ]? "
1334 getresp "$TZ"
1335 case "$resp" in
1336 "")
1337 echo "Timezone defaults to GMT"
1338 TZ="GMT"
1339 break;
1340 ;;
1341 "?")
1342 ls ${_zonepath}/usr/share/zoneinfo
1343 ;;
1344 *)
1345 _a=$resp
1346 while [ -d ${_zonepath}/usr/share/zoneinfo/$_a ]; do
1347 echo -n "There are several timezones available"
1348 echo " within zone '$_a'"
1349 echo -n "Select a sub-timezone ['?' for list]: "
1350 getresp ""
1351 case "$resp" in
1352 "?") ls ${_zonepath}/usr/share/zoneinfo/$_a ;;
1353 *) _a=${_a}/${resp}
1354 if [ -f ${_zonepath}/usr/share/zoneinfo/$_a ]; then
1355 break;
1356 fi
1357 ;;
1358 esac
1359 done
1360 if [ -f ${_zonepath}/usr/share/zoneinfo/$_a ]; then
1361 TZ="$_a"
1362 echo "You have selected timezone \"$_a\"".
1363 break 2
1364 fi
1365 echo "'/usr/share/zoneinfo/$_a' is not a valid timezone on this system."
1366 ;;
1367 esac
1368 done
1369 }
1370
1371 install_sets()
1372 {
1373 local _yup
1374 _yup="FALSE"
1375
1376 # Ask the user which media to load the distribution from.
1377 # Ask the user if they want verbose extraction. They might not want
1378 # it on, eg, SPARC frame buffer console.
1379 cat << \__install_sets_1
1380
1381 It is now time to extract the installation sets onto the hard disk.
1382 Make sure the sets are either on a local device (i.e. tape, CD-ROM) or on a
1383 network server.
1384
1385 Would you like to see each file listed during extraction (verbose) mode?
1386 On some console hardware, such as serial consoles and Sun frame buffers,
1387 this can extend the total extraction time.
1388 __install_sets_1
1389 echo -n "Use verbose listing for extractions? [y] "
1390 getresp "y"
1391 case "$resp" in
1392 y*|Y*)
1393 verbose_flag=v
1394 ;;
1395 *)
1396 echo "Not using verbose listing."
1397 verbose_flag=""
1398 ;;
1399 esac
1400
1401 if [ -d ${Default_sets_dir:-/dev/null} ]; then
1402 if dir_has_sets $Default_sets_dir $THESETS; then
1403 local_sets_dir=$Default_sets_dir
1404 fi
1405 fi
1406 if [ -n "${local_sets_dir}" ]; then
1407 install_from_mounted_fs ${local_sets_dir}
1408 if [ -n "$_setsdone" ]; then
1409 _yup="TRUE"
1410 fi
1411 fi
1412
1413 # Go on prodding for alternate locations
1414 resp="" # force at least one iteration
1415 while [ -z "${resp}" ]; do
1416 # If _yup is not FALSE, it means that we extracted sets above.
1417 # If that's the case, bypass the menu the first time.
1418 if [ "${_yup}" = "FALSE" ]; then
1419 echo -n "Install from (f)tp, (t)ape, (C)D-ROM, (N)FS"
1420 echo -n " or local (d)isk? "
1421 getresp ""
1422 case "$resp" in
1423 d*|D*)
1424 install_disk
1425 ;;
1426 f*|F*)
1427 install_ftp
1428 ;;
1429 t*|T*)
1430 install_tape
1431 ;;
1432 c*|C*)
1433 install_cdrom
1434 ;;
1435 n*|N*)
1436 install_nfs
1437 ;;
1438 *)
1439 echo "Invalid response: $resp"
1440 resp=""
1441 ;;
1442 esac
1443 else
1444 _yup="FALSE" # So we'll ask next time
1445 fi
1446
1447 # Give the user the opportunity to extract more sets. They
1448 # don't necessarily have to come from the same media.
1449 echo ""
1450 echo -n "Extract more sets? [n] "
1451 getresp "n"
1452 case "$resp" in
1453 y*|Y*)
1454 # Force loop to repeat
1455 resp=""
1456 ;;
1457
1458 *)
1459 ;;
1460 esac
1461 done
1462 }
1463
1464 munge_fstab()
1465 {
1466 local _fstab
1467 local _fstab_shadow
1468 local _dev
1469 local _mp
1470 local _fstype
1471 local _rest
1472
1473 # Now that the 'real' fstab is configured, we munge it into a 'shadow'
1474 # fstab which we'll use for mounting and unmounting all of the target
1475 # filesystems relative to /mnt. Mount all filesystems.
1476 _fstab=$1
1477 _fstab_shadow=$2
1478 ( while read _dev _mp _fstype _rest; do
1479 # Skip comment lines
1480 case "$_dev" in
1481 \#*) continue;;
1482 *) ;;
1483 esac
1484 # and some filesystem types (like there are swap,kernfs,...)
1485 case "$_fstype" in
1486 ffs|ufs|nfs) ;;
1487 *) continue;;
1488 esac
1489 if [ "$_mp" = "/" ]; then
1490 echo $_dev /mnt $_fstype $_rest
1491 else
1492 echo $_dev /mnt$_mp $_fstype $_rest
1493 fi
1494 done ) < $_fstab > $_fstab_shadow
1495 }
1496
1497 mount_fs()
1498 {
1499 # Must mount filesystems manually, one at a time, so we can make
1500 # sure the mount points exist.
1501 # $1 is a file in fstab format
1502 local _fstab
1503
1504 _fstab=$1
1505
1506 ( while read line; do
1507 set -- $line
1508 _dev=$1
1509 _mp=$2
1510 _fstype=$3
1511 _opt=$4
1512
1513 # If not the root filesystem, make sure the mount
1514 # point is present.
1515 if [ "$_mp" != "/mnt" ]; then
1516 mkdir -p $_mp
1517 fi
1518
1519 # Mount the filesystem. If the mount fails, exit
1520 # with an error condition to tell the outer
1521 # later to bail.
1522 if ! mount -v -t $_fstype -o async -o $_opt $_dev $_mp ; then
1523 # error message displated by mount
1524 exit 1
1525 fi
1526 done ) < $_fstab
1527
1528 if [ "$?" != "0" ]; then
1529 cat << \__mount_filesystems_1
1530
1531 FATAL ERROR: Cannot mount filesystems. Double-check your configuration
1532 and restart the installation process.
1533 __mount_filesystems_1
1534 exit
1535 fi
1536 }
1537
1538 unmount_fs()
1539 {
1540 # Unmount all filesystems and check their integrity.
1541 # Usage: [-fast] <fstab file>
1542 local _fast
1543 local _fstab
1544 local _pid
1545
1546 if [ "$1" = "-fast" ]; then
1547 _fast=1
1548 _fstab=$2
1549 else
1550 _fast=0
1551 _fstab=$1
1552 fi
1553
1554 if ! [ -f "${_fstab}" ] || ! [ -s "${_fstab}" ]; then
1555 echo "fstab empty" > /dev/tty
1556 return
1557 fi
1558
1559 if [ $_fast = 0 ]; then
1560 echo -n "Syncing disks..."
1561 _pid=$(twiddle)
1562 sync; sleep 4; sync; sleep 2; sync; sleep 2
1563 kill $_pid
1564 echo "done."
1565 fi
1566
1567 (
1568 _devs=""
1569 _mps=""
1570 # maintain reverse order
1571 while read line; do
1572 set -- $line
1573 _devs="$1 ${_devs}"
1574 _mps="$2 ${_mps}"
1575 done
1576 echo -n "Umounting filesystems... "
1577 for _mp in ${_mps}; do
1578 echo -n "${_mp} "
1579 umount ${_mp}
1580 done
1581 echo "Done."
1582
1583 if [ $_fast = 0 ]; then
1584 exit
1585 fi
1586 echo "Checking filesystem integrity..."
1587 for _dev in ${_devs}; do
1588 echo "${_dev}"
1589 fsck -f ${_dev}
1590 done
1591 echo "Done."
1592 ) < $_fstab
1593 }
1594
1595 check_fs()
1596 {
1597 # Check filesystem integrity.
1598 # $1 is a file in fstab format
1599 local _fstab
1600
1601 _fstab=$1
1602
1603 (
1604 _devs=""
1605 _mps=""
1606 while read line; do
1607 set -- $line
1608 _devs="$1 ${_devs}"
1609 _mps="$2 ${_mps}"
1610 done
1611
1612 echo "Checking filesystem integrity..."
1613 for _dev in ${_devs}; do
1614 echo "${_dev}"
1615 fsck -f ${_dev}
1616 done
1617 echo "Done."
1618 ) < $_fstab
1619 }
1620
1621 mi_mount_kernfs() {
1622 # Make sure kernfs is mounted.
1623 if [ ! -d /kern ] || [ ! -e /kern/msgbuf ]; then
1624 mkdir /kern > /dev/null 2>&1
1625 /sbin/mount_kernfs /kern /kern
1626 fi
1627 }
1628
1629 mi_filter_msgbuf() {
1630 # Remove timestemps, sort.
1631 sed -e 's/^\[[0-9. ]*\] //' < /kern/msgbuf | sort -u
1632 }
1633
1634 mi_filter_dmesg() {
1635 # Remove timestemps, sort.
1636 dmesg | awk '{ h=$0; gsub("^[[0-9. ]*] ", "", h); print h; }' \
1637 | sort -u
1638 }
1639