If the file descriptor passed to dprintf is connected to /dev/kmsg on a modern Linux kernel then dprintf fails (apparently because /dev/kmsg does not support seeking.) Steps to reproduce: 1. Run a Linux kernel with new-style /dev/kmsg (I was running Debian Jessie's v3.16 kernel but others as old as v3.8 show the same symptom.) 2. Compile the following code: #include <stdio.h> int main() { int r = dprintf(1, "test\n"); fprintf(stderr, "Result: %d %m\n", r); return 0; } 3. Run ./a.out and the result is as expected test Result: 5 Success 4. Run "./a.out >/dev/kmsg" and dprintf fails: Result: -1 Bad file descriptor and no output appears in the kernel log. Expected result: dprintf should work just as well on /dev/kmsg as anything else. Reproduced in Debian Jessie's glibc v2.19 and glibc master at 56cf2763819d2f721c98f2b8bcc04a3c673837d3.
I think this is a bug in the /dev/kmsg driver. It should return ESPIPE instead of EBADF.
The problem appears to be that devkmsg_open returns without allocating a devkmsg_user struct if opened with O_WRONLY, which causes devkmsg_llseek to return EBADF, even though the file is properly opened. Please report that to the kernel devs.
(In reply to Andreas Schwab from comment #2) > The problem appears to be that devkmsg_open returns without allocating a > devkmsg_user struct if opened with O_WRONLY, which causes devkmsg_llseek to > return EBADF, even though the file is properly opened. Please report that > to the kernel devs. I think that's intentional. A write-only /dev/kmsg is intended to be lighter-weight than a readable one. What seems to be wrong is unconditionally returning EBADF in that situation. ESPIPE would presumably be better. Even if the device were opened for reading too and we got past that point I think dprintf would still get upset since SEEK_CUR isn't handled so devkmsg_llseek would yield EINVAL. I think both cases need fixing. I'll try posting a kernel patch. Thanks for your help.
(In reply to Mike Crowe from comment #3) > Even if the device were opened for reading too and we got past that point I > think dprintf would still get upset since SEEK_CUR isn't handled so > devkmsg_llseek would yield EINVAL. This case can be reproduced with "./a.out 1<>/dev/kmsg" which yields: Result: -1 Invalid argument
(In reply to Andreas Schwab from comment #2) > Please report that to the kernel devs. http://lkml.iu.edu/hypermail/linux/kernel/1501.1/05813.html
Isn't it something of a bug (performance, if nothing else) that dprintf is making useless seek attempts on the file descriptor?
Are they useless?
Yes. Presumably the seek is part of setting up the general-case FILE for glibc's libio stdio ops to know about, but it's completely irrelevant to a single write-only operation on a temporary FILE structure. dprintf should be operating more like the virtual FILEs used for snprintf, fmemopen, fopencookie, etc. rather than using the same ops as fopen so it doesn't pull in all this overhead to every write.