Я пишу программу, которая при запуске из двух отдельных сеансов bash как два отдельных процесса открывает именованный канал между ними, чтобы позволить передавать строки от одного к другому.Почему stat() возвращает EFAULT?
Когда процесс сначала выполняется с одного терминала, он проверяет stat(fname, buf) == -1
, чтобы увидеть, существует ли файл по пути fname
, а если нет, создает его. Затем процесс предполагает, что, поскольку он должен был сделать FIFO
, он будет отправлять сообщения через него и соответственно.
После этого программа может быть запущена с другого терминала, который должен определить, что он будет приемником сообщений через трубу, проверив stat(fname, buf) == -1
. Условие должно возвращать false сейчас, и stat(fname, buf)
сам должен вернуть 0
, потому что теперь существует файл на fname
.
Но по причинам, которые я не могу различить, когда выполняется второй процесс, stat(fname, buf)
все еще возвращает -1
. Переменная errno
установлена в EFAULT
. Страница man
для stat()
только описывает EFAULT
как «Плохой адрес». Любая помощь, определяющая, почему возникает ошибка или что означает «Плохой адрес». было бы очень оценено.
Я проверил, что файл действительно создан первым процессом, как предполагалось. Первый процесс ждет на линии pipe = open(fname, O_WRONLY);
, потому что он не может продолжаться до тех пор, пока не откроется другой конец pipe
.
Редактировать: Ниже приведена автономная реализация моего кода. Я подтвердил, что он компилирует и испытывает проблему, описанную здесь.
#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;
}
Показать код в вопросе, предпочтительно в [SSCCE] (http://www.sscce.org). Это не похоже на то, что для воспроизведения потребуется много кода. – WhozCraig
EFAULT скорее всего означает, что либо 'fname', либо' buf' являются недопустимыми указателями. – Art
Кроме того, использование 'stat' таким способом - отличный способ проверить, существует ли файл. Вы открываете себя до [TOCTOU] (http://en.wikipedia.org/wiki/Time_of_check_to_time_of_use) гонок. – Art