4

I have been looking for several examples (on this page and others) of how to get the USB flash memory path folder (something like /media/john/B5D6-DC71) in order to make a c++ program to save files on this device. I mean, I want that the program detect a new device and get its folder path for (as I said) saving files on it.

I found a good one using libudev library I have changed it a bit and the code does everything what I want except giving the path. It gives me a lot of attributes and functions that I can find here: https://www.kernel.org/pub/linux/utils/kernel/hotplug/libudev/libudev-udev-device.html. But I didn't find what I want... maybe it is there but I made a mistake or maybe it is no there...

Anyone can help me? Here is the code I use:

#include <libudev.h>
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <unistd.h>
#include <string.h>
#include <iostream>

using namespace std;

static
struct udev_device*
get_child(struct udev* udev, struct udev_device* parent, const char* subsystem) {
  struct udev_device* child = NULL;
  struct udev_enumerate *enumerate = udev_enumerate_new(udev);

  udev_enumerate_add_match_parent(enumerate, parent);
  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);
      child = udev_device_new_from_syspath(udev, path);
      break;
  }

  udev_enumerate_unref(enumerate);
  return child;
}

static void enumerate_usb_mass_storage(struct udev* udev) {
  struct udev_enumerate* 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);

  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* scsi = udev_device_new_from_syspath(udev, path);

      struct udev_device* block = get_child(udev, scsi, "block");
      struct udev_device* scsi_disk = get_child(udev, scsi, "scsi_disk");

      struct udev_device* usb
          = udev_device_get_parent_with_subsystem_devtype(scsi, "usb", "usb_device");

      if (block && scsi_disk && usb) {
          printf("block = %s, usb = %s:%s, scsi = %s, name = %s, size = %s, x = %i, x = %s, x = %s\n",
                 udev_device_get_devnode(block),
                 udev_device_get_sysattr_value(usb, "idVendor"),
                 udev_device_get_sysattr_value(usb, "idProduct"),
                 udev_device_get_sysattr_value(scsi, "vendor"),
udev_device_get_sysattr_value(usb, "udev"),
udev_device_get_sysattr_value(usb, "udev_root"),
udev_device_get_sysattr_value(usb, "size"),
udev_device_get_sysattr_value(usb, "speed"),
udev_device_get_sysattr_value(usb, "bMaxPower"));

      }

      if (block) {
          udev_device_unref(block);
      }

      if (scsi_disk) {
          udev_device_unref(scsi_disk);
      }
      udev_device_unref(scsi);
  }

  udev_enumerate_unref(enumerate);
}

int main(){


    struct udev* udev = udev_new();
    enumerate_usb_mass_storage(udev);


    struct udev_device *dev;
    struct udev_monitor *mon;
    int fd;

    mon = udev_monitor_new_from_netlink(udev, "udev");
    udev_monitor_filter_add_match_subsystem_devtype(mon, "block", NULL);
    udev_monitor_enable_receiving(mon);
    fd = udev_monitor_get_fd(mon);

    while (1) {

        fd_set fds;
        struct timeval tv;
        int ret;

        FD_ZERO(&fds);
        FD_SET(fd, &fds);
        tv.tv_sec = 0;
        tv.tv_usec = 0;

        ret = select(fd+1, &fds, NULL, NULL, &tv);

        /* Check if our file descriptor has received data. */
        if (ret > 0 && FD_ISSET(fd, &fds))
        {
            printf("\nselect() says there should be data\n");

            dev = udev_monitor_receive_device(mon);
            if (dev) {
                printf("Got Device\n");
                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));
                printf("   Action: %s\n", udev_device_get_action(dev));
                cout << udev_get_run_path (dev) << endl;

                if( strcmp(udev_device_get_action(dev),"add")==0 ) cout << "conectat" << endl; 
                udev_device_unref(dev);
            }
            else {
                printf("No Device from receive_device(). An error occured.\n");
            }                   
        }
        usleep(250*1000);
        fflush(stdout);
    }




  udev_unref(udev);
  return 0;
}
kien bui
  • 1,760
  • 2
  • 17
  • 33
Joan C
  • 51
  • 3
  • I don't think you'll find mount point path in libudev API. Udev monitors and provides info about *devices*. Then some other component (maybe some script in `/etc/udev/rules.d/` or maybe `udisks` or maybe your IDE) triggers that new device is inserted and *mounts* it to some directory. Udev is not aware of it. AFAIK, modern distros use `udisks` for that, so you probably want it's D-Bus API. – gavv Sep 28 '15 at 16:20
  • I think you are right. I will try in another way as you suggest. Thank you so much!! – Joan C Sep 28 '15 at 21:10
  • I also get the problem sam with you. I need to detect mobile devices (connected/plug/unplug) using libudev library. But now I still can't find any solution. – kien bui Mar 22 '18 at 08:52

0 Answers0