天天看點

在 Linux 中管理裝置

探索 <code>/dev</code> 目錄可以讓您知道如何直接通路到 linux 中的裝置。

……

太好了 !歡迎回來。現在我們可以繼續更詳盡地探讨 <code>/dev</code> 目錄。

<a target="_blank"></a>

關于這些裝置檔案,要記住的一件重要的事情,就是它們大多不是裝置驅動程式。更準确地描述來說,它們是裝置驅動程式的門戶。資料從應用程式或作業系統傳遞到裝置檔案,然後裝置檔案将它傳遞給裝置驅動程式,驅動程式再将它發給實體裝置。反向的資料通道也可以用,從實體裝置通過裝置驅動程式,再到裝置檔案,最後到達應用程式或其他裝置。

讓我們以一個典型指令的資料流程來直覺地看看。

在 Linux 中管理裝置

圖 1:一個典型指令的簡單資料流程。

在上面的圖 1 中,顯示一個簡單指令的簡化資料流程。從一個 gui 終端仿真器,例如 konsole 或 xterm 中發出 <code>cat /etc/resolv.conf</code> 指令,它會從磁盤中讀取 <code>resolv.conf</code> 檔案,磁盤裝置驅動程式處理裝置的具體功能,例如在硬碟驅動器上定位檔案并讀取它。資料通過裝置檔案傳遞,然後從指令到裝置檔案,然後到 6 号僞終端的裝置驅動,然後在終端會話中顯示。

當然, <code>cat</code> 指令的輸出可以以下面的方式被重定向到一個檔案, <code>cat /etc/resolv.conf &gt; /etc/resolv.bak</code> ,這樣會建立該檔案的備份。在這種情況下,圖 1 左側的資料流量将保持不變,而右邊的資料流量将通過 <code>/dev/sda2</code> 裝置檔案、硬碟裝置驅動程式,然後到硬碟驅動器本身。

這些裝置檔案使得使用标準流 (std/io) 和重定向通路 linux 或 unix 計算機上的任何一個裝置非常容易。隻需将資料流定向到裝置檔案,即可将資料發送到該裝置。

裝置檔案至少可以按兩種方式劃分。第一種也是最常用的分類是根據與裝置相關聯的資料流進行劃分。比如,tty (teletype) 和串行裝置被認為是基于字元的,因為資料流的傳送和處理是以一次一個字元或位元組進行的;而塊類型裝置(如硬碟驅動器)是以塊為機關傳輸資料,通常為 256 個位元組的倍數。

您可以在終端上以一個非 root 使用者,改變目前工作目錄(<code>pwd</code>)到 <code>/dev</code> ,并顯示長目錄清單。 這将顯示裝置檔案清單、檔案權限及其主、次裝置号。 例如,下面的裝置檔案隻是我的 fedora 24 工作站上<code>/dev</code> 目錄中的幾個檔案。 它們表示磁盤和 tty 裝置類型。 注意輸出中每行的最左邊的字元。 <code>b</code> 代表是塊類型裝置,<code>c</code> 代表字元裝置。

<code>brw-rw---- 1 root disk 8, 0 nov 7 07:06 sda</code>

<code>brw-rw---- 1 root disk 8, 1 nov 7 07:06 sda1</code>

<code>brw-rw---- 1 root disk 8, 16 nov 7 07:06 sdb</code>

<code>brw-rw---- 1 root disk 8, 17 nov 7 07:06 sdb1</code>

<code>brw-rw---- 1 root disk 8, 18 nov 7 07:06 sdb2</code>

<code>crw--w---- 1 root tty 4, 0 nov 7 07:06 tty0</code>

<code>crw--w---- 1 root tty 4, 1 nov 7 07:07 tty1</code>

<code>crw--w---- 1 root tty 4, 10 nov 7 07:06 tty10</code>

<code>crw--w---- 1 root tty 4, 11 nov 7 07:06 tty11</code>

識别裝置檔案更詳細和更明确的方法是使用裝置主要以及次要号。 磁盤裝置主裝置号為 8,将它們指定為 scsi 塊裝置。請注意,所有 pata 和 sata 硬碟驅動器都由 scsi 子系統管理,因為舊的 ata 子系統多年前就由于代碼品質糟糕而被認為不可維護。造成的結果就是,以前被稱為 “hd[a-z]” 的硬碟驅動器現在被稱為 “sd[a-z]”。

你大概可以從上面的示例中推出磁盤驅動器次裝置号的模式。次裝置号 0、 16、 32 等等,直到 240,是整個磁盤的号。是以主/次 8/16 表示整個磁盤 <code>/dev/sdb</code> , 8/17 是第一個分區的裝置檔案,<code>/dev/sdb1</code>。數字 8/34 代表 <code>/dev/sdc2</code>。

在上面清單中的 tty 裝置檔案編号更簡單一些,從 tty0 到 tty63 。

讓我們花幾分鐘時間,執行幾個有趣的實驗,示範 linux 裝置檔案的強大和靈活性。 大多數 linux 發行版都有 1 到 7 個虛拟控制台,可用于使用 shell 接口登入到本地控制台會話。 可以使用 <code>ctrl-alt-f1</code>(控制台 1),<code>ctrl-alt-f2</code>(控制台 2)等鍵盤組合鍵來通路。

請按 <code>ctrl-alt-f2</code> 切換到控制台 2。在某些發行版,登入顯示的資訊包括了與此控制台關聯的 tty 裝置,但大多不包括。它應該是 tty2,因為你是在控制台 2 中。

以非 root 使用者身份登入。 然後你可以使用 <code>who am i</code> 指令 — 是的,就是這個指令,帶空格 — 來确定哪個 tty 裝置連接配接到這個控制台。

在我們實際執行此實驗之前,看看 <code>/dev</code> 中的 tty2 和 tty3 的裝置清單。

<code>ls -l /dev/tty[23]</code>

有大量的 tty 裝置,但我們不關心他們中的大多數,隻注意 tty2 和 tty3 裝置。 作為裝置檔案,它們沒什麼特别之處。它們都隻是字元類型裝置。我們将使用這些裝置進行此實驗。 tty2 裝置連接配接到虛拟控制台 2,tty3 裝置連接配接到虛拟控制台 3。

按 <code>ctrl-alt-f3</code> 切換到控制台 3。再次以同一非 root 使用者身份登入。 現在在控制台 3 上輸入以下指令。

<code>echo "hello world" &gt; /dev/tty2</code>

按 <code>ctrl-alt-f2</code> 鍵以傳回到控制台 2。字元串 “hello world”(沒有引号)将顯示在控制台 2。

該實驗也可以使用 gui 桌面上的終端仿真器來執行。 桌面上的終端會話使用 <code>/dev</code> 中的僞終端裝置,如 <code>/dev/pts/1</code>。 使用 konsole 或 xterm 打開兩個終端會話。 确定它們連接配接到哪些僞終端,并使用一個向另一個發送消息。

現在繼續實驗,使用 <code>cat</code> 指令,試試在不同的終端上顯示 <code>/etc/fstab</code> 檔案。

另一個有趣的實驗是使用 <code>cat</code> 指令将檔案直接列印到列印機。 假設您的列印機裝置是<code>/dev/usb/lp0</code>,并且您的列印機可以直接列印 pdf 檔案,以下指令将在您的列印機上列印 <code>test.pdf</code>檔案。

<code>cat test.pdf &gt; /dev/usb/lp0</code>

<code>/dev</code> 目錄包含一些非常有趣的裝置檔案,這些檔案是硬體的入口,人們通常不認為這是硬碟驅動器或顯示器之類的裝置。 例如,系統存儲器 ram 不是通常被認為是“裝置”的東西,而 <code>/dev/mem</code> 是通過其可以實作對存儲器的直接通路的入口。 下面的例子有一些有趣的結果。

<code>dd if=/dev/mem bs=2048 count=100</code>

上面的 <code>dd</code> 指令提供比簡單地使用 <code>cat</code> 指令 dump 所有系統的記憶體提供了更多的控制。 它提供了指定從 <code>/dev/mem</code> 讀取多少資料的能力,還允許指定從存儲器哪裡開始讀取資料。雖然讀取了一些記憶體,但核心響應了以下錯誤,在 <code>/var/log/messages</code> 中可以看到。

<code>nov 14 14:37:31 david kernel: usercopy: kernel memory exposure attempt detected from ffff9f78c0010000 (dma-kmalloc-512) (2048 bytes)</code>

這個錯誤意味着核心正在通過保護屬于其他程序的記憶體來完成它的工作,這正是它應該工作的方式。 是以,雖然可以使用 <code>/dev/mem</code> 來顯示存儲在 ram 記憶體中的資料,但是通路的大多數記憶體空間是受保護的并且會導緻錯誤。 隻可以通路由核心記憶體管理器配置設定給運作 <code>dd</code> 指令的 bash shell 的虛拟記憶體,而不會導緻錯誤。 抱歉,但你不能窺視不屬于你的記憶體,除非你發現了一個可利用的漏洞。

<code>/dev</code> 中還有一些非常有趣的裝置檔案。 裝置檔案 <code>null</code>,<code>zero</code>,<code>random</code> 和 <code>urandom</code> 不與任何實體裝置相關聯。

例如,空裝置 <code>/dev/null</code> 可以用作來自 shell 指令或程式的輸出重定向的目标,以便它們不顯示在終端上。 我經常在我的 bash 腳本中使用這個,以防止向使用者展示可能會讓他們感到困惑的輸出。<code>/dev/null</code> 裝置可用于産生一個空字元串。 使用如下所示的 <code>dd</code> 指令檢視 <code>/dev/null</code> 裝置檔案的一些輸出。

<code># dd if=/dev/null bs=512 count=500 | od -c</code>

<code>0+0 records in</code>

<code>0+0 records out</code>

<code>0 bytes copied, 1.5885e-05 s, 0.0 kb/s</code>

<code>0000000</code>

注意,因為空字元什麼也沒有是以确實沒有可見的輸出。 注意看看位元組數。

<code>/dev/random</code> 和 <code>/dev/urandom</code> 裝置也很有趣。 正如它們的名字所暗示的,它們都産生随機輸出,不僅僅是數字,而是任何位元組組合。 <code>/dev/urandom</code> 裝置産生的是确定性的随機輸出,并且非常快。 這意味着輸出由算法确定,并使用種子字元串作為起點。 結果,如果原始種子是已知的,則黑客可以再現輸出,盡管非常困難,但這是有可能的。 使用指令 <code>cat /dev/urandom</code> 可以檢視典型的輸出,使用<code>ctrl-c</code> 退出。

<code>/dev/random</code> 裝置檔案生成非确定性的随機輸出,但它産生的輸出更慢一些。 該輸出不是由依賴于先前數字的算法确定的,而是由擊鍵動作和滑鼠移動而産生的。 這種方法使得複制特定系列的随機數要困難得多。使用 <code>cat</code> 指令去檢視一些來自 <code>/dev/random</code> 裝置檔案輸出。嘗試移動滑鼠以檢視它如何影響輸出。

正如其名字所暗示的,<code>/dev/zero</code> 裝置檔案産生一個無止境的零作為輸出。 注意,這些是八進制零,而不是ascii字元零(<code>0</code>)。 使用如下所示的 <code>dd</code> 檢視 <code>/dev/zero</code> 裝置檔案中的一些輸出

<code># dd if=/dev/zero bs=512 count=500 | od -c</code>

<code>0000000 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0</code>

<code>*</code>

<code>500+0 records in</code>

<code>500+0 records out</code>

<code>256000 bytes (256 kb, 250 kib) copied, 0.00126996 s, 202 mb/s</code>

<code>0764000</code>

請注意,此指令的位元組數不為零。

在過去,在 <code>/dev</code> 中的裝置檔案都是在安裝時建立的,導緻一個目錄中有幾乎所有的裝置檔案,盡管大多數檔案永遠不會用到。 在不常發生的情況,例如需要新的裝置檔案,或意外删除後需要重新建立裝置檔案,可以使用 <code>mknod</code> 程式手動建立裝置檔案。 前提是你必須知道裝置的主要和次要号碼。

回到 <code>/dev</code> 中的檔案清單,注意檔案的日期和時間。 所有檔案都是在上次啟動時建立的。 您可以使用<code>uptime</code> 或者 <code>last</code> 指令來驗證這一點。在上面我的裝置清單中,所有這些檔案都是在 11 月 7 日上午 7:06 建立的,這是我最後一次啟動系統。

當然, <code>mknod</code> 指令仍然可用, 但新的 <code>makedev</code> (是的,所有字母大寫,在我看來是違背 linux 使用小寫指令名的原則的) 指令提供了一個建立裝置檔案的更容易的界面。 在目前版本的 fedora 或 centos 7 中,預設情況下不安裝 <code>makedev</code> 指令;它安裝在 centos 6。您可以使用 yum 或 dnf 來安裝 makedev 包。

有趣的是,我很久沒有建立一個裝置檔案的需要了。 然而,最近我遇到一個有趣的情況,其中一個我常使用的裝置檔案沒有建立,我不得不建立它。 之後該裝置再沒出過問題。是以丢失裝置檔案的情況仍然可以發生,知道如何處理它可能很重要。

裝置檔案有無數種,您遇到的裝置檔案我可能沒有涵蓋到。 這些資訊在所下面引用的資源中有大量的細節資訊可用。 關于這些檔案的功能和工具,我希望我已經給您一些基本的了解,下一步您自己可以探索更多。

原文釋出時間為:2017-01-08

本文來自雲栖社群合作夥伴“linux中國”

繼續閱讀