Udev 是自 kernel 2.6 以降,取代傳統靜態(static)的 devfs,改以動態(dynamic)的方式來管理 /dev/ 之下所有裝置的子系統。除此之外,它也取代了原先 hotplug 的功能,經常性地監看系統狀態,並於週邊元件發生異動,例如插入或拔除 USB 裝置、記憶卡、外接電源等設備時,尋找並載入合適的核心模組(kernel module)、建立並命名 device nodes、建立 links,或作出其它適當的反應。
典型的 Linux 系統在 /etc/udev/rules.d/ 資料夾下會有許多,在檔案名稱上具有先後順序(lexicographical order)的規則檔案 *.rules。這些規則所做的,通常是,裝備的重新命名(renaming),權限(permission)的設定,連結(links)的產生與移除等工作,例如新增一個數位電視裝置(dvb)時,將其權限更改為 666,或是固定把某一顆硬碟(HDD)的第一個 partition 永遠都取個暱名(persistent naming)叫做:
/dev/disk/by-id/usb-ST316002_3AS_34331B612222-part1以避免有時是 /dev/sda1、/dev/sdc1,有時候又成為 /dev/hda1 的困擾。然而,如果沒有這些 rules 的話,kernel 還是會賦予預設的名稱與權限。
本文的重點不(not)在於如何撰寫(writing)或修改 udev 規則(rules),也不在於如何更改新增裝置的名稱及權限。而在於,脫離 udev rules 的特殊語法(syntax),另外以我們已經熟悉的 Bourne-shell-script 來設計當週邊設備有所異動時,我們想要的反應及動作,例如,發出聲響(sound effects),跳出視窗(pop-up windows),或是自動 mount 之後,備份特定檔案(file backup)等。
如果你在指令行下
$ ps -e | grep udev可以看到 udevd 的話,就表示說,你的 Linux 系統上已經有一個所謂的 udev deamon 正在管理核心(kernel)裡所傳送出來的 uevents。這時,/dev/ 資料夾裡的檔案是動態配置的(dynamically polulated),譬如說,如果系統上沒有 sdg 這個 block device,那麼在 /dev/ 裡也不會有 sdg 這個檔案。如果你的 kernel 版本(可以 uname -r 查詢)是 >= 2.6.13 的話,那麼你就可以跟著本文一步一步地來玩一些有趣的實驗,這可能包括像是插入(insert)或拔出(unplug)一個隨身碟(thumb-drive)或一張記憶卡(SD card)時,讓電腦發出你所要的聲音(sound),或是跳出一個視窗(pop-up window),或者是自動 mount 一個 partition,或是甚至於在 mount 之後自動播放影音或是自動瀏覽照片(media-players)。雖然我們不建議像 autorun.bat 這種極具安全疑慮(security issues)的功能,但是這自然也是很容易辦到的。
因為我個人所使用的是 kernel 版本 2.6.27.59 上的 Debian Etch 或 Lenny,所以我們接下來就以此平台為基礎,開始做一些簡單有趣的實驗。
我們先以 root 的權限在 /etc/udev/rules.d/ 這個資料夾裡建立一個新檔:
$ sudo vim /etc/udev/rules.d/z99_test.rules檔案內容只要一行:
RUN+="/home/nobody/my_script"在這裡我們假設 nobody 是你的帳號名稱(user name),my_script 是放在 HOME 裡的任何一個可執行的程式。我們將用 shell-script 來示範這個程式如何被 udev 執行。其實在你建好 z99_test.rules 之後,udev 就已經開始執行 my_script 這個程式了。雖然此刻它還不存在,但是 udev 系統在找不到這個檔案的時候也不會抱怨。每次有電腦周邊元件異動時(uevent),例如,usb device 插入或拔出時,udev 系統都會去 /etc/udev/rules.d/ 資料夾裡依序查看並執行所有的 rules,當輪到我們剛剛才建立的 z99_test.rules 時,它便會去執行 my_script。
接下來我們便要來寫個叫做 my_script 的程式:
$ cd ~/裡面的內容就先放兩行就好了:
$ vim my_script
#!/bin/sh其中第一行是 UNIX 標準的 shell-script "shebang",它是用來告訴系統,這個 script 是要由 /bin/sh 來執行。第二行則呼叫一個聲音播放程式出來播放一個聲音檔。儲存這個檔案,再做(必要!):
aplay /usr/share/sounds/KDE_Beep_Bottles.wav
$ chmod 755 my_script然後先測試一下,是否有聲音:
$ ./my_script如果你的系統上沒有 aplay 或是那個 wav 檔,就以任何你系統上有的程式或聲音檔來取代。但是我們還是建議用 aplay 跟沒有壓縮的 wav 檔案。因為 aplay 檔案小、啟動快,且會用 ALSA 的 dmix 播放聲音檔,這樣的話,就不會因為可能正在聽別的東西,而使得這個程式要發出的聲音被擋住,不能播放。aplay(1) 在 Debain/Etch 是包含於 alsa-utils 這個 package 裡面。
再來,你就可以拿任何一個 usb 隨身碟插進去,試試看囉!你每次一插進去一個隨身碟,大概會聽到這個聲音檔被播放約 7 次,拔出隨身碟時,也大概會聽到 3 次這個聲音。
如果發生原因不明的問題的話,可以試試看:
$ sudo /etc/init.d/udev reload我們剛剛建立了 /etc/udev/rules.d/z99_test.rules 之後,沒有執行以上的 reload,是因為它是新建立的規則檔案(new rule files),但是如果這個檔案的內容經過修改的話,則必須執行以上的 reload,修改過的內容才會生效。
如果讓 my_script 的聲音播放指令在背景執行的話,例如:
那麼你很可能就不會聽得見那麼多次。這是因為這個指令被放到背景執行(backgrounding)之後,這個程式就結束了,而 udev 系統很快地再次執行這一行指令時,也會一再地放到背景去執行……,這些聲音就都重疊在一起,不能清楚地算出是被執行了幾次。#!/bin/shaplay /usr/share/sounds/KDE_Beep_Bottles.wav &
值得注意的是,如果在 my_script 這個程式裡,因為打錯字(typo)而執行錯誤的話,我們將完全無法察覺,也看不見任何的錯誤訊息(error messages),這是因為 udev 執行這個程式的時候,沒有 tty 可用,所以這個程式裡所產生的任何文字輸出(character output),我們都看不到。唯一的辦法是,讓這個程式把所有的訊息輸出到我們指定的 log file 裡。關於這一點,我們以後會介紹非常方便的 stdout 以及 stderr 的 redirection 方法。
基本架構已經建立,從現在開始,每當系統上「發生了什麼事件」(uevent),udev 系統都會去 /etc/udev/rules.d/ 資料夾裡依序查看並執行所有的 rules,當輪到我們剛剛才建立的 z99_test.rules 時,我們的程式 my_script 就會被執行一次。只要我們 shell-script 程式技巧足夠充分,對 udev 系統足夠了解,就可以在這個 script 裡為所欲為。在這一系列文章的下個單元,我們要繼續探討如何讓這個程式做更有用的事情。
下個單元:Linux 的 udev 是個有趣又有用的玩具(2)
References:
[1] Markus Gattol, Udev or how I manage my Gadgets,
http://www.markus-gattol.name/ws/udev.html
[2] Daniel Drake, Writing udev rules,
http://reactivated.net/writing_udev_rules.html
[3] ArchWiki, udev,
https://wiki.archlinux.org/index.php/Udev
[4] udev - Wikipedia, the free encyclopedia
http://en.wikipedia.org/wiki/Udev
[5] Chapter 20. Dynamic Kernel Device Management with udev http://doc.opensuse.org/products/opensuse/openSUSE/opensuse-reference/cha.udev.html
[6] Udev - ALSA wiki
http://alsa.opensrc.org/Udev
沒有留言:
張貼留言