NetBSD Problem Report #45749
From www@NetBSD.org Tue Dec 27 21:06:16 2011
Return-Path: <www@NetBSD.org>
Received: from mail.netbsd.org (mail.netbsd.org [204.152.190.11])
by www.NetBSD.org (Postfix) with ESMTP id 66E0763DD64
for <gnats-bugs@gnats.NetBSD.org>; Tue, 27 Dec 2011 21:06:16 +0000 (UTC)
Message-Id: <20111227210615.0A8C063DD4A@www.NetBSD.org>
Date: Tue, 27 Dec 2011 21:06:15 +0000 (UTC)
From: gnrp@komkon2.de
Reply-To: gnrp@komkon2.de
To: gnats-bugs@NetBSD.org
Subject: disklabel(8) uses wrong boundaries for several values, destroys disklabels
X-Send-Pr-Version: www-1.0
>Number: 45749
>Category: bin
>Synopsis: disklabel(8) uses wrong boundaries for several values, destroys disklabels
>Confidential: no
>Severity: serious
>Priority: high
>Responsible: bin-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Tue Dec 27 21:10:00 +0000 2011
>Last-Modified: Wed Dec 28 17:15:03 +0000 2011
>Originator: Julian Fagir
>Release: NetBSD-current
>Organization:
>Environment:
>Description:
disklabel(8) in interactional mode sets several values too high.
I think, it should be d_npartitions, d_interleave, d_trackskew, d_cylskew being defined as uint16_t, but imported as SCNu32. Specifying a large value simply messes up your disklabel.
I tried replacing all SCNu32 of the inappropriate values of SCNu16 (see attached diff). This solves formal issues, but neither the segfault nor does it check for the right values.
While I didn't track down the segfault, there's another obvious flaw: The input is simply scanf'ed. There is no check whether the input value is *really* the value typed in - if you type in a value too large for 16 uint (or for 32 uint), then simply the highest value is taken.
If you type in bogus stuff, but scanf succeeds, there is no warning nor error, only the found integer is taken.
>How-To-Repeat:
# disklabel -i wd1
Enter '?' for help
partition> P
4 partitions:
# size offset fstype [fsize bsize cpg/sgs]
c: 2088387 63 unused 0 0 # (Cyl. 0*- 2071*)
d: 4194304 0 unused 0 0 # (Cyl. 0 - 4161*)
partition> I
# Current values:
# /dev/rwd1d:
type: ESDI
disk: VBOX HARDDISK
label: fictitious
flags:
bytes/sector: 512
sectors/track: 63
tracks/cylinder: 16
sectors/cylinder: 1008
cylinders: 4161
total sectors: 4194304
rpm: 3600
interleave: 1
trackskew: 0
cylinderskew: 0
headswitch: 0 # microseconds
track-to-track seek: 0 # microseconds
drivedata: 0
Disk type [?] [ESDI]:
Disk name [VBOX HARDDISK ]:
Label name [fictitious]:
Number of partitions [4]: 4294967295
Sector size (bytes) [512]:
Number of sectors per track [63]:
Number of tracks per cylinder [16]:
Number of sectors/cylinder [1008]:
Total number of cylinders [4161]:
Total number of sectors [4194304]:
Hardware sectors interleave [1]:
Sector 0 skew, per track [0]:
Sector 0 skew, per cylinder [0]:
Head switch time (usec) [0]:
Track seek time (usec) [0]:
partition> P
65535 partitions:
# size offset fstype [fsize bsize cpg/sgs]
c: 2088387 63 unused 0 0 # (Cyl. 0*- 2071*)
d: 4194304 0 unused 0 0 # (Cyl. 0 - 4161*)
x: 1685549615 25649 unused 0 0 # (Cyl. 25*- 1672197+)
º: 134556356 0 unused 0 0 # (Cyl. 0 - 133488+)
Á: 4096 1914 ISO9660 60 # (Cyl. 1*- 5*)
Ã: 986 31 unused 152 0 # (Cyl. 0*- 1*)
Å: 16 96 unused 0 0 # (Cyl. 0*- 0*)
Æ: 16 4096 MSDOS # (Cyl. 4*- 4*)
Ç: 64 0 32 # (Cyl. 0 - 0*)
È: 4096 126 64 # (Cyl. 0*- 4*)
Ê: 84 3 unused 64 0 # (Cyl. 0*- 0*)
Ì: 2 64 unused 0 0 # (Cyl. 0*- 0*)
Í: 80 4096 Version 6 # (Cyl. 4*- 4*)
Î: 96 0 96 # (Cyl. 0 - 0*)
Ï: 8192 84 128 # (Cyl. 0*- 8*)
Ñ: 72 3 unused 128 0 # (Cyl. 0*- 0*)
Ó: 2 128 unused 0 0 # (Cyl. 0*- 0*)
Ô: 144 8192 Version 6 # (Cyl. 8*- 8*)
Õ: 128 0 160 # (Cyl. 0 - 0*)
Ö: 8192 50 192 # (Cyl. 0*- 8*)
Ø: 46 2 unused 96 0 # (Cyl. 0*- 0*)
Ú: 2 192 unused 0 0 # (Cyl. 0*- 0*)
Û: 208 12288 Version 6 # (Cyl. 12*- 12*)
Ü: 224 0 224 # (Cyl. 0 - 0*)
Ý: 16384 72 unused 3 3 # (Cyl. 0*- 16*)
ß: 68 3 unused 64 0 # (Cyl. 0*- 0*)
á: 2 256 unused 0 0 # (Cyl. 0*- 0*)
â: 272 16384 Version 6 # (Cyl. 16*- 16*)
ã: 64 0 32 # (Cyl. 0 - 0*)
ä: 20480 70 64 # (Cyl. 0*- 20*)
æ: 67 3 unused 112 0 # (Cyl. 0*- 0*)
è: 2 320 unused 0 0 # (Cyl. 0*- 0*)
é: 336 20480 Version 6 # (Cyl. 20*- 20*)
ê: 320 0 96 # (Cyl. 0 - 0*)
ë: 20480 58 64 # (Cyl. 0*- 20*)
í: 55 2 unused 240 0 # (Cyl. 0*- 0*)
ï: 2 384 unused 0 0 # (Cyl. 0*- 0*)
ð: 400 24576 Version 6 # (Cyl. 24*- 24*)
ñ: 176 0 160 # (Cyl. 0 - 0*)
ò: 24576 58 192 # (Cyl. 0*- 24*)
ô: 56 2 unused 384 0 # (Cyl. 0*- 0*)
ö: 2 448 unused 0 0 # (Cyl. 0*- 0*)
÷: 464 28672 Version 6 # (Cyl. 28*- 28*)
ø: 368 0 224 # (Cyl. 0 - 0*)
ù: 28672 59 96 # (Cyl. 0*- 28*)
û: 65 3 unused 528 0 # (Cyl. 0*- 0*)
ý: 2 512 unused 0 0 # (Cyl. 0*- 0*)
þ: 1024 32768 swap # (Cyl. 32*- 33*)
ÿ: 1024 3146780672 unused 0 0 # (Cyl. 3121806+- 3121807+)
: 32768 15 unused 1 8 # (Cyl. 0*- 32*)
[1] Segmentation fault (core dumped) disklabel -i wd1
>Fix:
The following patch does only solve one problem: It changes the 32 uint variable to the name 'u32' and introduces another 16 bit uint 'u16' which is used for the 16 bit values. Neither the segfaults nor the checks for right values are solved.
--- interact.c
+++ interact.c
@@ -150,11 +150,12 @@
cmd_info(struct disklabel *lp, char *s, int fd)
{
char line[BUFSIZ];
char def[BUFSIZ];
int v, i;
- u_int32_t u;
+ u_int32_t u32;
+ u_int16_t u16;
printf("# Current values:\n");
showinfo(stdout, lp, specname);
/* d_type */
@@ -207,15 +208,15 @@
i = getinput(":", "Number of partitions", def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if (sscanf(line, "%" SCNu32, &u) != 1) {
+ if (sscanf(line, "%" SCNu16, &u16) != 1) {
printf("Invalid number of partitions `%s'\n", line);
continue;
}
- lp->d_npartitions = u;
+ lp->d_npartitions = u16;
break;
}
/* d_secsize */
for (;;) {
@@ -223,15 +224,15 @@
i = getinput(":", "Sector size (bytes)", def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if (sscanf(line, "%" SCNu32, &u) != 1) {
+ if (sscanf(line, "%" SCNu32, &u32) != 1) {
printf("Invalid sector size `%s'\n", line);
continue;
}
- lp->d_secsize = u;
+ lp->d_secsize = u32;
break;
}
/* d_nsectors */
for (;;) {
@@ -239,15 +240,15 @@
i = getinput(":", "Number of sectors per track", def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if (sscanf(line, "%" SCNu32, &u) != 1) {
+ if (sscanf(line, "%" SCNu32, &u32) != 1) {
printf("Invalid number of sectors `%s'\n", line);
continue;
}
- lp->d_nsectors = u;
+ lp->d_nsectors = u32;
break;
}
/* d_ntracks */
for (;;) {
@@ -255,15 +256,15 @@
i = getinput(":", "Number of tracks per cylinder", def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if (sscanf(line, "%" SCNu32, &u) != 1) {
+ if (sscanf(line, "%" SCNu32, &u32) != 1) {
printf("Invalid number of tracks `%s'\n", line);
continue;
}
- lp->d_ntracks = u;
+ lp->d_ntracks = u32;
break;
}
/* d_secpercyl */
for (;;) {
@@ -271,16 +272,16 @@
i = getinput(":", "Number of sectors/cylinder", def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if (sscanf(line, "%" SCNu32, &u) != 1) {
+ if (sscanf(line, "%" SCNu32, &u32) != 1) {
printf("Invalid number of sector/cylinder `%s'\n",
line);
continue;
}
- lp->d_secpercyl = u;
+ lp->d_secpercyl = u32;
break;
}
/* d_ncylinders */
for (;;) {
@@ -288,15 +289,15 @@
i = getinput(":", "Total number of cylinders", def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if (sscanf(line, "%" SCNu32, &u) != 1) {
+ if (sscanf(line, "%" SCNu32, &u32) != 1) {
printf("Invalid sector size `%s'\n", line);
continue;
}
- lp->d_ncylinders = u;
+ lp->d_ncylinders = u32;
break;
}
/* d_secperunit */
for (;;) {
@@ -304,15 +305,15 @@
i = getinput(":", "Total number of sectors", def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if (sscanf(line, "%" SCNu32, &u) != 1) {
+ if (sscanf(line, "%" SCNu32, &u32) != 1) {
printf("Invalid number of sectors `%s'\n", line);
continue;
}
- lp->d_secperunit = u;
+ lp->d_secperunit = u32;
break;
}
/* d_rpm */
@@ -322,15 +323,15 @@
i = getinput(":", "Hardware sectors interleave", def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if (sscanf(line, "%" SCNu32, &u) != 1) {
+ if (sscanf(line, "%" SCNu16, &u16) != 1) {
printf("Invalid sector interleave `%s'\n", line);
continue;
}
- lp->d_interleave = u;
+ lp->d_interleave = u16;
break;
}
/* d_trackskew */
for (;;) {
@@ -338,15 +339,15 @@
i = getinput(":", "Sector 0 skew, per track", def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if (sscanf(line, "%" SCNu32, &u) != 1) {
+ if (sscanf(line, "%" SCNu16, &u16) != 1) {
printf("Invalid track sector skew `%s'\n", line);
continue;
}
- lp->d_trackskew = u;
+ lp->d_trackskew = u16;
break;
}
/* d_cylskew */
for (;;) {
@@ -354,15 +355,15 @@
i = getinput(":", "Sector 0 skew, per cylinder", def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if (sscanf(line, "%" SCNu32, &u) != 1) {
+ if (sscanf(line, "%" SCNu16, &u16) != 1) {
printf("Invalid cylinder sector `%s'\n", line);
continue;
}
- lp->d_cylskew = u;
+ lp->d_cylskew = u16;
break;
}
/* d_headswitch */
for (;;) {
@@ -370,15 +371,15 @@
i = getinput(":", "Head switch time (usec)", def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if (sscanf(line, "%" SCNu32, &u) != 1) {
+ if (sscanf(line, "%" SCNu32, &u32) != 1) {
printf("Invalid head switch time `%s'\n", line);
continue;
}
- lp->d_headswitch = u;
+ lp->d_headswitch = u32;
break;
}
/* d_trkseek */
for (;;) {
@@ -386,15 +387,15 @@
i = getinput(":", "Track seek time (usec)", def, line);
if (i == -1)
return;
else if (i == 0)
break;
- if (sscanf(line, "%" SCNu32, &u) != 1) {
+ if (sscanf(line, "%" SCNu32, &u32) != 1) {
printf("Invalid track seek time `%s'\n", line);
continue;
}
- lp->d_trkseek = u;
+ lp->d_trkseek = u32;
break;
}
}
>Audit-Trail:
From: Julian Djamil Fagir <gnrp@komkon2.de>
To: gnats-bugs@NetBSD.org
Cc:
Subject: Re: bin/45749: disklabel(8) uses wrong boundaries for several
values, destroys disklabels
Date: Wed, 28 Dec 2011 18:11:43 +0100
--Sig_/P/X_PV2fUdUR7IiqBsKCNe8
Content-Type: multipart/mixed; boundary="MP_/t1SNLi=bRAWDFfVn/Pf24iE"
--MP_/t1SNLi=bRAWDFfVn/Pf24iE
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline
Hi,
the attached diffs should solve the issue of invalid string input.
Not very thoroughly tested, mainly only the tests below.
If you know more test scenarios, please tell me or test it yourself.
Regards, Julian
# ./disklabel -i wd1
Enter '?' for help
partition> I
# Current values:
# /dev/rwd1d:
type: ESDI
disk: VBOX HARDDISK =20
label: fictitious
flags:
bytes/sector: 512
sectors/track: 63
tracks/cylinder: 16
sectors/cylinder: 1008
cylinders: 4161
total sectors: 4194304
rpm: 3600
interleave: 1
trackskew: 0
cylinderskew: 0
headswitch: 0 # microseconds
track-to-track seek: 0 # microseconds
drivedata: 0=20
Disk type [?] [ESDI]:=20
Disk name [VBOX HARDDISK ]:=20
Label name [fictitious]:=20
Number of partitions [4]: 65536
Invalid number of partitions `65536'
Number of partitions [4]: 65535nee
Invalid number of partitions `65535nee'
Number of partitions [4]: nee65535
Invalid number of partitions `nee65535'
Number of partitions [4]: 65535
Sector size (bytes) [512]:=20
...
--MP_/t1SNLi=bRAWDFfVn/Pf24iE
Content-Type: text/x-patch
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename=extern.h.diff
--- extern.h
+++ extern.h
@@ -28,9 +28,11 @@
int checklabel(struct disklabel *);
void showinfo(FILE *, struct disklabel *, const char *);
void showpartitions(FILE *, struct disklabel *, int);
void showpartition(FILE *, struct disklabel *, int, int);
void interact(struct disklabel *, int);
+int strtouint16(char *, uint16_t *);
+int strtouint32(char *, uint32_t *);
int list_fs_types(void);
=20
extern char specname[];
extern int Cflag;
--MP_/t1SNLi=bRAWDFfVn/Pf24iE
Content-Type: text/x-patch
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename=interact.c.diff
--- interact.c
+++ interact.c
@@ -150,11 +150,12 @@
cmd_info(struct disklabel *lp, char *s, int fd)
{
char line[BUFSIZ];
char def[BUFSIZ];
int v, i;
- u_int32_t u;
+ u_int32_t u32;
+ u_int16_t u16;
=20
printf("# Current values:\n");
showinfo(stdout, lp, specname);
=20
/* d_type */
@@ -207,15 +208,15 @@
i =3D getinput(":", "Number of partitions", def, line);
if (i =3D=3D -1)
return;
else if (i =3D=3D 0)
break;
- if (sscanf(line, "%" SCNu32, &u) !=3D 1) {
+ if (strtouint16(line, &u16)) {
printf("Invalid number of partitions `%s'\n", line);
continue;
}
- lp->d_npartitions =3D u;
+ lp->d_npartitions =3D u16;
break;
}
=20
/* d_secsize */
for (;;) {
@@ -223,15 +224,15 @@
i =3D getinput(":", "Sector size (bytes)", def, line);
if (i =3D=3D -1)
return;
else if (i =3D=3D 0)
break;
- if (sscanf(line, "%" SCNu32, &u) !=3D 1) {
+ if (strtouint32(line, &u32)) {
printf("Invalid sector size `%s'\n", line);
continue;
}
- lp->d_secsize =3D u;
+ lp->d_secsize =3D u32;
break;
}
=20
/* d_nsectors */
for (;;) {
@@ -239,15 +240,15 @@
i =3D getinput(":", "Number of sectors per track", def, line);
if (i =3D=3D -1)
return;
else if (i =3D=3D 0)
break;
- if (sscanf(line, "%" SCNu32, &u) !=3D 1) {
+ if (strtouint32(line, &u32)) {
printf("Invalid number of sectors `%s'\n", line);
continue;
}
- lp->d_nsectors =3D u;
+ lp->d_nsectors =3D u32;
break;
}
=20
/* d_ntracks */
for (;;) {
@@ -255,15 +256,15 @@
i =3D getinput(":", "Number of tracks per cylinder", def, line);
if (i =3D=3D -1)
return;
else if (i =3D=3D 0)
break;
- if (sscanf(line, "%" SCNu32, &u) !=3D 1) {
+ if (strtouint32(line, &u32)) {
printf("Invalid number of tracks `%s'\n", line);
continue;
}
- lp->d_ntracks =3D u;
+ lp->d_ntracks =3D u32;
break;
}
=20
/* d_secpercyl */
for (;;) {
@@ -271,16 +272,16 @@
i =3D getinput(":", "Number of sectors/cylinder", def, line);
if (i =3D=3D -1)
return;
else if (i =3D=3D 0)
break;
- if (sscanf(line, "%" SCNu32, &u) !=3D 1) {
+ if (strtouint32(line, &u32)) {
printf("Invalid number of sector/cylinder `%s'\n",
line);
continue;
}
- lp->d_secpercyl =3D u;
+ lp->d_secpercyl =3D u32;
break;
}
=20
/* d_ncylinders */
for (;;) {
@@ -288,15 +289,15 @@
i =3D getinput(":", "Total number of cylinders", def, line);
if (i =3D=3D -1)
return;
else if (i =3D=3D 0)
break;
- if (sscanf(line, "%" SCNu32, &u) !=3D 1) {
+ if (strtouint32(line, &u32)) {
printf("Invalid sector size `%s'\n", line);
continue;
}
- lp->d_ncylinders =3D u;
+ lp->d_ncylinders =3D u32;
break;
}
=20
/* d_secperunit */
for (;;) {
@@ -304,15 +305,15 @@
i =3D getinput(":", "Total number of sectors", def, line);
if (i =3D=3D -1)
return;
else if (i =3D=3D 0)
break;
- if (sscanf(line, "%" SCNu32, &u) !=3D 1) {
+ if (strtouint32(line, &u32)) {
printf("Invalid number of sectors `%s'\n", line);
continue;
}
- lp->d_secperunit =3D u;
+ lp->d_secperunit =3D u32;
break;
}
=20
/* d_rpm */
=20
@@ -322,15 +323,15 @@
i =3D getinput(":", "Hardware sectors interleave", def, line);
if (i =3D=3D -1)
return;
else if (i =3D=3D 0)
break;
- if (sscanf(line, "%" SCNu32, &u) !=3D 1) {
+ if (strtouint16(line, &u16)) {
printf("Invalid sector interleave `%s'\n", line);
continue;
}
- lp->d_interleave =3D u;
+ lp->d_interleave =3D u16;
break;
}
=20
/* d_trackskew */
for (;;) {
@@ -338,15 +339,15 @@
i =3D getinput(":", "Sector 0 skew, per track", def, line);
if (i =3D=3D -1)
return;
else if (i =3D=3D 0)
break;
- if (sscanf(line, "%" SCNu32, &u) !=3D 1) {
+ if (strtouint16(line, &u16)) {
printf("Invalid track sector skew `%s'\n", line);
continue;
}
- lp->d_trackskew =3D u;
+ lp->d_trackskew =3D u16;
break;
}
=20
/* d_cylskew */
for (;;) {
@@ -354,15 +355,15 @@
i =3D getinput(":", "Sector 0 skew, per cylinder", def, line);
if (i =3D=3D -1)
return;
else if (i =3D=3D 0)
break;
- if (sscanf(line, "%" SCNu32, &u) !=3D 1) {
+ if (strtouint16(line, &u16)) {
printf("Invalid cylinder sector `%s'\n", line);
continue;
}
- lp->d_cylskew =3D u;
+ lp->d_cylskew =3D u16;
break;
}
=20
/* d_headswitch */
for (;;) {
@@ -370,15 +371,15 @@
i =3D getinput(":", "Head switch time (usec)", def, line);
if (i =3D=3D -1)
return;
else if (i =3D=3D 0)
break;
- if (sscanf(line, "%" SCNu32, &u) !=3D 1) {
+ if (strtouint32(line, &u32)) {
printf("Invalid head switch time `%s'\n", line);
continue;
}
- lp->d_headswitch =3D u;
+ lp->d_headswitch =3D u32;
break;
}
=20
/* d_trkseek */
for (;;) {
@@ -386,15 +387,15 @@
i =3D getinput(":", "Track seek time (usec)", def, line);
if (i =3D=3D -1)
return;
else if (i =3D=3D 0)
break;
- if (sscanf(line, "%" SCNu32, &u) !=3D 1) {
+ if (strtouint32(line, &u32)) {
printf("Invalid track seek time `%s'\n", line);
continue;
}
- lp->d_trkseek =3D u;
+ lp->d_trkseek =3D u32;
break;
}
}
=20
=20
--MP_/t1SNLi=bRAWDFfVn/Pf24iE
Content-Type: text/x-patch
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename=main.c.diff
--- main.c
+++ main.c
@@ -1937,6 +1935,42 @@
free(list);
}
}
=20
return ret;
+}
+
+/* Convert a string to a uint16_t. Returns -1 on error, 0 on success. */
+int
+strtouint16(char *intstr, uint16_t *val16)
+{
+ long int lval;
+ char *endstr;
+
+ lval =3D strtoll(intstr, &endstr, 10);
+ if (*endstr !=3D '\0')
+ return -1;
+ if (lval > UINT16_MAX)
+ return -1;
+
+ *val16 =3D (uint16_t) lval;
+
+ return 0;
+}
+
+/* Convert a string to a uint32_t. Returns -1 on error, 0 on success. */
+int
+strtouint32(char *intstr, uint32_t *val32)
+{
+ long int lval;
+ char *endstr;
+
+ lval =3D strtoll(intstr, &endstr, 10);
+ if (*endstr !=3D '\0')
+ return -1;
+ if (lval > UINT32_MAX)
+ return -1;
+
+ *val32 =3D (uint32_t) lval;
+
+ return 0;
}
--MP_/t1SNLi=bRAWDFfVn/Pf24iE--
--Sig_/P/X_PV2fUdUR7IiqBsKCNe8
Content-Type: application/pgp-signature; name=signature.asc
Content-Disposition: attachment; filename=signature.asc
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
iEYEARECAAYFAk77Tc8ACgkQc7h7cu1Hpp4/GwCdFdFccXLhCJdDHjcaQ9ZO+R/G
nwsAoKUBJ5xiTdS0lOQapyKkN3JVB1Ft
=PRpE
-----END PGP SIGNATURE-----
--Sig_/P/X_PV2fUdUR7IiqBsKCNe8--
(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.