udev_device_get_property_value и udev_device_get_sysattr_value возвращают null для атрибутов дескриптора udev при отключении на последних ядрах Linux - PullRequest
0 голосов
/ 18 марта 2019

udev_device_get_property_value и udev_device_get_sysattr_value возвращают null для атрибутов дескриптора udev, таких как VID, PID, серийный номер в последних ядрах Linux (Ubuntu 18.04, CentOS 7 с ядром версии 4.2 и выше). Следующая программа работает нормально со всеми дистрибутивами со старыми версиями ядра, но не с более новыми версиями ядра.

/* List and monitor USB devices using libudev.
 *  *
 *   * gcc -o udev_monitor_usb udev_monitor_usb.c -ludev
 *    * ./udev_monitor_usb
 *     */
#include <libudev.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#define SUBSYSTEM "usb"

static void print_device(struct udev_device* dev)
{

    const char* action = udev_device_get_action(dev);
    if (! action)
        action = "exists";

    const char* vendor = udev_device_get_sysattr_value(dev, "idVendor");
    if (! vendor)
        vendor = "0000";

    const char* product = udev_device_get_sysattr_value(dev, "idProduct");
    if (! product)
        product = "0000";

    printf("\n*****************************************************\n");
    printf("****** using : udev_device_get_sysattr_value \n");
    printf("VID/PID: %s %s\n", udev_device_get_sysattr_value(dev, "idVendor"),
                udev_device_get_sysattr_value(dev, "idProduct"));
    printf("manufacturer & Product: %s %s\n", udev_device_get_sysattr_value(dev, "manufacturer"),
                udev_device_get_sysattr_value(dev, "product"));
    printf("Serial: %s \n", udev_device_get_sysattr_value(dev, "serial"));
    printf("*****************************************************\n");

    /**struct udev_list_entry *devs, *devs_list_entry;
    devs = udev_device_get_sysattr_list_entry( dev );
    udev_list_entry_foreach( devs_list_entry, devs )
    {
        const char *attr;
        attr = udev_list_entry_get_name( devs_list_entry );
        printf("Attribute name: %s\n", attr);
    }*/

    printf("****** using : udev_device_get_property_value \n");
    const char *pid = NULL;
    pid = udev_device_get_property_value(dev, "ID_MODEL_ID");
    if(NULL != pid)
    {
        printf("PID is :%s\n", pid);
    }
    else
    {
        printf("PID is NULL: %s\n", pid);
    }    

    const char *vid = NULL;
    vid = udev_device_get_property_value(dev, "ID_VENDOR_ID");
    if(NULL != vid)
    {
    printf("VID is :%s\n", vid);
    }
    else
    {
        char *errorCode = strerror(errno);
        printf("strerror: %s\n", errorCode);
        printf("VID is NULL: %s\n", vid);
    }
    printf("*****************************************************\n");

    printf("%s %s %6s %s:%s %s\n",
           udev_device_get_subsystem(dev),
           udev_device_get_devtype(dev),
           action,
           vendor,
           product,
           udev_device_get_devnode(dev));
}

static void process_device(struct udev_device* dev)
{
    if (dev) {
        if (udev_device_get_devnode(dev))
            print_device(dev);

        udev_device_unref(dev);
    }
}

static void enumerate_devices(struct udev* udev)
{
    struct udev_enumerate* enumerate = udev_enumerate_new(udev);

    udev_enumerate_add_match_subsystem(enumerate, SUBSYSTEM);
    udev_enumerate_scan_devices(enumerate);

    struct udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate);
    struct udev_list_entry* entry;

    udev_list_entry_foreach(entry, devices) {
        const char* path = udev_list_entry_get_name(entry);
        struct udev_device* dev = udev_device_new_from_syspath(udev, path);
        process_device(dev);
    }

    udev_enumerate_unref(enumerate);
}

static void monitor_devices(struct udev* udev)
{
    struct udev_monitor* mon = udev_monitor_new_from_netlink(udev, "udev");

    udev_monitor_filter_add_match_subsystem_devtype(mon, SUBSYSTEM, "usb_device");
    udev_monitor_enable_receiving(mon);

    int fd = udev_monitor_get_fd(mon);

    while (1) {
        fd_set fds;
        FD_ZERO(&fds);
        FD_SET(fd, &fds);

        int ret = select(fd+1, &fds, NULL, NULL, NULL);
        if (ret <= 0)
            break;

        if (FD_ISSET(fd, &fds)) {
            struct udev_device* dev = udev_monitor_receive_device(mon);
            process_device(dev);
        }
    }
}

int main(void)
{
    struct udev* udev = udev_new();
    if (!udev) {
        fprintf(stderr, "udev_new() failed\n");
        return 1;
    }

    enumerate_devices(udev);
    monitor_devices(udev);

    udev_unref(udev);
    return 0;
}

Программа выдает следующий вывод на Ubuntu 18.04 (ядро 4.15.0-20-generic) при отключении USB-устройства

*****************************************************
****** using : udev_device_get_sysattr_value 
VID/PID: (null) (null)
manufacturer & Product: (null) (null)
Serial: (null) 
*****************************************************
****** using : udev_device_get_property_value 
PID is NULL: (null)
strerror: No such file or directory
VID is NULL: (null)
*****************************************************
usb usb_device unbind 0000:0000 /dev/bus/usb/003/007

*****************************************************
****** using : udev_device_get_sysattr_value 
VID/PID: (null) (null)
manufacturer & Product: (null) (null)
Serial: (null) 
*****************************************************
****** using : udev_device_get_property_value 
PID is NULL: (null)
strerror: No such file or directory
VID is NULL: (null)
*****************************************************
usb usb_device remove 0000:0000 /dev/bus/usb/003/007

есть 2 события, сгенерированные udev, которые называются remove и unbind. значения, заданные как {null} для обоих событий. из-за этого я не могу уничтожить использованные объекты при отсоединении устройства. я делаю неправильный способ получить значения атрибута?

...