udev是一种工具,它能够根据系统中的硬件设备的状态动态更新设备文件,包括设备文件的创建,删除等,设备文件通常放在/dev目录下。使用udev后,在/dev目录下就只包含系统中真正存在的设备。udev同时提供了监视接口,当设备的状态改变时,监视接口可以向应用程序报告发生的事件,当设备加入系统或从系统移除时都可以接到通知。

udev只支持linux-2.6及以上版本的内核,因为udev严重依赖于sysfs文件系统提供的信息,而sysfs文件系统只在linux-2.6内核中才有。

udev能够实现所有devfs实现的功能。但udev运行在用户模式中,而devfs运行在内核模式中。

作用:

1. 动态创建或删除设备文件

2. 遍历sysfs设备文件

3. hotplug(利用netlink)

使用udev需要先安装libudev库,在程序中包含libudev.h头文件,并且在编译时加上-ludev告诉编译器去链接udev库。

1. 安装libudev

sudo apt-get install libudev-dev

2. 编写测试代码udev-hotplugin.c

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/select.h>
#include <linux/types.h>
#include <linux/netlink.h>
#include <libudev.h>#undef asmlinkage
#ifdef __i386__
#define asmlinkage __attribute__((regparm(0)))
#else
#define asmlinkage
#endifstatic int udev_exit;static void asmlinkage sig_handler(int signum)
{if (signum == SIGINT || signum == SIGTERM)udev_exit = 1;
}static void print_device(struct udev_device *device, const char *source, int env)
{struct timeval tv;struct timezone tz;gettimeofday(&tv, &tz);printf("%-6s[%llu.%06u] %-8s %s (%s)\n",source,(unsigned long long) tv.tv_sec, (unsigned int) tv.tv_usec,udev_device_get_action(device),udev_device_get_devpath(device),udev_device_get_subsystem(device));if (env) {struct udev_list_entry *list_entry;udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))printf("%s=%s\n",udev_list_entry_get_name(list_entry),udev_list_entry_get_value(list_entry));printf("\n");}}int udevadm_monitor(struct udev *udev)
{struct sigaction act;int env = 0;int print_kernel = 1;struct udev_monitor *kernel_monitor = NULL;fd_set readfds;int rc = 0;if (getuid() != 0) {fprintf(stderr, "root privileges needed to subscribe to kernel events\n");goto out;}/* set signal handlers */memset(&act, 0x00, sizeof(struct sigaction));act.sa_handler = (void (*)(int)) sig_handler;sigemptyset(&act.sa_mask);act.sa_flags = SA_RESTART;sigaction(SIGINT, &act, NULL);sigaction(SIGTERM, &act, NULL);printf("monitor will print the received events.\n");if (print_kernel) {kernel_monitor = udev_monitor_new_from_netlink(udev, "udev"); //这里的udev源码中没有"udev"这个参数,不加进去返回值就为NULL,所以要加这个if (kernel_monitor == NULL) {rc = 3;printf("udev_monitor_new_from_netlink() error\n");goto out;}if (udev_monitor_enable_receiving(kernel_monitor) < 0) {rc = 4;goto out;}printf("UEVENT the kernel uevent: \n");}printf("\n");while (!udev_exit) {int fdcount;FD_ZERO(&readfds);if (kernel_monitor != NULL)FD_SET(udev_monitor_get_fd(kernel_monitor), &readfds);fdcount = select(udev_monitor_get_fd(kernel_monitor)+1, &readfds, NULL, NULL, NULL);if (fdcount < 0) {if (errno != EINTR)fprintf(stderr, "error receiving uevent message: %m\n");continue;}if ((kernel_monitor != NULL) && FD_ISSET(udev_monitor_get_fd(kernel_monitor), &readfds)) {struct udev_device *device;device = udev_monitor_receive_device(kernel_monitor);if (device == NULL)continue;print_device(device, "UEVENT", env);udev_device_unref(device);}}out:udev_monitor_unref(kernel_monitor);return rc;
}int main(int argc, char *argv[])
{struct udev *udev;int rc = 1;udev = udev_new();if (udev == NULL)goto out;udevadm_monitor(udev);goto out;rc = 2;out:udev_unref(udev);return rc;
}

3. 测试

1)编译

gcc -o udevhotplug udev-hotplugin.c -ludev

2)以root权限执行

sudo ./udevhotplug

当插拔一个USB设备时,显示如下:

4. libudev API介绍

4.1 初始化

首先调用udev_new,创建一个udev library context。udev library context采用引用记数机制,创建的context默认引用记数为1,使用udev_ref和udev_unref增加或减少引用记数,如果引用记数为0,则释放内部资源。

4.2 枚举设备

使用udev_enumrate_new创建一个枚举器,用于扫描系统已接设备。使用udev_enumrate_ref和udev_enumrate_unref增加或减少引用记数。

使用udev_enumrate_add_match/nomatch_xxx系列函数增加枚举的过滤器,过滤关键字以字符表示,如"block"设备。

使用udev_enumrate_scan_xxx系列函数扫描/sys目录下,所有与过滤器匹配的设备。扫描完成后的数据结构是一个链表,使用udev_enumerate_get_list_entry获取链表的首个结点,使用udev_list_entry_foreach遍历整个链表。

4.3 监控设备插拔 udev的设备插拔基于netlink实现。

1)使用udev_monitor_new_from_netlink创建一个新的monitor,函数的第二个参数是事件源的名称,可选"kernel"或"udev"。基于"kernel"的事件通知要早于"udev",但相关的设备结点未必创建完成,所以一般应用的设计要基于"udev"进行监控。

2)使用udev_monitor_filter_add_match_subsystem_devtype增加一个基于设备类型的udev事件过滤器,例如: "block"设备。

3)使用udev_monitor_enable_receiving启动监控过程。监控可以使用udev_monitor_get_fd获取一个文件描述符,基于返回的fd可以执行poll操作,简化程序设计。

4)插拔事件到达后,可以使用udev_monitor_receive_device获取产生事件的设备映射。调用udev_device_get_action可以获得一个字符串:"add"或者"remove",以及"change", "online", "offline"等,但后三个未知什么情况下会产生。

4.4 获取设备信息

使用udev_list_entry_get_name可以得到一个设备结点的sys路径,基于这个路径使用udev_device_new_from_syspath可以创建一个udev设备的映射,用于获取设备属性。获取设备属性使用udev_device_get_properties_list_entry,返回一个存储了设备所有属性信息的链表,使用udev_list_entry_foreach遍历链表,使用udev_list_entry_get_name和udev_list_entry_get_value获取属性的名称和值。

在linux下使用udev获取热插拔(hotplug)事件相关推荐

  1. Linux下通过v4l2获取视频设备名、支持的编解码及视频size列表实现

    早些时候给出了在Windows下通过dshow获取视频设备信息的实现,包括获取视频设备名.获取每种视频设备支持的编解码格式列表.每种编解码格式支持的video size列表,见:https://blo ...

  2. java 收集系统资源_方法:Linux 下用JAVA获取CPU、内存、磁盘的系统资源信息

    CPU使用率: InputStream is = null; InputStreamReader isr = null; BufferedReader brStat = null; StringTok ...

  3. linux格式化gat分区,Linux 下使用udev永久绑定带库设备方法

    Linux 下使用udev永久绑定带库设备方法 在Linux 系统下配置带库设备,传统的方法是当安装完lin_tape驱动后会在/dev/路径下生成IBMtape,IBMchanger 这样的驱动设备 ...

  4. linux u盘插入事件,Linux 下监控USB设备拔插事件

    Linux 下监控USB设备拔插事件 发布时间:2018-01-29 00:00, 浏览次数:1111 , 标签: Linux USB * 使用Netlink来实现 这是一个特殊的socket,可以接 ...

  5. Linux下自动检测USB热插拔

    做嵌入式开发,尤其在网关.路由器或者其他支持USB设备的终端上,为了提高用户体验,我们常常需要支持自动识别并挂载USB设备功能.某些应用程序,在使用USB设备的过程中,也希望能够侦测到USB断开事件, ...

  6. 有关Linux下request.getRealPath(/)获取路径的问题

    request.getRealPath("/") 在window获取的是服务器的根目录,结尾包含分隔符, 如E:\apache-tomcat-6.0.29-bak\apache-t ...

  7. Linux下百度云盘报 获取bdstoken失败

    在用linux下百度云盘工具(bcloud),登录时,报获取bdstoken失败. 在网上搜了一下,解决办法如下. 找到auth.py文件 locate auth.py |grep bcloud 结果 ...

  8. sigar如何获取linux的buffer内存,Linux 下使用Sigar 获取内存信息

    上一篇文章介绍了linux下的sigar 库,并使用sigar 库来获取cpu 使用率,本文在这里介绍一下如何使用sigar 库获取内存信息. 和cpu 一样,sigar中有和内存相关的结构体siga ...

  9. linux c 读取摄像头,Linux下onvif客户端获取ipc摄像头 获取能力:GetCapabilities

    getcapabilities:获取能力,主要目的获取设备能力信息(获取媒体服务地址) 鉴权:但是在调用获取设备能力之前是需要鉴权的.onvif协议规定,部分接口需要鉴权,部分接口不需要鉴权,在调用需 ...

最新文章

  1. vue单选,多选,多选的内容显示在页面可删除
  2. 5.6 前端开发日报
  3. JSON数据格式:以及XML文件格式,YML文件格式,properties文件格式
  4. Java、Apache Tomcat下载与安装及环境变量配置
  5. 3、Finished with error: FormatException: Bad UTF-8 encoding 0xc3 (at offset 169)
  6. 并不对劲的noip2018
  7. 【分享】iOS功能界面漂亮的弹出框
  8. (53)Xilinx时钟原语-BUG与IBUFG(第11天)
  9. Windows Server 2003证书服务配置与管理
  10. 2019 年度全球程序员薪酬报告:40岁以后普遍遭遇收入天花板
  11. ADFS令牌解密,令牌签名证书到期处理
  12. MemoryBarrier方法
  13. 解决Chrome无法翻译此网页
  14. SD卡容量变小恢复方法
  15. ddos是攻击服务器还是网站,服务器遭到DDoS攻击选高防IP还是CDN?
  16. Git:rebase 是什么
  17. iOS 高级工程师是怎么进阶
  18. php找零页面,JS实现找零张数最小
  19. 高并发其实挺容易的,当你明白了一万并发的原理,然后扩展到百万、千万、亿万级很easy
  20. c++模板类声明和定义的问题

热门文章

  1. 《文明之光 第二册》一一10.1 罗卡尔角的夕阳—— 葡、西的殖民时代(1)
  2. CSS拉伸resize
  3. Immutable 详解及 React 中实践
  4. Powershell 查看软件是否成功安装
  5. centos 输入密码正确进不去系统
  6. mysql(slow-query) 快速开启慢日志查询的方法
  7. ubuntu11.10安装arm-linux-gcc详解
  8. js 中使用 时间datetime 类型到前端iOS 不兼容问题
  9. first() mysql_EF6配合MySQL或MSSQL(CodeFirst模式)配置指引
  10. aes256 加密后的长度_视频会议Zoom 5.0版本重大更新,增强加密功能提供更多安全选项...