Why is stat() returning EFAULT?
c, errno, mkfifo, named-pipes, stat
Solution
You have this piece of code:
struct stat* buf;
...
if (((!pitcher && !catcher && stat(fname, buf) == -1)
When you call `stat()`, buf isn't initalized and there's no telling what it points to.
You must allocate some storage for it, so `stat()` has a valid place to store the result. The easiest thing is to just allocate it on the stack:
struct stat buf;
...
if (((!pitcher && !catcher && stat(fname, &buf) == -1)
Problem
I'm writing a program that when run from two separate bash sessions as two separate processes, opens a named pipe between the two to allow strings to be sent from one to the other. When the process is first executed from one terminal, it checks `stat(fname, buf) == -1` to see if a file at path `fname` exists and if not, creates it. The process then assumes that since it was the one to make the `FIFO`, it is the one that will be sending messages through it and continues accordingly. After that occurs, the program can then be run from another terminal that should determine that it will be the receiver of messages through the pipe by checking `stat(fname, buf) == -1`. The condition should return false now, and `stat(fname, buf)` itself should return `0` because there exists a file at `fname` now. But for reasons I am unable to discern, when the second process is run, `stat(fname, buf)` still returns `-1`. The variable `errno` is set to `EFAULT`. The `man` page for `stat()` only decribes `EFAULT` as "Bad address." Any help determining why the error occurs or what is meant by "Bad address." would be greaty appreciated. I've verified that the file is indeed created by the first process as intended. The first process waits at the line `pipe = open(fname, O_WRONLY);` because it can't continue until the other end of `pipe` is opened. Edit: The following is a self-contained implementation of my code. I have confirmed that it compiles and experiences the problem I described here. ``` #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #define MAX_LINE 80 #define oops(m,x) { perror(m); exit(x); } int main(int argc, char const *argv[]) { char line[MAX_LINE]; int pipe, pitcher, catcher, initPitcher, quit; struct stat* buf; char* fname = "/tmp/absFIFOO"; initPitcher = catcher = pitcher = quit = 0; while (!quit) { if (((!pitcher && !catcher && stat(fname, buf) == -1) || pitcher) && !quit) { // Then file does not exist if (errno == ENOENT) { // printf("We're in the file does not exist part\n"); if (!pitcher && !catcher) { // Then this must be the first time we're running the program. This process will take care of the unlink(). initPitcher = 1; int stat; if (stat = mkfifo(fname, 0600) < 0) oops("Cannot make FIFO", stat); } pitcher = 1; // open a named pipe pipe = open(fname, O_WRONLY); printf("Enter line: "); fgets(line, MAX_LINE, stdin); if (!strcmp(line, "quit\n")) { quit = 1; } // actually write out the data and close the pipe write(pipe, line, strlen(line)); close(pipe); } } else if (((!pitcher && !catcher) || catcher) && !quit) { // The first condition is just a check to see if this is the first time we've run the program. We could check if stat(...) == 0, but that would be unnecessary catcher = 1; pipe = open("/tmp/absFIFO", O_RDONLY); // set the mode to blocking (note '~') int flags; flags &= ~O_NONBLOCK; fcntl(pipe, F_SETFL, flags); //what does this do? // read the data from the pipe read(pipe, line, MAX_LINE); if (!strcmp(line, "quit\n")) { quit = 1; } printf("Received line: %s\n", line); // close the pipe close(pipe); } } if (initPitcher) unlink(fname); return 0; } ```