如何通过 ioctl 调用或其他方式查明 SCSI 设备(例如 /etc/sda)是否是磁盘?

发布于 2024-08-30 00:09:28 字数 1061 浏览 7 评论 0原文

如何通过 ioctl 调用或其他方式查明 SCSI 设备(例如 /dev/sda)是否是磁盘? 我已尝试以下操作,但 ioctl 调用失败。我的/dev/sda是一个U盘。

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

int main(int argc, char** argv) {
    char *dev = "/dev/sda";
    struct sg_scsi_id m_id;
    int rc;
    int fd;

    fd = open(dev, O_RDONLY | O_NONBLOCK);
    if (fd < 0) {
        perror(dev);
    }
    memset(&m_id, 0, sizeof (m_id));
    rc = ioctl(fd, SG_GET_SCSI_ID, &m_id);
    if (rc < 0) {
        close(fd);
        printf("FAIL: ioctl SG_GET_SCSI_ID, rc=%d, errno=%d\n", rc, errno);
    } else {
        if (m_id.scsi_type == TYPE_DISK || m_id.scsi_type == 14) {
            printf("OK: is disk\n");
        } else {
            printf("OK: is NOT disk\n");
        }
    }
    close(fd);
    return (EXIT_SUCCESS);
}
// result is: FAIL: ioctl SG_GET_SCSI_ID, rc=-1, errno=22

How to find out if SCSI device (say /dev/sda) is a disk or not via ioctl calls or other ?
I have tried the following but the ioctl call fails. My /dev/sda is a USB flash disk.

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

int main(int argc, char** argv) {
    char *dev = "/dev/sda";
    struct sg_scsi_id m_id;
    int rc;
    int fd;

    fd = open(dev, O_RDONLY | O_NONBLOCK);
    if (fd < 0) {
        perror(dev);
    }
    memset(&m_id, 0, sizeof (m_id));
    rc = ioctl(fd, SG_GET_SCSI_ID, &m_id);
    if (rc < 0) {
        close(fd);
        printf("FAIL: ioctl SG_GET_SCSI_ID, rc=%d, errno=%d\n", rc, errno);
    } else {
        if (m_id.scsi_type == TYPE_DISK || m_id.scsi_type == 14) {
            printf("OK: is disk\n");
        } else {
            printf("OK: is NOT disk\n");
        }
    }
    close(fd);
    return (EXIT_SUCCESS);
}
// result is: FAIL: ioctl SG_GET_SCSI_ID, rc=-1, errno=22

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

吲‖鸣 2024-09-06 00:09:28

我已经使用 SG_IO 解决了这个问题,并根据 的规范直接解释二进制数据INQUIRY 命令(字段:外围设备类型)并根据 SCSI 外围设备类型(如果 per.dev.type 为 00h 或 0Eh,则为磁盘)

int is_disk_sd(char *dev) {
    unsigned char sense[32];
    struct sg_io_hdr io_hdr;
    char scsi_data[SCSI_LEN];
    struct hd_geometry geo;
    // request for "standard inquiry data"
    unsigned char inq_cmd[] = {INQUIRY, 0, 0, 0, SCSI_LEN, 0};
    int fd;

    fd = open(dev, O_RDONLY | O_NONBLOCK);
    if (fd < 0) {
        perror(dev);
    }

    memset(&io_hdr, 0, sizeof (io_hdr));
    io_hdr.interface_id = 'S';
    io_hdr.cmdp = inq_cmd;
    io_hdr.cmd_len = sizeof (inq_cmd);
    io_hdr.dxferp = scsi_data;
    io_hdr.dxfer_len = sizeof (scsi_data);
    io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
    io_hdr.sbp = sense;
    io_hdr.mx_sb_len = sizeof (sense);
    io_hdr.timeout = 5000;

    if (ioctl(fd, SG_IO, &io_hdr) < 0) {
        close(fd);
        return 0;
    } else {
        close(fd);
        if (scsi_data[1] & 0x80) {
            return 0; // support is removable
        }
        if ((scsi_data[0] & 0x1f) || ((scsi_data[0] & 0x1f) != 0xe)) { // 0 or 14 (00h or 0Eh)
            return 0; // not direct access neither simplified direct access device
        }
        return 1;
    }
}

I have solved this using SG_IO and interpreting the binary data directly according to the specification of the INQUIRY command (field: peripheral device type) and interpreting them according to SCSI Peripheral Device Types (is disk if per. dev. type is either 00h or 0Eh)

int is_disk_sd(char *dev) {
    unsigned char sense[32];
    struct sg_io_hdr io_hdr;
    char scsi_data[SCSI_LEN];
    struct hd_geometry geo;
    // request for "standard inquiry data"
    unsigned char inq_cmd[] = {INQUIRY, 0, 0, 0, SCSI_LEN, 0};
    int fd;

    fd = open(dev, O_RDONLY | O_NONBLOCK);
    if (fd < 0) {
        perror(dev);
    }

    memset(&io_hdr, 0, sizeof (io_hdr));
    io_hdr.interface_id = 'S';
    io_hdr.cmdp = inq_cmd;
    io_hdr.cmd_len = sizeof (inq_cmd);
    io_hdr.dxferp = scsi_data;
    io_hdr.dxfer_len = sizeof (scsi_data);
    io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
    io_hdr.sbp = sense;
    io_hdr.mx_sb_len = sizeof (sense);
    io_hdr.timeout = 5000;

    if (ioctl(fd, SG_IO, &io_hdr) < 0) {
        close(fd);
        return 0;
    } else {
        close(fd);
        if (scsi_data[1] & 0x80) {
            return 0; // support is removable
        }
        if ((scsi_data[0] & 0x1f) || ((scsi_data[0] & 0x1f) != 0xe)) { // 0 or 14 (00h or 0Eh)
            return 0; // not direct access neither simplified direct access device
        }
        return 1;
    }
}
债姬 2024-09-06 00:09:28

也许您可以从 /sys/bus/scsi/devices/*/ 文件系统获取有用的信息。

Maybe you can get useful information from /sys/bus/scsi/devices/*/ filesystem.

安穩 2024-09-06 00:09:28

HDIO_GET_IDENTITY 似乎适用于磁盘,但不适用于闪存驱动器。我认为这就是 hdparm -i 使用的。

HDIO_GET_IDENTITY seems to work for me on disks but not on flash drives. I think this is what hdparm -i uses.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文