2012-06-11 17 views
6

मैं एक एसडी कार्ड की उपस्थिति की जांच करना चाहता हूं, और एसडी कार्ड जोड़ने/निकालने के लिए सूचनाएं प्राप्त करना चाहता हूं।एसडी कार्ड घटनाओं के लिए अधिसूचनाएं कैसे प्राप्त करें?

अब तक मैंने libudev का उपयोग किया है, और मैंने एक छोटा सा एप्लीकेशन बनाया है जो एसडी कार्ड घटनाओं के लिए सुनता है।

कोड नीचे सूचीबद्ध है:

#include <unistd.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <stddef.h> 
#include <errno.h> 
#include <sys/time.h> //debug -> remove me 

#include <libudev.h> 

#define ADD_FILTER "add" 
#define REMOVE_FILTER "remove" 
#define SUBSYSTEM_FILTER "block" 
#define ATTR_FILTER "ID_MODEL" 
#define SD_ATTR_VALUE "SD_MMC" 
#define ATTR_ACTIVE_SD "ID_PART_TABLE_TYPE" 

static bool isDeviceSD(struct udev_device *device); 
static bool isDevPresent(struct udev *device); 
static void print_device(struct udev_device *device, const char *source); //for debugging -> remove me 
static bool s_bSD_present; 

int main() 
{ 
    struct udev *udev; 
    struct udev_monitor *udev_monitor = NULL; 
    fd_set readfds; 
    s_bSD_present = false; 

    udev = udev_new(); 
    if (udev == NULL) 
    { 
     printf("udev_new FAILED \n"); 
     return 1; 
    } 

    s_bSD_present = isDevPresent(udev); 
    if(s_bSD_present) 
    { 
     printf("+++SD is plugged in \n"); 
    } 
    else 
    { 
     printf("---SD is not plugged in \n"); 
    } 

    udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); 
    if (udev_monitor == NULL) { 
     printf("udev_monitor_new_from_netlink FAILED \n"); 
     return 1; 
    } 

    //add some filters 
    if(udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, SUBSYSTEM_FILTER, NULL) < 0) 
    { 
     printf("udev_monitor_filter_add_match_subsystem_devtype FAILED \n"); 
     return 1; 
    } 

    if (udev_monitor_enable_receiving(udev_monitor) < 0) 
    { 
     printf("udev_monitor_enable_receiving FAILED \n"); 
     return 1; 
    } 

    while (1) { 
     printf("Polling for new data... \n"); 

     int fdcount = 0; 

     FD_ZERO(&readfds); 

     if (udev_monitor != NULL) 
     { 
      FD_SET(udev_monitor_get_fd(udev_monitor), &readfds); 
     } 

     fdcount = select(udev_monitor_get_fd(udev_monitor)+1, &readfds, NULL, NULL, NULL); 
     if (fdcount < 0) 
     { 
      if (errno != EINTR) 
       printf("Error receiving uevent message\n"); 
      continue; 
     } 

     if ((udev_monitor != NULL) && FD_ISSET(udev_monitor_get_fd(udev_monitor), &readfds)) 
     { 
      struct udev_device *device; 

      device = udev_monitor_receive_device(udev_monitor); 
      if (device == NULL) 
       continue; 

      //check the action 
      const char* szAction = udev_device_get_action(device); 
      if(strcmp(szAction, ADD_FILTER) == 0) 
      { 
       if(!s_bSD_present && isDeviceSD(device)) 
       { 
        s_bSD_present = true; 
        printf("+++SD has been plugged in \n"); 
       } 
      } 
      else if(strcmp(szAction, REMOVE_FILTER) == 0) 
      { 
       if(s_bSD_present && isDeviceSD(device)) 
       { 
        s_bSD_present = false; 
        printf("---SD has been removed \n"); 
       } 
      } 

      udev_device_unref(device); 
     } 
    } 

    return 0; 
} 

static bool isDeviceSD(struct udev_device *device) 
{ 
    bool retVal = false; 
    struct udev_list_entry *list_entry = 0; 
    struct udev_list_entry* model_entry = 0; 
    struct udev_list_entry* active_sd_entry = 0; 

    list_entry = udev_device_get_properties_list_entry(device); 
    model_entry = udev_list_entry_get_by_name(list_entry, ATTR_FILTER); 
    if(0 != model_entry) 
    { 
     const char* szModelValue = udev_list_entry_get_value(model_entry); 
     active_sd_entry = udev_list_entry_get_by_name(list_entry, ATTR_ACTIVE_SD); 
     if(strcmp(szModelValue, SD_ATTR_VALUE) == 0 && active_sd_entry != 0) 
     { 
      printf("Device is SD \n"); 
      retVal = true; 

      //print_device(device, "UDEV"); 
     } 
    } 
    return retVal; 
} 


static bool isDevPresent(struct udev *device) 
{ 
    bool retVal = false; 
    struct udev_enumerate *enumerate; 
    struct udev_list_entry *devices, *dev_list_entry; 

    enumerate = udev_enumerate_new(device); 
    udev_enumerate_add_match_subsystem(enumerate, SUBSYSTEM_FILTER); 
    udev_enumerate_scan_devices(enumerate); 
    devices = udev_enumerate_get_list_entry(enumerate); 

    udev_list_entry_foreach(dev_list_entry, devices) 
    { 
     struct udev_device *dev; 
     const char* dev_path = udev_list_entry_get_name(dev_list_entry); 
     dev = udev_device_new_from_syspath(device, dev_path); 

     if(true == isDeviceSD(dev)) 
     { 
      retVal = true; 
      udev_device_unref(dev); 
      break; 
     } 

     udev_device_unref(dev); 
    } 
    udev_enumerate_unref(enumerate); 

    return retVal; 
} 


static void print_device(struct udev_device *device, const char *source) 
{ 
     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)); 

      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"); 

} 

इस कोड को एसडी कार्ड के लिए सूचनाएं जोड़ें/निकालें मिल जाएगा (और एसडी प्रारंभिक अवस्था - खामियों को दूर/अनप्लग)। हालांकि, यह एक हैक से अधिक है, और यह सभी मामलों में काम नहीं करता है।

मैं वर्तमान में डिवाइस के ID_MODEL विशेषता का उपयोग करता हूं और यह जांचता हूं कि यह SD_MMC है - एसडी कार्ड के लिए। मुझे अभी इस प्रकार के कार्ड की आवश्यकता है, इसलिए यह पर्याप्त है।

जब कोई एसडी कार्ड डाला जाता है, तो निम्न घटनाएं सबसिस्टम ब्लॉक के लिए भेजी जाती हैं: 2 change ईवेंट, और प्रत्येक विभाजन के लिए 1 add ईवेंट। घटना गुण नीचे सूचीबद्ध हैं:

<----- change event - subsystem block - disk type disk -----> 

UDEV [1339412734.522055] change /devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1/1-1:1.0/host11/target11:0:0/11:0:0:2/block/sdd (block) 
UDEV_LOG=3 
ACTION=change 
DEVPATH=/devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1/1-1:1.0/host11/target11:0:0/11:0:0:2/block/sdd 
SUBSYSTEM=block 
DEVNAME=/dev/sdd 
DEVTYPE=disk 
SEQNUM=3168 
ID_VENDOR=Generic- 
ID_VENDOR_ENC=Generic- 
ID_VENDOR_ID=0bda 
ID_MODEL=SD_MMC 
ID_MODEL_ENC=SD\x2fMMC\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20 
ID_MODEL_ID=0151 
ID_REVISION=1.00 
ID_SERIAL=Generic-_SD_MMC_20060413092100000-0:2 
ID_SERIAL_SHORT=20060413092100000 
ID_TYPE=disk 
ID_INSTANCE=0:2 
ID_BUS=usb 
ID_USB_INTERFACES=:080650: 
ID_USB_INTERFACE_NUM=00 
ID_USB_DRIVER=usb-storage 
ID_PATH=pci-0000:02:03.0-usb-0:1:1.0-scsi-0:0:0:2 
ID_PART_TABLE_TYPE=dos 
UDISKS_PRESENTATION_NOPOLICY=0 
UDISKS_PARTITION_TABLE=1 
UDISKS_PARTITION_TABLE_SCHEME=mbr 
UDISKS_PARTITION_TABLE_COUNT=2 
MAJOR=8 
MINOR=48 
DEVLINKS=/dev/block/8:48 /dev/disk/by-id/usb-Generic-_SD_MMC_20060413092100000-0:2 /dev/disk/by-path/pci-0000:02:03.0-usb-0:1:1.0-scsi-0:0:0:2 

<----- add event partition 1 - subsystem block - disk type partition -----> 

UDEV [1339412734.719107] add  /devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1/1-1:1.0/host11/target11:0:0/11:0:0:2/block/sdd/sdd1 (block) 
UDEV_LOG=3 
ACTION=add 
DEVPATH=/devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1/1-1:1.0/host11/target11:0:0/11:0:0:2/block/sdd/sdd1 
SUBSYSTEM=block 
DEVNAME=/dev/sdd1 
DEVTYPE=partition 
SEQNUM=3169 
ID_VENDOR=Generic- 
ID_VENDOR_ENC=Generic- 
ID_VENDOR_ID=0bda 
ID_MODEL=SD_MMC 
ID_MODEL_ENC=SD\x2fMMC\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20 
ID_MODEL_ID=0151 
ID_REVISION=1.00 
ID_SERIAL=Generic-_SD_MMC_20060413092100000-0:2 
ID_SERIAL_SHORT=20060413092100000 
ID_TYPE=disk 
ID_INSTANCE=0:2 
ID_BUS=usb 
ID_USB_INTERFACES=:080650: 
ID_USB_INTERFACE_NUM=00 
ID_USB_DRIVER=usb-storage 
ID_PATH=pci-0000:02:03.0-usb-0:1:1.0-scsi-0:0:0:2 
ID_PART_TABLE_TYPE=dos 
ID_FS_UUID=6343c7b9-92a9-4d8f-bdd8-893f1190f294 
ID_FS_UUID_ENC=6343c7b9-92a9-4d8f-bdd8-893f1190f294 
ID_FS_VERSION=1.0 
ID_FS_TYPE=ext2 
ID_FS_USAGE=filesystem 
UDISKS_PRESENTATION_NOPOLICY=0 
UDISKS_PARTITION=1 
UDISKS_PARTITION_SCHEME=mbr 
UDISKS_PARTITION_NUMBER=1 
UDISKS_PARTITION_TYPE=0x83 
UDISKS_PARTITION_SIZE=1006919680 
UDISKS_PARTITION_SLAVE=/sys/devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1/1-1:1.0/host11/target11:0:0/11:0:0:2/block/sdd 
UDISKS_PARTITION_OFFSET=11618304 
UDISKS_PARTITION_ALIGNMENT_OFFSET=0 
MAJOR=8 
MINOR=49 
DEVLINKS=/dev/block/8:49 /dev/disk/by-id/usb-Generic-_SD_MMC_20060413092100000-0:2-part1 /dev/disk/by-path/pci-0000:02:03.0-usb-0:1:1.0-scsi-0:0:0:2-part1 /dev/disk/by-uuid/6343c7b9-92a9-4d8f-bdd8-893f1190f294 

<----- add event partition 2 - subsystem block - disk type partition -----> 

UDEV [1339412734.731338] add  /devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1/1-1:1.0/host11/target11:0:0/11:0:0:2/block/sdd/sdd2 (block) 
UDEV_LOG=3 
ACTION=add 
DEVPATH=/devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1/1-1:1.0/host11/target11:0:0/11:0:0:2/block/sdd/sdd2 
SUBSYSTEM=block 
DEVNAME=/dev/sdd2 
DEVTYPE=partition 
SEQNUM=3170 
ID_VENDOR=Generic- 
ID_VENDOR_ENC=Generic- 
ID_VENDOR_ID=0bda 
ID_MODEL=SD_MMC 
ID_MODEL_ENC=SD\x2fMMC\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20 
ID_MODEL_ID=0151 
ID_REVISION=1.00 
ID_SERIAL=Generic-_SD_MMC_20060413092100000-0:2 
ID_SERIAL_SHORT=20060413092100000 
ID_TYPE=disk 
ID_INSTANCE=0:2 
ID_BUS=usb 
ID_USB_INTERFACES=:080650: 
ID_USB_INTERFACE_NUM=00 
ID_USB_DRIVER=usb-storage 
ID_PATH=pci-0000:02:03.0-usb-0:1:1.0-scsi-0:0:0:2 
ID_PART_TABLE_TYPE=dos 
UDISKS_PRESENTATION_NOPOLICY=0 
UDISKS_PARTITION=1 
UDISKS_PARTITION_SCHEME=mbr 
UDISKS_PARTITION_NUMBER=2 
UDISKS_PARTITION_TYPE=0xda 
UDISKS_PARTITION_SIZE=11618304 
UDISKS_PARTITION_FLAGS=boot 
UDISKS_PARTITION_SLAVE=/sys/devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1/1-1:1.0/host11/target11:0:0/11:0:0:2/block/sdd 
UDISKS_PARTITION_OFFSET=1022410752 
UDISKS_PARTITION_ALIGNMENT_OFFSET=0 
MAJOR=8 
MINOR=50 
DEVLINKS=/dev/block/8:50 /dev/disk/by-id/usb-Generic-_SD_MMC_20060413092100000-0:2-part2 /dev/disk/by-path/pci-0000:02:03.0-usb-0:1:1.0-scsi-0:0:0:2-part2 

change घटना से मैं के बारे में कि क्या डिवाइस जोड़ा गया है या हटा दिया किसी भी जानकारी को अलग नहीं कर सकता। मैं डिवाइस का नाम \dev\sdd खोलने की कोशिश की है, लेकिन मैं अनुमति नहीं है, तो यह है कि विकल्प गिर जाता है ...

अब मैं सिर्फ विभाजन (add/remove) के लिए कार्रवाई विशेषता जाँच कर रहा हूँ के लिए।

कार्यक्रम का यह संस्करण एसडी कार्ड के लिए बहुत अच्छी तरह से काम करता है जिनमें विभाजन हैं। जब कोई विभाजन नहीं होता है, तो केवल change ईवेंट प्राप्त होते हैं।

तो मेरा प्रश्न है: क्या कोई तरीका है कि मैं जांच सकता हूं कि मीडिया को change ईवेंट से जोड़ा/हटा दिया गया था या नहीं? या यह जांचने का कोई और तरीका है कि डिवाइस उपलब्ध है या नहीं (विभाजन समस्या को ध्यान में रखते हुए)?

डिवाइस विशेषता पुनरावृत्ति को सुधारने या अधिसूचनाएं प्राप्त करने की विधि का कोई सुझाव स्वागत किया जाएगा।

पीएस और मैं libusb का उपयोग नहीं कर सकता :)।

+0

क्या आप यह जांच नहीं सकते कि कोई ईवेंट प्राप्त करने के बाद ब्लॉक डिवाइस मौजूद है या नहीं? – Behrooz

+0

ठीक है, मैंने 'DEVNAME' मान ('\ dev \ sdd') पर [open] (http://linux.die.net/man/2/open) को कॉल करने का प्रयास किया लेकिन मुझे अनुमति नहीं है, इसलिए कॉल हमेशा विफल रहता है। डिवाइस मौजूद है या नहीं, यह जांचने के अन्य तरीके हैं? –

+0

http://www.linuxquestions.org/questions/programming-9/checking-if-a-file-exists-in-c-21700/ – Behrooz

उत्तर

1

ठीक है। तो मैंने विभाजन के बिना एसडी कार्ड के लिए पीसी पर काम किया।

अद्यतन कोड यह है:

#include <unistd.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <stddef.h> 
#include <errno.h> 
#include <sys/time.h> //debug -> remove me 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 

#include <libudev.h> 

#define ADD_FILTER "add" 
#define REMOVE_FILTER "remove" 
#define SUBSYSTEM_FILTER "block" 
#define DEVTYPE_FILTER "disk" 
#define ATTR_FILTER "ID_MODEL" 
#define SD_ATTR_VALUE "SD_MMC" 
#define ATTR_ADDED_DISK "UDISKS_PARTITION_TABLE" // attribute is available for "change" event when SD card is added (n/a when removed) 

static bool isDeviceSD(struct udev_device *device); //checks if device is SD card (MMC) 
static bool isDevPresent(struct udev *device); //checks if device is present (SD + added) 
static bool isDeviceAdded(struct udev_device *device); //checks if device is added (presence of attribute ATTR_ADDED_DISK) 
static void print_device(struct udev_device *device, const char *source); //for debugging -> remove me 
static bool s_bSD_present; 

int main() 
{ 
    struct udev *udev; 
    struct udev_monitor *udev_monitor = NULL; 
    fd_set readfds; 
    s_bSD_present = false; 

    udev = udev_new(); 
    if (udev == NULL) 
    { 
     printf("udev_new FAILED \n"); 
     return 1; 
    } 

    if(isDevPresent(udev)) 
    { 
     s_bSD_present = true; 
     printf("+++SD is plugged in \n"); 
    } 
    else 
    { 
     printf("---SD is not plugged in \n"); 
    } 

    udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); 
    if (udev_monitor == NULL) { 
     printf("udev_monitor_new_from_netlink FAILED \n"); 
     return 1; 
    } 

    //add some filters 
    if(udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, SUBSYSTEM_FILTER, DEVTYPE_FILTER) < 0) 
    { 
     printf("udev_monitor_filter_add_match_subsystem_devtype FAILED \n"); 
     return 1; 
    } 

    if (udev_monitor_enable_receiving(udev_monitor) < 0) 
    { 
     printf("udev_monitor_enable_receiving FAILED \n"); 
     return 1; 
    } 

    while (1) { 
     printf("Polling for new data... \n"); 

     int fdcount = 0; 

     FD_ZERO(&readfds); 

     if (udev_monitor != NULL) 
     { 
      FD_SET(udev_monitor_get_fd(udev_monitor), &readfds); 
     } 

     fdcount = select(udev_monitor_get_fd(udev_monitor)+1, &readfds, NULL, NULL, NULL); 
     if (fdcount < 0) 
     { 
      if (errno != EINTR) 
       printf("Error receiving uevent message\n"); 
      continue; 
     } 

     if ((udev_monitor != NULL) && FD_ISSET(udev_monitor_get_fd(udev_monitor), &readfds)) 
     { 
      struct udev_device *device; 

      device = udev_monitor_receive_device(udev_monitor); 
      if (device == NULL) 
       continue; 

      //check presence 
      if(isDeviceSD(device) && isDeviceAdded(device)) 
      { 
       if(!s_bSD_present) //guard for double "change" events 
       { 
        s_bSD_present = true; 
        printf("+++SD has been plugged in \n"); 
       } 
      } 
      else 
      { 
       if(s_bSD_present) //not needed -> just keeping consistency 
       { 
        s_bSD_present = false; 
        printf("---SD has been removed \n"); 
       } 
      } 

      udev_device_unref(device); 
     } 
    } 

    return 0; 
} 

static bool isDeviceSD(struct udev_device *device) 
{ 
    bool retVal = false; 
    struct udev_list_entry *list_entry = 0; 
    struct udev_list_entry* model_entry = 0; 

    list_entry = udev_device_get_properties_list_entry(device); 
    model_entry = udev_list_entry_get_by_name(list_entry, ATTR_FILTER); 
    if(0 != model_entry) 
    { 
     const char* szModelValue = udev_list_entry_get_value(model_entry); 
     if(strcmp(szModelValue, SD_ATTR_VALUE) == 0) 
     { 
      //printf("Device is SD \n"); 
      retVal = true; 

      //print_device(device, "UDEV"); 
     } 
    } 
    return retVal; 
} 

static bool isDeviceAdded(struct udev_device *device) 
{ 
    bool retVal = false; 
    struct udev_list_entry *list_entry = 0; 
    struct udev_list_entry* added_disk_entry = 0; 


    list_entry = udev_device_get_properties_list_entry(device); 
    added_disk_entry = udev_list_entry_get_by_name(list_entry,/* "DEVNAME" */ ATTR_ADDED_DISK); 
    if(0 != added_disk_entry) 
    { 
     retVal = true; 
    } 
    return retVal; 
} 


static bool isDevPresent(struct udev *device) 
{ 
    bool retVal = false; 
    struct udev_enumerate *enumerate; 
    struct udev_list_entry *devices, *dev_list_entry; 

    enumerate = udev_enumerate_new(device); 
    udev_enumerate_add_match_subsystem(enumerate, SUBSYSTEM_FILTER); 
    udev_enumerate_scan_devices(enumerate); 
    devices = udev_enumerate_get_list_entry(enumerate); 

    udev_list_entry_foreach(dev_list_entry, devices) 
    { 
     struct udev_device *dev; 
     const char* dev_path = udev_list_entry_get_name(dev_list_entry); 
     dev = udev_device_new_from_syspath(device, dev_path); 

     if(isDeviceSD(dev) && isDeviceAdded(dev)) 
     { 
      retVal = true; 
      udev_device_unref(dev); 
      break; 
     } 

     udev_device_unref(dev); 
    } 
    udev_enumerate_unref(enumerate); 

    return retVal; 
} 


static void print_device(struct udev_device *device, const char *source) 
{ 
     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)); 

      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"); 

} 

समाधान (अभी भी बहुत उज्जवल नहीं) कुछ विशेषता है जो उपलब्ध है केवल जब एसडी कार्ड जोड़ा जाता है है के लिए जाँच कर रहा है (जैसे UDISKS_PARTITION_TABLE)।

यह x86 पर अच्छी तरह से काम करता है।

संबंधित मुद्दे