2009年3月20日 星期五

udev操作 如何從udevinfo udevmonitor的觀察來寫udev rule

udev
userspace device management
目的是允許使用者動態的管理device node


#===============
# 緣起
#===============
1.
device node是Linux系統user space跟hardware device溝通的介面
$ ls -al /dev
...
crw-rw---- 1 root audio 14, 12 2009-03-18 08:54 adsp //ALSA audio
crw-rw---- 1 root dialout 188, 0 2009-03-18 17:05 ttyUSB0 //usb serial port
brw-rw---- 1 root disk 8, 1 2009-03-18 08:54 sda1 //HD
brw-rw---- 1 root disk 1, 0 2009-03-18 08:54 ram0 //ram
crw-rw---- 1 root audio 10, 135 2009-03-18 08:54 rtc //real time clock
...
P.S.
c: character device, b: block device

2.
傳統使用者自己手動device node,
後來有devfs可以自動建立device node,但有缺點是建立的規則是寫在driver內,無法在user space決定node的名字屬性等等[2]

3.
sysfs是一個在2.6 kernel新出的檔案系統,由kernel本身管理,當device plug進系統時,會顯示基本的device資訊,udev會利用這個資訊,以及設定的rule條件,來建立
或是執行一些額外的程式

#===============
# 提供的功能
#===============
1. Rename a device node from the default name to something else
(自己可以device node名字)
2. Provide an alternative/persistent name for a device node by creating a symbolic link to the default device node
(可以建立device node別名-symbolic link)
3. Name a device node based on the output of a program
(名字的決定還可以呼叫外部程式)
4. Change permissions and ownership of a device node
(預設建立的device node權限可以改變)
(例如usb device預設建立出來0660,可以改變一建立就是0666)
5. Launch a script when a device node is created or deleted (typically when a device is attached or unplugged)
(可以在device node建立或是刪除時執行外部script)
6. Rename network interfaces
(network interface也可以改名)
[1]

#===============
# rules的範例
#===============
+------------------------------------------------------------------------------------------------
Q1. Change permissions and ownership of a device node

dnwOTG USB driver是一個根據drivers/usb/usb-skeleton.c的usb driver
當VENDOR_ID和PRODUCT_ID符合的裝置plug之後,會主動建立/dev/dnwOTG這device node
但是他的權限是0660 root root所以變成一般使用者無法直接read/write
一般情況
$ ll /dev/dnwOTG -al
crw-rw---- 1 root root 180, 192 2009-03-18 18:36 /dev/dnwOTG

如何加入規則希望變成這樣
$ ll /dev/dnwOTG -al
crw-rw-rw- 1 root root 180, 192 2009-03-18 18:35 /dev/dnwOTG

Answer:
1. 使用工具程式udevmonitor
$ udevmonitor --udev
(執行dnw c2000000, 使得usb device出現,會觀察到)

UDEV [1237372815.218233] add /devices/pci0000:00/0000:00:1d.7/usb5/5-3 (usb)
UDEV [1237372815.218391] add /class/usb_endpoint/usbdev5.118_ep00 (usb_endpoint)
UDEV [1237372815.255269] add /devices/pci0000:00/0000:00:1d.7/usb5/5-3/5-3:1.0 (usb)
UDEV [1237372815.255379] add /class/usb/dnwOTG (usb)
^^^^^^^^^^^^^^^^^^^^
UDEV [1237372815.255465] add /class/usb_endpoint/usbdev5.118_ep81 (usb_endpoint)
UDEV [1237372815.255550] add /class/usb_endpoint/usbdev5.118_ep02 (usb_endpoint)
UDEV [1237372815.278249] add /class/usb_device/usbdev5.118 (usb_device)

得知有這一udev event

2. 使用工具程式udevinfo
$ udevinfo -a -p /class/usb/dnwOTG
...
looking at device '/class/usb/dnwOTG':
KERNEL=="dnwOTG"
SUBSYSTEM=="usb"
DRIVER==""
ATTR{dev}=="180:192"
...

3. 加入規則改變mode
sudo vi /etc/udev/rules.d/40-permissions.rules
最後一行加入
KERNEL=="dnwOTG", MODE="0666"

+------------------------------------------------------------------------------------------------
Q2. 希望能當mvp kernel開完,OTG ready同時在host PC自己建立好network usb0 (不用在ifdown usb0;ifup usb0)

Answer:
1. 使用工具程式udevmonitor
$ udevmonitor --udev
...
UDEV [1237373325.456422] add /class/usb_endpoint/usbdev5.122_ep01 (usb_endpoint)
UDEV [1237373325.462935] add /class/usb_device/usbdev5.122 (usb_device)
UDEV [1237373325.632610] add /class/net/usb0 (net)
^^^^^^^^^^^^^^^^^
...

得知有這一udev event

2. 使用工具程式udevinfo
$ udevinfo -a -p /class/net/usb0
...
looking at device '/class/net/usb0':
KERNEL=="usb0"
SUBSYSTEM=="net"
DRIVER==""
ATTR{weight}=="0"
ATTR{tx_queue_len}=="1000"
ATTR{flags}=="0x1003"
ATTR{mtu}=="1500"
ATTR{operstate}=="unknown"
ATTR{dormant}=="0"
ATTR{carrier}=="1"
ATTR{broadcast}=="ff:ff:ff:ff:ff:ff"
ATTR{address}=="42:f9:d6:bf:97:10"
ATTR{link_mode}=="0"
ATTR{type}=="1"
ATTR{features}=="0x0"
ATTR{ifindex}=="31"
ATTR{iflink}=="31"
ATTR{addr_len}=="6"
...

3. 加入規則
sudo vi /etc/udev/rules.d/80-programs.rules
最後加入
# 當usb0進來且條件是SUBSYSTEM=="net", ACTION=="add" 執行/lib/udev/usb0nic的程式
KERNEL=="usb0", SUBSYSTEM=="net", ACTION=="add", \
RUN+="usb0nic on"

# 當usb0進來且條件是SUBSYSTEM=="net", ACTION=="remove" 執行/lib/udev/usb0nic的程式
KERNEL=="usb0", SUBSYSTEM=="net", ACTION=="remove", \
RUN+="usb0nic off"

4. 編輯usb0nic
$ sudo vi /lib/udev/usb0nic
#! /bin/sh
if test -z "$1"
then
exit
else
if [ $1 == "on" ];then
usb_exist=`ifconfig | awk '/usb0/{print $1}'`
if [ $usb_exist == "usb0" ]; then
ifdown usb0
fi
ifup usb0
fi
if [ $1 == "off" ];then
ifdown usb0
fi
fi

$ sudo chmod +x /lib/udev/usb0nic

#===============
# 參考資料
#===============
1. [Writing udev rules,version 0.74], Daniel Drake (dsd), http://reactivated.net/writing_udev_rules.html
詳細說明如何寫udev rules,使用實際範例說明,淺顯易懂
2. [udev and devfs - The final word], Greg Kroah-Hartman, http://kernel.org/pub/linux/utils/kernel/hotplug/udev_vs_devfs
udev的創始者說明udev跟devfs的差異和比較

1 則留言:

YJ 提到...

(1)請問一下,udev 可處理 usb auto mount/umount,但是如果是 usb dvd-rom 放入光碟片按進片鍵時,udev 是否可偵測到呢? 我目前從 /var/log/messages 與 dmesg 都無法看到光碟進片的訊息。而且 udev 完全無法對此有反應。 (2) 請問據您所知, udev 是否可用來處理偵測網路連線/斷線的應用呢?以目前網路上找到的資料來看,用途似乎在偵測並處理硬體裝置的變更。