歡迎光臨
每天分享高質量文章

在 Linux 中如何編寫基本的 udev 規則 | Linux 中國

理解 udev 背後的基本概念,學習如何寫簡單的規則。
— Egidio Docile


本文導航
編譯自 | https://linuxconfig.org/tutorial-on-how-to-write-basic-udev-rules-in-linux 
 作者 | Egidio Docile
 譯者 | qhwdw

讀者物件

理解 udev 背後的基本概念,學習如何寫簡單的規則。

要求

◈ root 許可權

難度

中等

約定

◈ # – 要求給定的命令使用 root 許可權或者直接以一個 root 使用者或者使用 sudo 命令去執行。
◈ $ – 要求給定的命令以一個普通的非特權使用者執行。

介紹

在 GNU/Linux 系統中,雖然裝置的底層支援是在核心層面處理的,但是,它們相關的事件管理是在使用者空間中透過 udev 來管理的。確切地說是由 udevd 守護行程來完成的。學習如何去寫規則,並應用到發生的這些事件上,將有助於我們修改系統的行為並使它適合我們的需要。

規則如何組織

udev 規則是定義在一個以 .rules 為副檔名的檔案中。那些檔案主要放在兩個位置:/usr/lib/udev/rules.d,這個目錄用於存放系統安裝的規則;/etc/udev/rules.d/ 這個目錄是保留給自定義規則的。

定義那些規則的檔案的命名慣例是使用一個數字作為字首(比如,50-udev-default.rules),並且以它們在目錄中的詞彙順序進行處理的。在 /etc/udev/rules.d 中安裝的檔案,會改寫安裝在系統預設路徑中的同名檔案。

規則語法

如果你理解了 udev 規則的行為邏輯,它的語法並不複雜。一個規則由兩個主要的節構成:match 部分,它使用一系列用逗號分隔的鍵定義了規則應用的條件,而 action 部分,是當條件滿足時,我們執行一些動作。

測試案例

講解可能的選項的最好方法莫過於配置一個真實的案例,因此,我們去定義一個規則作為演示,當滑鼠被連線時禁用觸控板。顯然,在該規則定義中提供的屬性將反映我的硬體。

我們將在 /etc/udev/rules.d/99-togglemouse.rules 檔案中用我們喜歡的文字編輯器來寫我們的規則。一條規則定義允許跨多個行,但是,如果是這種情況,必須在一個換行字元之前使用一個反斜線(\)表示行的延續,就和 shell 指令碼一樣。這是我們的規則:

  1. ACTION=="add" \

  2. , ATTRS{idProduct}=="c52f" \

  3. , ATTRS{idVendor}=="046d" \

  4. , ENV{DISPLAY}=":0" \

  5. , ENV{XAUTHORITY}="/run/user/1000/gdm/Xauthority" \

  6. , RUN+="/usr/bin/xinput --disable 16"

我們來分析一下這個規則。

運運算元

首先,對已經使用以及將要使用的運運算元解釋如下:

== 和 != 運運算元

== 是相等運運算元,而 != 是不等於運運算元。透過使用它們,我們可以確認規則上應用的鍵是否匹配各自的值。

分配運運算元 = 和 :=

= 是賦值運運算元,是用於為一個鍵賦值。當我們想要賦值,並且想確保它不會被其它規則所改寫,我們就需要使用 := 運運算元來代替,使用這個運運算元分配的值,它就不能被改變。

+= 和 -= 運運算元

+= 和 -= 運運算元各自用於從一個指定的鍵定義的值串列中增加或者移除一個值。

我們使用的鍵

現在,來分析一下在這個規則中我們使用的鍵。首先,我們有一個 ACTION 鍵:透過使用它,當在一個裝置上發生了特定的事件,我們將指定我們要應用的規則的具體內容。有效的值有 addremove  以及 change。 

然後,我們使用 ATTRS 關鍵字去指定一個屬性去匹配。我們可以使用 udevadm info 命令去列出一個裝置屬性,提供它的名字或者 sysfs 路徑即可:

  1. udevadm info -ap /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.1/0003:046D:C52F.0010/input/input39

  2. Udevadm info starts with the device specified by the devpath and then

  3. walks up the chain of parent devices. It prints for every device

  4. found, all possible attributes in the udev rules key format.

  5. A rule to match, can be composed by the attributes of the device

  6. and the attributes from one single parent device.

  7.  looking at device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.1/0003:046D:C52F.0010/input/input39':

  8.    KERNEL=="input39"

  9.    SUBSYSTEM=="input"

  10.    DRIVER==""

  11.    ATTR{name}=="Logitech USB Receiver"

  12.    ATTR{phys}=="usb-0000:00:1d.0-1.2/input1"

  13.    ATTR{properties}=="0"

  14.    ATTR{uniq}==""

  15.  looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.1/0003:046D:C52F.0010':

  16.    KERNELS=="0003:046D:C52F.0010"

  17.    SUBSYSTEMS=="hid"

  18.    DRIVERS=="hid-generic"

  19.    ATTRS{country}=="00"

  20.  looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.1':

  21.    KERNELS=="2-1.2:1.1"

  22.    SUBSYSTEMS=="usb"

  23.    DRIVERS=="usbhid"

  24.    ATTRS{authorized}=="1"

  25.    ATTRS{bAlternateSetting}==" 0"

  26.    ATTRS{bInterfaceClass}=="03"

  27.    ATTRS{bInterfaceNumber}=="01"

  28.    ATTRS{bInterfaceProtocol}=="00"

  29.    ATTRS{bInterfaceSubClass}=="00"

  30.    ATTRS{bNumEndpoints}=="01"

  31.    ATTRS{supports_autosuspend}=="1"

  32.  looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2':

  33.    KERNELS=="2-1.2"

  34.    SUBSYSTEMS=="usb"

  35.    DRIVERS=="usb"

  36.    ATTRS{authorized}=="1"

  37.    ATTRS{avoid_reset_quirk}=="0"

  38.    ATTRS{bConfigurationValue}=="1"

  39.    ATTRS{bDeviceClass}=="00"

  40.    ATTRS{bDeviceProtocol}=="00"

  41.    ATTRS{bDeviceSubClass}=="00"

  42.    ATTRS{bMaxPacketSize0}=="8"

  43.    ATTRS{bMaxPower}=="98mA"

  44.    ATTRS{bNumConfigurations}=="1"

  45.    ATTRS{bNumInterfaces}==" 2"

  46.    ATTRS{bcdDevice}=="3000"

  47.    ATTRS{bmAttributes}=="a0"

  48.    ATTRS{busnum}=="2"

  49.    ATTRS{configuration}=="RQR30.00_B0009"

  50.    ATTRS{devnum}=="12"

  51.    ATTRS{devpath}=="1.2"

  52.    ATTRS{idProduct}=="c52f"

  53.    ATTRS{idVendor}=="046d"

  54.    ATTRS{ltm_capable}=="no"

  55.    ATTRS{manufacturer}=="Logitech"

  56.    ATTRS{maxchild}=="0"

  57.    ATTRS{product}=="USB Receiver"

  58.    ATTRS{quirks}=="0x0"

  59.    ATTRS{removable}=="removable"

  60.    ATTRS{speed}=="12"

  61.    ATTRS{urbnum}=="1401"

  62.    ATTRS{version}==" 2.00"

  63.    [...]

上面截取了執行這個命令之後的輸出的一部分。正如你從它的輸出中看到的那樣,udevadm 從我們提供的指定路徑開始,並且提供了所有父級裝置的資訊。註意裝置的屬性都是以單數的形式報告的(比如,KERNEL),而它的父級是以複數形式出現的(比如,KERNELS)。父級資訊可以做為規則的一部分,但是同一時間只能有一個父級可以被取用:不同父級裝置的屬性混合在一起是不能工作的。在上面我們定義的規則中,我們使用了一個父級裝置屬性:idProduct 和 idVendor。 

在我們的規則中接下來做的事情是,去使用 ENV 關鍵字:它既可以用於設定也可以用於去匹配環境變數。我們給 DISPLAY 和 XAUTHORITY 分配值。當我們使用 X 伺服器程式進行互動去設定一些需要的資訊時,這些變數是非常必要的:使用 DISPLAY 變數,我們指定伺服器執行在哪個機器上,用的是哪個顯示和螢幕;使用 XAUTHORITY 提供了一個檔案路徑,其包含了 Xorg 認證和授權資訊。這個檔案一般位於使用者的家目錄中。 

最後,我們使用了 RUN 字:它用於執行外部程式。非常重要:這裡沒有立即執行,但是一旦所有的規則被解析,將執行各種動作。在這個案例中,我們使用 xinput 實用程式去改變觸控板的狀態。我不想解釋這裡的 xinput 的語法,它超出了本文的範圍,只需要註意這個觸控板的 ID 是 16。 

規則設定完成之後,我們可以透過使用 udevadm test 命令去除錯它。這個命令對除錯非常有用,它並不真實去執行 RUN 指定的命令:

  1. $ udevadm test --action="add" /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.1/0003:046D:C52F.0010/input/input39

我們提供給命令的是使用 --action 選項,以及裝置的 sysfs 路徑的模擬動作。如果沒有報告錯誤,說明我們的規則執行的很好。要在真實的環境中去使用它,我們需要重新載入規則:

  1. # udevadm control --reload

這個命令將重新載入規則檔案,但是,它只對重新載入之後發生的事件有效果。

我們透過建立一個 udev 規則瞭解了基本的概念和邏輯,這隻是 udev 規則中眾多的選項和可能的設定中的一小部分。udev 手冊頁提供了一個詳盡的串列,如果你想深入瞭解,請參考它。


via: https://linuxconfig.org/tutorial-on-how-to-write-basic-udev-rules-in-linux

作者:Egidio Docile[2] 譯者:qhwdw 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出

LCTT 譯者

qhwdw ? ? ? ? ?
共計翻譯:73 篇
貢獻時間:112 天


推薦文章

< 左右滑動檢視相關文章 >

點選圖片、輸入文章 ID 或識別二維碼直達

贊(0)

分享創造快樂

© 2023 知識星球   網站地圖