Как узнать, является ли устройство SCSI (скажем, /etc/sda) диском или нет, с помощью вызовов ioctl или других способов?

Как узнать, является ли устройство SCSI (скажем, /dev/sda) диском или нет, с помощью вызовов ioctl или других способов? Я пробовал следующее, но вызов ioctl терпит неудачу. Мой /dev/sda — это флешка.

#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

person clyfe    schedule 23.04.2010    source источник


Ответы (3)


Я решил эту проблему, используя SG_IO и интерпретируя двоичные данные непосредственно в соответствии со спецификацией команды INQUIRY ( поле: тип периферийного устройства) и интерпретировать их в соответствии с типами периферийных устройств SCSI (диск, если пер. тип устройства — 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;
    }
}
person clyfe    schedule 26.04.2010

Возможно, вы можете получить полезную информацию из файловой системы /sys/bus/scsi/devices/*/.

person Juraj    schedule 23.04.2010
comment
ty, это действительно помогает, я покопаюсь еще, чтобы сделать это через жесткий ioctl. [root@localhost ~]# cat /proc/scsi/scsi Подключенные устройства: Хост: scsi1 Канал: 00 Идентификатор: 00 Лун: 00 Поставщик: SanDisk Модель: Cruzer Rev: 8.01 Тип: Прямой доступ Версия ANSI SCSI: 02 - person clyfe; 23.04.2010

HDIO_GET_IDENTITY у меня работает на дисках, но не на флешках. Я думаю, это то, что использует hdparm -i.

person Eric Seppanen    schedule 23.04.2010
comment
Он работает на диске SATA, используя libata, чтобы он отображался как /dev/sda. У меня нет под рукой SCSI-диска, чтобы проверить. - person Eric Seppanen; 26.04.2010