Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

umockdev-record not capturing USB mass storage ioctl calls #251

Open
Degoah opened this issue Jul 8, 2024 · 4 comments
Open

umockdev-record not capturing USB mass storage ioctl calls #251

Degoah opened this issue Jul 8, 2024 · 4 comments

Comments

@Degoah
Copy link

Degoah commented Jul 8, 2024

Description:

I am trying to use umockdev-record to capture the behavior of my application that interacts with a USB mass storage device. My trivial application, named get_usb_stick_info, uses the ioctl system call with the SG_IO command to retrieve information from the device.

The application code is provided below:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <scsi/sg.h>
#include <sys/ioctl.h>

#define INQUIRY_CMDLEN 6
#define INQUIRY_REPLY_LEN 96
#define SENSE_LEN 32

int main(int argc, char* argv[]) {
  const char *device = argv[1];   
  int fd = open(device, O_RDONLY);
  if (fd < 0) {
    perror("Failed to open device");
    return 1;
  }

  unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {0x12, 0, 0, 0, INQUIRY_REPLY_LEN, 0};
  unsigned char inqBuff[INQUIRY_REPLY_LEN];
  unsigned char senseBuffer[SENSE_LEN];

  sg_io_hdr_t io_hdr;
  memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
  memset(inqBuff, 0, INQUIRY_REPLY_LEN);
  memset(senseBuffer, 0, SENSE_LEN);

  io_hdr.interface_id = 'S';
  io_hdr.cmd_len = sizeof(inqCmdBlk);
  io_hdr.mx_sb_len = sizeof(senseBuffer);
  io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
  io_hdr.dxfer_len = INQUIRY_REPLY_LEN;
  io_hdr.dxferp = inqBuff;
  io_hdr.cmdp = inqCmdBlk;
  io_hdr.sbp = senseBuffer;
  io_hdr.timeout = 2000;  // 2 seconds timeout

  if (ioctl(fd, SG_IO, &io_hdr) < 0) {
    perror("SG_IO ioctl failed");
    close(fd);
    return 1;
  }

  if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK) {
    fprintf(stderr, "SCSI command failed\n");
    close(fd);
    return 1;
  }

  printf("Vendor ID: %.8s\n", &inqBuff[8]);
  printf("Product ID: %.16s\n", &inqBuff[16]);
  printf("Product Revision: %.4s\n", &inqBuff[32]);

  close(fd);
  return 0;
}

However, when I record the interaction using the following command:

umockdev-record /dev/sda > usb_stick.umockdev
umockdev-record --ioctl /dev/sda=usb_stick.ioctl ./get_usb_stick_info /dev/sda

The generated file usb_stick.ioctl file only contains the line @dev /dev/sda.

It seems that umockdev-record is not capturing the actual ioctl system calls being made by my application.

Expected Behavior:

The usb_stick.ioctl file should contain the details of the ioctl system call. This would allow me to replay the interaction with the USB device in a mock environment.

System Information:

umockdev version: 018.1
@martinpitt martinpitt changed the title umockdev-record not capturing ioctl calls umockdev-record not capturing USB mass storage ioctl calls Jul 8, 2024
@martinpitt
Copy link
Owner

Right, umockdev doesn't do mass storage. That's too complicated to emulate, you are better off with using scsi_debug, loop devices, etc. If you don't actually need to mount it, just get information, then it should be possible though -- contributions appreciated! (I won't work on this myself).

@Degoah
Copy link
Author

Degoah commented Jul 8, 2024

I've spent several hours trying to achieve this with umockdev. Based on your response, it seems like updating the documentation to explicitly mention that mass storage devices are not currently supported would be helpful for future users.

@Degoah
Copy link
Author

Degoah commented Jul 8, 2024

I see, loop device could be used...Yes, I don't need to mount the devices for my integration/unit tests. But right now I'm unsure, how to achieve this with loop devices. Am I right, that I need to create an image file, format it for example with ext4 and map it onto a loop device to get the filesystem information (label, model serial no.) for example with the "blkid" library?

@benzea
Copy link
Collaborator

benzea commented Jul 8, 2024

What is the easiest solution probably depends a lot on what you need. One could:

  1. Add support for the ioctl to umockdev (in ioctl-tree.c), that is an option especially of the ioctl is simple
  2. Add some custom support for it (like the USB pcap support), that is possibly more complicated
  3. Implement the ioctl entirely yourself in the test infrastructure (similar to point 2, but no need for umockdev changes; see e.g. fwupd Add some "basic" ioctl based tests for NVME and AMD-GPU fwupd/fwupd#6870)
  4. Or, as Martin already suggested, using some entirely separate infrastructure to test this.

Those are just a few ideas, I am sure there are other possible solutions. What makes sense for you likely depends a lot on what exactly you need to test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants