mirror of
https://github.com/AltraMayor/f3.git
synced 2025-09-17 02:56:12 -04:00
f3probe: map block device to underlying USB device
The code is based on udev_example.c available on the following page: libudev and Sysfs Tutorial http://www.signal11.us/oss/udev/ f3probe nows requires library libudev. This patch also updates the following files to reflect the dependency of f3probe on libudev, and the experimental status of f3probe: Makefile and README.
This commit is contained in:
parent
c7beb92aba
commit
c1c7a95f0b
2
Makefile
2
Makefile
@ -14,7 +14,7 @@ f3read: utils.o f3read.o
|
||||
$(CC) -o $@ $^
|
||||
|
||||
f3probe: libprobe.o f3probe.o
|
||||
$(CC) -o $@ $^
|
||||
$(CC) -o $@ $^ -ludev
|
||||
|
||||
-include *.d
|
||||
|
||||
|
26
README
26
README
@ -1,8 +1,27 @@
|
||||
### Compile on Linux, Apple Mac, Windows/Cygwin, and FreeBSD
|
||||
### Compile stable software on Linux, Apple Mac, Windows/Cygwin, and FreeBSD
|
||||
|
||||
make
|
||||
|
||||
### Use example
|
||||
|
||||
### Compile experimental software on Linux
|
||||
|
||||
make experimental
|
||||
|
||||
NOTES:
|
||||
- Experimental software might compile on non-Linux platforms, but
|
||||
there is no guarantee given that they are only tested on Linux.
|
||||
- Please do not e-mail me saying that you want an experimental software
|
||||
to run on your platform; I already know that.
|
||||
- If you want experimental software to run on your platform,
|
||||
help to port them, or find someone that can port them for you.
|
||||
If you do port the software, please send me a patch to help others.
|
||||
- Currently, only f3probe is experimental.
|
||||
- f3proble requires the library libudev to compile.
|
||||
On Ubuntu, you can install this library with the following command:
|
||||
sudo apt-get install libudev-dev
|
||||
|
||||
|
||||
### Use example of f3write/f3read
|
||||
|
||||
./f3write /media/5EBD-5C80/
|
||||
./f3read /media/5EBD-5C80/
|
||||
@ -10,7 +29,8 @@ make
|
||||
Please replace "/media/5EBD-5C80/" with the appropriate path.
|
||||
USB devices are mounted in "/Volumes" on Macs.
|
||||
|
||||
### For more information see http://oss.digirati.com.br/f3/
|
||||
For more information see http://oss.digirati.com.br/f3/
|
||||
|
||||
|
||||
### Files
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
Version 5.0 - ??? ??, 201?
|
||||
|
||||
* add f3probe (experimental).
|
||||
|
||||
Version 4.0 - Sep 9, 2014
|
||||
|
||||
* add support for FreeBSD.
|
||||
|
102
libprobe.c
102
libprobe.c
@ -4,6 +4,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
@ -15,6 +16,7 @@
|
||||
#include <err.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/usbdevice_fs.h>
|
||||
#include <libudev.h>
|
||||
|
||||
#include "libprobe.h"
|
||||
|
||||
@ -277,11 +279,87 @@ static void bdev_free(struct device *dev)
|
||||
free((void *)bdev->filename);
|
||||
}
|
||||
|
||||
static bool is_block_dev(int fd)
|
||||
{
|
||||
struct stat stat;
|
||||
assert(!fstat(fd, &stat));
|
||||
return S_ISBLK(stat.st_mode);
|
||||
}
|
||||
|
||||
static char *map_block_to_usb_dev(const char *block_dev)
|
||||
{
|
||||
struct udev *udev;
|
||||
struct udev_enumerate *enumerate;
|
||||
struct udev_list_entry *devices, *dev_list_entry;
|
||||
char *usb_dev_path = NULL;
|
||||
|
||||
udev = udev_new();
|
||||
if (!udev)
|
||||
err(errno, "Can't create udev");
|
||||
|
||||
/* XXX Avoid the enumeration using udev_device_new_from_devnum(). */
|
||||
enumerate = udev_enumerate_new(udev);
|
||||
assert(enumerate);
|
||||
assert(!udev_enumerate_add_match_subsystem(enumerate, "block"));
|
||||
assert(!udev_enumerate_scan_devices(enumerate));
|
||||
devices = udev_enumerate_get_list_entry(enumerate);
|
||||
assert(devices);
|
||||
|
||||
udev_list_entry_foreach(dev_list_entry, devices) {
|
||||
const char *sys_path, *dev_path;
|
||||
struct udev_device *dev, *parent_dev;
|
||||
|
||||
/* Get the filename of the /sys entry for the device,
|
||||
* and create a udev_device object (dev) representing it.
|
||||
*/
|
||||
sys_path = udev_list_entry_get_name(dev_list_entry);
|
||||
dev = udev_device_new_from_syspath(udev, sys_path);
|
||||
|
||||
/* usb_device_get_devnode() returns the path to
|
||||
* the device node itself in /dev.
|
||||
*/
|
||||
dev_path = udev_device_get_devnode(dev);
|
||||
if (strcmp(block_dev, dev_path)) {
|
||||
assert(!udev_device_unref(dev));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* The device pointed to by dev contains information about
|
||||
* the USB device.
|
||||
* In order to get information about the USB device,
|
||||
* get the parent device with the subsystem/devtype pair of
|
||||
* "usb"/"usb_device".
|
||||
* This will be several levels up the tree,
|
||||
* but the function will find it.
|
||||
*/
|
||||
parent_dev = udev_device_get_parent_with_subsystem_devtype(
|
||||
dev, "usb", "usb_device");
|
||||
if (!parent_dev)
|
||||
err(errno, "Unable to find parent usb device of `%s'",
|
||||
block_dev);
|
||||
|
||||
usb_dev_path = strdup(udev_device_get_devnode(parent_dev));
|
||||
/* @parent_dev is not referenced, and will be freed when
|
||||
* the child (i.e. @dev) is freed.
|
||||
* See udev_device_get_parent_with_subsystem_devtype() for
|
||||
* details.
|
||||
*/
|
||||
assert(!udev_device_unref(dev));
|
||||
break;
|
||||
}
|
||||
/* Free the enumerator object. */
|
||||
assert(!udev_enumerate_unref(enumerate));
|
||||
|
||||
assert(!udev_unref(udev));
|
||||
return usb_dev_path;
|
||||
}
|
||||
|
||||
/* XXX Test if it's a device, or a partition.
|
||||
* If a partition, warn user, and ask for confirmation before
|
||||
* going ahead.
|
||||
* Suggest how to call f3probe with the correct device name if
|
||||
* the block device is a partition.
|
||||
* Use udev to do these tests.
|
||||
*/
|
||||
/* XXX Test for write access of the block device to give
|
||||
* a nice error message.
|
||||
@ -289,10 +367,10 @@ static void bdev_free(struct device *dev)
|
||||
*/
|
||||
struct device *create_block_device(const char *filename)
|
||||
{
|
||||
/* TODO */
|
||||
const char *usb_filename = "/dev/bus/usb/002/015";
|
||||
const char *usb_filename;
|
||||
struct block_device *bdev;
|
||||
|
||||
struct block_device *bdev = malloc(sizeof(*bdev));
|
||||
bdev = malloc(sizeof(*bdev));
|
||||
if (!bdev)
|
||||
goto error;
|
||||
|
||||
@ -306,10 +384,23 @@ struct device *create_block_device(const char *filename)
|
||||
goto filename;
|
||||
}
|
||||
|
||||
if (!is_block_dev(bdev->fd)) {
|
||||
err(EINVAL, "File `%s' is not a block device", filename);
|
||||
goto fd;
|
||||
}
|
||||
|
||||
/* XXX Add support for block devices backed by SCSI, SATA, and ATA. */
|
||||
usb_filename = map_block_to_usb_dev(filename);
|
||||
if (!usb_filename) {
|
||||
err(EINVAL, "Block device `%s' is not backed by a USB device",
|
||||
filename);
|
||||
goto fd;
|
||||
}
|
||||
|
||||
bdev->hw_fd = open(usb_filename, O_WRONLY | O_NONBLOCK);
|
||||
if (bdev->hw_fd < 0) {
|
||||
err(errno, "Can't open device `%s'", usb_filename);
|
||||
goto fd;
|
||||
goto usb_filename;
|
||||
}
|
||||
|
||||
bdev->dev.read_block = bdev_read_block;
|
||||
@ -318,8 +409,11 @@ struct device *create_block_device(const char *filename)
|
||||
bdev->dev.get_size_gb = bdev_get_size_gb;
|
||||
bdev->dev.free = bdev_free;
|
||||
|
||||
free((void *)usb_filename);
|
||||
return &bdev->dev;
|
||||
|
||||
usb_filename:
|
||||
free((void *)usb_filename);
|
||||
fd:
|
||||
assert(!close(bdev->fd));
|
||||
filename:
|
||||
|
Loading…
x
Reference in New Issue
Block a user