4

Some kinds of pseudo-files, like many in the procfs and sysfs virtual file systems, have no file size (stat returns st_size == 0) and do not support SEEK_END in fseek. These file system objects, such as /proc/cpuinfo, behave more like FIFOs than regular random-access files. Unfortunately, they lie about their file type too: their st_mode field includes the S_IFREG bit, which implies a regular file, not the S_IFIFO bit.

This causes problems with input code that tries to be "smarter" about managing data, and there any many reports of tools which hang when they look at /proc/* files.

I'm working on one of those tools, which has a general-purpose stream input system that can get a stream from various sources, indicated by the user. I can also handle non-random-access streams like pipes and sockets which are purely "sequential," and the same techniques used for them would work on procfs/sysfs/other virtual file system objects -- but I must be able to tell unambiguously when I'm looking at one.

Given a FILE pointer, file descriptor, or file pathname, how can I determine in C whether I'm looking at one of these troublesome pseudo-file objects? (Note: just checking for a path beginning with /proc is not sufficient, since a file system can be mounted arbitrarily. I need the OS to tell me if I can trust a file's st_size and SEEK_END.) Is there a reasonably portable-ish solution for modern *nixes?

(This is a programming question; feel free to migrate it to SO if required.)

3

If you stat a file descriptor and it turns out that the size is reported as 0, then either the file is empty or the size is unknown. If the file is empty, there's not much point playing games to read it more efficiently.

So, if the size is unknown, you will have to use your alternate code path, and if the file is empty, using the alternate code path shouldn't be a problem.

I'd warn against trying to diagnose file type just based on the filename, since that will open you up to a bait-and-switch attack (or bug). You shouldn't try to figure out anything until you've opened the file successfully, and then you should make sure that you use the file descriptor, directly or indirectly, rather than the name, because the name might no longer be associated with the same file.

Hope that helps.

  • 1
    The insight about 0-length files is brilliant. Although Hauke's answered the question I asked (which is probably more valuable to future readers), you've solved my problem. – librik Jun 22 '13 at 5:19
3

Checking the path is only the second best idea. You can check the file system (device) instead: st_dev=makedev(0, 14). If the major number is 0 then it's proc, sys or the like.

Even the kernel cannot be sure about the nature of a file. Imagine a FUSE mount which contains parts of /proc. The kernel would assume a normal file system whereas it is a pseudo file system with the problems you want to avoid.

But if you know that SEEK_END doesn't work why don't you use that for the test?

  • Thanks! I assume you mean I would use major(st.st_dev) == 0? But your point about partial mounts is well-taken; that's why I hoped it was possible to ask the file directly. In answer to your last question: SEEK_END seeks to the beginning of the data in the pseudo-file rather than the end, which is wrong, but consistent with the (also incorrect) size of 0. So you can't use it to distinguish the pseudo-file from an regular empty file. – librik Jun 22 '13 at 0:38
  • Hm, I can't find documentation that a major device ID of 0 means "proc, sys, or the like," although experimentation on Linux machines demonstrates it. Could you point me in the right direction, please? – librik Jun 22 '13 at 5:24
  • 2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.