Hi Ken,
David's committed a directory test now, but I still think the underlying
cause is interesting, and some mess remains.
mhshow calls parse_mime()
parse_mime() calls get_content()
get_content() decides it's a message with a single text/plain part
(default)
Then the MIME display routines are called, and you end up in
open7Bit().
The part where YOU fail, "internal error (3)", I go past.
When Paul first reported the problem, I could re-create it and got the
"internal error". Then when the next email arrived, I couldn't. I can
create it consistently now depending on the directory I specify.
$ mhshow -file /tmp
$ mhshow -file /boot
mhshow: internal error(3)
$
On this (Arch, it's rather good) Linux, I see that
429 read_more (m_getfld_state_t s) {
443 num_read = fread (s->readpos, 1, MSG_INPUT_SIZE, s->iob);
does
fread(0x15cd030, 1, 4096, 0x15d1790 <unfinished ...>
SYS_fstat(3, 0x7fffa80952c0) = 0
SYS_read(3, "", 4096) = -21 (EISDIR)
<... fread resumed>) = 0
That causes Getc() to return EOF. So m_getfld() return FILEEOF. And
get_content() breaks its first loop on the first iteration.
ct->c_first_hf is still zero bytes, which the code assumes is a NULL
pointer, so that big loop is never entered.
We reach this epilogue and say the directory that yielded no bytes is
7-bit text/plain.
547 /*
* Check if we saw a Content-Type field.
* If not, then assign a default value for
* it, and the Init function.
*/
if (!ct->c_ctline) {
557 if (toplevel < 0) {
562 } else {
/*
* Else default type is text/plain
*/
if (get_ctinfo ("text/plain", ct, 0) == NOTOK)
goto out;
ct->c_type = CT_TEXT;
ct->c_ctinitfnx = InitText;
}
}
/* Use default Transfer-Encoding, if necessary */
if (!ct->c_celine) {
ct->c_encoding = CE_7BIT;
Init7Bit (ct);
}
return ct;
So far, similar behaviour and output can be seen with `mhshow -file
/dev/null' as that too yields no bytes. Should an email with no headers
be an error at this point, instead of being blessed as text/plain?
So, why the different behaviour for /tmp v. /boot? Ken pointed out the
`internal error(3)' test.
2148 int cc, fd, len, own_ct_fp = 0;
2238 if ((len = ct->c_end - ct->c_begin) < 0)
The values seen here are
/tmp ct->c_begin: 0 ct->c_end: 0
/boot ct->c_begin: 0 ct->c_end: 9223372036854775807
$ dc <<<16o9223372036854775807p
7FFFFFFFFFFFFFFF
Line 2148, quoted above, shows len is int, 32b here, so it gets the
bottom 32 bits of a large positive number in a buggy truncation and
becomes negative, -1. -1 - 0 < 0 is true.
Why is c_end the maximum signed 64b for /boot?
$ stat -c '%04D %n' /etc/passwd / /home /tmp /boot
0801 /etc/passwd
0801 /
0803 /home
0024 /tmp
0801 /boot
$
$ strace -e open,lseek perl -le \
> 'for (@ARGV) {open(F, $_); sysseek F, 0, 2}' \
> /etc/passwd / /home /tmp /boot |&
> egrep '^(open|lseek.*END)' |
> grep -B1 END
open("/etc/passwd", O_RDONLY) = 3
lseek(3, 0, SEEK_END) = 1713
open("/", O_RDONLY) = 3
lseek(3, 0, SEEK_END) = 9223372036854775807
open("/home", O_RDONLY) = 3
lseek(3, 0, SEEK_END) = 9223372036854775807
open("/tmp", O_RDONLY) = 3
lseek(3, 0, SEEK_END) = -1 EINVAL (Invalid argument)
open("/boot", O_RDONLY) = 3
lseek(3, 0, SEEK_END) = 9223372036854775807
$
IIRC, this is valid POSIX. :-) I suspect Paul has a similar filesystem
arrangement for /tmp to me.
--
Cheers, Ralph.
https://plus.google.com/+RalphCorderoy
_______________________________________________
Nmh-workers mailing list
Nmh-workers(_at_)nongnu(_dot_)org
https://lists.nongnu.org/mailman/listinfo/nmh-workers