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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

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

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

?

udev是一種工具,它能夠根據(jù)系統(tǒng)中的硬件設(shè)備的狀態(tài)動(dòng)態(tài)更新設(shè)備文件,包括設(shè)備文件的創(chuàng)建,刪除等,設(shè)備文件通常放在/dev目錄下。使用udev后,在/dev目錄下就只包含系統(tǒng)中真正存在的設(shè)備。udev同時(shí)提供了監(jiān)視接口,當(dāng)設(shè)備的狀態(tài)改變時(shí),監(jiān)視接口可以向應(yīng)用程序報(bào)告發(fā)生的事件,當(dāng)設(shè)備加入系統(tǒng)或從系統(tǒng)移除時(shí)都可以接到通知。

udev只支持linux-2.6及以上版本的內(nèi)核,因?yàn)閡dev嚴(yán)重依賴(lài)于sysfs文件系統(tǒng)提供的信息,而sysfs文件系統(tǒng)只在linux-2.6內(nèi)核中才有。

udev能夠?qū)崿F(xiàn)所有devfs實(shí)現(xiàn)的功能。但udev運(yùn)行在用戶(hù)模式中,而devfs運(yùn)行在內(nèi)核模式中。

?

作用:

1. 動(dòng)態(tài)創(chuàng)建或刪除設(shè)備文件

2. 遍歷sysfs設(shè)備文件

3. hotplug(利用netlink)

?

使用udev需要先安裝libudev庫(kù),在程序中包含libudev.h頭文件,并且在編譯時(shí)加上-ludev告訴編譯器去鏈接udev庫(kù)。

?

1. 安裝libudev

sudo apt-get install libudev-dev

?

2. 編寫(xiě)測(cè)試代碼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源碼中沒(méi)有"udev"這個(gè)參數(shù),不加進(jìn)去返回值就為NULL,所以要加這個(gè)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. 測(cè)試

1)編譯

gcc -o udevhotplug udev-hotplugin.c -ludev

2)以root權(quán)限執(zhí)行

sudo ./udevhotplug

當(dāng)插拔一個(gè)USB設(shè)備時(shí),顯示如下:

?

4. libudev API介紹

4.1 初始化

首先調(diào)用udev_new,創(chuàng)建一個(gè)udev library context。udev library context采用引用記數(shù)機(jī)制,創(chuàng)建的context默認(rèn)引用記數(shù)為1,使用udev_ref和udev_unref增加或減少引用記數(shù),如果引用記數(shù)為0,則釋放內(nèi)部資源。

?

4.2 枚舉設(shè)備

使用udev_enumrate_new創(chuàng)建一個(gè)枚舉器,用于掃描系統(tǒng)已接設(shè)備。使用udev_enumrate_ref和udev_enumrate_unref增加或減少引用記數(shù)。

使用udev_enumrate_add_match/nomatch_xxx系列函數(shù)增加枚舉的過(guò)濾器,過(guò)濾關(guān)鍵字以字符表示,如"block"設(shè)備。

使用udev_enumrate_scan_xxx系列函數(shù)掃描/sys目錄下,所有與過(guò)濾器匹配的設(shè)備。掃描完成后的數(shù)據(jù)結(jié)構(gòu)是一個(gè)鏈表,使用udev_enumerate_get_list_entry獲取鏈表的首個(gè)結(jié)點(diǎn),使用udev_list_entry_foreach遍歷整個(gè)鏈表。

?

4.3 監(jiān)控設(shè)備插拔?udev的設(shè)備插拔基于netlink實(shí)現(xiàn)。

1)使用udev_monitor_new_from_netlink創(chuàng)建一個(gè)新的monitor,函數(shù)的第二個(gè)參數(shù)是事件源的名稱(chēng),可選"kernel"或"udev"?;?#34;kernel"的事件通知要早于"udev",但相關(guān)的設(shè)備結(jié)點(diǎn)未必創(chuàng)建完成,所以一般應(yīng)用的設(shè)計(jì)要基于"udev"進(jìn)行監(jiān)控。

2)使用udev_monitor_filter_add_match_subsystem_devtype增加一個(gè)基于設(shè)備類(lèi)型的udev事件過(guò)濾器,例如: "block"設(shè)備。

3)使用udev_monitor_enable_receiving啟動(dòng)監(jiān)控過(guò)程。監(jiān)控可以使用udev_monitor_get_fd獲取一個(gè)文件描述符,基于返回的fd可以執(zhí)行poll操作,簡(jiǎn)化程序設(shè)計(jì)。

4)插拔事件到達(dá)后,可以使用udev_monitor_receive_device獲取產(chǎn)生事件的設(shè)備映射。調(diào)用udev_device_get_action可以獲得一個(gè)字符串:"add"或者"remove",以及"change", "online", "offline"等,但后三個(gè)未知什么情況下會(huì)產(chǎn)生。

?

4.4 獲取設(shè)備信息

使用udev_list_entry_get_name可以得到一個(gè)設(shè)備結(jié)點(diǎn)的sys路徑,基于這個(gè)路徑使用udev_device_new_from_syspath可以創(chuàng)建一個(gè)udev設(shè)備的映射,用于獲取設(shè)備屬性。獲取設(shè)備屬性使用udev_device_get_properties_list_entry,返回一個(gè)存儲(chǔ)了設(shè)備所有屬性信息的鏈表,使用udev_list_entry_foreach遍歷鏈表,使用udev_list_entry_get_name和udev_list_entry_get_value獲取屬性的名稱(chēng)和值。

?

總結(jié)

以上是生活随笔為你收集整理的在linux下使用udev获取热插拔(hotplug)事件的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。