tips: 這一章的習題是真的多,花費了我許多時間,說實話,這本書的習題難度對我而言還是挺大的。這裏有一些小建議,看的時候可以同時參考其他書,我參考的是《UNIX環境高級編程》和《Linux C編程一站式學習》,第二本我在最底下留下了鏈接,是在線版本的。然後這一章的很多題還是不太懂,如果你知道答案歡迎評論告訴我,謝謝。
5.2
現在的biff
命令是用來控制命令行環境下有新郵件時是否提示,和作者的意思似乎不太一樣……
5.3
試了一下, ln
只能創建設備文件的軟鏈接,
5.4
使用mknod
重新創建,比如
sudo mknod /dev/ttytest c 5 0
其中c
表示字符設備,後面的兩個數字分別是主設備號和從設備號。
5.5
這是一個排列組合問題,但是有個條件是lseek
操作要在write
之前完成,所以並不是 4x3x2 種情況,而是 6 種可能的組合,分別是:用戶A、B 順序定位寫入操作的兩種情況、用戶A和B定位後完成寫入的四種情況,前一種結果是正確寫入,後一種是A覆蓋B或者B覆蓋A。
5.6
在 do_sys_open
函數中調用 build_open_flags
函數,其中
if (flags & O_APPEND)
acc_mode |= MAY_APPEND;
校驗了並設置了 O_APPEND
。我查閱的是Linux 2.6
的代碼,在 mm\filemap.c
文件中有一個函數_generic_file_aio_write
,Linux 大多數文件系統的 write 函數都調用這個函數,其中調用了 generic_write_checks
函數,其中
if (file->f_flags & O_APPEND)
*pos = i_size_read(inode);
表明如果發現文件是以追加方式打開的,則將從 inode 中讀取到的最新文件大小作爲偏移量,從而實現了自動定位。
5.7
這個問題有點複雜,我沒有搞懂,推薦一篇文章
5.8
這裏我寫了一段簡答的代碼測試了一下,代碼寫的比較爛,多多包涵
#include <stdio.h>;
#include <string.h>;
#include <stdlib.h>;
int main(int argc, char const *argv[])
{
int result;
char str1[] = "first string\n";
char str2[] = "second string\n";
FILE *file1 = fopen("test", "a");
if (file1 < 0)
{
perror("fopen error");
exit(1);
}
FILE *file2 = fopen("test", "a");
if (file2 < 0)
{
perror("fopen error");
exit(1);
}
result = fwrite(str1, strlen(str1), 1, file1);
result = fwrite(str2, strlen(str2), 1, file2);
result = fwrite(str1, strlen(str1), 1, file1);
result = fwrite(str2, strlen(str2), 1, file2);
fclose(file1);
fclose(file2);
return 0;
}
運行後結果如下:
first string
first string
second string
second string
從結果上來看 fopen
僅僅是在打開文件後定位文件的末尾,每次都是在此基礎上寫入的。
5.9
在我的deepin15.11
上分別輸出:
- echo is on , since its bit is 1
- bash: /dev/lp: 沒有那個文件或目錄
- tcgetattr: Inappropriate ioctl for device
- bash: tty: 沒有那個文件或目錄
5.10
我這裏兩個 tty 分別連接到 /dev/pts/1
和 /dev/pts/2
,按照書上的步驟第四步顯示回顯開啓,第五步顯示回顯關閉。
使用 stty 也是一樣,至於原因我還不知道…
5.13
查看了APUE
相關章節,發現有三種 O_SYNC,O_SYNC
要求等待數據和屬性都寫入才返回,O_DSYNC
只要求等待數據寫入,O_RSYNC
要求讀取時緩存中的所有內容全部讀取完才返回,至於習題中只要求 i-節點也就是屬性的沒有找到。
5.14
向終端文件寫入數據就是把數據發送到設備,權限寫意味着允許向終端發送數據(書上原話)。那麼讀權限就意味着允許接受終端數據。
可是我設置了權限以後向 ls
這樣的命令可以使用,who > /dev/pts/1
就提示權限不足了。
5.15
不支持 read 和 write 的沒找到,不支持 lseek 的有 gpmctl
.
5.16
沒看懂題目
5.17
還是沒看懂題目
5.18
當我們在 shell 下運行 ls
這樣的命令的時候,實際上系統會先調用fork
創建一個子進程,然後在調用exec
運行ls
程序。這個子進程的進程控制塊(PCB
)是根據父進程複製而來的,所以其中控制終端的信息是一樣的,因此終端處於無回顯狀態。而每次打開同一個文件返回的文件描述符是不一樣的,是相互獨立的,所以不能自動獲得自動添加模式。
519
這道題想通過把終端的標準輸出設置爲O_APPEND
,結果沒有成功…
5.20
通過fcntl
設置的都是當前進程如何訪問設備或文件的訪問控制屬性,例如讀、寫、追加、非阻塞、加鎖 等,但並不設置文件或設備本身的屬性,例如文件的讀寫權限、串口波特率等。ioctl
函數用於設置某些設備本身的屬性,例如串口波特率、終端窗口大小。
5.21
/dev/null
設備文件只有一個作用,往它裏面寫任何數據都被直接丟棄。因此保證了該命令執行時屏幕上沒有任何輸出,既不打印正常信息也不打印錯誤信息,讓命令安靜地執行,這種寫法在 Shell 腳本中很常見。
/dev/zero
是“零”設備,可以無限的提供空字符(0x00
,ASCII
代碼NUL
),常用來生成一個特定大小的文件。
除此之外還有/dev/random
,隨機數設備,提供不間斷的隨機字節流,生隨機數據依賴系統中斷,當系統中斷不足時,/dev/random
設備會“掛起”,因而產生數據速度較慢,但隨機性好;還有一個類似的叫/dev/urandom
,不依賴系統中斷,數據產生速度快,但隨機性較低。
參考資料:
深入解析Linux內核I/O剖析(open,write實現)
rename代碼閱讀(linux 3.10.104)
Linux C編程一站式學習
Linux C 編程 —— fcntl、ioctl和stat區別
Linux中的虛擬設備/dev/null、/dev/zero、/dev/random和/dev/urandom