Skip to content

Commit

Permalink
f3probe: map block device to underlying USB device
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
AltraMayor committed Sep 21, 2014
1 parent c7beb92 commit c1c7a95
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 8 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ f3read: utils.o f3read.o
$(CC) -o $@ $^

f3probe: libprobe.o f3probe.o
$(CC) -o $@ $^
$(CC) -o $@ $^ -ludev

-include *.d

Expand Down
26 changes: 23 additions & 3 deletions README
Original file line number Diff line number Diff line change
@@ -1,16 +1,36 @@
### 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/

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

Expand Down
4 changes: 4 additions & 0 deletions changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
Version 5.0 - ??? ??, 201?

* add f3probe (experimental).

Version 4.0 - Sep 9, 2014

* add support for FreeBSD.
Expand Down
102 changes: 98 additions & 4 deletions libprobe.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include <sys/ioctl.h>
#include <sys/types.h>
Expand All @@ -15,6 +16,7 @@
#include <err.h>
#include <linux/fs.h>
#include <linux/usbdevice_fs.h>
#include <libudev.h>

#include "libprobe.h"

Expand Down Expand Up @@ -277,22 +279,98 @@ 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.
* If it fails, suggest running f3probe as root.
*/
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;

Expand All @@ -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;
Expand All @@ -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:
Expand Down

0 comments on commit c1c7a95

Please sign in to comment.