diff --git a/include/bsdiskinfo.h b/include/bsdiskinfo.h index b40770f..1ec7b4a 100644 --- a/include/bsdiskinfo.h +++ b/include/bsdiskinfo.h @@ -43,8 +43,8 @@ #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_MOUNTS 128 -#define MAX_DISKS 64 +#define MAX_MOUNTS 128 /* Maximum tracked active filesystem mount topologies */ +#define MAX_DISKS 64 /* Maximum concurrent physical storage units allowed */ /* * Base hardware identity properties (similar to smartctl -i output). diff --git a/src/cli.c b/src/cli.c index 00f24e2..fbd3d73 100644 --- a/src/cli.c +++ b/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("Firmware Version: %s\n", props->fw_version); printf("LU WWN Device Id: %s\n", props->wwn); - + /* Display advanced ATA hardware descriptors unpacked by the core library */ 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("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("Determined Type: %s\n", props->type_str); /* Render storage payload storage capacity with explicit units computing */ double gib = (double)props->mediasize / (1024.0 * 1024.0 * 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); } else { - printf("User Capacity: %llu bytes (%.2f GiB)\n", + printf("User Capacity: %llu bytes (%.2f GiB)\n", (unsigned long long)props->mediasize, gib); } diff --git a/src/libbsdiskinfo.c b/src/libbsdiskinfo.c index 5618d3b..d133637 100644 --- a/src/libbsdiskinfo.c +++ b/src/libbsdiskinfo.c @@ -30,6 +30,7 @@ #define _GNU_SOURCE /* For strcasestr support */ +#include #include #include #include @@ -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) */ 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 * 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))) { - /* 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)); } 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)); } else if (major & (1 << 12)) { 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)); - } else if (major & (1 << 10)) { + } else if (major & (1 << 7)) { 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 { 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 (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)) { ver = "SATA 3.3"; } 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"; } - /* Append signaling interface speed specs mapping data */ if (sata_cap & 0x0006) { snprintf(props->sata_version, sizeof(props->sata_version), "%s, 6.0 Gb/s", ver); } 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->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 */ cam_dev = cam_open_device(base_disk, O_RDWR); if (cam_dev == NULL) return; @@ -418,6 +429,11 @@ static void query_cam_properties( success = 1; } } + + /* Filter out fake success on SAT(12) loop as well */ + if (success && ident_buf->model[0] == 0) { + success = 0; + } } if (success) { @@ -463,7 +479,7 @@ static void query_cam_properties( /* Parse advanced hardware descriptors from the verified buffer */ 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)) { props->physical_sector_size = props->logical_sector_size * (1 << (ident_buf->pss & 0x000F)); } else { @@ -478,6 +494,7 @@ static void query_cam_properties( props->smart_supported = 0; props->smart_enabled = 0; } } else { + fprintf(stderr, "[ERROR] %s: ATA Pass-Through rejected or returned empty payload (hardware timeout/fault)\n", base_disk); *pt_failed = 1; } } @@ -493,61 +510,67 @@ static void query_cam_properties( ccb->ataio.cmd.command = 0xEC; if (cam_send_ccb(cam_dev, ccb) == 0 && (ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { - char real_model[41]; - 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)); - - 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; + if (ident_buf->model[0] == 0) { + fprintf(stderr, "[ERROR] %s: IDENTIFY DEVICE returned empty payload (hardware fault)\n", base_disk); } else { - props->rotation_rate = -1; - *is_ssd = 0; - } + char real_model[41]; + 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 */ - parse_advanced_ata_fields(ident_buf, props); + 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)); - /* Parse Sector Sizes (Word 106: Physical sector size) */ - 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; - } + 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 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; + /* 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 { + 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); } }