From b78e268e5803215c31376a2187dd067c4a2ad4c4 Mon Sep 17 00:00:00 2001 From: Matej Kenda Date: Wed, 10 Jun 2026 23:48:52 +0200 Subject: [PATCH 1/2] fix: drive encryption detection treated MODE SENSE success as failure sg_modesense returns the transferred byte count (> 0) on success, but is_ame and sg_set_key compared the result against 0/DEVICE_GOOD. is_ame therefore always reported the drive as non-AME, and sg_set_key bailed out before issuing SECURITY PROTOCOL OUT, so setting a data key always failed on encrypting drives. Compare against < 0 like the other sg_modesense callers, and normalize sg_set_key's success return. Not verified on encrypting tape hardware; the logic follows the documented sg_modesense return convention. --- src/tape_drivers/linux/sg/sg_tape.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/tape_drivers/linux/sg/sg_tape.c b/src/tape_drivers/linux/sg/sg_tape.c index 19f2beb8..47b60132 100644 --- a/src/tape_drivers/linux/sg/sg_tape.c +++ b/src/tape_drivers/linux/sg/sg_tape.c @@ -4630,7 +4630,9 @@ static bool is_ame(void *device) unsigned char buf[TC_MP_READ_WRITE_CTRL_SIZE] = {0}; const int ret = sg_modesense(device, TC_MP_READ_WRITE_CTRL, TC_MP_PC_CURRENT, 0, buf, sizeof(buf)); - if (ret != 0) { + /* sg_modesense returns the transferred byte count (> 0) on success and a + * negative error code on failure. */ + if (ret < 0) { char message[100] = {0}; sprintf(message, "failed to get MP %02Xh (%d)", TC_MP_READ_WRITE_CTRL, ret); ltfsmsg(LTFS_DEBUG, 30392D, __FUNCTION__, message); @@ -4720,7 +4722,7 @@ int sg_set_key(void *device, const unsigned char *keyalias, const unsigned char unsigned char buf[TC_MP_READ_WRITE_CTRL_SIZE] = {0}; ret = sg_modesense(device, TC_MP_READ_WRITE_CTRL, TC_MP_PC_CURRENT, 0, buf, sizeof(buf)); - if (ret != DEVICE_GOOD) + if (ret < 0) /* sg_modesense returns a byte count (> 0) on success */ goto out; ltfs_u16tobe(buffer + 0, sps); @@ -4767,8 +4769,9 @@ int sg_set_key(void *device, const unsigned char *keyalias, const unsigned char memset(buf, 0, sizeof(buf)); ret = sg_modesense(device, TC_MP_READ_WRITE_CTRL, TC_MP_PC_CURRENT, 0, buf, sizeof(buf)); - if (ret != DEVICE_GOOD) + if (ret < 0) /* sg_modesense returns a byte count (> 0) on success */ goto out; + ret = DEVICE_GOOD; /* normalize the byte count to a success code */ free: free(buffer); From 4224ef21f8b966af3697c315f9c9e58413b75ff7 Mon Sep 17 00:00:00 2001 From: Matej Kenda Date: Fri, 12 Jun 2026 10:26:59 +0200 Subject: [PATCH 2/2] fix: iokit_set_xattr reported success as failure The function collected DEVICE_GOOD in ret when one of the vendor attributes matched, but returned the hardcoded initial error, so every successful set was reported as -LTFS_NO_XATTR. Return ret, matching the sg backend. Found by -Wunused-but-set-variable. Also remove two write-only variables in the same file. --- src/tape_drivers/osx/iokit/iokit_tape.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/tape_drivers/osx/iokit/iokit_tape.c b/src/tape_drivers/osx/iokit/iokit_tape.c index 76f14628..ea6b86bd 100644 --- a/src/tape_drivers/osx/iokit/iokit_tape.c +++ b/src/tape_drivers/osx/iokit/iokit_tape.c @@ -285,7 +285,7 @@ static int _get_dump(struct iokit_data *priv, char *fname) long long data_length, buf_offset; int dumpfd = -1; int transfer_size, num_transfers, excess_transfer; - int i, bytes; + int bytes; unsigned char cap_buf[DUMP_HEADER_SIZE]; unsigned char *dump_buf; int buf_id; @@ -331,14 +331,11 @@ static int _get_dump(struct iokit_data *priv, char *fname) /* start to transfer data */ buf_offset = 0; - i = 0; ltfsmsg(LTFS_DEBUG, 30859D); while(num_transfers) { int length; - i++; - /* Allocation Length is transfer_size or excess_transfer*/ if(excess_transfer && num_transfers == 1) length = excess_transfer; @@ -3412,7 +3409,9 @@ int iokit_set_xattr(void *device, const char *name, const char *buf, size_t size free(null_terminated); ltfs_profiler_add_entry(priv->profiler, NULL, TAPEBEND_REQ_EXIT(REQ_TC_SETXATTR)); - return -LTFS_NO_XATTR; + /* ret is DEVICE_GOOD when one of the vendor attributes matched above; + * returning the hardcoded failure reported success as an error. */ + return ret; } #define BLOCKLEN_DATA_SIZE 6 @@ -3629,7 +3628,7 @@ static const char *_generate_product_name(const char *product_id) int iokit_get_device_list(struct tc_drive_info *buf, int count) { - int i, ret; + int i; int found = 0; int32_t devs = iokit_get_ssc_device_count(); int drive_type; @@ -3646,10 +3645,7 @@ int iokit_get_device_list(struct tc_drive_info *buf, int count) if( devs > 0 ) { for (i = 0; i < devs; i++) { if(iokit_find_ssc_device(iokit_device, i) != 0) - { - ret = -EDEV_DEVICE_UNOPENABLE; continue; - } drive_type = iokit_get_drive_identifier(iokit_device, &identifier); if (!drive_type) { if (found < count && buf) { @@ -3665,7 +3661,7 @@ int iokit_get_device_list(struct tc_drive_info *buf, int count) } found ++; } - ret = iokit_free_device(iokit_device); + iokit_free_device(iokit_device); } }