NetBSD Problem Report #48881
From woods@once.weird.com Sun Jun 8 04:10:57 2014
Return-Path: <woods@once.weird.com>
Received: from mail.netbsd.org (mail.netbsd.org [149.20.53.66])
(using TLSv1 with cipher ECDHE-RSA-AES256-SHA (256/256 bits))
(Client CN "mail.netbsd.org", Issuer "Postmaster NetBSD.org" (verified OK))
by mollari.NetBSD.org (Postfix) with ESMTPS id 40F04A6521
for <gnats-bugs@gnats.NetBSD.org>; Sun, 8 Jun 2014 04:10:57 +0000 (UTC)
Message-Id: <m1WtURX-001ECZC@once.weird.com>
Date: Sat, 7 Jun 2014 21:10:51 -0700 (PDT)
From: "Greg A. Woods" <woods@planix.com>
Sender: "Greg A. Woods" <woods@once.weird.com>
To: gnats-bugs@gnats.NetBSD.org
Subject: /etc/hosts file parsing broken (since Aug 2013)
X-Send-Pr-Version: 3.95
>Number: 48881
>Category: lib
>Synopsis: /etc/hosts file parsing broken (since Aug 2013)
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: lib-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sun Jun 08 04:15:00 +0000 2014
>Last-Modified: Wed Jun 18 03:15:00 +0000 2014
>Originator: Greg A. Woods
>Release: NetBSD current 2014/06/06
>Organization:
Planix, Inc.; Kelowna, BC; Canada
>Environment:
System: NetBSD
>Description:
some massive changes to the gethost*() functions introduced a
bug in the parsing of the /etc/hosts file due to unsafe use of
fgetln():
http://mail-index.netbsd.org/source-changes/2013/08/16/msg046780.html
>How-To-Repeat:
try running a LAN server with /etc/hosts alone
>Fix:
This is most definitely _NOT_ the best or safest fix, but it
does work for me for now.
I don't think fgetln() ensures an extra byte at the end of
buffer is always available to be clobbered with a NUL.
A proper fix that also deals with the missing-last-newline issue
will probably require copying the line (up to the first newline
or llen, whichever comes first) to a new buffer anyway (as per
the example in fgetln(3)) so maybe that should be done for every
line just to be safe.
The final fix will need to be pulled up to netbsd-5 and netbsd-6 too.
Index: gethnamaddr.c
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/lib/libc/net/gethnamaddr.c,v
retrieving revision 1.90
diff -u -u -r1.90 gethnamaddr.c
--- gethnamaddr.c 24 Jan 2014 17:26:18 -0000 1.90
+++ gethnamaddr.c 8 Jun 2014 03:56:37 -0000
@@ -740,6 +740,7 @@
{
char *p, *name;
char *cp, **q;
+ char nxt;
int af, len;
size_t llen, anum;
char **aliases;
@@ -762,12 +763,17 @@
goto again;
if (*p == '#')
goto again;
- p[llen] = '\0';
- if (!(cp = strpbrk(p, "#\n")))
+ nxt = p[llen]; /* xxx this may not be safe... */
+ p[llen] = '\0'; /* xxx this may not be safe... */
+ if (!(cp = strpbrk(p, "#\n"))) { /* xxx this ignores the last line if it does not end in a newline!!! */
+ p[llen] = nxt;
goto again;
+ }
*cp = '\0';
- if (!(cp = strpbrk(p, " \t")))
+ if (!(cp = strpbrk(p, " \t"))) {
+ p[llen] = nxt;
goto again;
+ }
*cp++ = '\0';
if (inet_pton(AF_INET6, p, &host_addr) > 0) {
af = AF_INET6;
@@ -786,14 +792,18 @@
}
__res_put_state(res);
} else {
+ p[llen] = nxt;
goto again;
}
/* if this is not something we're looking for, skip it. */
- if (hent->h_addrtype != 0 && hent->h_addrtype != af)
+ if (hent->h_addrtype != 0 && hent->h_addrtype != af) {
+ p[llen] = nxt;
goto again;
- if (hent->h_length != 0 && hent->h_length != len)
+ }
+ if (hent->h_length != 0 && hent->h_length != len) {
+ p[llen] = nxt;
goto again;
-
+ }
while (*cp == ' ' || *cp == '\t')
cp++;
if ((cp = strpbrk(name = cp, " \t")) != NULL)
>Audit-Trail:
From: "Greg A. Woods" <woods@planix.ca>
To: NetBSD GNATS <gnats-bugs@NetBSD.org>
Cc:
Subject: Re: lib/48881: /etc/hosts file parsing broken (since Aug 2013)
Date: Fri, 13 Jun 2014 15:03:49 -0700
Appended is a new improved patch that would fully fix the bug for
netbsd-5 (but the patch is against -current, and fixes the missing final
newline ase for -current), and it includes some new test cases for
-current.
I was of course unable to reproduce the original bug in in -current.
The bug is only really nasty in the netbsd-5 branch (since NetBSD-5.2).
It disappears (in an un-documented way) in -current because of changes
in the implementation fgetln().
In netbsd-5 writing the NUL byte past the length returned by fgetln()
tromps on the first character of the next line and so that line is
treated as empty (the next strpbrk() can't find any newline or '#').
Only a blank or comment line in the input will "accidentally" reset the
bug and allow the code to see the full next line and confuse the heck
out of the person trying to figure out the problem.
The code could probably use getdelim() or getline() instead of fgetln()
if it really wants to assume the result is a C string. Otherwise it
should follow the rules for portable use of fgetln(). Better to be
clearly safe than sorry.
However the code still doesn't work correctly for the missing final
newline case (i.e. the last entry in a hosts file with no final newline
on that last entry cannot be found by name or by address).
The extra mallocs could be avoided in all but the missing final newline
case I suppose (while still using fgetln()), but at the expense of more
complex code. However now that the aliases array is also malloced there
doesn't seem to be any point to trying to avoid using malloc in this
code, and it's not likely anyone will have huge numbers of entries in
/etc/hosts (and thus huge numbers of mallocs) anyway.
--=20
Greg A. Woods
Planix, Inc.
<woods@planix.com> +1 250 762-7675 http://www.planix.com/
Index: tests/lib/libc/net/t_hostent.sh
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvs/master/m-NetBSD/main/src/tests/lib/libc/net/t_hostent.sh,v
retrieving revision 1.10
diff -u -r1.10 t_hostent.sh
--- tests/lib/libc/net/t_hostent.sh 13 Jan 2014 11:08:14 -0000 1.10
+++ tests/lib/libc/net/t_hostent.sh 13 Jun 2014 20:49:05 -0000
@@ -41,6 +41,30 @@
al4=3D"127.0.0.1"
loc4=3D"name=3D$l4, length=3D4, addrtype=3D2, aliases=3D[localhost. localh=
ost.localdomain.] addr_list=3D[$al4]\n"
=20
+# Many more combinations should be provided in hosts and tried here,
+# but this should scratch most major features and edge cases, though
+# just one at a time....
+
+f4=3D"oldfoohost.local"
+af4=3D"10.0.1.1"
+resf4=3D"name=3Dfoohost.local, length=3D4, addrtype=3D2, aliases=3D[$f4] a=
ddr_list=3D[$af4]\n"
+
+cm4=3D"commented.local"
+acm4=3D"10.0.2.2"
+rescm4=3D"name=3Dcommented, length=3D4, addrtype=3D2, aliases=3D[$cm4] add=
r_list=3D[$acm4]\n"
+
+sp4=3D"spaced.local"
+asp4=3D"10.0.3.3"
+ressp4=3D"name=3D$sp4, length=3D4, addrtype=3D2, aliases=3D[] addr_list=3D=
[$asp4]\n"
+
+msp4=3D"multispaced.local"
+amsp4=3D"10.0.4.4"
+resmsp4=3D"name=3D$msp4, length=3D4, addrtype=3D2, aliases=3D[] addr_list=
=3D[$amsp4]\n"
+
+nnl4=3D"nonewline.local"
+annl4=3D"10.10.10.10"
+resnnl4=3D"name=3Dnonewline, length=3D4, addrtype=3D2, aliases=3D[$nnl4] a=
ddr_list=3D[$annl4]\n"
+
dir=3D"$(atf_get_srcdir)"
res=3D"-r ${dir}/resolv.conf"
=20
@@ -131,6 +155,56 @@
atf_check -o inline:"$loc4" -x "${dir}/h_hostent -f ${dir}/hosts -t file =
-4 $l4"
}
=20
+atf_test_case hostsbynamelookup4a
+hostsbynamelookup4a_head()
+{
+ atf_set "descr" "Checks /etc/hosts name lookup by alias for AF_INET"
+}
+hostsbynamelookup4a_body()
+{
+ atf_check -o inline:"$resf4" -x "${dir}/h_hostent -f ${dir}/hosts -t file=
-4 $f4"
+}
+
+atf_test_case hostsbynamelookup4b
+hostsbynamelookup4b_head()
+{
+ atf_set "descr" "Checks /etc/hosts name lookup with comment for AF_INET"
+}
+hostsbynamelookup4b_body()
+{
+ atf_check -o inline:"$rescm4" -x "${dir}/h_hostent -f ${dir}/hosts -t fil=
e -4 $cm4"
+}
+
+atf_test_case hostsbynamelookup4c
+hostsbynamelookup4c_head()
+{
+ atf_set "descr" "Checks /etc/hosts name lookup with space for AF_INET"
+}
+hostsbynamelookup4c_body()
+{
+ atf_check -o inline:"$ressp4" -x "${dir}/h_hostent -f ${dir}/hosts -t fil=
e -4 $sp4"
+}
+
+atf_test_case hostsbynamelookup4d
+hostsbynamelookup4d_head()
+{
+ atf_set "descr" "Checks /etc/hosts name lookup with multiple spaces for A=
F_INET"
+}
+hostsbynamelookup4d_body()
+{
+ atf_check -o inline:"$resmsp4" -x "${dir}/h_hostent -f ${dir}/hosts -t fi=
le -4 $msp4"
+}
+
+atf_test_case hostsbynamelookup4e
+hostsbynamelookup4e_head()
+{
+ atf_set "descr" "Checks /etc/hosts name lookup with no newline for AF_INE=
T"
+}
+hostsbynamelookup4e_body()
+{
+ atf_check -o inline:"$resnnl4" -x "${dir}/h_hostent -f ${dir}/hosts -t fi=
le -4 $nnl4"
+}
+
atf_test_case hostsbynamelookup6
hostsbynamelookup6_head()
{
@@ -151,6 +225,56 @@
atf_check -o inline:"$loc4" -x "${dir}/h_hostent -f ${dir}/hosts -t file =
-4 -a $al4"
}
=20
+atf_test_case hostsbyaddrlookup4a
+hostsbyaddrlookup4a_head()
+{
+ atf_set "descr" "Checks /etc/hosts address lookup again for AF_INET"
+}
+hostsbyaddrlookup4a_body()
+{
+ atf_check -o inline:"$resf4" -x "${dir}/h_hostent -f ${dir}/hosts -t file=
-4 -a $af4"
+}
+
+atf_test_case hostsbyaddrlookup4b
+hostsbyaddrlookup4b_head()
+{
+ atf_set "descr" "Checks /etc/hosts address lookup with comment for AF_INE=
T"
+}
+hostsbyaddrlookup4b_body()
+{
+ atf_check -o inline:"$rescm4" -x "${dir}/h_hostent -f ${dir}/hosts -t fil=
e -4 -a $acm4"
+}
+
+atf_test_case hostsbyaddrlookup4c
+hostsbyaddrlookup4c_head()
+{
+ atf_set "descr" "Checks /etc/hosts address lookup with space for AF_INET"
+}
+hostsbyaddrlookup4c_body()
+{
+ atf_check -o inline:"$ressp4" -x "${dir}/h_hostent -f ${dir}/hosts -t fil=
e -4 -a $asp4"
+}
+
+atf_test_case hostsbyaddrlookup4d
+hostsbyaddrlookup4d_head()
+{
+ atf_set "descr" "Checks /etc/hosts address lookup with multiple spaces fo=
r AF_INET"
+}
+hostsbyaddrlookup4d_body()
+{
+ atf_check -o inline:"$resmsp4" -x "${dir}/h_hostent -f ${dir}/hosts -t fi=
le -4 -a $amsp4"
+}
+
+atf_test_case hostsbyaddrlookup4e
+hostsbyaddrlookup4e_head()
+{
+ atf_set "descr" "Checks /etc/hosts address lookup with no newline for AF_=
INET"
+}
+hostsbyaddrlookup4e_body()
+{
+ atf_check -o inline:"$resnnl4" -x "${dir}/h_hostent -f ${dir}/hosts -t fi=
le -4 -a $annl4"
+}
+
atf_test_case hostsbyaddrlookup6
hostsbyaddrlookup6_head()
{
@@ -229,8 +353,18 @@
atf_add_test_case gethostbyaddr6
=20
atf_add_test_case hostsbynamelookup4
+ atf_add_test_case hostsbynamelookup4a
+ atf_add_test_case hostsbynamelookup4b
+ atf_add_test_case hostsbynamelookup4c
+ atf_add_test_case hostsbynamelookup4d
+ atf_add_test_case hostsbynamelookup4e
atf_add_test_case hostsbynamelookup6
atf_add_test_case hostsbyaddrlookup4
+ atf_add_test_case hostsbyaddrlookup4a
+ atf_add_test_case hostsbyaddrlookup4b
+ atf_add_test_case hostsbyaddrlookup4c
+ atf_add_test_case hostsbyaddrlookup4d
+ atf_add_test_case hostsbyaddrlookup4e
atf_add_test_case hostsbyaddrlookup6
=20
atf_add_test_case dnsbynamelookup4
Index: tests/lib/libc/net/hosts
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvs/master/m-NetBSD/main/src/tests/lib/libc/net/hosts,v
retrieving revision 1.1
diff -u -r1.1 hosts
--- tests/lib/libc/net/hosts 16 Aug 2013 15:29:45 -0000 1.1
+++ tests/lib/libc/net/hosts 13 Jun 2014 20:55:14 -0000
@@ -1,3 +1,5 @@
+# -*- eval (setq require-final-newline nil) -*-
+#
# $NetBSD: hosts,v 1.1 2013/08/16 15:29:45 christos Exp $
#
# Host Database
@@ -9,3 +11,19 @@
#
::1 localhost localhost. localhost.localdomain.
127.0.0.1 localhost localhost. localhost.localdomain.
+
+# some test hosts...
+
+10.0.0.0 network network.localdomain
+
+10.0.1.1 foohost.local oldfoohost.local
+10.0.2.2 commented commented.local # trailing comment
+10.0.3.3 spaced.local
+10.0.4.4 multispaced.local
+
+10.255.255.255 broadcast broadcast.localdomain
+
+# N.B.: no trailing newline!!!
+# (non-emacs users do this: printf %s "$(< hosts)" > t && mv t hosts)
+# xxx or maybe the test setup should do it....
+10.10.10.10 nonewline nonewline.local
\ No newline at end of file
Index: lib/libc/net/gethnamaddr.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvs/master/m-NetBSD/main/src/lib/libc/net/gethnamaddr.c,v
retrieving revision 1.90
diff -u -r1.90 gethnamaddr.c
--- lib/libc/net/gethnamaddr.c 24 Jan 2014 17:26:18 -0000 1.90
+++ lib/libc/net/gethnamaddr.c 13 Jun 2014 20:28:45 -0000
@@ -83,8 +83,6 @@
# define LOG_AUTH 0
#endif
=20
-#define MULTI_PTRS_ARE_ALIASES 1 /* XXX - experimental */
-
#include <nsswitch.h>
#include <stdlib.h>
#include <string.h>
@@ -378,7 +376,6 @@
had_error++;
break;
}
-#if MULTI_PTRS_ARE_ALIASES
cp +=3D n;
if (cp !=3D erdata)
goto no_recovery;
@@ -395,19 +392,6 @@
bp +=3D n;
}
break;
-#else
- hent->h_name =3D bp;
- if (res->options & RES_USE_INET6) {
- n =3D strlen(bp) + 1; /* for the \0 */
- if (n >=3D MAXHOSTNAMELEN) {
- had_error++;
- break;
- }
- bp +=3D n;
- map_v4v6_hostent(hent, &bp, ep);
- }
- goto success;
-#endif
case T_A:
case T_AAAA:
if (strcasecmp(hent->h_name, bp) !=3D 0) {
@@ -738,7 +722,7 @@
struct hostent *
gethostent_r(FILE *hf, struct hostent *hent, char *buf, size_t buflen, int=
*he)
{
- char *p, *name;
+ char *ln, *p, *name;
char *cp, **q;
int af, len;
size_t llen, anum;
@@ -753,21 +737,30 @@
}
setup(aliases, maxaliases);
again:
- if ((p =3D fgetln(hf, &llen)) =3D=3D NULL) {
+ if ((ln =3D fgetln(hf, &llen)) =3D=3D NULL) {
free(aliases);
*he =3D HOST_NOT_FOUND;
return NULL;
}
if (llen < 1)
goto again;
- if (*p =3D=3D '#')
+ if (*ln =3D=3D '#')
goto again;
+ /* xxx we only really need to alloc and copy IFF no newline */
+ if (! (p =3D malloc(llen + 1))) {
+ goto nospc;
+ }
+ memcpy(p, ln, llen);
p[llen] =3D '\0';
- if (!(cp =3D strpbrk(p, "#\n")))
- goto again;
- *cp =3D '\0';
- if (!(cp =3D strpbrk(p, " \t")))
+ if ((cp =3D strpbrk(p, "#\n")) !=3D NULL) {
+ /* trim any comment to EOL, or the newline */
+ *cp =3D '\0';
+ }
+ if (!(cp =3D strpbrk(p, " \t"))) {
+ /* there must be at least two words on a line */
+ free(p);
goto again;
+ }
*cp++ =3D '\0';
if (inet_pton(AF_INET6, p, &host_addr) > 0) {
af =3D AF_INET6;
@@ -786,14 +779,18 @@
}
__res_put_state(res);
} else {
+ free(p);
goto again;
}
/* if this is not something we're looking for, skip it. */
- if (hent->h_addrtype !=3D 0 && hent->h_addrtype !=3D af)
+ if (hent->h_addrtype !=3D 0 && hent->h_addrtype !=3D af) {
+ free(p);
goto again;
- if (hent->h_length !=3D 0 && hent->h_length !=3D len)
+ }
+ if (hent->h_length !=3D 0 && hent->h_length !=3D len) {
+ free(p);
goto again;
-
+ }
while (*cp =3D=3D ' ' || *cp =3D=3D '\t')
cp++;
if ((cp =3D strpbrk(name =3D cp, " \t")) !=3D NULL)
@@ -823,6 +820,7 @@
hent->h_aliases[anum] =3D NULL;
=20
*he =3D NETDB_SUCCESS;
+ free(p);
free(aliases);
return hent;
nospc:
From: Robert Elz <kre@munnari.OZ.AU>
To: gnats-bugs@NetBSD.org
Cc:
Subject: Re: lib/48881: /etc/hosts file parsing broken (since Aug 2013)
Date: Sat, 14 Jun 2014 06:07:19 +0700
Date: Fri, 13 Jun 2014 22:05:00 +0000 (UTC)
From: "Greg A. Woods" <woods@planix.ca>
Message-ID: <20140613220500.E37EAA6550@mollari.NetBSD.org>
Apart from your QP encoded patch being totally mangled by gnats,
the fgetln fixes are probably needed but ...
| However the code still doesn't work correctly for the missing final
| newline case (i.e. the last entry in a hosts file with no final newline
| on that last entry cannot be found by name or by address).
That should not be "fixed" - unix lines are terminated by newlines, a "line"
that has no terminating newline is not a line at all, and should be
ignored in places like that - in particular, one way (aside from using
brain dead editors) to get such a state, is to write the file back to
a full filesystem, the file will be truncated at the end of the last free
available block, almost certainly in the middle of a line - using that broken
line as if it were valid data would be a mistake.
kre
From: "Greg A. Woods" <woods@planix.ca>
To: NetBSD GNATS <gnats-bugs@NetBSD.org>
Cc:
Subject: Re: lib/48881: /etc/hosts file parsing broken (since Aug 2013)
Date: Fri, 13 Jun 2014 20:05:16 -0700
At Fri, 13 Jun 2014 23:10:01 +0000 (UTC), Robert Elz <kre@munnari.OZ.AU> wr=
ote:
Subject: Re: lib/48881: /etc/hosts file parsing broken (since Aug 2013)
>=20
> Apart from your QP encoded patch being totally mangled by gnats,
Yes, gnats should probably given a helping hand to get it to try to
catch up with the now decades-old use of MIME.
> That should not be "fixed" - unix lines are terminated by newlines, a "l=
ine"
> that has no terminating newline is not a line at all, and should be
> ignored in places like that - in particular, one way (aside from using
> brain dead editors) to get such a state, is to write the file back to
> a full filesystem, the file will be truncated at the end of the last free
> available block, almost certainly in the middle of a line - using that b=
roken
> line as if it were valid data would be a mistake.
I understand what you are saying, and for the most part I agree with
you, but I think there are worse problems caused by not parsing the text
after the last newline in files that don't end in a newline.
ed and vi will both quietly open such files and show that last "line"
and also happily quit without asking to save the file (though they will
also both silently add a final newline if any part of the file is
changed and it is saved). (I think maybe they should both warn that the
file was read without a final newline and ask to save the file on quit
even if no changes were made by the user.)
less, more, grep, awk, and probably most other tools one might use to
examine text files will all happily read the text after the final
newline and parse or show it as a true "line" of text in the file.
About the only way a more naive admin will discover a problem with a
missing final newline is to hexdump the file, or maybe they might cat or
tail the file and notice the next shell prompt doesn't appear at the
beginning of the line after the end of the file's contents.
--=20
Greg A. Woods
Planix, Inc.
<woods@planix.com> +1 250 762-7675 http://www.planix.com/
From: David Holland <dholland-bugs@netbsd.org>
To: gnats-bugs@NetBSD.org
Cc:
Subject: Re: lib/48881: /etc/hosts file parsing broken (since Aug 2013)
Date: Wed, 18 Jun 2014 03:13:16 +0000
On Sat, Jun 14, 2014 at 03:10:05AM +0000, Greg A. Woods wrote:
>> That should not be "fixed" - unix lines are terminated by
>> newlines, a "line" that has no terminating newline is not a line
>> at all, and should be ignored in places like that - in
>> particular, one way (aside from using brain dead editors) to get
>> such a state, is to write the file back to a full filesystem, the
>> file will be truncated at the end of the last free available
>> block, almost certainly in the middle of a line - using that
>> broken line as if it were valid data would be a mistake.
>
> I understand what you are saying, and for the most part I agree with
> you, but I think there are worse problems caused by not parsing the text
> after the last newline in files that don't end in a newline.
> [...]
I mostly don't agree: a partial line should either be a line or a
syntax error, and in either case ignoring it silently is wrong :-)
--
David A. Holland
dholland@netbsd.org
>Unformatted:
(Contact us)
$NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.