24 使用 udev
進行動態核心裝置管理 #
核心可以新增或移除執行中系統內幾乎所有的裝置。裝置狀態的變更 (無論裝置插入或移除) 必須傳播至使用者空間。插入及識別裝置後需要對其進行設定。如果辨識到的裝置狀態發生任何變更,必須通知該裝置的使用者。udev
會提供所需的基礎結構,以便動態維護 /dev
目錄中的裝置節點檔案和符號連結。udev
規則能將外部工具插入核心裝置事件處理。因而,您可以透過新增在核心裝置處理過程中執行的特定程序檔,來自訂 udev
裝置處理方式,或者可以在裝置處理期間要求並輸入其他資料進行評估。
24.1 /dev
目錄 #
/dev
中的裝置節點可用來存取對應的核心裝置。透過 udev
,/dev
目錄會反映核心的目前狀態。每個核心裝置都有一個對應的裝置檔案。如果裝置與系統的連接中斷,該裝置節點就會遭到移除。
/dev
目錄的內容保存在暫存檔案系統中,而且所有檔案都會在每次系統開機時顯示。根據系統設計,手動建立或修改的檔案在重新開機後都將遺失。無論可使用 systemd-tmpfiles 建立的對應核心裝置狀態為何,靜態檔案和目錄都必須在 /dev
目錄中。組態檔案可在 /usr/lib/tmpfiles.d/
和 /etc/tmpfiles.d/
中找到;如需詳細資訊,請參閱 systemd-tmpfiles(8)
線上文件。
24.2 核心 uevent
和 udev
#
sysfs
檔案系統會輸出必要的裝置資訊。每個核心已偵測和啟始化的裝置,都會建立包含其裝置名稱的目錄。其中會包含裝置特定的屬性內容。
每次新增或移除裝置時,核心都會傳送 uevent 來通知 udev
此變更。udev
精靈會在啟動時從 /usr/lib/udev/rules.d/*.rules
和 /etc/udev/rules.d/*.rules
檔案中讀取並剖析所有規則,然後將剖析結果保留在記憶體中。如果變更、新增或移除了規則檔案,精靈可以使用 udevadm control --reload
指令重新載入這些規則在記憶體中的表示。如需有關 udev
規則及其語法的詳細資訊,請參閱第 24.6 節 「使用 udev
規則影響核心裝置事件處理」。
每個收到的事件都將與提供的規則集合進行比對。這些規則可新增或變更事件環境識別碼、要求要建立之裝置節點的特定名稱、新增指向該節點的符號連結,或是新增要在裝置節點建立後執行的程式。驅動程式核心 uevent
是從核心網路連結插槽接收。
24.3 驅動程式、核心模組和裝置 #
核心匯流排驅動程式會查探裝置。核心 (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
自動觸發。
24.4 開機和初始裝置設定 #
在 udev
精靈執行之前,於開機過程中發生的所有裝置事件都會遺失,這是因為處理這些事件的基礎結構位於根檔案系統中,在該階段無法使用。為彌補這一損失,核心在 sysfs
檔案系統中之每部裝置的裝置目錄中都提供了一份 uevent
檔案。使用 add
寫入該檔案,核心便可重新傳送與開機期間所遺失的相同事件。負責 /sys
中所有 uevent
檔案的簡易迴圈,可以再次觸發所有事件,建立裝置節點並執行裝置設定。
例如,開機期間出現的 USB 滑鼠可能無法由早期的開機邏輯啟始化,這是因為當時尚無法使用驅動程式。裝置探查事件遺失,而且無法找到裝置的核心模組。您無需手動搜尋連接的裝置,udev
會在根檔案系統可用後向核心要求所有裝置事件,這樣 USB 滑鼠裝置的事件就會再次執行。現在,它會在已掛接根目錄檔案系統中找到核心模組,並讓 USB 滑鼠完成啟始化。
從使用者空間的角度,執行期間的裝置冷插拔 (ColdPlud) 順序和裝置探查並沒有明顯的不同。這兩種情況都會使用相同規則來進行比對,而且會執行相同的設定程式。
24.5 監控執行中的 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 變更執行中精靈的記錄優先程度。
24.6 使用 udev
規則影響核心裝置事件處理 #
udev
規則可以比對核心新增至事件本身的任何內容,或者核心輸出到 sysfs
的任何資訊。規則也可向外部程式要求其他資訊。系統會將事件與目錄 /usr/lib/udev/rules.d/
(適用於預設規則) 和 /etc/udev/rules.d
(系統專屬的組態) 中提供的所有規則進行比對。
規則檔案中的每一行都包含至少一個鍵值組合。鍵類型共有兩種,包括比對和指定鍵。當所有比對鍵都與指定值相符時就會套用規則,而該指定值就會指定給指定鍵。相符規則可以指定裝置節點的名稱、新增指向該節點的符號連結,或是在事件處理過程中執行指定的程式。如果找不到任何符合規則,就會使用預設的裝置節點名稱來建立裝置節點。如需有關規則語法和系統提供之用於比對或輸入資料的鍵的詳細資訊,請參閱 udev
man 頁面。以下範例規則提供了對 udev
規則語法的基本介紹。這些範例規則全部摘自 udev
預設規則集 /usr/lib/udev/rules.d/50-udev-default.rules
。
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"
主控台
規則包含三個鍵:一個比對鍵 (KERNEL
) 以及兩個指定鍵 (MODE
、OPTIONS
)。KERNEL
比對規則用於搜尋類型為主控台
的所有項目的裝置清單。只有完全符合的項目才有效,才會觸發此規則讓其執行。MODE
鍵用於將特殊權限指派給裝置節點,在此案例中,僅此裝置的擁有者才會被指派讀取與寫入權限。OPTIONS
鍵用於將此規則做為要套用至所有此類型裝置的最後一條規則。符合此特殊裝置類型的任何後續規則都不會生效。
序列裝置
規則在 50-udev-default.rules
中雖已不再可用,但仍值得瞭解一下。它包含兩個比對鍵 (KERNEL
和 ATTRS
) 與一個指派鍵 (SYMLINK
)。KERNEL
鍵用於搜尋類型為 ttyUSB
的所有裝置。使用 *
萬用字元時,此鍵可比對多部此類裝置。第二個比對鍵 ATTRS
用於檢查 sysfs
中針對 ttyUSB
裝置的 product
屬性檔案是否包含特定字串。指派鍵 (SYMLINK
) 用於觸發將符號連結新增至 /dev/pilot
下的此裝置。此鍵中使用的運算子 (+=
) 將告知 udev
額外執行此動作,即使先前或之後的規則會新增其他符號連結也是如此。由於此規則包含兩個比對鍵,因此僅當兩個條件均滿足時才適用。
印表機
規則可處理 USB 印表機,它包含兩個比對鍵,必須同時套用這兩個鍵才能套用整個規則 (SUBSYSTEM
與 KERNEL
)。三個指定鍵用於命名此裝置類型 (NAME
)、建立符號裝置連結 (SYMLINK
) 以及對此裝置類型的成員進行分組 (GROUP
)。在 KERNEL
鍵中使用 *
萬用字元可使其符合多部 lp
印表機裝置。可以在 NAME
與 SYMLINK
鍵中使用替代項,透過內部裝置名稱延伸這些字串。例如,第一部 lp
USB 印表機的符號連結會讀取 /dev/usblp0
。
核心韌體載入程式
規則可讓 udev
在執行時期透過外部輔助程式程序檔載入其他韌體。SUBSYSTEM
比對鍵可搜尋韌體
子系統。ACTION
鍵可檢查是否已新增任何屬於韌體
子系統的裝置。RUN+=
鍵可觸發執行 firmware.sh
程序檔以查找要載入的韌體。
某些一般特性適用於所有規則:
每條規則都包含一個或多個以逗號分隔的鍵值對。
鍵的操作由運算子決定。
udev
規則支援多個運算子。每個指定值必須括在引號中。
規則檔案中的每一行都表示一條規則。如果某規則的長度超出一行,請使用
\
連接不同的行,就如同在外圍程序語法中一樣。udev
規則支援符合*
、?
與[]
模式的外圍程序式模式。udev
規則支援替代項。
24.6.1 在 udev
規則中使用運算子 #
建立金鑰時,您可以根據要建立的金鑰類型從多個運算子中進行選擇。比對鍵通常用於尋找符合或明顯不符合搜尋值的值。比對鍵可包含以下運算子:
==
比較是否相等。如果鍵包含搜尋模式,則所有符合此模式的結果均有效。
!=
比較是否不相等。如果鍵包含搜尋模式,則所有符合此模式的結果均有效。
指派鍵可使用以下運算子:
=
將某個值指派給鍵。如果鍵先前包含值清單,則此鍵將重設並僅指派單一值。
+=
將某個值新增至包含項目清單的鍵。
:=
指派最終值。不允許後續規則再做任何變更。
24.6.2 在 udev
規則中使用替代項 #
udev
規則支援使用佔位符與替代項。使用方式與任何其他程序檔中的方式類似。在 udev
規則中可以使用以下替代項:
%r
,$root
依預設為裝置目錄
/dev
。%p
,$devpath
DEVPATH
的值。%k
,$kernel
KERNEL
的值或內部裝置名稱。%n
,$number
裝置編號。
%N
,$tempnode
裝置檔案的暫存名稱。
%M
,$major
裝置的主要編號。
%m
,$minor
裝置的次要編號。
%s{ATTRIBUTE}
,$attr{ATTRIBUTE}
sysfs
屬性的值 (透過 ATTRIBUTE 指定)。%E{VARIABLE}
,$env{VARIABLE}
環境變數的值 (透過 VARIABLE 指定)。
%c
,$result
PROGRAM
的輸出。%%
%
字元。$$
$
字元。
24.6.3 使用 udev
比對鍵 #
比對鍵定義要套用 udev
規則所必須滿足的條件。以下為可用的比對鍵:
ACTION
事件動作的名稱,例如新增或移除裝置時的
add
或remove
。DEVPATH
事件裝置的裝置路徑,例如
DEVPATH=/bus/pci/drivers/ipw3945
,用於搜尋與 ipw3945 驅動程式相關的所有事件。KERNEL
事件裝置的內部 (核心) 名稱。
SUBSYSTEM
事件裝置的子系統,例如
SUBSYSTEM=usb
,適用於與 USB 裝置相關的所有事件。ATTR{FILENAME}
事件裝置的
sysfs
屬性。例如,若要比對vendor
屬性檔案名稱中包含的字串,可以使用ATTR{vendor}=="On[sS]tream"
。KERNELS
讓
udev
向上搜尋裝置路徑,以尋找相符的裝置名稱。SUBSYSTEMS
讓
udev
向上搜尋裝置路徑,以尋找相符的裝置子系統名稱。DRIVERS
讓
udev
向上搜尋裝置路徑,以尋找相符的裝置驅動程式名稱。ATTRS{FILENAME}
讓
udev
向上搜尋裝置路徑,以尋找與sysfs
屬性值相符的裝置。ENV{KEY}
環境變數的值,例如
ENV{ID_BUS}="ieee1394
,用於搜尋與 FireWire 匯流排 ID 相關的所有事件。PROGRAM
讓
udev
執行外部程式。若要成功執行,程式必須以離開碼零返回。RESULT
鍵可使用程式的輸出 (列印至 STDOUT)。RESULT
比對上次
PROGRAM
呼叫的輸出字串。即可將此鍵包含於相同規則中 (如PROGRAM
鍵),也可含於後續規則中。
24.6.4 使用 udev
指定鍵 #
與上述比對鍵不同,指定鍵不會說明必須滿足的條件,而是將值、名稱和動作指定給 udev
維護的裝置節點。
NAME
要建立之裝置節點的名稱。如果規則已設定了節點名稱,則將忽略適用於此節點的所有其他含
NAME
鍵的規則。SYMLINK
與要建立的節點相關聯之符號連結的名稱。可以為多項比對規則新增符號連結以便使用裝置節點進行建立。您還可以使用空格字元分隔符號連結名稱,從而為一項規則中的一個節點指定多個符號連結。
OWNER、GROUP、MODE
新裝置節點的權限。在此處指定的值將覆寫已編譯的任何項目。
ATTR{KEY}
指定要寫入事件裝置之
sysfs
屬性的值。如果使用運算子==
,也會使用此鍵來比對sysfs
屬性的值。ENV{KEY}
告知
udev
將某變數輸出到環境中。如果使用運算子==
,也會使用此鍵來比對環境變數。RUN
告知
udev
將某程式新增至要為此裝置執行的程式清單。對極短任務套用此項時要格外小心,以免封鎖此裝置的其他事件。LABEL
在
GOTO
可以跳轉之處新增一個標籤。GOTO
告知
udev
跳過數個規則,繼續執行GOTO
鍵所參考標籤對應的規則。IMPORT{TYPE}
將變數載入事件環境,如外部程式的輸出。
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
為區塊裝置上的所有可用分割區建立裝置節點。
24.7 永久裝置命名 #
動態裝置目錄和 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 -> ../../sdd1
24.8 udev
使用的檔案 #
/sys/*
由 Linux 核心提供的虛擬檔案系統,可輸出所有目前已知裝置。
udev
用此資訊在/dev
中建立裝置節點。/dev/*
動態建立的裝置節點和使用 systemd-tmpfiles 建立的靜態內容;如需詳細資訊,請參閱
systemd-tmpfiles(8)
線上文件。
下列檔案和目錄包含了 udev
基礎結構的重要元件:
/etc/udev/udev.conf
udev
主組態檔。/etc/udev/rules.d/*
系統專屬的
udev
事件比對規則。可在這裡新增自訂規則,以修改或覆寫/usr/lib/udev/rules.d/*
中的預設規則。系統依英數字元順序剖析檔案。檔案中優先程度較高的規則會修改或覆寫優先程度較低的規則。數值越小,優先程度越高。
/usr/lib/udev/rules.d/*
預設的
udev
事件比對規則。此目錄中的檔案由套件擁有,將在更新時覆寫。請勿在這裡新增、移除或編輯檔案,應該使用/etc/udev/rules.d
。/usr/lib/udev/*
udev
規則中呼叫的協助程式。/usr/lib/tmpfiles.d/
和/etc/tmpfiles.d/
針對靜態
/dev
內容。
24.9 更多資訊 #
如需關於 udev
基礎結構的詳細資訊,請參閱下列 man 頁面:
udev
關於
udev
、鍵、規則和其他重要組態問題的一般資訊。udevadm
udevadm
可用於控制udev
的執行時期行為、要求核心事件、管理事件佇列以及提供簡單的除錯機制。udevd
關於
udev
事件管理精靈的資訊。