f3probe: add option --manual-reset

The current reset method isn't supported for all USB drives,
what leads to wrong conclusions about some fake drives.

The option --manual-reset allows users to unplug and plug back
the USB drive being tested to manually reset the drive.
This commit is contained in:
Michel Machado 2014-08-28 14:42:51 -04:00
parent 73a657deec
commit 35a351ff39
3 changed files with 51 additions and 21 deletions

View File

@ -43,6 +43,8 @@ static struct argp_option options[] = {
"Run a unit test; it ignores all other debug options", 0}, "Run a unit test; it ignores all other debug options", 0},
{"destructive", 'n', NULL, 0, {"destructive", 'n', NULL, 0,
"Do not restore blocks of the device after probing it", 2}, "Do not restore blocks of the device after probing it", 2},
{"manual-reset", 'm', NULL, 0,
"Ask user to manually reset the drive", 0},
{ 0 } { 0 }
}; };
@ -59,6 +61,9 @@ struct args {
uint64_t fake_size_byte; uint64_t fake_size_byte;
int wrap; int wrap;
int block_order; int block_order;
bool manual_reset;
/* 3 free bytes. */
}; };
static long long arg_to_long_long(const struct argp_state *state, static long long arg_to_long_long(const struct argp_state *state,
@ -132,6 +137,10 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
args->save = false; args->save = false;
break; break;
case 'm':
args->manual_reset = true;
break;
case ARGP_KEY_INIT: case ARGP_KEY_INIT:
args->filename = NULL; args->filename = NULL;
break; break;
@ -284,7 +293,7 @@ static int test_device(struct args *args)
? create_file_device(args->filename, args->real_size_byte, ? create_file_device(args->filename, args->real_size_byte,
args->fake_size_byte, args->wrap, args->block_order, args->fake_size_byte, args->wrap, args->block_order,
args->keep_file) args->keep_file)
: create_block_device(args->filename); : create_block_device(args->filename, args->manual_reset);
assert(dev); assert(dev);
if (args->save) { if (args->save) {
@ -345,6 +354,7 @@ int main(int argc, char **argv)
.fake_size_byte = 1ULL << 34, .fake_size_byte = 1ULL << 34,
.wrap = 31, .wrap = 31,
.block_order = 9, .block_order = 9,
.manual_reset = false,
}; };
/* Read parameters. */ /* Read parameters. */

View File

@ -324,6 +324,21 @@ static inline int bdev_open(const char *filename)
return open(filename, O_RDWR | O_DIRECT | O_SYNC); return open(filename, O_RDWR | O_DIRECT | O_SYNC);
} }
/* XXX Monitor the USB subsytem to know when the drive was unplugged and
* plugged back to continue instead of waiting for a key.
*/
static int bdev_manual_reset(struct device *dev)
{
struct block_device *bdev = dev_bdev(dev);
assert(!close(bdev->fd));
printf("Please unplug and plug back the USB drive, and press a key to continue...\n");
getchar();
bdev->fd = bdev_open(bdev->filename);
if (bdev->fd < 0)
err(errno, "Can't REopen device `%s'", bdev->filename);
return 0;
}
static int bdev_reset(struct device *dev) static int bdev_reset(struct device *dev)
{ {
struct block_device *bdev = dev_bdev(dev); struct block_device *bdev = dev_bdev(dev);
@ -338,8 +353,10 @@ static int bdev_reset(struct device *dev)
static void bdev_free(struct device *dev) static void bdev_free(struct device *dev)
{ {
struct block_device *bdev = dev_bdev(dev); struct block_device *bdev = dev_bdev(dev);
assert(!close(bdev->hw_fd)); if (bdev->hw_fd >= 0)
assert(!close(bdev->fd)); assert(!close(bdev->hw_fd));
if (bdev->fd >= 0)
assert(!close(bdev->fd));
free((void *)bdev->filename); free((void *)bdev->filename);
} }
@ -446,14 +463,14 @@ static int ilog2(uint64_t x)
* Suggest how to call f3probe with the correct device name if * Suggest how to call f3probe with the correct device name if
* the block device is a partition. * the block device is a partition.
* Use udev to do these tests. * Use udev to do these tests.
* Make sure that no partition of the drive is mounted.
*/ */
/* XXX Test for write access of the block device to give /* XXX Test for write access of the block device to give
* a nice error message. * a nice error message.
* If it fails, suggest running f3probe as root. * If it fails, suggest running f3probe as root.
*/ */
struct device *create_block_device(const char *filename) struct device *create_block_device(const char *filename, int manual_reset)
{ {
const char *usb_filename;
struct block_device *bdev; struct block_device *bdev;
int block_size; int block_size;
@ -476,18 +493,25 @@ struct device *create_block_device(const char *filename)
goto fd; goto fd;
} }
/* XXX Add support for block devices backed by SCSI, SATA, and ATA. */ if (manual_reset) {
usb_filename = map_block_to_usb_dev(filename); bdev->hw_fd = -1;
if (!usb_filename) { bdev->dev.reset = bdev_manual_reset;
err(EINVAL, "Block device `%s' is not backed by a USB device", } else {
filename); /* XXX Add support for block devices backed by SCSI and ATA. */
goto fd; const char *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); bdev->hw_fd = open(usb_filename, O_WRONLY | O_NONBLOCK);
if (bdev->hw_fd < 0) { free((void *)usb_filename);
err(errno, "Can't open device `%s'", usb_filename); if (bdev->hw_fd < 0) {
goto usb_filename; err(errno, "Can't open device `%s'", usb_filename);
goto fd;
}
bdev->dev.reset = bdev_reset;
} }
assert(!ioctl(bdev->fd, BLKGETSIZE64, &bdev->dev.size_byte)); assert(!ioctl(bdev->fd, BLKGETSIZE64, &bdev->dev.size_byte));
@ -498,14 +522,10 @@ struct device *create_block_device(const char *filename)
bdev->dev.read_block = bdev_read_block; bdev->dev.read_block = bdev_read_block;
bdev->dev.write_block = bdev_write_block; bdev->dev.write_block = bdev_write_block;
bdev->dev.reset = bdev_reset;
bdev->dev.free = bdev_free; bdev->dev.free = bdev_free;
free((void *)usb_filename);
return &bdev->dev; return &bdev->dev;
usb_filename:
free((void *)usb_filename);
fd: fd:
assert(!close(bdev->fd)); assert(!close(bdev->fd));
filename: filename:

View File

@ -36,7 +36,7 @@ struct device *create_file_device(const char *filename,
uint64_t real_size_byte, uint64_t fake_size_byte, int wrap, uint64_t real_size_byte, uint64_t fake_size_byte, int wrap,
int block_order, int keep_file); int block_order, int keep_file);
struct device *create_block_device(const char *filename); struct device *create_block_device(const char *filename, int manual_reset);
struct device *create_safe_device(struct device *dev, int max_blocks); struct device *create_safe_device(struct device *dev, int max_blocks);