2014-02-07 4 views
0

Я пишу программу, которая при запуске из двух отдельных сеансов 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; 
} 
+0

Показать код в вопросе, предпочтительно в [SSCCE] (http://www.sscce.org). Это не похоже на то, что для воспроизведения потребуется много кода. – WhozCraig

+0

EFAULT скорее всего означает, что либо 'fname', либо' buf' являются недопустимыми указателями. – Art

+0

Кроме того, использование 'stat' таким способом - отличный способ проверить, существует ли файл. Вы открываете себя до [TOCTOU] (http://en.wikipedia.org/wiki/Time_of_check_to_time_of_use) гонок. – Art

ответ

1

У вас есть этот кусок кода:

struct stat* buf; 
... 
if (((!pitcher && !catcher && stat(fname, buf) == -1) 

Когда вы звоните stat(), ЬиЕ не initalized и там никто не знает, что он указывает.

Вы должны выделить для него некоторое хранилище, поэтому у stat() есть место, где можно сохранить результат. Проще всего просто выделить его в стек:

struct stat buf; 
... 
if (((!pitcher && !catcher && stat(fname, &buf) == -1) 
+0

Предположительно, поскольку он не возвращает 'EFAULT' для первого запуска,' stat' проверяет, существует ли файл перед проверкой указателя. Это кажется мне обратным (сначала я проверяю параметры, и все, что не попадает в файловую систему до того, как это происходит), но эта случайная реализация stat ведет себя как http: //www.cs.fsu. edu/~ baker/devices/lxr/http/source/linux/fs/stat.c –

+0

Большое спасибо! Теперь я вижу, и я полагаю, что я должен сделать то же самое для 'fname', чтобы его пространство было выделено. Я все еще новичок в указателях. Сегфап бы подтолкнул меня к этому. – anthonybrice

+0

@ user110524 fname в порядке. У вас есть строковый литерал, и вы указываете fname на начало этого строкового литерала, что хорошо. (хотя, поскольку вы не можете изменить строковый литерал, вы можете сделать его const: const char * fname = "/ tmp/absFIFOO";) – nos

0

Вы не показали свой код, но EFAULT означает "плохой адрес. Это означает, что вы неправильно назначили (или передали) свой буфер для stat или имя файла (fname).

0

buf не инициализируется нигде. Что именно вы ожидаете?

+0

Спасибо за объяснение. Я ожидал бы segfault. Я понятия не имею, почему это не вызывает этого сейчас. – anthonybrice

+1

@anthonybrice Вы получаете segfault на системах GNU/Hurd (хорошая вещь IMO). – Demi

Смежные вопросы