Порядковый номер Карты памяти в соответствии с Linux C++

Там какой-либо путь состоит в том, чтобы определить s/n карты памяти в Linux с помощью C++?

Если не C++ является там каким-либо другим путем, отличающимся от hwinfo -disk и hdparm -i ?

9
задан clyfe 16 January 2012 в 20:45
поделиться

2 ответа

Я попытаюсь обобщить свой опыт по извлечению серийного номера накопителя в Linux.
Я предполагаю, что вам нужен серийный номер устройства хранения (согласно спецификации SCSI), а не серийный номер USB-устройства (согласно USB спецификация в Дескриптор устройства ), это разные объекты.

ВНИМАНИЕ!
Большинство устройств имеют тенденцию реализовывать серийный номер в USB-контроллере и оставлять серийный номер внутреннего SCSI-диска нереализованным.
Итак, если вы хотите однозначно идентифицировать USB-устройство, лучше всего создать строку из дескриптора устройства (спецификация USB), например VendorId-ProductId-HardwareRevision -SerialNumber
Далее я опишу, как получить серийный номер запоминающего устройства в соответствии с запросом.

Диски делятся на 2 категории (на самом деле их больше, но давайте упрощаем): ATA-подобные (hda, hdb ...) и SCSI-подобные (sda sdb ...). USB-накопители попадают в категорию во второй категории они называются подключенными к SCSI дисками . В обоих случаях вызовы ioctl могут использоваться для получения необходимой информации (в нашем случае - серийного номера).

Для устройств SCSI (включая USB-накопители) общий драйвер Linux и его API задокументированы в tldp .
Серийный номер на устройствах SCSI доступен в Vital Product Data (сокращенно: VPD) и может быть получен с помощью команды запроса SCSI . Утилита командной строки в Linux, которая может получить этот VPD, - это sdparm :

> yum install sdparm
> sdparm --quiet --page=sn /dev/sda
    Unit serial number VPD page:
    3BT1ZQGR000081240XP7

Обратите внимание, что не все устройства имеют этот серийный номер, рынок наводнен дешевыми подделками и некоторыми USB-флешками. диски возвращают странные серийные номера (например, мой sandisk cruzer возвращает только букву «u»). Чтобы преодолеть это, некоторые люди предпочитают создавать уникальный идентификатор, смешивая разные строки из VPD, такие как Product ID, Vendor ID и Serial Number.

Код в c:

#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 scsi_get_serial(int fd, void *buf, size_t buf_len) {
    // we shall retrieve page 0x80 as per http://en.wikipedia.org/wiki/SCSI_Inquiry_Command
    unsigned char inq_cmd[] = {INQUIRY, 1, 0x80, 0, buf_len, 0};
    unsigned char sense[32];
    struct sg_io_hdr io_hdr;
            int result;

    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 = buf;
    io_hdr.dxfer_len = buf_len;
    io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
    io_hdr.sbp = sense;
    io_hdr.mx_sb_len = sizeof (sense);
    io_hdr.timeout = 5000;

    result = ioctl(fd, SG_IO, &io_hdr);
    if (result < 0)
        return result;

    if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK)
        return 1;

    return 0;
}

int main(int argc, char** argv) {
    char *dev = "/dev/sda";
    char scsi_serial[255];
    int rc;
    int fd;

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

    memset(scsi_serial, 0, sizeof (scsi_serial));
    rc = scsi_get_serial(fd, scsi_serial, 255);
    // scsi_serial[3] is the length of the serial number
    // scsi_serial[4] is serial number (raw, NOT null terminated)
    if (rc < 0) {
        printf("FAIL, rc=%d, errno=%d\n", rc, errno);
    } else
    if (rc == 1) {
        printf("FAIL, rc=%d, drive doesn't report serial number\n", rc);
    } else {
        if (!scsi_serial[3]) {
            printf("Failed to retrieve serial for %s\n", dev);
            return -1;
        }
        printf("Serial Number: %.*s\n", (size_t) scsi_serial[3], (char *) & scsi_serial[4]);
    }
    close(fd);

    return (EXIT_SUCCESS);
}

Для полноты картины я также предоставлю код для получения серийного номера для устройств ATA (hda, hdb ...). Это НЕ будет работать с USB-устройствами.

#include <stdlib.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <linux/hdreg.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <cctype>
#include <unistd.h>

int main(){
    struct hd_driveid *id;
    char *dev = "/dev/hda";
    int fd;

    fd = open(dev, O_RDONLY|O_NONBLOCK);
    if(fd < 0) {
        perror("cannot open");
    }
    if (ioctl(fd, HDIO_GET_IDENTITY, id) < 0) {
        close(fd);
        perror("ioctl error");
    } else {
        // if we want to retrieve only for removable drives use this branching
        if ((id->config & (1 << 7)) || (id->command_set_1 & 4)) {
            close(fd);
            printf("Serial Number: %s\n", id->serial_no);
        } else {
            perror("support not removable");
        }
        close(fd);
    }
}
22
ответ дан 4 December 2019 в 08:33
поделиться

Вероятно, лучший способ сделать то, что инструменты командной строки (опять же, вероятно) делают: проверить соответствующие файлы в / proc или / sys , но из кода C ++.

0
ответ дан 4 December 2019 в 08:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: