Libudev USB storage polling example in C part1
Here is a simple libudev example that performs the following:
- Enumerates static plugged in USB storage devices
- Using epoll, polls for USB and block device changes
To compile:
gcc -Wall -g -o udev_example usbtest2.c -ludev
The code:
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <unistd.h>
#include <errno.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define NUM_OF_EVENTS 5
int main(void)
{
struct udev *udev;
struct udev_enumerate *enumerate;
struct udev_list_entry *devices;
struct udev_device *dev;
int fd_udev = -1;
struct epoll_event ep_udev = { 0 };
struct udev_monitor *mon;
int fd_ep = -1;
udev = udev_new();
if (!udev) {
printf("Can't create udev\n");
exit(1);
}
/// What devices do we have plugged in at this moment in time?
enumerate = udev_enumerate_new(udev);
udev_enumerate_add_match_subsystem(enumerate, "scsi");
udev_enumerate_add_match_property(enumerate, "DEVTYPE", "scsi_device");
udev_enumerate_scan_devices(enumerate);
devices = udev_enumerate_get_list_entry(enumerate);
struct udev_list_entry *entry;
/// enumerate through any that are installed
udev_list_entry_foreach(entry, devices) {
const char *path = udev_list_entry_get_name(entry);
struct udev_device *scsi = udev_device_new_from_syspath(udev, path);
struct udev_device *usb = udev_device_get_parent_with_subsystem_devtype(scsi, "usb", "usb_device");
if (usb) {
printf("usb = %s:%s, scsi = %s\n",
udev_device_get_sysattr_value(usb, "idVendor"),
udev_device_get_sysattr_value(usb, "idProduct"),
udev_device_get_sysattr_value(scsi, "vendor"));
}
udev_device_unref(scsi);
}
udev_enumerate_unref(enumerate);
/// Begin active polling for USB input and output
mon = udev_monitor_new_from_netlink(udev, "udev");
udev_monitor_filter_add_match_subsystem_devtype(mon, "usb", "usb_device");
udev_monitor_filter_add_match_subsystem_devtype(mon, "block", NULL);
udev_monitor_enable_receiving(mon);
/// Setup epoll
fd_ep = epoll_create1(0);
if (fd_ep < 0) {
fprintf(stderr, "error creating epoll\n");
return 1;
}
fd_udev = udev_monitor_get_fd(mon);
ep_udev.events = EPOLLIN;
ep_udev.data.fd = fd_udev;
if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) < 0) {
fprintf(stderr, "fail to add fd to epoll\n");
return 2;
}
/// Polling loop for devices
while (1) {
int fdcount;
struct epoll_event ev[NUM_OF_EVENTS];
int i = 0;
fdcount = epoll_wait(fd_ep, ev, NUM_OF_EVENTS, -1);
if (fdcount < 0) {
if (errno != EINTR)
fprintf(stderr, "error receiving uevent message: %m\n");
continue;
}
for (i = 0; i < fdcount; i++) {
if (ev[i].data.fd == fd_udev && ev[i].events & EPOLLIN) {
dev = udev_monitor_receive_device(mon);
if (dev == NULL)
continue;
printf("\n Action: %s\n",udev_device_get_action(dev)); // add or remove events
printf(" Node: %s\n", udev_device_get_devnode(dev));
printf(" Subsystem: %s\n", udev_device_get_subsystem(dev));
printf(" Devtype: %s\n", udev_device_get_devtype(dev));
udev_unref(udev);
}
}
}
return 0;
}
Output from plugging in a sandisk USB storage device
usb = 0781:5406, scsi = SanDisk
usb = 0781:5406, scsi = SanDisk
Action: remove
Node: /dev/sdb
Subsystem: block
Devtype: disk
Action: remove
Node: /dev/sr1
Subsystem: block
Devtype: disk
Action: remove
Node: /dev/bus/usb/001/018
Subsystem: usb
Devtype: usb_device
Action: add
Node: /dev/bus/usb/004/028
Subsystem: usb
Devtype: usb_device
Action: add
Node: /dev/sr1
Subsystem: block
Devtype: disk
Action: change
Node: /dev/sr1
Subsystem: block
Devtype: disk
Action: add
Node: /dev/sdb
Subsystem: block
Devtype: disk
Add new comment