Chris_F
Chris_F

Reputation: 5567

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.

Upvotes: 5

Views: 280

Answers (2)

anatolyg
anatolyg

Reputation: 28300

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.

Upvotes: 7

Andrew Henle
Andrew Henle

Reputation: 1

fopen( "/dev/null", "w" ) means "open for writing, create if it doesn't exist, then truncate to zero bytes", which is not the same as open("/dev/null", O_WRONLY), which means "open for writing if it exists".

So fopen( "/dev/null", "w" ) uses something like open("/dev/null", O_WRONLY | O_TRUNC | O_CREAT, 0666 ); to either create or truncate the file, which also fails with "Permission denied" because the caller doesn't have permission on the Godbolt to truncate /dev/null.

Upvotes: 6

Related Questions