解析Linux中如何編寫基本的udev規(guī)則
2018-02-24 10:22:49
2539瀏覽
在GNU/Linux系統(tǒng)中,雖然設(shè)備的底層支持是在內(nèi)核層面處理的,但是,它們相關(guān)的事件管理是在用戶空間中通過udev來管理的。確切地說是由udevd守護(hù)進(jìn)程來完成的。學(xué)習(xí)如何去寫規(guī)則,并應(yīng)用到發(fā)生的這些事件上,將有助于我們修改系統(tǒng)的行為并使它適合我們的需要。
約定
#-要求給定的命令使用root權(quán)限或者直接以一個root用戶或者使用sudo命令去運行。
$-要求給定的命令以一個普通的非特權(quán)用戶運行。
規(guī)則如何組織
udev規(guī)則是定義在一個以.rules為擴(kuò)展名的文件中。那些文件主要放在兩個位置:/usr/lib/udev/rules.d,這個目錄用于存放系統(tǒng)安裝的規(guī)則;/etc/udev/rules.d/這個目錄是保留給自定義規(guī)則的。
定義那些規(guī)則的文件的命名慣例是使用一個數(shù)字作為前綴(比如,50-udev-default.rules),并且以它們在目錄中的詞匯順序進(jìn)行處理的。在/etc/udev/rules.d中安裝的文件,會覆蓋安裝在系統(tǒng)默認(rèn)路徑中的同名文件。
規(guī)則語法
如果你理解了udev規(guī)則的行為邏輯,它的語法并不復(fù)雜。一個規(guī)則由兩個主要的節(jié)構(gòu)成:match部分,它使用一系列用逗號分隔的鍵定義了規(guī)則應(yīng)用的條件,而action部分,是當(dāng)條件滿足時,我們執(zhí)行一些動作。
測試案例
講解可能的選項的最好方法莫過于配置一個真實的案例,因此,我們?nèi)ザx一個規(guī)則作為演示,當(dāng)鼠標(biāo)被連接時禁用觸摸板。顯然,在該規(guī)則定義中提供的屬性將反映我的硬件。
我們將在/etc/udev/rules.d/99-togglemouse.rules文件中用我們喜歡的文本編輯器來寫我們的規(guī)則。一條規(guī)則定義允許跨多個行,但是,如果是這種情況,必須在一個換行字符之前使用一個反斜線(\)表示行的延續(xù),就和shell腳本一樣。這是我們的規(guī)則:
ACTION=="add"\
,ATTRS{idProduct}=="c52f"\
,ATTRS{idVendor}=="046d"\
,ENV{DISPLAY}=":0"\
,ENV{XAUTHORITY}="/run/user/1000/gdm/Xauthority"\
,RUN+="/usr/bin/xinput--disable16"
我們來分析一下這個規(guī)則。
操作符
首先,對已經(jīng)使用以及將要使用的操作符解釋如下:
==和!=操作符
==是相等操作符,而!=是不等于操作符。通過使用它們,我們可以確認(rèn)規(guī)則上應(yīng)用的鍵是否匹配各自的值。
分配操作符=和:=
=是賦值操作符,是用于為一個鍵賦值。當(dāng)我們想要賦值,并且想確保它不會被其它規(guī)則所覆蓋,我們就需要使用:=操作符來代替,使用這個操作符分配的值,它就不能被改變。
+=和-=操作符
+=和-=操作符各自用于從一個指定的鍵定義的值列表中增加或者移除一個值。
我們使用的鍵
現(xiàn)在,來分析一下在這個規(guī)則中我們使用的鍵。首先,我們有一個ACTION鍵:通過使用它,當(dāng)在一個設(shè)備上發(fā)生了特定的事件,我們將指定我們要應(yīng)用的規(guī)則的具體內(nèi)容。有效的值有add、remove以及change。
然后,我們使用ATTRS關(guān)鍵字去指定一個屬性去匹配。我們可以使用udevadminfo命令去列出一個設(shè)備屬性,提供它的名字或者sysfs路徑即可:
udevadminfo-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
Udevadminfostartswiththedevicespecifiedbythedevpathandthen
walksupthechainofparentdevices.Itprintsforeverydevice
found,allpossibleattributesintheudevruleskeyformat.
Aruletomatch,canbecomposedbytheattributesofthedevice
andtheattributesfromonesingleparentdevice.
lookingatdevice'/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.1/0003:046D:C52F.0010/input/input39':
KERNEL=="input39"
SUBSYSTEM=="input"
DRIVER==""
ATTR{name}=="LogitechUSBReceiver"
ATTR{phys}=="usb-0000:00:1d.0-1.2/input1"
ATTR{properties}=="0"
ATTR{uniq}==""
lookingatparentdevice'/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.1/0003:046D:C52F.0010':
KERNELS=="0003:046D:C52F.0010"
SUBSYSTEMS=="hid"
DRIVERS=="hid-generic"
ATTRS{country}=="00"
lookingatparentdevice'/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.1':
KERNELS=="2-1.2:1.1"
SUBSYSTEMS=="usb"
DRIVERS=="usbhid"
ATTRS{authorized}=="1"
ATTRS{bAlternateSetting}=="0"
ATTRS{bInterfaceClass}=="03"
ATTRS{bInterfaceNumber}=="01"
ATTRS{bInterfaceProtocol}=="00"
ATTRS{bInterfaceSubClass}=="00"
ATTRS{bNumEndpoints}=="01"
ATTRS{supports_autosuspend}=="1"
lookingatparentdevice'/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2':
KERNELS=="2-1.2"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{authorized}=="1"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{bConfigurationValue}=="1"
ATTRS{bDeviceClass}=="00"
ATTRS{bDeviceProtocol}=="00"
ATTRS{bDeviceSubClass}=="00"
ATTRS{bMaxPacketSize0}=="8"
ATTRS{bMaxPower}=="98mA"
ATTRS{bNumConfigurations}=="1"
ATTRS{bNumInterfaces}=="2"
ATTRS{bcdDevice}=="3000"
ATTRS{bmAttributes}=="a0"
ATTRS{busnum}=="2"
ATTRS{configuration}=="RQR30.00_B0009"
ATTRS{devnum}=="12"
ATTRS{devpath}=="1.2"
ATTRS{idProduct}=="c52f"
ATTRS{idVendor}=="046d"
ATTRS{ltm_capable}=="no"
ATTRS{manufacturer}=="Logitech"
ATTRS{maxchild}=="0"
ATTRS{product}=="USBReceiver"
ATTRS{quirks}=="0x0"
ATTRS{removable}=="removable"
ATTRS{speed}=="12"
ATTRS{urbnum}=="1401"
ATTRS{version}=="2.00"
[...]
上面截取了運行這個命令之后的輸出的一部分。正如你從它的輸出中看到的那樣,udevadm從我們提供的指定路徑開始,并且提供了所有父級設(shè)備的信息。注意設(shè)備的屬性都是以單數(shù)的形式報告的(比如,KERNEL),而它的父級是以復(fù)數(shù)形式出現(xiàn)的(比如,KERNELS)。父級信息可以做為規(guī)則的一部分,但是同一時間只能有一個父級可以被引用:不同父級設(shè)備的屬性混合在一起是不能工作的。在上面我們定義的規(guī)則中,我們使用了一個父級設(shè)備屬性:idProduct和idVendor。
在我們的規(guī)則中接下來做的事情是,去使用ENV關(guān)鍵字:它既可以用于設(shè)置也可以用于去匹配環(huán)境變量。我們給DISPLAY和XAUTHORITY分配值。當(dāng)我們使用X服務(wù)器程序進(jìn)行交互去設(shè)置一些需要的信息時,這些變量是非常必要的:使用DISPLAY變量,我們指定服務(wù)器運行在哪個機(jī)器上,用的是哪個顯示和屏幕;使用XAUTHORITY提供了一個文件路徑,其包含了Xorg認(rèn)證和授權(quán)信息。這個文件一般位于用戶的家目錄中。
最后,我們使用了RUN字:它用于運行外部程序。非常重要:這里沒有立即運行,但是一旦所有的規(guī)則被解析,將運行各種動作。在這個案例中,我們使用xinput實用程序去改變觸摸板的狀態(tài)。我不想解釋這里的xinput的語法,它超出了本文的范圍,只需要注意這個觸摸板的ID是16。
規(guī)則設(shè)置完成之后,我們可以通過使用udevadmtest命令去調(diào)試它。這個命令對調(diào)試非常有用,它并不真實去運行RUN指定的命令:
$udevadmtest--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選項,以及設(shè)備的sysfs路徑的模擬動作。如果沒有報告錯誤,說明我們的規(guī)則運行的很好。要在真實的環(huán)境中去使用它,我們需要重新加載規(guī)則:
#udevadmcontrol--reload
這個命令將重新加載規(guī)則文件,但是,它只對重新加載之后發(fā)生的事件有效果。
我們通過創(chuàng)建一個udev規(guī)則了解了基本的概念和邏輯,這只是udev規(guī)則中眾多的選項和可能的設(shè)置中的一小部分。
最后想要了解更多關(guān)于Linux發(fā)展前景趨勢,請關(guān)注扣丁學(xué)堂Linux培訓(xùn)官網(wǎng)、微信等平臺,扣丁學(xué)堂IT職業(yè)在線學(xué)習(xí)教育平臺為您提供權(quán)威的Linux培訓(xùn)視頻教程系統(tǒng),通過千鋒扣丁學(xué)堂金牌講師在線錄制的Linux視頻教程課程,讓你快速掌握Linux從入門到精通開發(fā)實戰(zhàn)技能??鄱W(xué)堂Linux技術(shù)交流群:422345477。
【關(guān)注微信公眾號獲取更多的學(xué)習(xí)資料】
查看更多關(guān)于“Linux培訓(xùn)資訊”的相關(guān)文章>>
標(biāo)簽:
Linux命令
Linux視頻教程
Linux培訓(xùn)
Linux在線學(xué)習(xí)
Linux在線視頻