2014-02-07 53 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設置爲EFAULTstat()man頁僅將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(),BUF不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

感謝您的解釋。我會期待一個段錯誤。我不知道爲什麼這現在不會導致一個。 – anthonybrice

+1

@anthonybrice你在GNU/Hurd系統上得到了一個段錯誤(一個好東西IMO)。 – Demi