在 Linux 中管理設備
Linux 目錄結構中有很多有趣的功能,這次我會講到 /dev
目錄一些迷人之處。在繼續閱讀這篇文章之前,建議你看看我前面的文章。Linux 文件系統,一切皆為文件,這兩篇文章介紹了一些有趣的 Linux 文件系統概念。請先看看 - 我會等你看完再回來。
……
太好了 !歡迎回來。現在我們可以繼續更詳盡地探討 /dev
目錄。
設備文件
設備文件也稱為設備特定文件。設備文件用來為操作系統和用戶提供它們代表的設備介面。所有的 Linux 設備文件均位於 /dev
目錄下,是根 (/
) 文件系統的一個組成部分,因為這些設備文件在操作系統啟動過程中必須可以使用。
關於這些設備文件,要記住的一件重要的事情,就是它們大多不是設備驅動程序。更準確地描述來說,它們是設備驅動程序的門戶。數據從應用程序或操作系統傳遞到設備文件,然後設備文件將它傳遞給設備驅動程序,驅動程序再將它發給物理設備。反向的數據通道也可以用,從物理設備通過設備驅動程序,再到設備文件,最後到達應用程序或其他設備。
讓我們以一個典型命令的數據流程來直觀地看看。
圖 1:一個典型命令的簡單數據流程。
在上面的圖 1 中,顯示一個簡單命令的簡化數據流程。從一個 GUI 終端模擬器,例如 Konsole 或 xterm 中發出 cat /etc/resolv.conf
命令,它會從磁碟中讀取 resolv.conf
文件,磁碟設備驅動程序處理設備的具體功能,例如在硬碟驅動器上定位文件並讀取它。數據通過設備文件傳遞,然後從命令到設備文件,然後到 6 號偽終端的設備驅動,然後在終端會話中顯示。
當然, cat
命令的輸出可以以下面的方式被重定向到一個文件, cat /etc/resolv.conf > /etc/resolv.bak
,這樣會創建該文件的備份。在這種情況下,圖 1 左側的數據流量將保持不變,而右邊的數據流量將通過 /dev/sda2
設備文件、硬碟設備驅動程序,然後到硬碟驅動器本身。
這些設備文件使得使用標準流 (STD/IO) 和重定向訪問 Linux 或 Unix 計算機上的任何一個設備非常容易。只需將數據流定向到設備文件,即可將數據發送到該設備。
設備文件類別
設備文件至少可以按兩種方式劃分。第一種也是最常用的分類是根據與設備相關聯的數據流進行劃分。比如,tty (teletype) 和串列設備被認為是基於字元的,因為數據流的傳送和處理是以一次一個字元或位元組進行的;而塊類型設備(如硬碟驅動器)是以塊為單位傳輸數據,通常為 256 個位元組的倍數。
您可以在終端上以一個非 root 用戶,改變當前工作目錄(PWD
)到 /dev
,並顯示長目錄列表。 這將顯示設備文件列表、文件許可權及其主、次設備號。 例如,下面的設備文件只是我的 Fedora 24 工作站上 /dev
目錄中的幾個文件。 它們表示磁碟和 tty 設備類型。 注意輸出中每行的最左邊的字元。 b
代表是塊類型設備,c
代表字元設備。
brw-rw---- 1 root disk 8, 0 Nov 7 07:06 sda
brw-rw---- 1 root disk 8, 1 Nov 7 07:06 sda1
brw-rw---- 1 root disk 8, 16 Nov 7 07:06 sdb
brw-rw---- 1 root disk 8, 17 Nov 7 07:06 sdb1
brw-rw---- 1 root disk 8, 18 Nov 7 07:06 sdb2
crw--w---- 1 root tty 4, 0 Nov 7 07:06 tty0
crw--w---- 1 root tty 4, 1 Nov 7 07:07 tty1
crw--w---- 1 root tty 4, 10 Nov 7 07:06 tty10
crw--w---- 1 root tty 4, 11 Nov 7 07:06 tty11
識別設備文件更詳細和更明確的方法是使用設備主要以及次要號。 磁碟設備主設備號為 8,將它們指定為 SCSI 塊設備。請注意,所有 PATA 和 SATA 硬碟驅動器都由 SCSI 子系統管理,因為舊的 ATA 子系統多年前就由於代碼質量糟糕而被認為不可維護。造成的結果就是,以前被稱為 「hd[a-z]」 的硬碟驅動器現在被稱為 「sd[a-z]」。
你大概可以從上面的示例中推出磁碟驅動器次設備號的模式。次設備號 0、 16、 32 等等,直到 240,是整個磁碟的號。所以主/次 8/16 表示整個磁碟 /dev/sdb
, 8/17 是第一個分區的設備文件,/dev/sdb1
。數字 8/34 代表 /dev/sdc2
。
在上面列表中的 tty 設備文件編號更簡單一些,從 tty0 到 tty63 。
Kernel.org 上的 Linux 下的已分配設備文件是設備類型和主次編號分配的正式註冊表。它可以幫助您了解所有當前定義的設備的主要/次要號碼。
趣味設備文件
讓我們花幾分鐘時間,執行幾個有趣的實驗,演示 Linux 設備文件的強大和靈活性。 大多數 Linux 發行版都有 1 到 7 個虛擬控制台,可用於使用 shell 介面登錄到本地控制台會話。 可以使用 Ctrl-Alt-F1
(控制台 1),Ctrl-Alt-F2
(控制台 2)等鍵盤組合鍵來訪問。
請按 Ctrl-Alt-F2
切換到控制台 2。在某些發行版,登錄顯示的信息包括了與此控制台關聯的 tty 設備,但大多不包括。它應該是 tty2,因為你是在控制台 2 中。
以非 root 用戶身份登錄。 然後你可以使用 who am i
命令 — 是的,就是這個命令,帶空格 — 來確定哪個 tty 設備連接到這個控制台。
在我們實際執行此實驗之前,看看 /dev
中的 tty2 和 tty3 的設備列表。
ls -l /dev/tty[23]
有大量的 tty 設備,但我們不關心他們中的大多數,只注意 tty2 和 tty3 設備。 作為設備文件,它們沒什麼特別之處。它們都只是字元類型設備。我們將使用這些設備進行此實驗。 tty2 設備連接到虛擬控制台 2,tty3 設備連接到虛擬控制台 3。
按 Ctrl-Alt-F3
切換到控制台 3。再次以同一非 root 用戶身份登錄。 現在在控制台 3 上輸入以下命令。
echo "Hello world" > /dev/tty2
按 Ctrl-Alt-f2
鍵以返回到控制台 2。字元串 「Hello world」(沒有引號)將顯示在控制台 2。
該實驗也可以使用 GUI 桌面上的終端模擬器來執行。 桌面上的終端會話使用 /dev
中的偽終端設備,如 /dev/pts/1
。 使用 Konsole 或 Xterm 打開兩個終端會話。 確定它們連接到哪些偽終端,並使用一個向另一個發送消息。
現在繼續實驗,使用 cat
命令,試試在不同的終端上顯示 /etc/fstab
文件。
另一個有趣的實驗是使用 cat
命令將文件直接列印到印表機。 假設您的印表機設備是 /dev/usb/lp0
,並且您的印表機可以直接列印 PDF 文件,以下命令將在您的印表機上列印 test.pdf
文件。
cat test.pdf > /dev/usb/lp0
/dev
目錄包含一些非常有趣的設備文件,這些文件是硬體的入口,人們通常不認為這是硬碟驅動器或顯示器之類的設備。 例如,系統存儲器 RAM 不是通常被認為是「設備」的東西,而 /dev/mem
是通過其可以實現對存儲器的直接訪問的入口。 下面的例子有一些有趣的結果。
dd if=/dev/mem bs=2048 count=100
上面的 dd
命令提供比簡單地使用 cat
命令 dump 所有系統的內存提供了更多的控制。 它提供了指定從 /dev/mem
讀取多少數據的能力,還允許指定從存儲器哪裡開始讀取數據。雖然讀取了一些內存,但內核響應了以下錯誤,在 /var/log/messages
中可以看到。
Nov 14 14:37:31 david kernel: usercopy: kernel memory exposure attempt detected from ffff9f78c0010000 (dma-kmalloc-512) (2048 bytes)
這個錯誤意味著內核正在通過保護屬於其他進程的內存來完成它的工作,這正是它應該工作的方式。 所以,雖然可以使用 /dev/mem
來顯示存儲在 RAM 內存中的數據,但是訪問的大多數內存空間是受保護的並且會導致錯誤。 只可以訪問由內核內存管理器分配給運行 dd
命令的 BASH shell 的虛擬內存,而不會導致錯誤。 抱歉,但你不能窺視不屬於你的內存,除非你發現了一個可利用的漏洞。
/dev
中還有一些非常有趣的設備文件。 設備文件 null
,zero
,random
和 urandom
不與任何物理設備相關聯。
例如,空設備 /dev/null
可以用作來自 shell 命令或程序的輸出重定向的目標,以便它們不顯示在終端上。 我經常在我的 BASH 腳本中使用這個,以防止向用戶展示可能會讓他們感到困惑的輸出。 /dev/null
設備可用於產生一個空字元串。 使用如下所示的 dd
命令查看 /dev/null
設備文件的一些輸出。
# dd if=/dev/null bs=512 count=500 | od -c
0+0 records in
0+0 records out
0 bytes copied, 1.5885e-05 s, 0.0 kB/s
0000000
注意,因為空字元什麼也沒有所以確實沒有可見的輸出。 注意看看位元組數。
/dev/random
和 /dev/urandom
設備也很有趣。 正如它們的名字所暗示的,它們都產生隨機輸出,不僅僅是數字,而是任何位元組組合。 /dev/urandom
設備產生的是確定性的隨機輸出,並且非常快。 這意味著輸出由演算法確定,並使用種子字元串作為起點。 結果,如果原始種子是已知的,則黑客可以再現輸出,儘管非常困難,但這是有可能的。 使用命令 cat /dev/urandom
可以查看典型的輸出,使用 Ctrl-c
退出。
/dev/random
設備文件生成非確定性的隨機輸出,但它產生的輸出更慢一些。 該輸出不是由依賴於先前數字的演算法確定的,而是由擊鍵動作和滑鼠移動而產生的。 這種方法使得複製特定系列的隨機數要困難得多。使用 cat
命令去查看一些來自 /dev/random
設備文件輸出。嘗試移動滑鼠以查看它如何影響輸出。
正如其名字所暗示的,/dev/zero
設備文件產生一個無止境的零作為輸出。 注意,這些是八進位零,而不是ASCII字元零(0
)。 使用如下所示的 dd
查看 /dev/zero
設備文件中的一些輸出
# dd if=/dev/zero bs=512 count=500 | od -c
0000000
*
500+0 records in
500+0 records out
256000 bytes (256 kB, 250 KiB) copied, 0.00126996 s, 202 MB/s
0764000
請注意,此命令的位元組數不為零。
創建設備文件
在過去,在 /dev
中的設備文件都是在安裝時創建的,導致一個目錄中有幾乎所有的設備文件,儘管大多數文件永遠不會用到。 在不常發生的情況,例如需要新的設備文件,或意外刪除後需要重新創建設備文件,可以使用 mknod
程序手動創建設備文件。 前提是你必須知道設備的主要和次要號碼。
CentOS 和 RHEL 6、7,以及 Fedora 的所有版本——可以追溯到至少 Fedora 15,使用較新的創建設備文件的方法。 所有設備文件都是在引導時創建的。 這是因為 udev 設備管理器在設備添加和刪除發生時會進行檢測。這可實現在主機啟動和運行時的真正的動態即插即用功能。 它還在引導時執行相同的任務,通過在引導過程的很早的時期檢測系統上安裝的所有設備。 Linux.com 上有一篇很棒的對 udev 的描述。
回到 /dev
中的文件列表,注意文件的日期和時間。 所有文件都是在上次啟動時創建的。 您可以使用 uptime
或者 last
命令來驗證這一點。在上面我的設備列表中,所有這些文件都是在 11 月 7 日上午 7:06 創建的,這是我最後一次啟動系統。
當然, mknod
命令仍然可用, 但新的 MAKEDEV
(是的,所有字母大寫,在我看來是違背 Linux 使用小寫命令名的原則的) 命令提供了一個創建設備文件的更容易的界面。 在當前版本的 Fedora 或 CentOS 7 中,默認情況下不安裝 MAKEDEV
命令;它安裝在 CentOS 6。您可以使用 YUM 或 DNF 來安裝 MAKEDEV 包。
結論
有趣的是,我很久沒有創建一個設備文件的需要了。 然而,最近我遇到一個有趣的情況,其中一個我常使用的設備文件沒有創建,我不得不創建它。 之後該設備再沒出過問題。所以丟失設備文件的情況仍然可以發生,知道如何處理它可能很重要。
設備文件有無數種,您遇到的設備文件我可能沒有涵蓋到。 這些信息在所下面引用的資源中有大量的細節信息可用。 關於這些文件的功能和工具,我希望我已經給您一些基本的了解,下一步您自己可以探索更多。
資源
- 一切皆文件, David Both, Opensource.com
- Linux 文件系統介紹, David Both, Opensource.com
- 文件系統層次結構, The Linux Documentation Project
- 設備文件, Wikipedia
- Linux 下已分配設備, Kernel.org
via: https://opensource.com/article/16/11/managing-devices-linux
作者:David Both 譯者:erlinux 校對:jasminepeng
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive