处理 hotplug 传统的方法是,在内核中执行一个称为 hotplug 的程序,相关参数通过环境变量传递过来,再由 hotplug 通知其它关注 hotplug 事件的应用程序。这样做不但效率低下,而且感觉也不那么优雅。新的方法是采用 NETLINK 实现的,这是一种特殊类型的 socket ,专门用于内核空间与用户空间的异步通信。下面的这个简单的例子,可以监听来自内核 hotplug 的事件。
#include < stdio .h>
#include <stdlib.h>
#include < string .h>
#include < ctype .h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <sys/ socket .h>
#include <linux/types.h>
#include <linux/netlink.h>
#include < errno .h>
static int init_hotplug_sock ( void )
{
struct sockaddr_nl snl ;
const int buffersize = 16 * 1024 * 1024;
int retval ;
memset (& snl , 0x00, sizeof ( struct sockaddr_nl));
snl .nl_family = AF_NETLINK;
snl .nl_pid = getpid ();
snl .nl_groups = 1;
int hotplug_sock = socket (PF_NETLINK, SOCK_DGRAM , NETLINK_KOBJECT_UEVENT);
if ( hotplug_sock == -1) {
printf ( "error getting socket: %s" , strerror ( errno ));
return -1;
}
/* set receive buffersize */
setsockopt ( hotplug_sock , SOL_SOCKET , SO_RCVBUFFORCE, & buffersize , sizeof ( buffersize ));
retval = bind ( hotplug_sock , ( struct sockaddr *) & snl , sizeof ( struct sockaddr_nl));
if ( retval < 0) {
printf ( "bind failed: %s" , strerror ( errno ));
close ( hotplug_sock );
hotplug_sock = -1;
return -1;
}
return hotplug_sock ;
}
#define UEVENT_BUFFER_SIZE 2048
int main ( int argc , char * argv [])
{
int hotplug_sock = init_hotplug_sock ();
while (1)
{
char buf [ UEVENT_BUFFER_SIZE *2] = {0};
recv ( hotplug_sock , & buf , sizeof ( buf ), 0);
printf ( "%s/n" , buf );
}
return 0;
}
编译:
gcc -g hotplug.c -o hotplug_monitor
运行后插 / 拔 U 盘,可以看到:
add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1
add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/usbdev2.2_ep00
add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0
add@/class/scsi_host/host2
add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/usbdev2.2_ep81
add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/usbdev2.2_ep02
add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/usbdev2.2_ep83
add@/class/usb_device/usbdev2.2
add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/host2/target2:0:0/2:0:0:0
add@/class/scsi_disk/2:0:0:0
add@/block/sda
add@/block/sda/sda1
add@/class/scsi_device/2:0:0:0
add@/class/scsi_generic/sg0
remove@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/usbdev2.2_ep81
remove@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/usbdev2.2_ep02
remove@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/usbdev2.2_ep83
remove@/class/scsi_generic/sg0
remove@/class/scsi_device/2:0:0:0
remove@/class/scsi_disk/2:0:0:0
remove@/block/sda/sda1
remove@/block/sda
remove@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/host2/target2:0:0/2:0:0:0
remove@/class/scsi_host/host2
remove@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0
remove@/class/usb_device/usbdev2.2
remove@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/usbdev2.2_ep00
remove@/devices/pci0000:00/0000:00:1d.1/usb2/2-1