Ich möchte das Vorhandensein einer SD-Karte überprüfen und Benachrichtigungen für SD-Karte hinzufügen/entfernen erhalten.Wie erhalte ich Benachrichtigungen für SD-Karten-Ereignisse?
Bisher habe ich libudev
verwendet, und ich habe eine kleine Anwendung gemacht, die für SD-Kartenereignisse abhört.
Der Code ist unten aufgeführt:
#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");
}
Dieser Code erhalten Benachrichtigungen für SD-Karte hinzufügen/entfernen (und der Ausgangszustand der SD - plugged/unplugged). Es ist jedoch eher ein Hack, und es funktioniert nicht in allen Fällen.
Ich verwende derzeit das ID_MODEL
Attribut des Geräts und prüfen, ob es SD_MMC
ist - für SD-Karten. Ich brauche nur diese Art von Karte für jetzt, also ist es genug.
Wenn eine SD-Karte eingesetzt wird, werden folgende Ereignisse für den Subsystemblock gesendet: 2 change
Ereignisse und 1 add
Ereignis für jede Partition. Die Ereigniseigenschaften sind unten aufgeführt:
<----- 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
Vom change
Ereignisse kann ich keine Informationen extrahieren darüber, ob das Gerät hinzugefügt oder entfernt wurde. Ich habe versucht, \dev\sdd
die Gerätenamen zu öffnen, aber ich habe keine Berechtigungen, so dass Option fällt ...
Denn jetzt bin ich nur für die Partitionen, das action-Attributs Prüfung (add
/remove
).
Diese Version des Programms funktioniert ziemlich gut für SD-Karten, die Partitionen haben. Wenn keine Partitionen vorhanden sind, werden nur die Ereignisse change
empfangen.
Also meine Frage ist: Gibt es eine Möglichkeit, ich kann überprüfen, ob das Medium wurde hinzugefügt/entfernt von der change
Ereignis? Oder gibt es eine andere Möglichkeit zu überprüfen, ob ein Gerät verfügbar ist (unter Berücksichtigung des Partitionsproblems)?
Jeder Vorschlag zur Verbesserung der Geräteattribut-Iteration oder der Methode, die Benachrichtigungen zu erhalten, wäre zu begrüßen.
P.S. Und ich kann libusb
:) nicht verwenden.
können Sie nicht überprüfen, ob das Blockgerät existiert, nachdem Sie ein Ereignis erhalten haben? – Behrooz
Nun, ich habe versucht, [open] (http://linux.die.net/man/2/open) auf dem 'DEVNAME'-Wert (' \ dev \ sdd') aufzurufen, aber ich habe keine Berechtigungen, also Der Anruf schlägt immer fehl. Gibt es andere Möglichkeiten zu überprüfen, ob das Gerät existiert? –
http://www.linuxquestions.org/questions/programming-9/checking-if-a-file-exists-in-c-21700/ – Behrooz