一、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報頭,包括指定接收緩存等工作。該函數會阻塞直到有熱拔插事件產生。