mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Added helper application to create device reports on Linux systems without .NET framework available.
This commit is contained in:
6
DiscImageChef.Device.Report/CMakeLists.txt
Normal file
6
DiscImageChef.Device.Report/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.9)
|
||||||
|
project(DiscImageChef_Device_Report C)
|
||||||
|
|
||||||
|
set(CMAKE_C_STANDARD 90)
|
||||||
|
|
||||||
|
add_executable(DiscImageChef_Device_Report main.c scsi.c scsi.h main.h ata.h ata.c atapi.c atapi.h)
|
||||||
236
DiscImageChef.Device.Report/ata.c
Normal file
236
DiscImageChef.Device.Report/ata.c
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
//
|
||||||
|
// Created by claunia on 11/12/17.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <scsi/sg.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "ata.h"
|
||||||
|
#include "scsi.h"
|
||||||
|
|
||||||
|
int AtaProtocolToScsiDirection(int protocol)
|
||||||
|
{
|
||||||
|
switch(protocol)
|
||||||
|
{
|
||||||
|
case ATA_PROTOCOL_DEVICE_DIAGNOSTICS:
|
||||||
|
case ATA_PROTOCOL_DEVICE_RESET:
|
||||||
|
case ATA_PROTOCOL_HARD_RESET:
|
||||||
|
case ATA_PROTOCOL_NO_DATA:
|
||||||
|
case ATA_PROTOCOL_SOFT_RESET:
|
||||||
|
case ATA_PROTOCOL_RETURN_RESPONSE:
|
||||||
|
return SG_DXFER_NONE;
|
||||||
|
case ATA_PROTOCOL_PIO_IN:
|
||||||
|
case ATA_PROTOCOL_UDMA_IN:
|
||||||
|
return SG_DXFER_FROM_DEV;
|
||||||
|
case ATA_PROTOCOL_PIO_OUT:
|
||||||
|
case ATA_PROTOCOL_UDMA_OUT:
|
||||||
|
return SG_DXFER_TO_DEV;
|
||||||
|
default:
|
||||||
|
return SG_DXFER_TO_FROM_DEV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *AtaToCString(unsigned char* string, int len)
|
||||||
|
{
|
||||||
|
unsigned char* buffer = malloc(len + 1);
|
||||||
|
unsigned char* ptr = buffer;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < len; i+=2)
|
||||||
|
{
|
||||||
|
*ptr++ = *(string + i + 1);
|
||||||
|
*ptr++ = *(string + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[len] = 0x00;
|
||||||
|
*ptr = *(buffer + len);
|
||||||
|
|
||||||
|
for(i = len; i >= 0; i--, *ptr--)
|
||||||
|
{
|
||||||
|
if(*ptr == 0x20 || *ptr == 0x00)
|
||||||
|
*ptr = 0;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SendAtaCommandChs(int fd, AtaRegistersCHS registers, AtaErrorRegistersCHS **errorRegisters, int protocol, int transferRegister, unsigned char *buffer, unsigned int buffer_len, int transferBlocks)
|
||||||
|
{
|
||||||
|
unsigned char cdb[16];
|
||||||
|
memset(&cdb, 0, 16);
|
||||||
|
cdb[0] = SCSI_ATA_PASSTHROUGH_16;
|
||||||
|
cdb[1] = (unsigned char)((protocol << 1) & 0x1E);
|
||||||
|
if(transferRegister != ATA_TRANSFER_NONE && protocol != ATA_PROTOCOL_NO_DATA)
|
||||||
|
{
|
||||||
|
switch(protocol)
|
||||||
|
{
|
||||||
|
case ATA_PROTOCOL_PIO_IN:
|
||||||
|
case ATA_PROTOCOL_UDMA_IN:
|
||||||
|
cdb[2] = 0x08;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cdb[2] = 0x00;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(transferBlocks)
|
||||||
|
cdb[2] |= 0x04;
|
||||||
|
|
||||||
|
cdb[2] |= (transferRegister & 0x03);
|
||||||
|
}
|
||||||
|
|
||||||
|
cdb[4] = registers.feature;
|
||||||
|
cdb[6] = registers.sectorCount;
|
||||||
|
cdb[8] = registers.sector;
|
||||||
|
cdb[10] = registers.cylinderLow;
|
||||||
|
cdb[12] = registers.cylinderHigh;
|
||||||
|
cdb[13] = registers.deviceHead;
|
||||||
|
cdb[14] = registers.command;
|
||||||
|
|
||||||
|
unsigned char *sense_buf;
|
||||||
|
int error = SendScsiCommand(fd, &cdb, 16, buffer, buffer_len, &sense_buf, AtaProtocolToScsiDirection(protocol));
|
||||||
|
|
||||||
|
*errorRegisters = malloc(sizeof(AtaErrorRegistersCHS));
|
||||||
|
memset(*errorRegisters, 0, sizeof(AtaErrorRegistersCHS));
|
||||||
|
(*errorRegisters)->error = sense_buf[11];
|
||||||
|
(*errorRegisters)->sectorCount = sense_buf[13];
|
||||||
|
(*errorRegisters)->sector = sense_buf[15];
|
||||||
|
(*errorRegisters)->cylinderLow = sense_buf[17];
|
||||||
|
(*errorRegisters)->cylinderHigh = sense_buf[19];
|
||||||
|
(*errorRegisters)->deviceHead = sense_buf[20];
|
||||||
|
(*errorRegisters)->status = sense_buf[21];
|
||||||
|
|
||||||
|
if(error != 0)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
return (*errorRegisters)->error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SendAtaCommandLba28(int fd, AtaRegistersLBA28 registers, AtaErrorRegistersLBA28 **errorRegisters, int protocol, int transferRegister, unsigned char *buffer, unsigned int buffer_len, int transferBlocks)
|
||||||
|
{
|
||||||
|
unsigned char cdb[16];
|
||||||
|
memset(&cdb, 0, 16);
|
||||||
|
cdb[0] = SCSI_ATA_PASSTHROUGH_16;
|
||||||
|
cdb[1] = (unsigned char)((protocol << 1) & 0x1E);
|
||||||
|
if(transferRegister != ATA_TRANSFER_NONE && protocol != ATA_PROTOCOL_NO_DATA)
|
||||||
|
{
|
||||||
|
switch(protocol)
|
||||||
|
{
|
||||||
|
case ATA_PROTOCOL_PIO_IN:
|
||||||
|
case ATA_PROTOCOL_UDMA_IN:
|
||||||
|
cdb[2] = 0x08;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cdb[2] = 0x00;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(transferBlocks)
|
||||||
|
cdb[2] |= 0x04;
|
||||||
|
|
||||||
|
cdb[2] |= (transferRegister & 0x03);
|
||||||
|
}
|
||||||
|
|
||||||
|
cdb[2] |= 0x20;
|
||||||
|
|
||||||
|
cdb[4] = registers.feature;
|
||||||
|
cdb[6] = registers.sectorCount;
|
||||||
|
cdb[8] = registers.lbaLow;
|
||||||
|
cdb[10] = registers.lbaMid;
|
||||||
|
cdb[12] = registers.lbaHigh;
|
||||||
|
cdb[13] = registers.deviceHead;
|
||||||
|
cdb[14] = registers.command;
|
||||||
|
|
||||||
|
unsigned char *sense_buf;
|
||||||
|
int error = SendScsiCommand(fd, &cdb, 16, buffer, buffer_len, &sense_buf, AtaProtocolToScsiDirection(protocol));
|
||||||
|
|
||||||
|
*errorRegisters = malloc(sizeof(AtaErrorRegistersLBA28));
|
||||||
|
memset(*errorRegisters, 0, sizeof(AtaErrorRegistersLBA28));
|
||||||
|
(*errorRegisters)->error = sense_buf[11];
|
||||||
|
(*errorRegisters)->sectorCount = sense_buf[13];
|
||||||
|
(*errorRegisters)->lbaLow = sense_buf[15];
|
||||||
|
(*errorRegisters)->lbaMid= sense_buf[17];
|
||||||
|
(*errorRegisters)->lbaHigh = sense_buf[19];
|
||||||
|
(*errorRegisters)->deviceHead = sense_buf[20];
|
||||||
|
(*errorRegisters)->status = sense_buf[21];
|
||||||
|
|
||||||
|
if(error != 0)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
return (*errorRegisters)->error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SendAtaCommandLba48(int fd, AtaRegistersLBA48 registers, AtaErrorRegistersLBA48 **errorRegisters, int protocol, int transferRegister, unsigned char *buffer, unsigned int buffer_len, int transferBlocks)
|
||||||
|
{
|
||||||
|
unsigned char cdb[16];
|
||||||
|
memset(&cdb, 0, 16);
|
||||||
|
cdb[0] = SCSI_ATA_PASSTHROUGH_16;
|
||||||
|
cdb[1] = (unsigned char)((protocol << 1) & 0x1E);
|
||||||
|
cdb[1] |= 0x01;
|
||||||
|
if(transferRegister != ATA_TRANSFER_NONE && protocol != ATA_PROTOCOL_NO_DATA)
|
||||||
|
{
|
||||||
|
switch(protocol)
|
||||||
|
{
|
||||||
|
case ATA_PROTOCOL_PIO_IN:
|
||||||
|
case ATA_PROTOCOL_UDMA_IN:
|
||||||
|
cdb[2] = 0x08;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cdb[2] = 0x00;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(transferBlocks)
|
||||||
|
cdb[2] |= 0x04;
|
||||||
|
|
||||||
|
cdb[2] |= (transferRegister & 0x03);
|
||||||
|
}
|
||||||
|
|
||||||
|
cdb[2] |= 0x20;
|
||||||
|
|
||||||
|
cdb[3] = (uint8_t)((registers.feature & 0xFF00) >> 8);
|
||||||
|
cdb[4] = (uint8_t)(registers.feature & 0xFF);
|
||||||
|
cdb[5] = (uint8_t)((registers.sectorCount & 0xFF00) >> 8);
|
||||||
|
cdb[6] = (uint8_t)(registers.sectorCount & 0xFF);
|
||||||
|
cdb[7] = (uint8_t)((registers.lbaLow & 0xFF00) >> 8);
|
||||||
|
cdb[8] = (uint8_t)(registers.lbaLow & 0xFF);
|
||||||
|
cdb[9] = (uint8_t)((registers.lbaMid & 0xFF00) >> 8);
|
||||||
|
cdb[10] = (uint8_t)(registers.lbaMid & 0xFF);
|
||||||
|
cdb[11] = (uint8_t)((registers.lbaHigh & 0xFF00) >> 8);
|
||||||
|
cdb[12] = (uint8_t)(registers.lbaHigh & 0xFF);
|
||||||
|
cdb[13] = registers.deviceHead;
|
||||||
|
cdb[14] = registers.command;
|
||||||
|
|
||||||
|
unsigned char *sense_buf;
|
||||||
|
int error = SendScsiCommand(fd, &cdb, 16, buffer, buffer_len, &sense_buf, AtaProtocolToScsiDirection(protocol));
|
||||||
|
|
||||||
|
*errorRegisters = malloc(sizeof(AtaErrorRegistersLBA48));
|
||||||
|
memset(*errorRegisters, 0, sizeof(AtaErrorRegistersLBA48));
|
||||||
|
(*errorRegisters)->sectorCount = (uint16_t)((sense_buf[12] << 8) + sense_buf[13]);
|
||||||
|
(*errorRegisters)->lbaLow = (uint16_t)((sense_buf[14] << 8) + sense_buf[15]);
|
||||||
|
(*errorRegisters)->lbaMid = (uint16_t)((sense_buf[16] << 8) + sense_buf[17]);
|
||||||
|
(*errorRegisters)->lbaHigh = (uint16_t)((sense_buf[18] << 8) + sense_buf[19]);
|
||||||
|
(*errorRegisters)->deviceHead = sense_buf[20];
|
||||||
|
(*errorRegisters)->status = sense_buf[21];
|
||||||
|
|
||||||
|
if(error != 0)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
return (*errorRegisters)->error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Identify(int fd, unsigned char **buffer, AtaErrorRegistersCHS **errorRegisters)
|
||||||
|
{
|
||||||
|
*buffer = malloc(512);
|
||||||
|
memset(*buffer, 0, 512);
|
||||||
|
AtaRegistersCHS registers;
|
||||||
|
memset(®isters, 0, sizeof(AtaRegistersCHS));
|
||||||
|
|
||||||
|
registers.command = ATA_IDENTIFY_DEVICE;
|
||||||
|
|
||||||
|
int error = SendAtaCommandChs(fd, registers, errorRegisters, ATA_PROTOCOL_PIO_IN, ATA_TRANSFER_NONE, *buffer, 512, 0);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
114
DiscImageChef.Device.Report/ata.h
Normal file
114
DiscImageChef.Device.Report/ata.h
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
//
|
||||||
|
// Created by claunia on 11/12/17.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DISCIMAGECHEF_DEVICE_REPORT_ATA_H
|
||||||
|
#define DISCIMAGECHEF_DEVICE_REPORT_ATA_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t feature;
|
||||||
|
uint8_t sectorCount;
|
||||||
|
uint8_t sector;
|
||||||
|
uint8_t cylinderLow;
|
||||||
|
uint8_t cylinderHigh;
|
||||||
|
uint8_t deviceHead;
|
||||||
|
uint8_t command;
|
||||||
|
} AtaRegistersCHS;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t feature;
|
||||||
|
uint8_t sectorCount;
|
||||||
|
uint8_t lbaLow;
|
||||||
|
uint8_t lbaMid;
|
||||||
|
uint8_t lbaHigh;
|
||||||
|
uint8_t deviceHead;
|
||||||
|
uint8_t command;
|
||||||
|
}AtaRegistersLBA28;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint16_t feature;
|
||||||
|
uint16_t sectorCount;
|
||||||
|
uint16_t lbaLow;
|
||||||
|
uint16_t lbaMid;
|
||||||
|
uint16_t lbaHigh;
|
||||||
|
uint8_t deviceHead;
|
||||||
|
uint8_t command;
|
||||||
|
} AtaRegistersLBA48;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t status;
|
||||||
|
uint8_t error;
|
||||||
|
uint8_t sectorCount;
|
||||||
|
uint8_t sector;
|
||||||
|
uint8_t cylinderLow;
|
||||||
|
uint8_t cylinderHigh;
|
||||||
|
uint8_t deviceHead;
|
||||||
|
uint8_t command;
|
||||||
|
}AtaErrorRegistersCHS;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t status;
|
||||||
|
uint8_t error;
|
||||||
|
uint8_t sectorCount;
|
||||||
|
uint8_t lbaLow;
|
||||||
|
uint8_t lbaMid;
|
||||||
|
uint8_t lbaHigh;
|
||||||
|
uint8_t deviceHead;
|
||||||
|
uint8_t command;
|
||||||
|
} AtaErrorRegistersLBA28;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t status;
|
||||||
|
uint8_t error;
|
||||||
|
uint16_t sectorCount;
|
||||||
|
uint16_t lbaLow;
|
||||||
|
uint16_t lbaMid;
|
||||||
|
uint16_t lbaHigh;
|
||||||
|
uint8_t deviceHead;
|
||||||
|
uint8_t command;
|
||||||
|
} AtaErrorRegistersLBA48;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
ATA_TRANSFER_NONE = 0,
|
||||||
|
ATA_TRANSFER_FEATURE,
|
||||||
|
ATA_TRANSFER_SECTORCOUNT,
|
||||||
|
ATA_TRANSFTER_SPTSIU
|
||||||
|
} AtaTransferRegister;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ATA_PROTOCOL_HARD_RESET = 0,
|
||||||
|
ATA_PROTOCOL_SOFT_RESET = 1,
|
||||||
|
ATA_PROTOCOL_NO_DATA = 3,
|
||||||
|
ATA_PROTOCOL_PIO_IN = 4,
|
||||||
|
ATA_PROTOCOL_PIO_OUT = 5,
|
||||||
|
ATA_PROTOCOL_DMA = 6,
|
||||||
|
ATA_PROTOCOL_DMA_QUEUED = 7,
|
||||||
|
ATA_PROTOCOL_DEVICE_DIAGNOSTICS = 8,
|
||||||
|
ATA_PROTOCOL_DEVICE_RESET = 9,
|
||||||
|
ATA_PROTOCOL_UDMA_IN = 10,
|
||||||
|
ATA_PROTOCOL_UDMA_OUT = 11,
|
||||||
|
ATA_PROTOCOL_FPDMA = 12,
|
||||||
|
ATA_PROTOCOL_RETURN_RESPONSE = 15
|
||||||
|
} AtaProtocol;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
ATA_IDENTIFY_PACKET_DEVICE = 0xA1,
|
||||||
|
ATA_IDENTIFY_DEVICE = 0xEC
|
||||||
|
} AtaCommands;
|
||||||
|
|
||||||
|
unsigned char *AtaToCString(unsigned char* string, int len);
|
||||||
|
int SendAtaCommandChs(int fd, AtaRegistersCHS registers, AtaErrorRegistersCHS **errorRegisters, int protocol, int transferRegister, unsigned char *buffer, unsigned int buffer_len, int transferBlocks);
|
||||||
|
int SendAtaCommandLba28(int fd, AtaRegistersLBA28 registers, AtaErrorRegistersLBA28 **errorRegisters, int protocol, int transferRegister, unsigned char *buffer, unsigned int buffer_len, int transferBlocks);
|
||||||
|
int SendAtaCommandLba48(int fd, AtaRegistersLBA48 registers, AtaErrorRegistersLBA48 **errorRegisters, int protocol, int transferRegister, unsigned char *buffer, unsigned int buffer_len, int transferBlocks);
|
||||||
|
int Identify(int fd, unsigned char **buffer, AtaErrorRegistersCHS **errorRegisters);
|
||||||
|
#endif //DISCIMAGECHEF_DEVICE_REPORT_ATA_H
|
||||||
22
DiscImageChef.Device.Report/atapi.c
Normal file
22
DiscImageChef.Device.Report/atapi.c
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
//
|
||||||
|
// Created by claunia on 12/12/17.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "ata.h"
|
||||||
|
#include "atapi.h"
|
||||||
|
|
||||||
|
int IdentifyPacket(int fd, unsigned char **buffer, AtaErrorRegistersCHS **errorRegisters)
|
||||||
|
{
|
||||||
|
*buffer = malloc(512);
|
||||||
|
memset(*buffer, 0, 512);
|
||||||
|
AtaRegistersCHS registers;
|
||||||
|
memset(®isters, 0, sizeof(AtaRegistersCHS));
|
||||||
|
|
||||||
|
registers.command = ATA_IDENTIFY_PACKET_DEVICE;
|
||||||
|
|
||||||
|
int error = SendAtaCommandChs(fd, registers, errorRegisters, ATA_PROTOCOL_PIO_IN, ATA_TRANSFER_NONE, *buffer, 512, 0);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
8
DiscImageChef.Device.Report/atapi.h
Normal file
8
DiscImageChef.Device.Report/atapi.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
//
|
||||||
|
// Created by claunia on 12/12/17.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DISCIMAGECHEF_DEVICE_REPORT_ATAPI_H
|
||||||
|
#define DISCIMAGECHEF_DEVICE_REPORT_ATAPI_H
|
||||||
|
int IdentifyPacket(int fd, unsigned char **buffer, AtaErrorRegistersCHS **errorRegisters);
|
||||||
|
#endif //DISCIMAGECHEF_DEVICE_REPORT_ATAPI_H
|
||||||
95
DiscImageChef.Device.Report/main.c
Normal file
95
DiscImageChef.Device.Report/main.c
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include "scsi.h"
|
||||||
|
#include "ata.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "atapi.h"
|
||||||
|
|
||||||
|
#define DIC_VERSION "3.99.6.0"
|
||||||
|
#define DIC_COPYRIGHT "Copyright © 2011-2017 Natalia Portillo"
|
||||||
|
|
||||||
|
int main(int argc, void *argv[])
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
unsigned char *scsi_sense = NULL;
|
||||||
|
unsigned char *scsi_inq_data = NULL;
|
||||||
|
unsigned char *ata_ident = NULL;
|
||||||
|
unsigned char *atapi_ident = NULL;
|
||||||
|
AtaErrorRegistersCHS *ata_error_chs;
|
||||||
|
int scsi_error, ata_error;
|
||||||
|
unsigned char* manufacturer;
|
||||||
|
unsigned char* product;
|
||||||
|
unsigned char* revision;
|
||||||
|
int deviceType = DEVICE_TYPE_UNKNOWN;
|
||||||
|
|
||||||
|
printf("The Disc Image Chef Device Reporter for Linux %s\n", DIC_VERSION);
|
||||||
|
printf("%s\n", DIC_COPYRIGHT);
|
||||||
|
|
||||||
|
if(argc != 2)
|
||||||
|
{
|
||||||
|
printf("Usage:\n");
|
||||||
|
printf("%s <device_path>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = open(argv[1], O_RDONLY | O_NONBLOCK);
|
||||||
|
|
||||||
|
if(fd < 0)
|
||||||
|
{
|
||||||
|
printf("Error opening device: %s\n", strerror(errno));
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Support MMC, USB, FireWire, PCMCIA
|
||||||
|
|
||||||
|
scsi_error = Inquiry(fd, &scsi_inq_data, &scsi_sense);
|
||||||
|
|
||||||
|
if(scsi_error)
|
||||||
|
scsi_inq_data = NULL;
|
||||||
|
|
||||||
|
if(scsi_inq_data != NULL)
|
||||||
|
{
|
||||||
|
manufacturer = malloc(9);
|
||||||
|
manufacturer[8] = 0;
|
||||||
|
product = malloc(17);
|
||||||
|
product[16] = 0;
|
||||||
|
revision = malloc(5);
|
||||||
|
revision[4] = 0;
|
||||||
|
|
||||||
|
strncpy(manufacturer, scsi_inq_data + 8, 8);
|
||||||
|
strncpy(product, scsi_inq_data + 16, 16);
|
||||||
|
strncpy(revision, scsi_inq_data + 32, 4);
|
||||||
|
|
||||||
|
deviceType = DEVICE_TYPE_SCSI;
|
||||||
|
|
||||||
|
ata_error = IdentifyPacket(fd, &atapi_ident, &ata_error_chs);
|
||||||
|
|
||||||
|
if(!ata_error)
|
||||||
|
deviceType = DEVICE_TYPE_ATAPI;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(scsi_inq_data == NULL || strcmp(manufacturer,"ATA"))
|
||||||
|
{
|
||||||
|
ata_error = Identify(fd, &ata_ident, &ata_error_chs);
|
||||||
|
|
||||||
|
if(!ata_error)
|
||||||
|
{
|
||||||
|
deviceType = DEVICE_TYPE_ATA;
|
||||||
|
revision = AtaToCString(ata_ident + (23*2), 8);
|
||||||
|
product = AtaToCString(ata_ident + (27*2), 40);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Device type: %s\n", DeviceType[deviceType]);
|
||||||
|
printf("Manufacturer: %s\n", manufacturer);
|
||||||
|
printf("Product: %s\n", product);
|
||||||
|
printf("Revision: %s\n", revision);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
21
DiscImageChef.Device.Report/main.h
Normal file
21
DiscImageChef.Device.Report/main.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
//
|
||||||
|
// Created by claunia on 11/12/17.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DISCIMAGECHEF_DEVICE_REPORT_MAIN_H
|
||||||
|
#define DISCIMAGECHEF_DEVICE_REPORT_MAIN_H
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
DEVICE_TYPE_UNKNOWN,
|
||||||
|
DEVICE_TYPE_SCSI,
|
||||||
|
DEVICE_TYPE_ATA,
|
||||||
|
DEVICE_TYPE_ATAPI,
|
||||||
|
DEVICE_TYPE_USB,
|
||||||
|
DEVICE_TYPE_FIREWIRE,
|
||||||
|
DEVICE_TYPE_PCMCIA,
|
||||||
|
DEVICE_TYPE_MMC,
|
||||||
|
DEVICE_TYPE_SD
|
||||||
|
} DeviceTypes;
|
||||||
|
|
||||||
|
const char* DeviceType[] = { "Unknown", "SCSI", "ATA", "ATAPI", "USB", "FireWire", "PCMCIA", "MultiMediaCard", "SecureDigital" };
|
||||||
|
#endif //DISCIMAGECHEF_DEVICE_REPORT_MAIN_H
|
||||||
66
DiscImageChef.Device.Report/scsi.c
Normal file
66
DiscImageChef.Device.Report/scsi.c
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
//
|
||||||
|
// Created by claunia on 11/12/17.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <unitypes.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <scsi/sg.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "scsi.h"
|
||||||
|
|
||||||
|
int SendScsiCommand(int fd, void *cdb, unsigned char cdb_len, unsigned char *buffer, unsigned int buffer_len, unsigned char **senseBuffer, int direction)
|
||||||
|
{
|
||||||
|
if(buffer == NULL || cdb == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
*senseBuffer = malloc(32);
|
||||||
|
memset(*senseBuffer, 0, 32);
|
||||||
|
|
||||||
|
sg_io_hdr_t io_hdr;
|
||||||
|
memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
|
||||||
|
|
||||||
|
io_hdr.interface_id = 'S';
|
||||||
|
io_hdr.cmd_len = cdb_len;
|
||||||
|
io_hdr.mx_sb_len = 32;
|
||||||
|
io_hdr.dxfer_direction = direction;
|
||||||
|
io_hdr.dxfer_len = buffer_len;
|
||||||
|
io_hdr.dxferp = buffer;
|
||||||
|
io_hdr.cmdp = cdb;
|
||||||
|
io_hdr.sbp = *senseBuffer;
|
||||||
|
io_hdr.timeout = 10000;
|
||||||
|
|
||||||
|
int error = ioctl(fd, SG_IO, &io_hdr);
|
||||||
|
|
||||||
|
if(error < 0)
|
||||||
|
error = errno;
|
||||||
|
else
|
||||||
|
free(*senseBuffer);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Inquiry(int fd, unsigned char **buffer, unsigned char **senseBuffer)
|
||||||
|
{
|
||||||
|
unsigned char cmd_len = 6;
|
||||||
|
*buffer = malloc(36);
|
||||||
|
memset(*buffer, 0, 36);
|
||||||
|
char cdb[] = {SCSI_INQUIRY, 0, 0, 0, 36, 0};
|
||||||
|
|
||||||
|
int error = SendScsiCommand(fd, &cdb, cmd_len, *buffer, 36, senseBuffer, SG_DXFER_FROM_DEV);
|
||||||
|
|
||||||
|
if(error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
unsigned char pagesLength = *(*buffer + 4) + 5;
|
||||||
|
|
||||||
|
free(*buffer);
|
||||||
|
*buffer = malloc(pagesLength);
|
||||||
|
memset(*buffer, 0, pagesLength);
|
||||||
|
|
||||||
|
cdb[4] = pagesLength;
|
||||||
|
error = SendScsiCommand(fd, &cdb, cmd_len, *buffer, pagesLength, senseBuffer, SG_DXFER_FROM_DEV);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
17
DiscImageChef.Device.Report/scsi.h
Normal file
17
DiscImageChef.Device.Report/scsi.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// Created by claunia on 11/12/17.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DISCIMAGECHEF_DEVICE_REPORT_SCSI_H
|
||||||
|
#define DISCIMAGECHEF_DEVICE_REPORT_SCSI_H
|
||||||
|
|
||||||
|
int SendScsiCommand(int fd, void *cdb, unsigned char cdb_len, unsigned char *buffer, unsigned int buffer_len, unsigned char **senseBuffer, int direction);
|
||||||
|
int Inquiry(int fd, unsigned char **buffer, unsigned char **senseBuffer);
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SCSI_INQUIRY = 0x12,
|
||||||
|
SCSI_ATA_PASSTHROUGH_16 = 0x85
|
||||||
|
} ScsiCommands;
|
||||||
|
|
||||||
|
#endif //DISCIMAGECHEF_DEVICE_REPORT_SCSI_H
|
||||||
Reference in New Issue
Block a user