內核檢測到USB設備的插入之后,需要通知用戶空間進程來處理。目前有2種通知方式:
1.內核調用call_usermodehelper_setup()/call_usermodehelper_exec()從而運行用戶空間進程來處理。可以通過/sys/kernel/uevent_helper或者/proc/sys/kernel/hotplug來配置,指定用戶空間可執行程序的路徑。。
2.調用netlink_broadcast_filtered(),通過netlink的方式,將事件發送到用戶空間進程。
對於openwrt來說,他采用的是第二種方式。那么是哪個進程在監聽這類事件呢?是procd這個進程。關於procd進程的啟動,可以參照以下文章:
https://blog.csdn.net/angan4532/article/details/102303089
那么procd進程啟動時,就會創建一個NETLINK_KOBJECT_UEVENT類型的netlink的socket連接到內核。當內核檢測到事件后,就通過這個netlink socket 將uevent消息發送到procd.
那么procd收到uevent消息之后,對不同的消息會根據用戶設定的規則進行不同的處理。這個規則是由/etc/hotplug.json指定的。
下面看一下這個配置文件的內容:
[router] /etc # cat hotplug.json [ [ "case", "ACTION", { "add": [ [ "if", [ "and", [ "has", "MAJOR" ], [ "has", "MINOR" ], ], [ [ "if", [ "or", [ "eq", "DEVNAME", [ "null", "full", "ptmx", "zero" ], ], [ "regex", "DEVNAME", [ "^gpio", "^hvc" ], ], ], [ [ "makedev", "/dev/%DEVNAME%", "0666" ], [ "return" ], ] ], [ "if", [ "or", [ "eq", "DEVNAME", "mapper/control" ], [ "regex", "DEVPATH", "^ppp" ], ], [ [ "makedev", "/dev/%DEVNAME%", "0600" ], [ "return" ], ], ], [ "if", [ "has", "DEVNAME" ], [ "makedev", "/dev/%DEVNAME%", "0644" ], ], ], ], [ "if", [ "has", "FIRMWARE" ], [ [ "exec", "/sbin/hotplug-call", "%SUBSYSTEM%" ], [ "load-firmware", "/lib/firmware" ], [ "return" ] ] ], ], "remove" : [ [ "if", [ "and", [ "has", "DEVNAME" ], [ "has", "MAJOR" ], [ "has", "MINOR" ], ], [ "rm", "/dev/%DEVNAME%" ] ] ] } ], [ "if", [ "eq", "SUBSYSTEM", "platform" ], [ "exec", "/sbin/hotplug-call", "%SUBSYSTEM%" ] ], [ "if", [ "and", [ "has", "BUTTON" ], [ "eq", "SUBSYSTEM", "button" ], ], [ "exec", "/etc/rc.button/%BUTTON%" ] ], [ "if", [ "eq", "SUBSYSTEM", [ "net", "input", "usb", "usbmisc", "ieee1394", "block", "atm", "zaptel", "tty", "button", "dump" ] ], [ "exec", "/sbin/hotplug-call", "%SUBSYSTEM%" ] ], [ "if", [ "and", [ "eq", "SUBSYSTEM", "usb-serial" ], [ "regex", "DEVNAME", [ "^ttyUSB", "^ttyACM" ] ], ], [ "exec", "/sbin/hotplug-call", "tty" ] ], ] [router] /etc #
可以看到,這個規則文件里面,對於不同類型的uevent都指定了不同的處理方式。比方說對於usb存儲設備,他首先會用mkdev來創建device,然后會調用/sbin/hotplug-call,並傳入一個參數SUBSYSTEM。
/sbin/hotplug-call是一個腳本程序:
[router] /etc # cat /sbin/hotplug-call #!/bin/sh # Copyright (C) 2006-2010 OpenWrt.org export HOTPLUG_TYPE="$1" . /lib/functions.sh PATH=/usr/sbin:/usr/bin:/sbin:/bin LOGNAME=root USER=root export PATH LOGNAME USER export DEVICENAME="${DEVPATH##*/}" [ \! -z "$1" -a -d /etc/hotplug.d/$1 ] && { for script in $(ls /etc/hotplug.d/$1/* 2>&-); do ( [ -f $script ] && . $script ); done } [router] /etc #
這個腳本會調用/etc/hotplug.d/$SUBSYSTEM下面的所有腳本。這個腳本用戶可以自己指定。那么對於USB存儲設備來說,我們可能需要將這個設備mount到文件系統。