mirror of
https://github.com/AltraMayor/f3.git
synced 2025-09-10 07:39:31 -04:00
f3probe: make sure that the block device is a disk
This patch makes f3probe test that the block device passed is a disk, not a partition or something else. If the block device is a partition, the correct disk device is reported. Example of this new protection in action: $ sudo f3probe /dev/sdb1 [sudo] password for michel: F3 probe 4.0 Copyright (C) 2010 Digirati Internet LTDA. This is free software; see the source for copying conditions. Device `/dev/sdb1' is a partition of disk device `/dev/sdb'. You can run this program as follows: f3probe /dev/sdb Application cannot continue, finishing...
This commit is contained in:
parent
783ef37213
commit
dd6ebe6b99
93
libdevs.c
93
libdevs.c
@ -335,8 +335,6 @@ static struct udev_device *map_dev_to_usb_dev(struct udev_device *dev)
|
|||||||
*/
|
*/
|
||||||
usb_dev = udev_device_get_parent_with_subsystem_devtype(
|
usb_dev = udev_device_get_parent_with_subsystem_devtype(
|
||||||
dev, "usb", "usb_device");
|
dev, "usb", "usb_device");
|
||||||
if (!usb_dev)
|
|
||||||
err(errno, "Unable to find parent device");
|
|
||||||
|
|
||||||
/* @usb_dev is not referenced, and will be freed when
|
/* @usb_dev is not referenced, and will be freed when
|
||||||
* the child (i.e. @dev) is freed.
|
* the child (i.e. @dev) is freed.
|
||||||
@ -346,13 +344,21 @@ static struct udev_device *map_dev_to_usb_dev(struct udev_device *dev)
|
|||||||
return udev_device_ref(usb_dev);
|
return udev_device_ref(usb_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct udev_device *map_block_to_usb_dev(struct udev *udev, int block_fd)
|
static struct udev_device *dev_from_block_fd(struct udev *udev, int block_fd)
|
||||||
{
|
{
|
||||||
struct stat fd_stat;
|
struct stat fd_stat;
|
||||||
struct udev_device *dev, *usb_dev;
|
|
||||||
|
|
||||||
assert(!fstat(block_fd, &fd_stat));
|
assert(!fstat(block_fd, &fd_stat));
|
||||||
dev = udev_device_new_from_devnum(udev, 'b', fd_stat.st_rdev);
|
if (!S_ISBLK(fd_stat.st_mode))
|
||||||
|
err(EINVAL, "FD %i is not a block device", block_fd);
|
||||||
|
return udev_device_new_from_devnum(udev, 'b', fd_stat.st_rdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct udev_device *map_block_to_usb_dev(struct udev *udev, int block_fd)
|
||||||
|
{
|
||||||
|
struct udev_device *dev, *usb_dev;
|
||||||
|
|
||||||
|
dev = dev_from_block_fd(udev, block_fd);
|
||||||
assert(dev);
|
assert(dev);
|
||||||
usb_dev = map_dev_to_usb_dev(dev);
|
usb_dev = map_dev_to_usb_dev(dev);
|
||||||
assert(!udev_device_unref(dev));
|
assert(!udev_device_unref(dev));
|
||||||
@ -451,7 +457,9 @@ static int bdev_manual_usb_reset(struct device *dev)
|
|||||||
|
|
||||||
/* Obtain @bus_num and @dev_num of the USB device to monitor. */
|
/* Obtain @bus_num and @dev_num of the USB device to monitor. */
|
||||||
usb_dev = map_block_to_usb_dev(udev, bdev->fd);
|
usb_dev = map_block_to_usb_dev(udev, bdev->fd);
|
||||||
assert(usb_dev);
|
if (!usb_dev)
|
||||||
|
errx(1, "Unable to find USB parent device of block device `%s'",
|
||||||
|
bdev->filename);
|
||||||
devnode = udev_device_get_devnode(usb_dev);
|
devnode = udev_device_get_devnode(usb_dev);
|
||||||
id_vendor = udev_device_get_sysattr_value(usb_dev, "idVendor");
|
id_vendor = udev_device_get_sysattr_value(usb_dev, "idVendor");
|
||||||
id_product = udev_device_get_sysattr_value(usb_dev, "idProduct");
|
id_product = udev_device_get_sysattr_value(usb_dev, "idProduct");
|
||||||
@ -539,24 +547,27 @@ static void bdev_free(struct device *dev)
|
|||||||
free((void *)bdev->filename);
|
free((void *)bdev->filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_block_dev(int fd)
|
static struct udev_device *map_partition_to_disk(struct udev_device *dev)
|
||||||
{
|
{
|
||||||
struct stat stat;
|
struct udev_device *disk_dev;
|
||||||
assert(!fstat(fd, &stat));
|
|
||||||
return S_ISBLK(stat.st_mode);
|
disk_dev = udev_device_get_parent_with_subsystem_devtype(
|
||||||
|
dev, "block", "disk");
|
||||||
|
|
||||||
|
/* @disk_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.
|
||||||
|
*/
|
||||||
|
return udev_device_ref(disk_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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.
|
|
||||||
* Make sure that no partition of the drive is mounted.
|
|
||||||
*/
|
|
||||||
struct device *create_block_device(const char *filename, enum reset_type rt)
|
struct device *create_block_device(const char *filename, enum reset_type rt)
|
||||||
{
|
{
|
||||||
struct block_device *bdev;
|
struct block_device *bdev;
|
||||||
|
struct udev *udev;
|
||||||
|
struct udev_device *fd_dev, *usb_dev;
|
||||||
|
const char *s;
|
||||||
int block_size;
|
int block_size;
|
||||||
|
|
||||||
bdev = malloc(sizeof(*bdev));
|
bdev = malloc(sizeof(*bdev));
|
||||||
@ -580,10 +591,48 @@ struct device *create_block_device(const char *filename, enum reset_type rt)
|
|||||||
goto filename;
|
goto filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_block_dev(bdev->fd)) {
|
/* Make sure that @bdev->fd is a disk, not a partition, and that
|
||||||
err(EINVAL, "File `%s' is not a block device", filename);
|
* it is in fact backed by a USB device.
|
||||||
|
*/
|
||||||
|
udev = udev_new();
|
||||||
|
if (!udev) {
|
||||||
|
warn("Can't create udev");
|
||||||
goto fd;
|
goto fd;
|
||||||
}
|
}
|
||||||
|
fd_dev = dev_from_block_fd(udev, bdev->fd);
|
||||||
|
if (!fd_dev) {
|
||||||
|
fprintf(stderr, "Can't create udev device from `%s'\n",
|
||||||
|
filename);
|
||||||
|
goto udev;
|
||||||
|
}
|
||||||
|
assert(!strcmp(udev_device_get_subsystem(fd_dev), "block"));
|
||||||
|
s = udev_device_get_devtype(fd_dev);
|
||||||
|
if (!strcmp(s, "partition")) {
|
||||||
|
struct udev_device *disk_dev = map_partition_to_disk(fd_dev);
|
||||||
|
assert(disk_dev);
|
||||||
|
s = udev_device_get_devnode(disk_dev);
|
||||||
|
fprintf(stderr, "Device `%s' is a partition of disk device `%s'.\n"
|
||||||
|
"You can run this program as follows:\nf3probe %s\n",
|
||||||
|
filename, s, s);
|
||||||
|
/* For some reason, there already was a reference to @disk_dev
|
||||||
|
* before the call map_partition_to_disk().
|
||||||
|
*/
|
||||||
|
assert(udev_device_unref(disk_dev) == disk_dev);
|
||||||
|
goto fd_dev;
|
||||||
|
} else if (strcmp(s, "disk")) {
|
||||||
|
fprintf(stderr, "Device `%s' is not a disk, but `%s'",
|
||||||
|
filename, s);
|
||||||
|
goto fd_dev;
|
||||||
|
}
|
||||||
|
usb_dev = map_dev_to_usb_dev(fd_dev);
|
||||||
|
if (!usb_dev) {
|
||||||
|
fprintf(stderr, "Device `%s' is not backed by a USB device",
|
||||||
|
filename);
|
||||||
|
goto fd_dev;
|
||||||
|
}
|
||||||
|
assert(!udev_device_unref(usb_dev));
|
||||||
|
assert(!udev_device_unref(fd_dev));
|
||||||
|
assert(!udev_unref(udev));
|
||||||
|
|
||||||
switch (rt) {
|
switch (rt) {
|
||||||
case RT_MANUAL_USB:
|
case RT_MANUAL_USB:
|
||||||
@ -608,6 +657,10 @@ struct device *create_block_device(const char *filename, enum reset_type rt)
|
|||||||
|
|
||||||
return &bdev->dev;
|
return &bdev->dev;
|
||||||
|
|
||||||
|
fd_dev:
|
||||||
|
assert(!udev_device_unref(fd_dev));
|
||||||
|
udev:
|
||||||
|
assert(!udev_unref(udev));
|
||||||
fd:
|
fd:
|
||||||
assert(!close(bdev->fd));
|
assert(!close(bdev->fd));
|
||||||
filename:
|
filename:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user