udev 進行動態核心設備管理¶目錄
核心可以新增或移除執行中系統內幾乎所有的設備。設備狀態的變更 (已插入或移除設備) 必須傳播至使用者空間。一旦插入並辨識出設備,就必須立刻進行設定。如果辨識到的設備狀態發生任何變更,必須通知該設備的使用者。udev 會提供所需的基礎結構,以便動態維護 /dev 目錄中的設備節點檔案和符號連結。udev 規則能將外部工具插入核心設備事件處理。如此,您可以自定 udev 設備處理,例如,新增特定的程序檔以在核心設備處理過程中執行,或是在設備處理過程中要求並輸入其他資料進行評估。
目錄¶
/dev 中的設備節點可用來存取對應的核心設備。透過 udev,/dev 目錄會反映核心的目前狀態。每個核心設備都有一個對應的設備檔案。如果設備與系統的連接中斷,該設備節點就會遭到移除。
/dev 目錄的內容保存在暫存檔案系統中,而且所有檔案都會在每次系統開機時顯示。根據系統設計,手動建立或修改的檔案在重新開機後都將遺失。無論可存放於 /lib/udev/devices 目錄的對應核心設備狀態為何,靜態檔案和目錄都必須存在於 /dev 目錄中。在系統啟動時,該目錄內容將複製到 /dev 目錄,並具備與 /lib/udev/devices 中檔案相同的擁有權和許可權。
uevent 和 udev¶
sysfs 檔案系統會輸出必要的設備資訊。每個核心已偵測和啟始化的設備,都會建立包含其設備名稱的目錄。其中會包含設備特定的屬性內容。
每次新增或移除設備時,核心都會傳送 uevent 來通知 udev 此變更。udev 精靈會在啟動時從 /etc/udev/rules.d/*.rules 檔案中讀取並剖析一次所有指定的規則,然後將剖析結果保留在記憶體中。如果變更、新增或移除了規則檔案,精靈可以使用指令 udevadm control reload_rules 重新載入所有規則在記憶體內部的表示。此動作也可以在執行 /etc/init.d/boot.udev reload 時完成。如需有關 udev 規則及其語法的詳細資訊,請參閱第 13.6 節「透過 udev 規則影響核心設備事件的處理」。
每個收到的事件都將與提供的規則集合進行比對。這些規則可新增或變更事件環境識別碼、要求要建立之設備節點的特定名稱、新增指向該節點的符號連結,或是新增要在設備節點建立後執行的程式。驅動程式核心 uevent 是從核心網路連結插槽接收。
核心匯流排驅動程式會查探設備。核心 (kernel) 會為每個偵測到的設備建立一個內部設備結構,而驅動程式核心 (core) 會向 udev 精靈傳送一個 uevent。匯流排設備會以特殊格式的 ID 識別本身,表明其為何種設備。通常這些 ID 會包含廠商和產品 ID,以及其他子系統特定值。每個匯流排都會指定自己的 ID 配置,即所謂的 MODALIAS。核心會接收這些設備資訊,並根據這些資訊設定 MODALIAS ID 字串,然後隨事件一起傳送該字串。例如,USB 滑鼠的 ID 字串將如下所示:
MODALIAS=usb:v046DpC03Ed2000dc00dsc00dp00ic03isc01ip02
每個設備驅動程式都包含有設備可處理的已知別名清單。清單會包含在核心模組檔案本身。depmod 程式會讀取 ID 清單,並且為目前所有可用模組在核心的 /lib/modules 目錄中建立 modules.alias 檔案。透過此基礎結構,模組載入方式就會像在每次出現帶有 MODALIAS 識別碼的事件時呼叫 modprobe 一樣容易。如果是呼叫 modprobe $MODALIAS,此次呼叫就會比對設備的已組織設備別名和模組指定別名。如果有找到符合項目,該模組就可載入。以上這一切都是由 udev 自動觸發。
在 udev 精靈執行之前,於開機過程中發生的所有設備事件都會遺失,這是因為處理這些事件的基礎結構位於根檔案系統中,在該階段無法使用。為彌補這一損失,核心在 sysfs 檔案系統中之每部設備的設備目錄中都提供了一份 uevent 檔案。使用 add 寫入該檔案,核心便可重新傳送與開機期間所遺失的相同事件。負責 /sys 中所有 uevent 檔案的簡易迴圈,可以再次觸發所有事件,建立設備節點並執行設備設定。
例如,開機期間出現的 USB 滑鼠可能無法由早期的開機邏輯啟始化,這是因為當時尚無法使用驅動程式。設備探查事件遺失,而且無法找到設備的核心模組。udev 只需在根目錄檔案系統可用後向核心要求所有設備事件,這樣 USB 滑鼠設備的事件就會再次執行,因此並不需要手動搜尋可能連接的設備。現在,它會在已掛接根目錄檔案系統中找到核心模組,並讓 USB 滑鼠完成啟始化。
從使用者空間的角度,執行期間的設備冷插拔 (ColdPlud) 順序和設備探查並沒有明顯的不同。這兩種情況都會使用相同規則來進行比對,而且會執行相同的設定程式。
udev 精靈¶
udevadm monitor 程式可用來視覺化驅動程式核心事件以及 udev 事件程序的時間。
UEVENT[1185238505.276660] add /devices/pci0000:00/0000:00:1d.2/usb3/3-1 (usb) UDEV [1185238505.279198] add /devices/pci0000:00/0000:00:1d.2/usb3/3-1 (usb) UEVENT[1185238505.279527] add /devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0 (usb) UDEV [1185238505.285573] add /devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0 (usb) UEVENT[1185238505.298878] add /devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0/input/input10 (input) UDEV [1185238505.305026] add /devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0/input/input10 (input) UEVENT[1185238505.305442] add /devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0/input/input10/mouse2 (input) UEVENT[1185238505.306440] add /devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0/input/input10/event4 (input) UDEV [1185238505.325384] add /devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0/input/input10/event4 (input) UDEV [1185238505.342257] add /devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0/input/input10/mouse2 (input)
UEVENT 行會顯示核心已透過網路連結傳送的事件。UDEV 行會顯示已完成的 udev 事件處理常式。列印時間是百萬分之一秒。介於 UEVENT 和 UDEV 之間的時間是指 udev 處理此事件所耗費的時間,或者是 udev 精靈延遲執行以便此事件能與執行中相關事件同步的時間。例如,硬碟分割區的事件始終會等待主要磁碟設備事件完成,因為分割區事件可能與主要磁碟事件向硬體查詢的資料有關。
udevadm monitor --env 會顯示完整的事件環境:
ACTION=add DEVPATH=/devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0/input/input10 SUBSYSTEM=input SEQNUM=1181 NAME="Logitech USB-PS/2 Optical Mouse" PHYS="usb-0000:00:1d.2-1/input0" UNIQ="" EV=7 KEY=70000 0 0 0 0 REL=103 MODALIAS=input:b0003v046DpC03Ee0110-e0,1,2,k110,111,112,r0,1,8,amlsfw
udev 也會將訊息傳送到 syslog。控制哪些訊息要傳送到 syslog 的預設 syslog 優先程度是在 udev 的組態檔 /etc/udev/udev.conf 中指定。執行精靈的記錄優先程度可使用 udevadm control log_priority=level/number 來變更。
udev 規則影響核心設備事件的處理¶
udev 規則可以比對核心新增至事件本身的任何內容,或者核心輸出到 sysfs 的任何資訊。規則也可向外部程式要求其他資訊。每個事件都會與所有指定規則進行比對。所有規則都位於 /etc/udev/rules.d 目錄中。
規則檔案中的每一行都包含至少一個鍵值組合。鍵類型共有兩種,包括比對和指定鍵。當所有比對鍵都與指定值相符時就會套用規則,而該指定值就會指定給指定鍵。相符規則可以指定設備節點的名稱、新增指向該節點的符號連結,或是在事件處理過程中執行指定的程式。如果找不到任何符合規則,就會使用預設的設備節點名稱來建立設備節點。如需有關規則語法和系統提供之用於比對或輸入資料的鍵的詳細資訊,請參閱 udev man 頁面。以下範例規則提供了對 udev 規則語法的基本介紹。這些範例規則摘自 /etc/udev/rules.d/50-udev-default.rules 下的 udev 預設規則集。
範例 13.1. 範例 udev 規則¶
# console
KERNEL=="console", MODE="0600", OPTIONS="last_rule"
# serial devices
KERNEL=="ttyUSB*", ATTRS{product}=="[Pp]alm*Handheld*", SYMLINK+="pilot"
# printer
SUBSYSTEM=="usb", KERNEL=="lp*", NAME="usb/%k", SYMLINK+="usb%k", GROUP="lp"
# kernel firmware loader
SUBSYSTEM=="firmware", ACTION=="add", RUN+="firmware.sh"
console規則包含三個鍵︰一個比對鍵 (KERNEL) 以及兩個指定鍵 (MODE、OPTIONS)。KERNEL 比對規則用於搜尋類型為主控台的所有項目的設備清單。只有完全符合的項目才有效,才會觸發此規則讓其執行。MODE 鍵用於將特殊權限指派給設備節點,在此案例中,僅此設備的擁有者才會被指派讀取與寫入權限。OPTIONS 鍵用於將此規則做為要套用至所有此類型設備的最後一條規則。符合此特殊設備類型的任何後續規則都不會生效。
serial devices規則在 50-udev-default.rules 中雖已不再可用,但仍值得瞭解一下。它包含兩個比對鍵 (KERNEL 和 ATTRS) 與一個指派鍵 (SYMLINK)。KERNEL 鍵用於搜尋類型為 ttyUSB 的所有設備。使用 * 萬用字元時,此鍵可比對多部此類設備。第二個比對鍵 ATTRS 用於檢查 sysfs 中針對 ttyUSB 設備的 product 屬性檔案是否包含特定字串。指派鍵 (SYMLINK) 用於觸發將符號連結新增至 /dev/pilot 下的此設備。此鍵中使用的運算子 (+=) 將告知 udev 額外執行此動作,即使先前或之後的規則會新增其他符號連結也是如此。由於此規則包含兩個比對鍵,因此僅當兩個條件均滿足時才適用。
printer規則可處理 USB 印表機,它包含兩個比對鍵,必須同時套用這兩個鍵才能套用整個規則 (SUBSYSTEM 與 KERNEL)。三個指定鍵用於命名此設備類型 (NAME)、建立符號設備連結 (SYMLINK) 以及對此設備類型的成員進行分組 (GROUP)。在 KERNEL 鍵中使用 * 萬用字元可使其符合多部 lp 印表機設備。可以在 NAME 與 SYMLINK 鍵中使用替代項,透過內部設備名稱延伸這些字串。例如,第一部 lp USB 印表機的符號連結會讀取 /dev/usblp0。
kernel firmware loader規則可讓 udev 在執行時期透過外部輔助程式程序檔載入其他韌體。SUBSYSTEM 比對鍵可搜尋韌體子系統。ACTION 鍵可檢查是否已新增任何屬於韌體子系統的設備。RUN+= 鍵可觸發執行 firmware.sh 程序檔以查找要載入的韌體。
某些一般特性適用於所有規則︰
每條規則都包含一個或多個以逗號分隔的鍵值對。
鍵的操作由運算子決定。udev 規則支援多種不同的運算子。
每個指定值必須括在引號中。
規則檔案中的每一行都表示一條規則。如果某規則的長度超出一行,請將 \ 加入到不同行中,就如同在外圍程序語法中一樣。
udev 規則支援符合 *、? 與 [] 模式的外圍程序式模式。
udev 規則支援替代項。
udev 規則中使用運算子¶建立鍵時,您可以根據要建立的鍵類型從多個不同的運算子中進行選擇。比對鍵通常僅用於尋找符合或明顯不符合搜尋值的值。比對鍵可包含以下運算子︰
==
比較是否相等。如果鍵包含搜尋模式,則所有符合此模式的結果均有效。
!=
比較是否不相等。如果鍵包含搜尋模式,則所有符合此模式的結果均有效。
指派鍵可使用以下運算子︰
=
將某個值指派給鍵。如果鍵先前包含值清單,則此鍵將重設並僅指派單一值。
+=
將某個值新增至包含項目清單的鍵。
:=
指派最終值。不允許後續規則再做任何變更。
udev 規則中使用替代項¶
udev 規則支援使用佔位符與替代項。使用方式與任何其他程序檔中的方式類似。在 udev 規則中可以使用以下替代項︰
%r, $root
依預設為設備目錄 /dev。
%p, $devpath
DEVPATH 的值。
%k, $kernel
KERNEL 的值或內部設備名稱。
%n, $number
設備編號。
%N, $tempnode
設備檔案的暫存名稱。
%M, $major
設備的主要編號。
%m, $minor
設備的次要編號。
%s{屬性}, $attr{屬性}
sysfs 屬性的值 (由屬性指定)。
%E{變數}, $attr{變數}
環境變數的值 (由變數指定)。
%c, $result
PROGRAM 的輸出。
%%
% 字元。
$$
$ 字元。
udev 比對鍵¶
比對鍵定義要套用 udev 規則所必須滿足的條件。以下為可用的比對鍵:
ACTION
事件動作的名稱,例如新增或移除設備時的 add 或 remove。
DEVPATH
事件設備的設備路徑,例如 DEVPATH=/bus/pci/drivers/ipw3945,用於搜尋與 ipw3945 驅動程式相關的所有事件。
KERNEL
事件設備的內部 (核心) 名稱。
SUBSYSTEM
事件設備的子系統,例如 SUBSYSTEM=usb,適用於與 USB 設備相關的所有事件。
ATTR{檔案名稱}
事件設備的 sysfs 屬性。例如,若要比對 vendor 屬性檔案名稱中包含的字串,可以使用 ATTR{vendor}=="On[sS]tream"。
KERNELS
讓 udev 向上搜尋符合設備名稱的設備路徑。
SUBSYSTEMS
讓 udev 向上搜尋相符設備子系統名稱的設備路徑。
DRIVERS
讓 udev 向上搜尋相符設備驅動程式名稱的設備路徑。
ATTRS{檔案名稱}
讓 udev 向上搜尋與 sysfs 屬性值相符之設備的設備路徑。
ENV{鍵}
環境變數的值,例如 ENV{ID_BUS}="ieee1394,用於搜尋與 FireWire 匯流排 ID 相關的所有事件。
PROGRAM
讓 udev 執行外部程式。若要成功執行,程式必須以離開碼零返回。RESULT 鍵可使用程式的輸出 (列印至 stdout)。
RESULT
比對上次 PROGRAM 呼叫的輸出字串。即可將此鍵包含於相同規則中 (如 PROGRAM 鍵),也可含於後續規則中。
udev 指定鍵¶
與上述比對鍵不同,指定鍵不會說明必須滿足的條件,而是將值、名稱和動作指定給 udev 維護的設備節點。
NAME
要建立之設備節點的名稱。如果規則已設定了節點名稱,則將忽略適用於此節點的所有其他含 NAME 鍵的規則。
SYMLINK
與要建立的節點相關聯之符號連結的名稱。可以為多項比對規則新增符號連結以便使用設備節點進行建立。您還可以使用空格字元分隔符號連結名稱,從而為一項規則中的一個節點指定多個符號連結。
OWNER、GROUP、MODE
新設備節點的權限。在此處指定的值將覆寫已編譯的任何項目。
ATTR{鍵}
指定要寫入事件設備之 sysfs 屬性的值。如果使用運算子 ==,也會使用此鍵來比對 sysfs 屬性的值。
ENV{鍵}
告知 udev 將某變數輸出到環境中。如果使用運算子 ==,也會使用此鍵來比對環境變數。
RUN
告知 udev 將某程式新增至要為此設備執行的程式清單。對極短任務套用此項時要格外小心,以免封鎖此設備的其他事件。
LABEL
在 GOTO 可以跳轉之處新增一個標籤。
GOTO
告知 udev 跳過多項規則並根據 GOTO 鍵所參考之標籤對應的規則繼續。
IMPORT{類型}
將變數載入事件環境,如外部程式的輸出。udev 可輸入多種不同類型的變數。如果未指定任何類型,udev 會根據檔案權限的可執行位元嘗試自行決定類型。
program 可告知 udev 執行外部程式並輸入其輸出。
file 可告知 udev 輸入文字檔。
parent 可告知 udev 輸入父代設備中儲存的鍵。
WAIT_FOR_SYSFS
告知 udev 等待系統為特定設備建立指定的 sysfs 檔案。例如,WAIT_FOR_SYSFS="ioerr_cnt" 通知 udev 等待,直到 ioerr_cnt 檔案建立。
OPTIONS
OPTION 鍵可以包含多個值︰
last_rule 告知 udev 忽略所有後續規則。
ignore_device 告知 udev 完全忽略此事件。
ignore_remove 告知 udev 忽略針對該設備的所有後續移除事件。
all_partitions 告知 udev 為區塊設備上的所有可用分割區建立設備節點。
動態設備目錄和 udev 規則基礎結構讓系統可以為所有磁碟設備提供固定名稱,無論設備的辨識順序或所使用的連線為何。核心所建立的每個相應區塊設備,都會採用針對特定匯流排、磁碟類型或檔案系統所設計的工具進行檢查。udev 會根據核心動態提供的設備節點名稱,維護指向設備的永久符號連結類別:
/dev/disk
|-- by-id
| |-- scsi-SATA_HTS726060M9AT00_MRH453M4HWHG7B -> ../../sda
| |-- scsi-SATA_HTS726060M9AT00_MRH453M4HWHG7B-part1 -> ../../sda1
| |-- scsi-SATA_HTS726060M9AT00_MRH453M4HWHG7B-part6 -> ../../sda6
| |-- scsi-SATA_HTS726060M9AT00_MRH453M4HWHG7B-part7 -> ../../sda7
| |-- usb-Generic_STORAGE_DEVICE_02773 -> ../../sdd
| `-- usb-Generic_STORAGE_DEVICE_02773-part1 -> ../../sdd1
|-- by-label
| |-- Photos -> ../../sdd1
| |-- SUSE10 -> ../../sda7
| `-- devel -> ../../sda6
|-- by-path
| |-- pci-0000:00:1f.2-scsi-0:0:0:0 -> ../../sda
| |-- pci-0000:00:1f.2-scsi-0:0:0:0-part1 -> ../../sda1
| |-- pci-0000:00:1f.2-scsi-0:0:0:0-part6 -> ../../sda6
| |-- pci-0000:00:1f.2-scsi-0:0:0:0-part7 -> ../../sda7
| |-- pci-0000:00:1f.2-scsi-1:0:0:0 -> ../../sr0
| |-- usb-02773:0:0:2 -> ../../sdd
| |-- usb-02773:0:0:2-part1 -> ../../sdd1
`-- by-uuid
|-- 159a47a4-e6e6-40be-a757-a629991479ae -> ../../sda7
|-- 3e999973-00c9-4917-9442-b7633bd95b9e -> ../../sda6
`-- 4210-8F8C -> ../../sdd1udev 使用的檔案¶/sys/*
由 Linux 核心提供的虛擬檔案系統,可輸出所有目前已知設備。udev 用此資訊在 /dev 中建立設備節點。
/dev/*
動態建立的設備節點和開機時從 /lib/udev/devices/* 複製的靜態內容。
下列檔案和目錄包含了 udev 基礎結構的重要元件:
/etc/udev/udev.conf
udev 主組態檔
/etc/udev/rules.d/*
udev 事件符合規則。
/lib/udev/devices/*
靜態 /dev 內容。
/lib/udev/*
udev 規則中呼叫的協助程式。
如需關於 udev 基礎結構的詳細資訊,請參閱下列 man 頁面:
udev
關於 udev、鍵、規則和其他重要組態問題的一般資訊。
udevadm 可用於控制 udev 的執行時期行為、要求核心事件、管理事件佇列以及提供簡單的除錯機制。
udevd
關於 udev 事件管理精靈的資訊。