Browse Source

Identity: implement generic error logging and permission checks

- Added robust validation check for empty model string payload to gracefully
  detect faulty drives or bridge timeouts without dropping execution path.
- Integrated universal descriptive [ERROR] and [WARNING] logging to  stderr.
- Implemented proactive EACCES/EPERM routing checks at libcam initialization
  to safely guide users regarding necessary root/sudo/devfs operational
  rights.
- Cleaned up string boundary array warning layouts inside src/libbsdiskinfo.c.
master
Sergey Kiselev 3 months ago
parent
commit
8d9b050dd9
  1. 4
      include/bsdiskinfo.h
  2. 8
      src/cli.c
  3. 139
      src/libbsdiskinfo.c

4
include/bsdiskinfo.h

@ -43,8 +43,8 @@
#define MAX_SATA_LEN 64 /* Buffer size for SATA signaling capabilities and link speed */ #define MAX_SATA_LEN 64 /* Buffer size for SATA signaling capabilities and link speed */
#define MAX_SEC_LEN 32 /* Buffer size for internal ATA Security feature state */ #define MAX_SEC_LEN 32 /* Buffer size for internal ATA Security feature state */
#define MAX_MOUNTS 128 #define MAX_MOUNTS 128 /* Maximum tracked active filesystem mount topologies */
#define MAX_DISKS 64 #define MAX_DISKS 64 /* Maximum concurrent physical storage units allowed */
/* /*
* Base hardware identity properties (similar to smartctl -i output). * Base hardware identity properties (similar to smartctl -i output).

8
src/cli.c

@ -87,22 +87,22 @@ static void print_identity(const char *disk_name, struct disk_properties *props)
printf("Serial Number: %s\n", props->serial); printf("Serial Number: %s\n", props->serial);
printf("Firmware Version: %s\n", props->fw_version); printf("Firmware Version: %s\n", props->fw_version);
printf("LU WWN Device Id: %s\n", props->wwn); printf("LU WWN Device Id: %s\n", props->wwn);
/* Display advanced ATA hardware descriptors unpacked by the core library */ /* Display advanced ATA hardware descriptors unpacked by the core library */
printf("Form Factor: %s\n", props->form_factor); /* Nominal physical unit size dimensions */ printf("Form Factor: %s\n", props->form_factor); /* Nominal physical unit size dimensions */
printf("ATA Version: %s\n", props->ata_version); /* Major compliance standard tracking */ printf("ATA Version: %s\n", props->ata_version); /* Major compliance standard tracking */
printf("SATA Version: %s\n", props->sata_version); /* Signalling standard interface capabilities */ printf("SATA Version: %s\n", props->sata_version); /* Signalling standard interface capabilities */
printf("ATA Security: %s\n", props->security_status); /* Operational hardware security locks state */ printf("ATA Security: %s\n", props->security_status); /* Operational hardware security locks state */
printf("Determined Type: %s\n", props->type_str); printf("Determined Type: %s\n", props->type_str);
/* Render storage payload storage capacity with explicit units computing */ /* Render storage payload storage capacity with explicit units computing */
double gib = (double)props->mediasize / (1024.0 * 1024.0 * 1024.0); double gib = (double)props->mediasize / (1024.0 * 1024.0 * 1024.0);
if (gib >= 1024.0) { if (gib >= 1024.0) {
printf("User Capacity: %llu bytes (%.2f TiB)\n", printf("User Capacity: %llu bytes (%.2f TiB)\n",
(unsigned long long)props->mediasize, gib / 1024.0); (unsigned long long)props->mediasize, gib / 1024.0);
} else { } else {
printf("User Capacity: %llu bytes (%.2f GiB)\n", printf("User Capacity: %llu bytes (%.2f GiB)\n",
(unsigned long long)props->mediasize, gib); (unsigned long long)props->mediasize, gib);
} }

139
src/libbsdiskinfo.c

@ -30,6 +30,7 @@
#define _GNU_SOURCE /* For strcasestr support */ #define _GNU_SOURCE /* For strcasestr support */
#include <errno.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/ucred.h> #include <sys/ucred.h>
#include <sys/mount.h> #include <sys/mount.h>
@ -246,24 +247,25 @@ static void parse_advanced_ata_fields(struct ata_params *buf, struct disk_proper
/* 2. Major ATA Version standard handling (Word 80 & Word 222 Transport Framework) */ /* 2. Major ATA Version standard handling (Word 80 & Word 222 Transport Framework) */
if (major == 0xFFFF || major == 0x0000) { if (major == 0xFFFF || major == 0x0000) {
strlcpy(props->ata_version, "Unknown", sizeof(props->ata_version)); fprintf(stderr, "[WARNING] ATA Version unreadable: Word 80 reports invalid boundary (0x%04X)\n", major);
strlcpy(props->ata_version, "Unknown (Invalid Word 80)", sizeof(props->ata_version));
} }
/* /*
* Detect actual ATA/ACS revision specification standard level by * Detect actual ATA/ACS revision specification standard level by
* cross-verifying backward-compatible Word 80 flags against physical Word 222 transport bits. * cross-verifying backward-compatible Word 80 flags against physical Word 222 transport bits.
*/ */
else if ((major & (1 << 14)) || ((major & (1 << 11)) && (transport & 0x1000) && (transport & 0x0040))) { else if ((major & (1 << 14)) || ((major & (1 << 11)) && (transport & 0x1000) && (transport & 0x0040))) {
/* Word 80 Bit 14 OR (ATA8-ACS bit + SATA 3.1+ transport bit 12 + SATA 3.3 bit 6) -> ACS-4 */
strlcpy(props->ata_version, "ACS-4", sizeof(props->ata_version)); strlcpy(props->ata_version, "ACS-4", sizeof(props->ata_version));
} else if ((major & (1 << 13)) || ((major & (1 << 10)) && (transport & 0x1000))) { } else if ((major & (1 << 13)) || ((major & (1 << 10)) && (transport & 0x1000))) {
/* Word 80 Bit 13 OR (ATA-7+ bit + SATA 3.1+ transport bit 12) -> ACS-3 */
strlcpy(props->ata_version, "ACS-3", sizeof(props->ata_version)); strlcpy(props->ata_version, "ACS-3", sizeof(props->ata_version));
} else if (major & (1 << 12)) { } else if (major & (1 << 12)) {
strlcpy(props->ata_version, "ACS-2", sizeof(props->ata_version)); strlcpy(props->ata_version, "ACS-2", sizeof(props->ata_version));
} else if (major & (1 << 11)) { } else if ((major & (1 << 11)) || (major & (1 << 8))) {
strlcpy(props->ata_version, "ATA8-ACS", sizeof(props->ata_version)); strlcpy(props->ata_version, "ATA8-ACS", sizeof(props->ata_version));
} else if (major & (1 << 10)) { } else if (major & (1 << 7)) {
strlcpy(props->ata_version, "ATA/ATAPI-7", sizeof(props->ata_version)); strlcpy(props->ata_version, "ATA/ATAPI-7", sizeof(props->ata_version));
} else if (major & (1 << 6)) {
strlcpy(props->ata_version, "ATA/ATAPI-6", sizeof(props->ata_version));
} else { } else {
snprintf(props->ata_version, sizeof(props->ata_version), "ATA Minor/Legacy (0x%04X)", major); snprintf(props->ata_version, sizeof(props->ata_version), "ATA Minor/Legacy (0x%04X)", major);
} }
@ -276,7 +278,6 @@ static void parse_advanced_ata_fields(struct ata_params *buf, struct disk_proper
if (transport != 0xFFFF && transport != 0x0000 && (transport & 0x1000)) { if (transport != 0xFFFF && transport != 0x0000 && (transport & 0x1000)) {
if (strcmp(props->ata_version, "ACS-4") == 0) { if (strcmp(props->ata_version, "ACS-4") == 0) {
/* ACS-4 devices can scale between SATA 3.2 and SATA 3.3 */
if ((transport & (1 << 6)) && (transport & 0x0100)) { if ((transport & (1 << 6)) && (transport & 0x0100)) {
ver = "SATA 3.3"; ver = "SATA 3.3";
} else { } else {
@ -295,7 +296,6 @@ static void parse_advanced_ata_fields(struct ata_params *buf, struct disk_proper
else if (sata_cap & 0x0002) ver = "SATA 1.0a"; else if (sata_cap & 0x0002) ver = "SATA 1.0a";
} }
/* Append signaling interface speed specs mapping data */
if (sata_cap & 0x0006) { if (sata_cap & 0x0006) {
snprintf(props->sata_version, sizeof(props->sata_version), "%s, 6.0 Gb/s", ver); snprintf(props->sata_version, sizeof(props->sata_version), "%s, 6.0 Gb/s", ver);
} else if (sata_cap & 0x0004) { } else if (sata_cap & 0x0004) {
@ -342,6 +342,17 @@ static void query_cam_properties(
strlcpy(props->sata_version, "N/A", sizeof(props->sata_version)); strlcpy(props->sata_version, "N/A", sizeof(props->sata_version));
strlcpy(props->security_status, "N/A", sizeof(props->security_status)); strlcpy(props->security_status, "N/A", sizeof(props->security_status));
/* CRITICAL Check: Permissions routing validation */
cam_dev = cam_open_device(base_disk, O_RDWR);
if (cam_dev == NULL) {
if (errno == EACCES || errno == EPERM) {
fprintf(stderr, "[ERROR] %s: Permission denied. Accessing libcam transport layers requires root privileges (run with sudo).\n", base_disk);
} else {
fprintf(stderr, "[ERROR] %s: Failed to open CAM device node (errno: %d)\n", base_disk, errno);
}
return;
}
/* CRITICAL: Must use O_RDWR for transport-layer commands execution path to unlock */ /* CRITICAL: Must use O_RDWR for transport-layer commands execution path to unlock */
cam_dev = cam_open_device(base_disk, O_RDWR); cam_dev = cam_open_device(base_disk, O_RDWR);
if (cam_dev == NULL) return; if (cam_dev == NULL) return;
@ -418,6 +429,11 @@ static void query_cam_properties(
success = 1; success = 1;
} }
} }
/* Filter out fake success on SAT(12) loop as well */
if (success && ident_buf->model[0] == 0) {
success = 0;
}
} }
if (success) { if (success) {
@ -463,7 +479,7 @@ static void query_cam_properties(
/* Parse advanced hardware descriptors from the verified buffer */ /* Parse advanced hardware descriptors from the verified buffer */
parse_advanced_ata_fields(ident_buf, props); parse_advanced_ata_fields(ident_buf, props);
/* Parse Sector Sizes (Word 106: Physical sector size) */ /* Parse Sector Sizes (Word 106: Physical sector size / Advanced Format) */
if ((ident_buf->pss & 0x4000) && (ident_buf->pss & 0x2000)) { if ((ident_buf->pss & 0x4000) && (ident_buf->pss & 0x2000)) {
props->physical_sector_size = props->logical_sector_size * (1 << (ident_buf->pss & 0x000F)); props->physical_sector_size = props->logical_sector_size * (1 << (ident_buf->pss & 0x000F));
} else { } else {
@ -478,6 +494,7 @@ static void query_cam_properties(
props->smart_supported = 0; props->smart_enabled = 0; props->smart_supported = 0; props->smart_enabled = 0;
} }
} else { } else {
fprintf(stderr, "[ERROR] %s: ATA Pass-Through rejected or returned empty payload (hardware timeout/fault)\n", base_disk);
*pt_failed = 1; *pt_failed = 1;
} }
} }
@ -493,61 +510,67 @@ static void query_cam_properties(
ccb->ataio.cmd.command = 0xEC; ccb->ataio.cmd.command = 0xEC;
if (cam_send_ccb(cam_dev, ccb) == 0 && (ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { if (cam_send_ccb(cam_dev, ccb) == 0 && (ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
char real_model[41]; if (ident_buf->model[0] == 0) {
memcpy(real_model, ident_buf->model, sizeof(ident_buf->model)); fprintf(stderr, "[ERROR] %s: IDENTIFY DEVICE returned empty payload (hardware fault)\n", base_disk);
real_model[sizeof(ident_buf->model)] = '\0';
ata_str_fix(real_model, sizeof(real_model));
if (strlen(real_model) > 0) strlcpy(props->model, real_model, sizeof(props->model));
char real_serial[21];
memcpy(real_serial, ident_buf->serial, sizeof(ident_buf->serial));
real_serial[sizeof(ident_buf->serial)] = '\0';
ata_str_fix(real_serial, sizeof(real_serial));
if (strlen(real_serial) > 0) strlcpy(props->serial, real_serial, sizeof(props->serial));
char real_fw[9];
memcpy(real_fw, ident_buf->revision, sizeof(ident_buf->revision));
real_fw[sizeof(ident_buf->revision)] = '\0';
ata_str_fix(real_fw, sizeof(real_fw));
if (strlen(real_fw) > 0) strlcpy(props->fw_version, real_fw, sizeof(props->fw_version));
/* Parse LU WWN Device ID */
uint64_t wwn_val = 0;
for (int w = 0; w < 4; w++) {
wwn_val |= ((uint64_t)ident_buf->wwn[w]) << ((3 - w) * 16);
}
if (wwn_val != 0) snprintf(props->wwn, sizeof(props->wwn), "%016llx", (unsigned long long)wwn_val);
else strlcpy(props->wwn, "N/A", sizeof(props->wwn));
/* Parse Rotation Rate and SSD state flags */
if (ident_buf->media_rotation_rate == 1) {
props->rotation_rate = 0;
*is_ssd = 1;
} else if (ident_buf->media_rotation_rate > 1 && ident_buf->media_rotation_rate < 0xFFFF) {
props->rotation_rate = ident_buf->media_rotation_rate;
*is_ssd = 0;
} else { } else {
props->rotation_rate = -1; char real_model[41];
*is_ssd = 0; memcpy(real_model, ident_buf->model, sizeof(ident_buf->model));
} real_model[sizeof(ident_buf->model)] = '\0';
ata_str_fix(real_model, sizeof(real_model));
if (strlen(real_model) > 0) strlcpy(props->model, real_model, sizeof(props->model));
/* Parse advanced hardware descriptors from the direct AHCI buffer */ char real_serial[21];
parse_advanced_ata_fields(ident_buf, props); memcpy(real_serial, ident_buf->serial, sizeof(ident_buf->serial));
real_serial[sizeof(ident_buf->serial)] = '\0';
ata_str_fix(real_serial, sizeof(real_serial));
if (strlen(real_serial) > 0) strlcpy(props->serial, real_serial, sizeof(props->serial));
/* Parse Sector Sizes (Word 106: Physical sector size) */ char real_fw[9];
if ((ident_buf->pss & 0x4000) && (ident_buf->pss & 0x2000)) { memcpy(real_fw, ident_buf->revision, sizeof(ident_buf->revision));
props->physical_sector_size = props->logical_sector_size * (1 << (ident_buf->pss & 0x000F)); real_fw[sizeof(ident_buf->revision)] = '\0';
} else { ata_str_fix(real_fw, sizeof(real_fw));
props->physical_sector_size = props->logical_sector_size; if (strlen(real_fw) > 0) strlcpy(props->fw_version, real_fw, sizeof(props->fw_version));
}
/* Parse S.M.A.R.T. enablement states */ /* Parse LU WWN Device ID */
if (ident_buf->support.command1 & 0x0001) { uint64_t wwn_val = 0;
props->smart_supported = 1; for (int w = 0; w < 4; w++) {
props->smart_enabled = (ident_buf->enabled.command1 & 0x0001) ? 1 : 0; wwn_val |= ((uint64_t)ident_buf->wwn[w]) << ((3 - w) * 16);
} else { }
props->smart_supported = 0; props->smart_enabled = 0; if (wwn_val != 0) snprintf(props->wwn, sizeof(props->wwn), "%016llx", (unsigned long long)wwn_val);
else strlcpy(props->wwn, "N/A", sizeof(props->wwn));
/* Parse Rotation Rate and SSD state flags */
if (ident_buf->media_rotation_rate == 1) {
props->rotation_rate = 0;
*is_ssd = 1;
} else if (ident_buf->media_rotation_rate > 1 && ident_buf->media_rotation_rate < 0xFFFF) {
props->rotation_rate = ident_buf->media_rotation_rate;
*is_ssd = 0;
} else {
props->rotation_rate = -1;
*is_ssd = 0;
}
/* Parse advanced hardware descriptors from the direct AHCI buffer */
parse_advanced_ata_fields(ident_buf, props);
/* Parse Sector Sizes (Word 106: Physical sector size / Advanced Format) */
if ((ident_buf->pss & 0x4000) && (ident_buf->pss & 0x2000)) {
props->physical_sector_size = props->logical_sector_size * (1 << (ident_buf->pss & 0x000F));
} else {
props->physical_sector_size = props->logical_sector_size;
}
/* Parse S.M.A.R.T. enablement states */
if (ident_buf->support.command1 & 0x0001) {
props->smart_supported = 1;
props->smart_enabled = (ident_buf->enabled.command1 & 0x0001) ? 1 : 0;
} else {
props->smart_supported = 0; props->smart_enabled = 0;
}
} }
} else {
fprintf(stderr, "[ERROR] %s: Native ATA IDENTIFY command rejected by the controller\n", base_disk);
} }
} }

Loading…
Cancel
Save