一、UDEV是什么?
Udev是一个针对Linux内核2.6的可提供自动创建的设备节点和命名的解决方法的一个文件系统;其实与/etc/目录下的fstab文件类似
二、Udev如何获取内核这些模块的变化信息?
参考博客:http://blog.chinaunix.net/uid-24943863-id-3223000.html
新的Linux内核使用udev代替了hotplug作为热拔插管理,虽然有udevd管理热拔插,但有时候我们还是需要在应用程序中检测热拔插事件以便快速地处理,比如在读写SD卡的时候拔下SD卡,那么需要立即检测出该情况,然后结束读写线程,防止VFS崩溃。Netlink是面向数据包的服务,为内核与用户层搭建了一个高速通道,是udev实现的基础。该工作方式是异步的,用户空间程序不必使用轮询等技术来检测热拔插事件
内核中使用uevent事件通知用户空间,uevent首先在内核中调用netlink_kernel_create()函数创建一个socket套接字,该函数原型在netlink.h有定义,其类型是表示往用户空间发送消息的NETLINK_KOBJECT_UEVENT,groups=1,由于uevent只往用户空间发送消息而不接受,因此其输入回调函数input和cb_mutex都设置为NULL。
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <errno.h> 5 #include <sys/types.h> 6 #include <asm/types.h> 7 //该头文件需要放在netlink.h前面防止编译出现__kernel_sa_family未定义 8 #include <sys/socket.h> 9 #include <linux/netlink.h> 10 11 void MonitorNetlinkUevent() 12 { 13 int sockfd; 14 struct sockaddr_nl sa; 15 int len; 16 char buf[4096]; 17 struct iovec iov; 18 struct msghdr msg; 19 int i; 20 21 memset(&sa,0,sizeof(sa)); 22 sa.nl_family=AF_NETLINK; 23 sa.nl_groups=NETLINK_KOBJECT_UEVENT; 24 sa.nl_pid = 0;//getpid(); both is ok 25 memset(&msg,0,sizeof(msg)); 26 iov.iov_base=(void *)buf; 27 iov.iov_len=sizeof(buf); 28 msg.msg_name=(void *)&sa; 29 msg.msg_namelen=sizeof(sa); 30 msg.msg_iov=&iov; 31 msg.msg_iovlen=1; 32 33 sockfd=socket(AF_NETLINK,SOCK_RAW,NETLINK_KOBJECT_UEVENT); 34 if(sockfd==-1) 35 printf("socket creating failed:%s\n",strerror(errno)); 36 if(bind(sockfd,(struct sockaddr *)&sa,sizeof(sa))==-1) 37 printf("bind error:%s\n",strerror(errno)); 38 39 len=recvmsg(sockfd,&msg,0); 40 if(len<0) 41 printf("receive error\n"); 42 else if(len<32||len>sizeof(buf)) 43 printf("invalid message"); 44 for(i=0;i<len;i++) 45 if(*(buf+i)=='\0') 46 buf[i]='\n'; 47 printf("received %d bytes\n%s\n",len,buf); 48 } 49 50 int main(int argc,char **argv) 51 { 52 MonitorNetlinkUevent(); 53 return 0; 54 }
创建socket描述符的时候指定协议族为AF_NETLINK或者PF_NETLINK,套接字type选择SOCK_RAW或者SOCK_DGRAM,Netlink协议并不区分这两种类型,第三个参数协议填充NETLINK_KOBJECT_UEVENT表示接收内核uevent信息。接着就绑定该文件描述符到sockadd_nl,注意该结构体nl_groups是接收掩码,取~0是将接收所有来自内核的消息,我们接收热拔插只需要NETLINK_KOBJECT_UEVENT即可。接下来调用recvmsg开始接收内核消息,recvmsg函数需要我们填充message报头,包括指定接收缓存等工作。该函数会阻塞直到有热拔插事件产生。