Search code examples
cposixcompiler-explorer

Why does fopen() fail to open /dev/null but open() succeeds?


On Godbolt, opening /dev/null for writing fails when you use fopen but succeeds when you use open, and I have no idea why.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>

int main() {
    if (fopen("/dev/null", "w") == NULL) {
        perror("fopen");
    }
    if (open("/dev/null", O_WRONLY) == -1) {
        perror("open");
    }
}

https://godbolt.org/z/1Y6x58Tv6

Edit: I've since opened a bug report.


Solution

  • I mostly agree with the existing answer:

    fopen( "/dev/null", "w") means "open for writing, create if it doesn't exist, then truncate to zero bytes"

    By trial and error, I discovered that the problematic flag is O_CREAT — you can't create /dev/null if it doesn't exist. Go figure.

    Also by trial and error: the following works:

    fopen("/dev/null", "r+")
    

    Here, "r+" means "open for reading and writing", which is a clumsy way to say "the file should exist". You don't need read permissions, so it's less than ideal.


    Another way to make this work:

    int fd = open("/dev/null", O_WRONLY);
    FILE *f = fdopen(fd, "w");
    

    The manual page for fdopen says

    The mode of the stream ... must be compatible with the mode of the file descriptor

    which is vague, but of course this has no chance to fail because of O_CREATfdopen has no access to file name so it can't try to create it.


    This looks like a configuration problem on this specific system; fopen with plain "w" mode should work. So you shouldn't change the way you usually write code because of this.