日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

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

發布時間:2023/12/15 linux 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 在linux下使用udev获取热插拔(hotplug)事件 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

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"?;?#34;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)事件的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。