Linux -- dup, dup2, dup3

翻譯自Ubuntu 19版本下的Linux Programmer's Manual
  1. 函數名:dup, dup2, dup3 - 複製一個文件描述符

  2. 概要:

    #include <unistd.h>
    
    int dup(int oldfd);
    int dup2(int oldfd, int newfd);
    
    #define _GNU_SOURCE             /* 參閱 feature_test_macros(7) */
    #include <fcntl.h>              /* 獲取 O_*的常量定義 */
    #include <unistd.h>
    
    int dup3(int oldfd, int newfd, int flags);
    
  3. 描述:
      dup()系統調用創建文件描述符oldfd的副本,給新描述符使用編號最低的未使用的文件描述符。
      成功返回後,新舊文件描述符可以互換使用。它們引用相同打開的文件描述符(參見open(2)),因此共享文件偏移量和文件狀態標誌是一致的;例如,如果對其中一個文件描述符使用lseek(2)修改了文件偏移量,那麼對另一個也將改變偏移量。
      這兩個文件描述符不共享文件描述符標誌(close-on-exec標誌)。close-on-exec標誌(FD_CLOEXEC;請參閱fcntl(2)),對複製的文件描述符是關閉的。
    dup2()
      dup2()系統調用執行與dup()相同的任務,但是它沒有使用編號最低的未使用的文件描述符,而是使用newfd中指定的文件描述符號。如果文件描述符newfd以前是打開的,那麼在重用它之前將默認關閉已打開的文件描述符newfd。
      關閉和重用文件描述符newfd的步驟是自動執行的。這很重要,因爲嘗試使用close(2)和dup()實現等價的功能將受到競爭條件的限制,因此newfd可能在這兩個步驟之間重用。這種重用可能是因爲主程序被分配文件描述符的信號處理程序中斷,或者是因爲並行線程分配文件描述符。
    注意以下幾點:
      *如果oldfd不是有效的文件描述符,則調用失敗,newfd不會關閉。
      *如果oldfd是一個有效的文件描述符,並且newfd具有與oldfd相同的值,那麼dup2()什麼也不做,返回newfd。
    dup3()
    dup3()與dup2()相同,只是:
      調用者可以通過在標誌中指定O_CLOEXEC來強制爲新的文件描述符設置close-on-exec標誌。請參閱open(2)中對相同標誌的描述,瞭解這可能有用的原因。
      如果oldfd等於newfd,那麼dup3()將失敗,並帶有EINVAL錯誤。

  4. 返回值:
       如果成功,這些系統調用將返回新的文件描述符。在出現錯誤時,返回-1,並適當地設置errno。

  5. ERRORS:
      EBADF:oldfd不是一個打開的文件描述符。
      EBADF:newfd超出了文件描述符的允許範圍(請參閱getrlimit(2)中關於RLIMIT_NOFILE的討論)。
      EBUSY:(僅限Linux)在使用open(2)和dup()的競爭條件下,dup2()或dup3()可以返回此值。
      EINTR:dup2()或dup3()調用被信號中斷;參閱signal(7)。
      EINVAL:(dup3())標誌包含無效值。
      EINVAL:(dup3())oldfd等於newfd.
      EMFILE:每個進程對打開的文件描述符數量的限制已經達到(參見getrlimit(2)中對RLIMIT_NOFILE的討論)。

  6. 注意:
      當newfd超出範圍時,dup2()返回的錯誤值與fcntl(…, F_DUPFD, …)返回的錯誤值是不同的。在某些系統上,dup2()有時也會像F_DUPFD一樣返回EINVAL。
      如果newfd是打開的,那麼在close(2)時報告的任何錯誤都將丟失。如果這是值得關注的,那麼除非程序是單線程的,並且沒有在信號處理程序中分配文件描述符,否則正確的方法是在調用dup2()之前不關閉newfd,因爲上面描述了競爭條件。相反,可以使用如下代碼:

    /*獲取“newfd”的副本,以便隨後檢查close()錯誤;EBADF錯誤意味着“newfd”沒有打開。*/
    	tmpfd = dup(newfd);
         if (tmpfd == -1 && errno != EBADF) {
             /* 處理意外的dup()錯誤 */
         }
    /*原子操作,複製'oldfd'到'newfd'上*/
    	if (dup2(oldfd, newfd) == -1) {
           /* 處理 dup2()錯誤 */
        }
    /* 現在檢查“newfd”最初引用的文件上的close()錯誤 */
        if (tmpfd != -1) {
             if (close(tmpfd) == -1) {
                 /* 處理來自關閉的錯誤 */
             }
         }
    
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章