ioctl seems to change errno behaviour in 5.6.0rc2

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello,

I noticed cdparanoia stopped working with kernel 5.6.0rc2 while it worked fine
with 5.5.2 .

Running as root `cdparanoia -v -d /dev/sr0 [0]` with 5.6.0rc2, gives the
following errors:

Testing /dev/sr0 for SCSI/MMC interface
        no SG_IO support for device: /dev/sr0
Error trying to open /dev/sga exclusively (No such file or directory).

I checked that the sg module is loaded with both kernels and also did a diff of
the lsmod output with both kernels and didn't find anything suspicious.

After some tests, I did a small c application using code from cdparanoia where
it can be seen that the ioctl(fd, SG_IO, &hdr) call returns EINVAL in errno with
the 5.5.2 kernel but returns EFAULT with 5.6.0rc2 .

The code is attached and can be built just with `gcc test.c -o test` (note it's
hardcoded in main to use /dev/sr0, so it doesn't have any parameter).

Note that I'm not a cdparanoia developer (in fact, it seems to have been
unmaintained for many years), but I thought it might be interesting to report an
ioctl that changes the behaviour in different kernels.

Greetings,

-- 
Antonio Larrosa
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <scsi/sg.h>

int check_sgio(const char *device){
  int fd;
  struct sg_io_hdr hdr;

  if (!device) return 0;

  /* we don't really care what type of device it is -- if it can do
   * SG_IO, then we'll put it through the normal mmc/atapi/etc tests
   * later, but it's good enough for now. */
  fd = open(device, O_RDWR|O_NONBLOCK);
  if (fd < 0){
    printf("Could not access device %s to test for SG_IO support\n",device);
    return 0;
  }

  memset(&hdr, 0, sizeof (struct sg_io_hdr));
  /* First try with interface_id = 'A'; for all but the sg case,
   * that'll get us a -EINVAL if it supports SG_IO, and some other
   * error for all other cases. */
  hdr.interface_id = 'A';
  if (ioctl(fd, SG_IO, &hdr)) {
    int err=errno;
    printf("errno: %d\n", err);
    switch (err) {
    case EINVAL: /* sr and ata give us EINVAL when SG_IO is
                  * supported but interface_id is bad. */

    case ENOSYS: /* sg gives us ENOSYS when SG_IO is supported but
                  * interface_id is bad.  IMHO, this is wrong and
                  * needs fixing in the kernel. */

      close(fd);
      return 1;

    default: /* everything else gives ENOTTY, I think.  I'm just
              * going to be paranoid and reject everything else. */

      close(fd);
      return 0;

    }
  }
  /* if we get here, something is dreadfuly wrong. ioctl(fd,SG_IO,&hdr)
   * handled SG_IO, but took hdr.interface_id = 'A' as valid, and an empty
   * command as good.  Don't trust it. */
  printf("closing\n");
  close(fd);
  return 0;
}

int main(int argc, char**argv)
{
  const char *specialized_device = "/dev/sr0";

  if(check_sgio(specialized_device)){
     printf("SG_IO device: %s\n",specialized_device);
  }else{
     printf("no SG_IO support for device: %s\n",specialized_device);
  }
  return 0;
};

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]

  Powered by Linux