From 0b4398d6074473b65e779a05feb5911ad42cb2e3 Mon Sep 17 00:00:00 2001 From: JerryWang Date: Mon, 27 May 2024 15:45:22 +0800 Subject: [PATCH 1/9] [Add] Transcend plugin command for PLP health --- .../nvme-transcend-plphealthvalue.txt | 38 ++ plugins/transcend/transcend-nvme.c | 354 +++++++++++++++++- plugins/transcend/transcend-nvme.h | 2 +- 3 files changed, 380 insertions(+), 14 deletions(-) create mode 100644 Documentation/nvme-transcend-plphealthvalue.txt diff --git a/Documentation/nvme-transcend-plphealthvalue.txt b/Documentation/nvme-transcend-plphealthvalue.txt new file mode 100644 index 0000000000..930a1e546e --- /dev/null +++ b/Documentation/nvme-transcend-plphealthvalue.txt @@ -0,0 +1,38 @@ +nvme-transcend-plphealthvalue(1) +============================= + +NAME +---- +nvme-transcend-plphealthvalue - Use NVMe SMART table to analyze the plp health value of +Transcend device. + +SYNOPSIS +-------- +[verse] +'nvme transcend plphealthvalue' + +DESCRIPTION +----------- +Retrieves the NVMe Device SMART log page from the Transcend device and evaluate +plp health status of Transcend device. + +The parameter is mandatory and may be either the NVMe character +device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1). + +On success, the returned value would print plp health percentage value. + +OPTIONS +------- +none + +EXAMPLES +-------- +* Print the Transcend Device plp health value in a human readable format: ++ +------------ +# nvme transcend plphealthvalue /dev/nvme0 +------------ + +NVME +---- +Part of the nvme-user suite diff --git a/plugins/transcend/transcend-nvme.c b/plugins/transcend/transcend-nvme.c index 547fbf4ea9..070159b7ef 100644 --- a/plugins/transcend/transcend-nvme.c +++ b/plugins/transcend/transcend-nvme.c @@ -9,39 +9,90 @@ #include "nvme.h" #include "libnvme.h" #include "plugin.h" +#include +#include #define CREATE_CMD + +#define PLPRecordPath "PLPRec.txt" +#define PLPDataExpiredTime 20 + #include "transcend-nvme.h" static const __u32 OP_BAD_BLOCK = 0xc2; static const __u32 DW10_BAD_BLOCK = 0x400; static const __u32 DW12_BAD_BLOCK = 0x5a; +static const __u32 OP_HEALTH = 0xc2; +static const __u32 DW10_HEALTH = 0x01; +static const __u32 DW12_HEALTH = 0xb3; + +static const __u32 OP_ID = 0x06; +static const __u32 DW10_ID = 0x01; + +static const int iDis = 20; +static const double fullValue = 170; + +enum PLPErrorCode +{ + PLP_ERROR_NO_MATCH = -1, + PLP_ERROR_DATA_EXPIRED = -2 +}; + +const char *string_list[] = { + "UTE210T", + "MTE712P", + "MTE560P", + "MTE662P", + "MTE662P-I", + "MTS970P", + "MTS952P", + "MTS952P-I", + "MTS570P", + "MTS400P", + "SSD910T", + "SSD470P", + "SSD470P-I", + "SSD452P", + "SSD452P-I", + "SSD420P", + "MSA470P", + "MSA452P"}; +const int list_size = sizeof(string_list) / sizeof(string_list[0]); + +static int getPLPHealth(int argc, char **argv, struct command *cmd, struct plugin *plugin); +static int readUsefulPLPValue(const char *device); +static void recordPLPValue(const char *device, int value, bool isReplace); + static int getHealthValue(int argc, char **argv, struct command *cmd, struct plugin *plugin) { struct nvme_smart_log smart_log; char *desc = "Get nvme health percentage."; - int percent_used = 0, healthvalue = 0; + int percent_used = 0, healthvalue = 0; struct nvme_dev *dev; int result; OPT_ARGS(opts) = { - OPT_END() - }; + OPT_END()}; result = parse_and_open(&dev, argc, argv, desc, opts); - if (result) { + if (result) + { printf("\nDevice not found\n"); - return -1; + return PLP_ERROR_NO_MATCH; } result = nvme_get_log_smart(dev_fd(dev), 0xffffffff, false, &smart_log); - if (!result) { + if (!result) + { printf("Transcend NVME heath value: "); percent_used = smart_log.percent_used; - if (percent_used > 100 || percent_used < 0) { + if (percent_used > 100 || percent_used < 0) + { printf("0%%\n"); - } else { + } + else + { healthvalue = 100 - percent_used; printf("%d%%\n", healthvalue); } @@ -58,11 +109,11 @@ static int getBadblock(int argc, char **argv, struct command *cmd, struct plugin int result; OPT_ARGS(opts) = { - OPT_END() - }; + OPT_END()}; result = parse_and_open(&dev, argc, argv, desc, opts); - if (result) { + if (result) + { printf("\nDevice not found\n"); return -1; } @@ -76,11 +127,288 @@ static int getBadblock(int argc, char **argv, struct command *cmd, struct plugin nvmecmd.addr = (__u64)(uintptr_t)data; nvmecmd.data_len = 0x1; result = nvme_submit_admin_passthru(dev_fd(dev), &nvmecmd, NULL); - if (!result) { - int badblock = data[0]; + if (!result) + { + int badblock = data[0]; printf("Transcend NVME badblock count: %d\n", badblock); } dev_close(dev); return result; } + +const char *format_char_array(char *str, int strsize, unsigned char *chr, int chrsize) +{ + int b = 0; + while (b < chrsize && chr[b] == ' ') + b++; + int n = 0; + while (b + n < chrsize && chr[b + n]) + n++; + while (n > 0 && chr[b + n - 1] == ' ') + n--; + + if (n >= strsize) + n = strsize - 1; + + for (int i = 0; i < n; i++) + { + char c = chr[b + i]; + str[i] = (' ' <= c && c <= '~' ? c : '?'); + } + str[n] = 0; + return str; +} + +int contains_string(const char *str) +{ + for (int i = 0; i < list_size; i++) + { + if (strstr(str, string_list[i]) != NULL) + { + return 1; + } + } + return 0; +} + +static int getPLPHealth(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + char *desc = "Get nvme PLP Health."; + struct nvme_dev *dev; + int result; + int txtPLPHealth = -1; + int plpHealth_percentage = -1; + OPT_ARGS(opts) = { + OPT_END()}; + + result = parse_and_open(&dev, argc, argv, desc, opts); + if (result) + { + printf("\nDevice not found\n"); + return -1; + } + + unsigned char dataID[4096]; + struct nvme_passthru_cmd nvmecmdID; + + memset(&nvmecmdID, 0, sizeof(nvmecmdID)); + nvmecmdID.opcode = OP_ID; + nvmecmdID.cdw10 = DW10_ID; + nvmecmdID.addr = (__u64)(uintptr_t)dataID; + nvmecmdID.data_len = 4096; + result = nvme_submit_admin_passthru(dev_fd(dev), &nvmecmdID, NULL); + if (result) + { + printf("\nThis device is not support.\n"); + return -1; + } + else + { + char modelName[40]; + const char *model_str_byte; + model_str_byte = format_char_array((char *)modelName, sizeof(modelName), dataID, sizeof(dataID)); + if (!contains_string(model_str_byte)) + { + printf("\nThis device is not support.\n"); + return -1; + } + } + + txtPLPHealth = readUsefulPLPValue(dev->name); + if (txtPLPHealth >= 0) + { + plpHealth_percentage = txtPLPHealth; + printf("Capacitor health for PLP: %d%%\n", plpHealth_percentage); + } + else + { + unsigned char data[512]; + struct nvme_passthru_cmd nvmecmd; + + memset(&nvmecmd, 0, sizeof(nvmecmd)); + nvmecmd.opcode = OP_HEALTH; + nvmecmd.cdw10 = DW10_HEALTH; + nvmecmd.cdw12 = DW12_HEALTH; + nvmecmd.addr = (__u64)(uintptr_t)data; + nvmecmd.data_len = 512; + result = nvme_submit_admin_passthru(dev_fd(dev), &nvmecmd, NULL); + if (result) + { + printf("\nGet PLP Health Fail.\n"); + return PLP_ERROR_NO_MATCH; + } + else + { + int tDis = (int)(data[4 + 3] << 24) + (int)(data[4 + 2] << 16) + (int)(data[4 + 1] << 8) + (int)(data[4]); + int vDis1 = (int)(data[0]); + int vDis2 = (int)(data[1]); + if (vDis1 != 0 || vDis2 != 0) + { + int normalHealth = 0; + + if (vDis1 - vDis2 != 0) + { + normalHealth = (iDis * tDis) / (vDis1 - vDis2); + } + else + { + normalHealth = 0; + } + if (normalHealth >= 0) + { + if (fullValue - normalHealth >= 0) + { + plpHealth_percentage = (normalHealth / fullValue) * 100; + } + else + { + plpHealth_percentage = 100; + } + } + else + { + plpHealth_percentage = 0; + } + printf("Capacitor health for PLP: %d%%\n", plpHealth_percentage); + } + } + } + if (plpHealth_percentage >= 0) + { + if (txtPLPHealth == PLP_ERROR_DATA_EXPIRED) + { + recordPLPValue(dev->name, plpHealth_percentage, true); + } + else + { + recordPLPValue(dev->name, plpHealth_percentage, false); + } + } + dev_close(dev); + return result; +} + +int readUsefulPLPValue(const char *device) +{ + FILE *file; + char logFilePath[256]; + char str[256]; + char matchedStr[256] = ""; + int ret = -1; + + snprintf(logFilePath, sizeof(logFilePath), "%s", PLPRecordPath); + file = fopen(logFilePath, "r"); + if (!file) + { + return PLP_ERROR_NO_MATCH; + } + + while (fgets(str, sizeof(str), file)) + { + if (strncmp(str, device, strlen(device)) == 0) + { + strcpy(matchedStr, str); + break; + } + } + + fclose(file); + + if (matchedStr[0] == '\0') + { + return PLP_ERROR_NO_MATCH; + } + + char *token; + token = strtok(matchedStr, "#"); + token = strtok(NULL, "#"); + struct tm tm; + memset(&tm, 0, sizeof(tm)); + strptime(token, "%a %b %d %H:%M:%S %Y", &tm); + time_t t = mktime(&tm); + + time_t t_current = time(NULL); + int timeDiff = difftime(t_current, t); + + if (timeDiff <= PLPDataExpiredTime) + { + token = strtok(NULL, "#"); + ret = atoi(token); + return ret; + } + else + { + return PLP_ERROR_DATA_EXPIRED; + } +} + +void recordPLPValue(const char *device, int value, bool isReplace) +{ + char logFilePath[256]; + strncpy(logFilePath, PLPRecordPath, sizeof(logFilePath) - 1); + logFilePath[sizeof(logFilePath) - 1] = '\0'; + char tempFilePath[] = "temp.txt"; + + time_t ct = time(0); + char *timeStr = ctime(&ct); + if (timeStr == NULL) + { + perror("Error getting current time"); + return; + } + timeStr[strcspn(timeStr, "\n")] = '\0'; + + char line[256]; + sprintf(line, "%s#%s#%d", device, timeStr, value); + + if (isReplace) + { + FILE *filein = fopen(logFilePath, "r"); + FILE *fileout = fopen(tempFilePath, "w"); + if (filein == NULL || fileout == NULL) + { + perror("Error opening file"); + if (filein != NULL) + fclose(filein); + if (fileout != NULL) + fclose(fileout); + return; + } + + char str[256]; + while (fgets(str, sizeof(str), filein)) + { + if (strncmp(str, device, strlen(device)) == 0) + { + fprintf(fileout, "%s\n", line); + } + else + { + fprintf(fileout, "%s", str); + } + } + fclose(filein); + fclose(fileout); + + if (remove(logFilePath) == 0) + { + rename(tempFilePath, logFilePath); + } + else + { + remove(tempFilePath); + } + } + else + { + FILE *out = fopen(logFilePath, "a"); + if (out == NULL) + { + perror("Error opening file"); + return; + } + fprintf(out, "%s\n", line); + fclose(out); + } +} diff --git a/plugins/transcend/transcend-nvme.h b/plugins/transcend/transcend-nvme.h index 9c8988380c..c89027731c 100644 --- a/plugins/transcend/transcend-nvme.h +++ b/plugins/transcend/transcend-nvme.h @@ -12,7 +12,7 @@ PLUGIN(NAME("transcend", "Transcend vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("healthvalue", "NVME health percentage", getHealthValue) ENTRY("badblock", "Get NVME bad block number", getBadblock) - + ENTRY("plphealthvalue", "Get NVME PLP Health.", getPLPHealth) ) ); From 2049e2988a17bf27363d36dbb1995c7c44c2bd2b Mon Sep 17 00:00:00 2001 From: JerryWang Date: Mon, 27 May 2024 15:53:44 +0800 Subject: [PATCH 2/9] [Add] Transcend plugin command for PLP health --- meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/meson.build b/meson.build index 11f7cc5453..b1cd669976 100644 --- a/meson.build +++ b/meson.build @@ -281,6 +281,7 @@ sources = [ 'nvme-wrap.c', 'plugin.c', 'libnvme-wrap.c', + 'plugins/transcend/transcend-nvme.c' ] if json_c_dep.found() sources += [ From 55133c4d03bdd6e2991c6cb07b16e84b773fcde5 Mon Sep 17 00:00:00 2001 From: JerryWang Date: Mon, 21 Oct 2024 15:20:19 +0800 Subject: [PATCH 3/9] coding sytle fixed --- meson.build | 1 - plugins/transcend/transcend-nvme.c | 139 +++++++++++------------------ 2 files changed, 54 insertions(+), 86 deletions(-) diff --git a/meson.build b/meson.build index b1cd669976..11f7cc5453 100644 --- a/meson.build +++ b/meson.build @@ -281,7 +281,6 @@ sources = [ 'nvme-wrap.c', 'plugin.c', 'libnvme-wrap.c', - 'plugins/transcend/transcend-nvme.c' ] if json_c_dep.found() sources += [ diff --git a/plugins/transcend/transcend-nvme.c b/plugins/transcend/transcend-nvme.c index 070159b7ef..96d4aa4db0 100644 --- a/plugins/transcend/transcend-nvme.c +++ b/plugins/transcend/transcend-nvme.c @@ -58,7 +58,7 @@ const char *string_list[] = { "SSD420P", "MSA470P", "MSA452P"}; -const int list_size = sizeof(string_list) / sizeof(string_list[0]); +const int list_size = ARRAY_SIZE(string_list) / sizeof(string_list[0]); static int getPLPHealth(int argc, char **argv, struct command *cmd, struct plugin *plugin); static int readUsefulPLPValue(const char *device); @@ -68,31 +68,29 @@ static int getHealthValue(int argc, char **argv, struct command *cmd, struct plu { struct nvme_smart_log smart_log; char *desc = "Get nvme health percentage."; - int percent_used = 0, healthvalue = 0; + int percent_used = 0; + int healthvalue = 0; struct nvme_dev *dev; int result; OPT_ARGS(opts) = { - OPT_END()}; + OPT_END() + }; result = parse_and_open(&dev, argc, argv, desc, opts); - if (result) - { + if (result) { printf("\nDevice not found\n"); return PLP_ERROR_NO_MATCH; } result = nvme_get_log_smart(dev_fd(dev), 0xffffffff, false, &smart_log); - if (!result) - { + if (!result) { printf("Transcend NVME heath value: "); percent_used = smart_log.percent_used; - if (percent_used > 100 || percent_used < 0) - { + if (percent_used > 100 || percent_used < 0) { printf("0%%\n"); } - else - { + else { healthvalue = 100 - percent_used; printf("%d%%\n", healthvalue); } @@ -109,11 +107,11 @@ static int getBadblock(int argc, char **argv, struct command *cmd, struct plugin int result; OPT_ARGS(opts) = { - OPT_END()}; + OPT_END() + }; result = parse_and_open(&dev, argc, argv, desc, opts); - if (result) - { + if (result) { printf("\nDevice not found\n"); return -1; } @@ -127,10 +125,8 @@ static int getBadblock(int argc, char **argv, struct command *cmd, struct plugin nvmecmd.addr = (__u64)(uintptr_t)data; nvmecmd.data_len = 0x1; result = nvme_submit_admin_passthru(dev_fd(dev), &nvmecmd, NULL); - if (!result) - { + if (!result) { int badblock = data[0]; - printf("Transcend NVME badblock count: %d\n", badblock); } dev_close(dev); @@ -140,22 +136,26 @@ static int getBadblock(int argc, char **argv, struct command *cmd, struct plugin const char *format_char_array(char *str, int strsize, unsigned char *chr, int chrsize) { int b = 0; + int n = 0; + int i; + while (b < chrsize && chr[b] == ' ') b++; - int n = 0; + while (b + n < chrsize && chr[b + n]) n++; + while (n > 0 && chr[b + n - 1] == ' ') n--; if (n >= strsize) n = strsize - 1; - for (int i = 0; i < n; i++) - { + for (i = 0; i < n; i++) { char c = chr[b + i]; str[i] = (' ' <= c && c <= '~' ? c : '?'); } + str[n] = 0; return str; } @@ -180,11 +180,11 @@ static int getPLPHealth(int argc, char **argv, struct command *cmd, struct plugi int txtPLPHealth = -1; int plpHealth_percentage = -1; OPT_ARGS(opts) = { - OPT_END()}; + OPT_END() + }; result = parse_and_open(&dev, argc, argv, desc, opts); - if (result) - { + if (result) { printf("\nDevice not found\n"); return -1; } @@ -198,31 +198,26 @@ static int getPLPHealth(int argc, char **argv, struct command *cmd, struct plugi nvmecmdID.addr = (__u64)(uintptr_t)dataID; nvmecmdID.data_len = 4096; result = nvme_submit_admin_passthru(dev_fd(dev), &nvmecmdID, NULL); - if (result) - { + if (result) { printf("\nThis device is not support.\n"); return -1; } - else - { + else { char modelName[40]; const char *model_str_byte; model_str_byte = format_char_array((char *)modelName, sizeof(modelName), dataID, sizeof(dataID)); - if (!contains_string(model_str_byte)) - { + if (!contains_string(model_str_byte)) { printf("\nThis device is not support.\n"); return -1; } } txtPLPHealth = readUsefulPLPValue(dev->name); - if (txtPLPHealth >= 0) - { + if (txtPLPHealth >= 0) { plpHealth_percentage = txtPLPHealth; printf("Capacitor health for PLP: %d%%\n", plpHealth_percentage); } - else - { + else { unsigned char data[512]; struct nvme_passthru_cmd nvmecmd; @@ -233,55 +228,43 @@ static int getPLPHealth(int argc, char **argv, struct command *cmd, struct plugi nvmecmd.addr = (__u64)(uintptr_t)data; nvmecmd.data_len = 512; result = nvme_submit_admin_passthru(dev_fd(dev), &nvmecmd, NULL); - if (result) - { + if (result) { printf("\nGet PLP Health Fail.\n"); return PLP_ERROR_NO_MATCH; } - else - { + else { int tDis = (int)(data[4 + 3] << 24) + (int)(data[4 + 2] << 16) + (int)(data[4 + 1] << 8) + (int)(data[4]); int vDis1 = (int)(data[0]); int vDis2 = (int)(data[1]); - if (vDis1 != 0 || vDis2 != 0) - { + if (vDis1 != 0 || vDis2 != 0) { int normalHealth = 0; - if (vDis1 - vDis2 != 0) - { + if (vDis1 - vDis2 != 0) { normalHealth = (iDis * tDis) / (vDis1 - vDis2); } - else - { + else { normalHealth = 0; } - if (normalHealth >= 0) - { - if (fullValue - normalHealth >= 0) - { + if (normalHealth >= 0) { + if (fullValue - normalHealth >= 0) { plpHealth_percentage = (normalHealth / fullValue) * 100; } - else - { + else { plpHealth_percentage = 100; } } - else - { + else { plpHealth_percentage = 0; } printf("Capacitor health for PLP: %d%%\n", plpHealth_percentage); } } } - if (plpHealth_percentage >= 0) - { - if (txtPLPHealth == PLP_ERROR_DATA_EXPIRED) - { + if (plpHealth_percentage >= 0) { + if (txtPLPHealth == PLP_ERROR_DATA_EXPIRED) { recordPLPValue(dev->name, plpHealth_percentage, true); } - else - { + else { recordPLPValue(dev->name, plpHealth_percentage, false); } } @@ -299,15 +282,13 @@ int readUsefulPLPValue(const char *device) snprintf(logFilePath, sizeof(logFilePath), "%s", PLPRecordPath); file = fopen(logFilePath, "r"); - if (!file) - { + if (!file) { return PLP_ERROR_NO_MATCH; } while (fgets(str, sizeof(str), file)) { - if (strncmp(str, device, strlen(device)) == 0) - { + if (strncmp(str, device, strlen(device)) == 0) { strcpy(matchedStr, str); break; } @@ -315,8 +296,7 @@ int readUsefulPLPValue(const char *device) fclose(file); - if (matchedStr[0] == '\0') - { + if (matchedStr[0] == '\0') { return PLP_ERROR_NO_MATCH; } @@ -331,14 +311,12 @@ int readUsefulPLPValue(const char *device) time_t t_current = time(NULL); int timeDiff = difftime(t_current, t); - if (timeDiff <= PLPDataExpiredTime) - { + if (timeDiff <= PLPDataExpiredTime) { token = strtok(NULL, "#"); ret = atoi(token); return ret; } - else - { + else { return PLP_ERROR_DATA_EXPIRED; } } @@ -352,8 +330,7 @@ void recordPLPValue(const char *device, int value, bool isReplace) time_t ct = time(0); char *timeStr = ctime(&ct); - if (timeStr == NULL) - { + if (timeStr == NULL) { perror("Error getting current time"); return; } @@ -362,12 +339,10 @@ void recordPLPValue(const char *device, int value, bool isReplace) char line[256]; sprintf(line, "%s#%s#%d", device, timeStr, value); - if (isReplace) - { + if (isReplace) { FILE *filein = fopen(logFilePath, "r"); FILE *fileout = fopen(tempFilePath, "w"); - if (filein == NULL || fileout == NULL) - { + if (filein == NULL || fileout == NULL) { perror("Error opening file"); if (filein != NULL) fclose(filein); @@ -379,32 +354,26 @@ void recordPLPValue(const char *device, int value, bool isReplace) char str[256]; while (fgets(str, sizeof(str), filein)) { - if (strncmp(str, device, strlen(device)) == 0) - { + if (strncmp(str, device, strlen(device)) == 0) { fprintf(fileout, "%s\n", line); } - else - { + else { fprintf(fileout, "%s", str); } } fclose(filein); fclose(fileout); - if (remove(logFilePath) == 0) - { + if (remove(logFilePath) == 0) { rename(tempFilePath, logFilePath); } - else - { + else { remove(tempFilePath); } } - else - { + else { FILE *out = fopen(logFilePath, "a"); - if (out == NULL) - { + if (out == NULL) { perror("Error opening file"); return; } From 25d6e908559e787b758cbbd0c0ee128c2841877c Mon Sep 17 00:00:00 2001 From: JerryWang Date: Tue, 22 Oct 2024 15:59:06 +0800 Subject: [PATCH 4/9] Build error fixed --- plugins/transcend/transcend-nvme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/transcend/transcend-nvme.c b/plugins/transcend/transcend-nvme.c index 96d4aa4db0..1978f66a86 100644 --- a/plugins/transcend/transcend-nvme.c +++ b/plugins/transcend/transcend-nvme.c @@ -58,7 +58,7 @@ const char *string_list[] = { "SSD420P", "MSA470P", "MSA452P"}; -const int list_size = ARRAY_SIZE(string_list) / sizeof(string_list[0]); +const int list_size = sizeof(string_list) / sizeof(string_list[0]); static int getPLPHealth(int argc, char **argv, struct command *cmd, struct plugin *plugin); static int readUsefulPLPValue(const char *device); From 69701d50e1f5eba389069f85dcf2755179b7316a Mon Sep 17 00:00:00 2001 From: JerryWang Date: Tue, 22 Oct 2024 16:33:02 +0800 Subject: [PATCH 5/9] Build error fixed --- plugins/transcend/transcend-nvme.c | 5 ++--- plugins/transcend/transcend-nvme.h | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/plugins/transcend/transcend-nvme.c b/plugins/transcend/transcend-nvme.c index 1978f66a86..3376c765a2 100644 --- a/plugins/transcend/transcend-nvme.c +++ b/plugins/transcend/transcend-nvme.c @@ -33,8 +33,7 @@ static const __u32 DW10_ID = 0x01; static const int iDis = 20; static const double fullValue = 170; -enum PLPErrorCode -{ +enum PLPErrorCode { PLP_ERROR_NO_MATCH = -1, PLP_ERROR_DATA_EXPIRED = -2 }; @@ -58,7 +57,7 @@ const char *string_list[] = { "SSD420P", "MSA470P", "MSA452P"}; -const int list_size = sizeof(string_list) / sizeof(string_list[0]); +const int list_size = ARRAY_SIZE(string_list) / sizeof(string_list[0]); static int getPLPHealth(int argc, char **argv, struct command *cmd, struct plugin *plugin); static int readUsefulPLPValue(const char *device); diff --git a/plugins/transcend/transcend-nvme.h b/plugins/transcend/transcend-nvme.h index c89027731c..289562f0fa 100644 --- a/plugins/transcend/transcend-nvme.h +++ b/plugins/transcend/transcend-nvme.h @@ -4,7 +4,7 @@ #if !defined(TRANSCEND_NVME) || defined(CMD_HEADER_MULTI_READ) #define TRANSCEND_NVME - +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #include "cmd.h" From 3f47f5c8de579d18056ca344e640a635c2f1eb17 Mon Sep 17 00:00:00 2001 From: JerryWang Date: Tue, 22 Oct 2024 16:44:11 +0800 Subject: [PATCH 6/9] Fixed for coding sytle --- plugins/transcend/transcend-nvme.c | 33 ++++++++++-------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/plugins/transcend/transcend-nvme.c b/plugins/transcend/transcend-nvme.c index 3376c765a2..25d1209aaa 100644 --- a/plugins/transcend/transcend-nvme.c +++ b/plugins/transcend/transcend-nvme.c @@ -88,8 +88,7 @@ static int getHealthValue(int argc, char **argv, struct command *cmd, struct plu if (percent_used > 100 || percent_used < 0) { printf("0%%\n"); - } - else { + } else { healthvalue = 100 - percent_used; printf("%d%%\n", healthvalue); } @@ -200,8 +199,7 @@ static int getPLPHealth(int argc, char **argv, struct command *cmd, struct plugi if (result) { printf("\nThis device is not support.\n"); return -1; - } - else { + } else { char modelName[40]; const char *model_str_byte; model_str_byte = format_char_array((char *)modelName, sizeof(modelName), dataID, sizeof(dataID)); @@ -215,8 +213,7 @@ static int getPLPHealth(int argc, char **argv, struct command *cmd, struct plugi if (txtPLPHealth >= 0) { plpHealth_percentage = txtPLPHealth; printf("Capacitor health for PLP: %d%%\n", plpHealth_percentage); - } - else { + } else { unsigned char data[512]; struct nvme_passthru_cmd nvmecmd; @@ -230,8 +227,7 @@ static int getPLPHealth(int argc, char **argv, struct command *cmd, struct plugi if (result) { printf("\nGet PLP Health Fail.\n"); return PLP_ERROR_NO_MATCH; - } - else { + } else { int tDis = (int)(data[4 + 3] << 24) + (int)(data[4 + 2] << 16) + (int)(data[4 + 1] << 8) + (int)(data[4]); int vDis1 = (int)(data[0]); int vDis2 = (int)(data[1]); @@ -240,19 +236,16 @@ static int getPLPHealth(int argc, char **argv, struct command *cmd, struct plugi if (vDis1 - vDis2 != 0) { normalHealth = (iDis * tDis) / (vDis1 - vDis2); - } - else { + } else { normalHealth = 0; } if (normalHealth >= 0) { if (fullValue - normalHealth >= 0) { plpHealth_percentage = (normalHealth / fullValue) * 100; - } - else { + } else { plpHealth_percentage = 100; } - } - else { + } else { plpHealth_percentage = 0; } printf("Capacitor health for PLP: %d%%\n", plpHealth_percentage); @@ -314,8 +307,7 @@ int readUsefulPLPValue(const char *device) token = strtok(NULL, "#"); ret = atoi(token); return ret; - } - else { + } else { return PLP_ERROR_DATA_EXPIRED; } } @@ -355,8 +347,7 @@ void recordPLPValue(const char *device, int value, bool isReplace) { if (strncmp(str, device, strlen(device)) == 0) { fprintf(fileout, "%s\n", line); - } - else { + } else { fprintf(fileout, "%s", str); } } @@ -365,12 +356,10 @@ void recordPLPValue(const char *device, int value, bool isReplace) if (remove(logFilePath) == 0) { rename(tempFilePath, logFilePath); - } - else { + } else { remove(tempFilePath); } - } - else { + } else { FILE *out = fopen(logFilePath, "a"); if (out == NULL) { perror("Error opening file"); From 1f9aa256df4d7e0e8f3f2d0e6d4d593875f9f3c9 Mon Sep 17 00:00:00 2001 From: JerryWang Date: Fri, 1 Nov 2024 16:53:10 +0800 Subject: [PATCH 7/9] Correct coding style and naming rules Signed-off-by: WBJisMyName --- plugins/transcend/transcend-nvme.c | 614 ++++++++++++++--------------- plugins/transcend/transcend-nvme.h | 12 +- 2 files changed, 306 insertions(+), 320 deletions(-) diff --git a/plugins/transcend/transcend-nvme.c b/plugins/transcend/transcend-nvme.c index 25d1209aaa..2037611bd9 100644 --- a/plugins/transcend/transcend-nvme.c +++ b/plugins/transcend/transcend-nvme.c @@ -5,19 +5,18 @@ #include #include #include +#include +#include #include "nvme.h" #include "libnvme.h" #include "plugin.h" -#include -#include +#include "transcend-nvme.h" #define CREATE_CMD -#define PLPRecordPath "PLPRec.txt" -#define PLPDataExpiredTime 20 - -#include "transcend-nvme.h" +#define PLP_RECORD_PATH "PLPRec.txt" +#define PLP_DATA_EXPIRED_TIME 20 static const __u32 OP_BAD_BLOCK = 0xc2; static const __u32 DW10_BAD_BLOCK = 0x400; @@ -30,342 +29,327 @@ static const __u32 DW12_HEALTH = 0xb3; static const __u32 OP_ID = 0x06; static const __u32 DW10_ID = 0x01; -static const int iDis = 20; -static const double fullValue = 170; +static const int i_dis = 20; +static const double full_value = 170; -enum PLPErrorCode { - PLP_ERROR_NO_MATCH = -1, - PLP_ERROR_DATA_EXPIRED = -2 +enum plp_error_code { + PLP_ERROR_NO_MATCH = -1, + PLP_ERROR_DATA_EXPIRED = -2 }; const char *string_list[] = { - "UTE210T", - "MTE712P", - "MTE560P", - "MTE662P", - "MTE662P-I", - "MTS970P", - "MTS952P", - "MTS952P-I", - "MTS570P", - "MTS400P", - "SSD910T", - "SSD470P", - "SSD470P-I", - "SSD452P", - "SSD452P-I", - "SSD420P", - "MSA470P", - "MSA452P"}; -const int list_size = ARRAY_SIZE(string_list) / sizeof(string_list[0]); - -static int getPLPHealth(int argc, char **argv, struct command *cmd, struct plugin *plugin); -static int readUsefulPLPValue(const char *device); -static void recordPLPValue(const char *device, int value, bool isReplace); - -static int getHealthValue(int argc, char **argv, struct command *cmd, struct plugin *plugin) + "UTE210T", "MTE712P", "MTE560P", "MTE662P", "MTE662P-I", "MTS970P", + "MTS952P", "MTS952P-I", "MTS570P", "MTS400P", "SSD910T", "SSD470P", + "SSD470P-I", "SSD452P", "SSD452P-I", "SSD420P", "MSA470P", "MSA452P" +}; + +const int list_size = ARRAY_SIZE(string_list); + +static int get_plp_health(int argc, char **argv, struct command *cmd, struct plugin *plugin); +static int read_useful_plp_value(const char *device); +static void record_plp_value(const char *device, int value, bool is_replace); + +static int get_health_value(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - struct nvme_smart_log smart_log; - char *desc = "Get nvme health percentage."; - int percent_used = 0; - int healthvalue = 0; - struct nvme_dev *dev; - int result; - - OPT_ARGS(opts) = { - OPT_END() - }; - - result = parse_and_open(&dev, argc, argv, desc, opts); - if (result) { - printf("\nDevice not found\n"); - return PLP_ERROR_NO_MATCH; - } - result = nvme_get_log_smart(dev_fd(dev), 0xffffffff, false, &smart_log); - if (!result) { - printf("Transcend NVME heath value: "); - percent_used = smart_log.percent_used; - - if (percent_used > 100 || percent_used < 0) { - printf("0%%\n"); - } else { - healthvalue = 100 - percent_used; - printf("%d%%\n", healthvalue); - } - } - dev_close(dev); - return result; + struct nvme_smart_log smart_log; + char *desc = "Get nvme health percentage."; + int percent_used = 0; + int health_value = 0; + struct nvme_dev *dev; + int result; + + OPT_ARGS(opts) = { + OPT_END() + }; + + result = parse_and_open(&dev, argc, argv, desc, opts); + if (result) { + printf("\nDevice not found\n"); + return PLP_ERROR_NO_MATCH; + } + result = nvme_get_log_smart(dev_fd(dev), 0xffffffff, false, &smart_log); + if (!result) { + printf("Transcend NVME health value: "); + percent_used = smart_log.percent_used; + + if (percent_used > 100 || percent_used < 0) { + printf("0%%\n"); + } else { + health_value = 100 - percent_used; + printf("%d%%\n", health_value); + } + } + dev_close(dev); + return result; } -static int getBadblock(int argc, char **argv, struct command *cmd, struct plugin *plugin) +static int get_bad_block(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - - char *desc = "Get nvme bad block number."; - struct nvme_dev *dev; - int result; - - OPT_ARGS(opts) = { - OPT_END() - }; - - result = parse_and_open(&dev, argc, argv, desc, opts); - if (result) { - printf("\nDevice not found\n"); - return -1; - } - unsigned char data[1] = {0}; - struct nvme_passthru_cmd nvmecmd; - - memset(&nvmecmd, 0, sizeof(nvmecmd)); - nvmecmd.opcode = OP_BAD_BLOCK; - nvmecmd.cdw10 = DW10_BAD_BLOCK; - nvmecmd.cdw12 = DW12_BAD_BLOCK; - nvmecmd.addr = (__u64)(uintptr_t)data; - nvmecmd.data_len = 0x1; - result = nvme_submit_admin_passthru(dev_fd(dev), &nvmecmd, NULL); - if (!result) { - int badblock = data[0]; - printf("Transcend NVME badblock count: %d\n", badblock); - } - dev_close(dev); - return result; + char *desc = "Get nvme bad block number."; + struct nvme_dev *dev; + int result; + + OPT_ARGS(opts) = { + OPT_END() + }; + + result = parse_and_open(&dev, argc, argv, desc, opts); + if (result) { + printf("\nDevice not found\n"); + return -1; + } + unsigned char data[1] = {0}; + struct nvme_passthru_cmd nvme_cmd; + + memset(&nvme_cmd, 0, sizeof(nvme_cmd)); + nvme_cmd.opcode = OP_BAD_BLOCK; + nvme_cmd.cdw10 = DW10_BAD_BLOCK; + nvme_cmd.cdw12 = DW12_BAD_BLOCK; + nvme_cmd.addr = (__u64)(uintptr_t)data; + nvme_cmd.data_len = 0x1; + result = nvme_submit_admin_passthru(dev_fd(dev), &nvme_cmd, NULL); + if (!result) { + int bad_block = data[0]; + printf("Transcend NVME badblock count: %d\n", bad_block); + } + dev_close(dev); + return result; } -const char *format_char_array(char *str, int strsize, unsigned char *chr, int chrsize) +const char *format_char_array(char *str, int str_size, unsigned char *chr, int chr_size) { - int b = 0; - int n = 0; - int i; + int b = 0; + int n = 0; + int i; - while (b < chrsize && chr[b] == ' ') - b++; + while (b < chr_size && chr[b] == ' ') + b++; - while (b + n < chrsize && chr[b + n]) - n++; + while (b + n < chr_size && chr[b + n]) + n++; - while (n > 0 && chr[b + n - 1] == ' ') - n--; + while (n > 0 && chr[b + n - 1] == ' ') + n--; - if (n >= strsize) - n = strsize - 1; + if (n >= str_size) + n = str_size - 1; - for (i = 0; i < n; i++) { - char c = chr[b + i]; - str[i] = (' ' <= c && c <= '~' ? c : '?'); - } + for (i = 0; i < n; i++) { + char c = chr[b + i]; + str[i] = (' ' <= c && c <= '~' ? c : '?'); + } - str[n] = 0; - return str; + str[n] = 0; + return str; } int contains_string(const char *str) { - for (int i = 0; i < list_size; i++) - { - if (strstr(str, string_list[i]) != NULL) - { - return 1; - } - } - return 0; + int i; + + for (i = 0; i < list_size; i++) { + if (strstr(str, string_list[i]) != NULL) { + return 1; + } + } + return 0; } -static int getPLPHealth(int argc, char **argv, struct command *cmd, struct plugin *plugin) +static int get_plp_health(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - char *desc = "Get nvme PLP Health."; - struct nvme_dev *dev; - int result; - int txtPLPHealth = -1; - int plpHealth_percentage = -1; - OPT_ARGS(opts) = { - OPT_END() - }; - - result = parse_and_open(&dev, argc, argv, desc, opts); - if (result) { - printf("\nDevice not found\n"); - return -1; - } - - unsigned char dataID[4096]; - struct nvme_passthru_cmd nvmecmdID; - - memset(&nvmecmdID, 0, sizeof(nvmecmdID)); - nvmecmdID.opcode = OP_ID; - nvmecmdID.cdw10 = DW10_ID; - nvmecmdID.addr = (__u64)(uintptr_t)dataID; - nvmecmdID.data_len = 4096; - result = nvme_submit_admin_passthru(dev_fd(dev), &nvmecmdID, NULL); - if (result) { - printf("\nThis device is not support.\n"); - return -1; - } else { - char modelName[40]; - const char *model_str_byte; - model_str_byte = format_char_array((char *)modelName, sizeof(modelName), dataID, sizeof(dataID)); - if (!contains_string(model_str_byte)) { - printf("\nThis device is not support.\n"); - return -1; - } - } - - txtPLPHealth = readUsefulPLPValue(dev->name); - if (txtPLPHealth >= 0) { - plpHealth_percentage = txtPLPHealth; - printf("Capacitor health for PLP: %d%%\n", plpHealth_percentage); - } else { - unsigned char data[512]; - struct nvme_passthru_cmd nvmecmd; - - memset(&nvmecmd, 0, sizeof(nvmecmd)); - nvmecmd.opcode = OP_HEALTH; - nvmecmd.cdw10 = DW10_HEALTH; - nvmecmd.cdw12 = DW12_HEALTH; - nvmecmd.addr = (__u64)(uintptr_t)data; - nvmecmd.data_len = 512; - result = nvme_submit_admin_passthru(dev_fd(dev), &nvmecmd, NULL); - if (result) { - printf("\nGet PLP Health Fail.\n"); - return PLP_ERROR_NO_MATCH; - } else { - int tDis = (int)(data[4 + 3] << 24) + (int)(data[4 + 2] << 16) + (int)(data[4 + 1] << 8) + (int)(data[4]); - int vDis1 = (int)(data[0]); - int vDis2 = (int)(data[1]); - if (vDis1 != 0 || vDis2 != 0) { - int normalHealth = 0; - - if (vDis1 - vDis2 != 0) { - normalHealth = (iDis * tDis) / (vDis1 - vDis2); - } else { - normalHealth = 0; - } - if (normalHealth >= 0) { - if (fullValue - normalHealth >= 0) { - plpHealth_percentage = (normalHealth / fullValue) * 100; - } else { - plpHealth_percentage = 100; - } - } else { - plpHealth_percentage = 0; - } - printf("Capacitor health for PLP: %d%%\n", plpHealth_percentage); - } - } - } - if (plpHealth_percentage >= 0) { - if (txtPLPHealth == PLP_ERROR_DATA_EXPIRED) { - recordPLPValue(dev->name, plpHealth_percentage, true); - } - else { - recordPLPValue(dev->name, plpHealth_percentage, false); - } - } - dev_close(dev); - return result; + char *desc = "Get nvme PLP Health."; + struct nvme_dev *dev; + int result; + int txt_plp_health = -1; + int plp_health_percentage = -1; + OPT_ARGS(opts) = { + OPT_END() + }; + + result = parse_and_open(&dev, argc, argv, desc, opts); + if (result) { + printf("\nDevice not found\n"); + return -1; + } + + unsigned char data_id[4096]; + struct nvme_passthru_cmd nvme_cmd_id; + + memset(&nvme_cmd_id, 0, sizeof(nvme_cmd_id)); + nvme_cmd_id.opcode = OP_ID; + nvme_cmd_id.cdw10 = DW10_ID; + nvme_cmd_id.addr = (__u64)(uintptr_t)data_id; + nvme_cmd_id.data_len = 4096; + result = nvme_submit_admin_passthru(dev_fd(dev), &nvme_cmd_id, NULL); + if (result) { + printf("\nThis device is not supported.\n"); + dev_close(dev); + return -1; + } + char model_name[40]; + const char *model_str_byte; + model_str_byte = format_char_array((char *)model_name, sizeof(model_name), data_id, sizeof(data_id)); + if (!contains_string(model_str_byte)) { + printf("\nThis device is not supported.\n"); + dev_close(dev); + return -1; + } + + txt_plp_health = read_useful_plp_value(dev->name); + if (txt_plp_health >= 0) { + plp_health_percentage = txt_plp_health; + printf("Capacitor health for PLP: %d%%\n", plp_health_percentage); + } else { + unsigned char data[512]; + struct nvme_passthru_cmd nvme_cmd; + + memset(&nvme_cmd, 0, sizeof(nvme_cmd)); + nvme_cmd.opcode = OP_HEALTH; + nvme_cmd.cdw10 = DW10_HEALTH; + nvme_cmd.cdw12 = DW12_HEALTH; + nvme_cmd.addr = (__u64)(uintptr_t)data; + nvme_cmd.data_len = 512; + result = nvme_submit_admin_passthru(dev_fd(dev), &nvme_cmd, NULL); + if (result) { + printf("\nGet PLP Health Fail.\n"); + dev_close(dev); + return PLP_ERROR_NO_MATCH; + } else { + int t_dis = (int)(data[4 + 3] << 24) + (int)(data[4 + 2] << 16) + (int)(data[4 + 1] << 8) + (int)(data[4]); + int v_dis1 = (int)(data[0]); + int v_dis2 = (int)(data[1]); + if (v_dis1 != 0 || v_dis2 != 0) { + int normal_health = 0; + + if (v_dis1 - v_dis2 != 0) { + normal_health = (i_dis * t_dis) / (v_dis1 - v_dis2); + } else { + normal_health = 0; + } + if (normal_health >= 0) { + if (full_value - normal_health >= 0) { + plp_health_percentage = (normal_health / full_value) * 100; + } else { + plp_health_percentage = 100; + } + } else { + plp_health_percentage = 0; + } + printf("Capacitor health for PLP: %d%%\n", plp_health_percentage); + } + } + } + if (plp_health_percentage >= 0) { + if (txt_plp_health == PLP_ERROR_DATA_EXPIRED) { + record_plp_value(dev->name, plp_health_percentage, true); + } else { + record_plp_value(dev->name, plp_health_percentage, false); + } + } + dev_close(dev); + return result; } -int readUsefulPLPValue(const char *device) +int read_useful_plp_value(const char *device) { - FILE *file; - char logFilePath[256]; - char str[256]; - char matchedStr[256] = ""; - int ret = -1; - - snprintf(logFilePath, sizeof(logFilePath), "%s", PLPRecordPath); - file = fopen(logFilePath, "r"); - if (!file) { - return PLP_ERROR_NO_MATCH; - } - - while (fgets(str, sizeof(str), file)) - { - if (strncmp(str, device, strlen(device)) == 0) { - strcpy(matchedStr, str); - break; - } - } - - fclose(file); - - if (matchedStr[0] == '\0') { - return PLP_ERROR_NO_MATCH; - } - - char *token; - token = strtok(matchedStr, "#"); - token = strtok(NULL, "#"); - struct tm tm; - memset(&tm, 0, sizeof(tm)); - strptime(token, "%a %b %d %H:%M:%S %Y", &tm); - time_t t = mktime(&tm); - - time_t t_current = time(NULL); - int timeDiff = difftime(t_current, t); - - if (timeDiff <= PLPDataExpiredTime) { - token = strtok(NULL, "#"); - ret = atoi(token); - return ret; - } else { - return PLP_ERROR_DATA_EXPIRED; - } + FILE *file; + char log_file_path[256]; + char str[256]; + char matched_str[256] = ""; + int ret = -1; + + snprintf(log_file_path, sizeof(log_file_path), "%s", PLP_RECORD_PATH); + file = fopen(log_file_path, "r"); + if (!file) { + return PLP_ERROR_NO_MATCH; + } + + while (fgets(str, sizeof(str), file)) { + if (strncmp(str, device, strlen(device)) == 0) { + strcpy(matched_str, str); + break; + } + } + + fclose(file); + + if (matched_str[0] == '\0') { + return PLP_ERROR_NO_MATCH; + } + + char *token; + token = strtok(matched_str, "#"); + token = strtok(NULL, "#"); + struct tm tm; + memset(&tm, 0, sizeof(tm)); + strptime(token, "%a %b %d %H:%M:%S %Y", &tm); + time_t t = mktime(&tm); + + time_t t_current = time(NULL); + int time_diff = difftime(t_current, t); + + if (time_diff <= PLP_DATA_EXPIRED_TIME) { + token = strtok(NULL, "#"); + ret = atoi(token); + return ret; + } else { + return PLP_ERROR_DATA_EXPIRED; + } } -void recordPLPValue(const char *device, int value, bool isReplace) +void record_plp_value(const char *device, int value, bool is_replace) { - char logFilePath[256]; - strncpy(logFilePath, PLPRecordPath, sizeof(logFilePath) - 1); - logFilePath[sizeof(logFilePath) - 1] = '\0'; - char tempFilePath[] = "temp.txt"; - - time_t ct = time(0); - char *timeStr = ctime(&ct); - if (timeStr == NULL) { - perror("Error getting current time"); - return; - } - timeStr[strcspn(timeStr, "\n")] = '\0'; - - char line[256]; - sprintf(line, "%s#%s#%d", device, timeStr, value); - - if (isReplace) { - FILE *filein = fopen(logFilePath, "r"); - FILE *fileout = fopen(tempFilePath, "w"); - if (filein == NULL || fileout == NULL) { - perror("Error opening file"); - if (filein != NULL) - fclose(filein); - if (fileout != NULL) - fclose(fileout); - return; - } - - char str[256]; - while (fgets(str, sizeof(str), filein)) - { - if (strncmp(str, device, strlen(device)) == 0) { - fprintf(fileout, "%s\n", line); - } else { - fprintf(fileout, "%s", str); - } - } - fclose(filein); - fclose(fileout); - - if (remove(logFilePath) == 0) { - rename(tempFilePath, logFilePath); - } else { - remove(tempFilePath); - } - } else { - FILE *out = fopen(logFilePath, "a"); - if (out == NULL) { - perror("Error opening file"); - return; - } - fprintf(out, "%s\n", line); - fclose(out); - } -} + char log_file_path[256]; + strncpy(log_file_path, PLP_RECORD_PATH, sizeof(log_file_path) - 1); + log_file_path[sizeof(log_file_path) - 1] = '\0'; + char temp_file_path[] = "temp.txt"; + + time_t ct = time(0); + char *time_str = ctime(&ct); + if (time_str == NULL) { + perror("Error getting current time"); + return; + } + time_str[strcspn(time_str, "\n")] = '\0'; + + char line[256]; + snprintf(line, sizeof(line), "%s#%s#%d", device, time_str, value); + + if (is_replace) { + FILE *file_in = fopen(log_file_path, "r"); + FILE *file_out = fopen(temp_file_path, "w"); + if (file_in == NULL || file_out == NULL) { + perror("Error opening file"); + if (file_in != NULL) + fclose(file_in); + if (file_out != NULL) + fclose(file_out); + return; + } + + char str[256]; + while (fgets(str, sizeof(str), file_in)) { + if (strncmp(str, device, strlen(device)) == 0) { + fprintf(file_out, "%s\n", line); + } else { + fprintf(file_out, "%s", str); + } + } + fclose(file_in); + fclose(file_out); + + if (remove(log_file_path) == 0) { + rename(temp_file_path, log_file_path); + } else { + remove(temp_file_path); + } + } else { + FILE *out = fopen(log_file_path, "a"); + if (out == NULL) { + perror("Error opening file"); + return; + } + fprintf(out, "%s\n", line); + fclose(out); + } +} \ No newline at end of file diff --git a/plugins/transcend/transcend-nvme.h b/plugins/transcend/transcend-nvme.h index 289562f0fa..021bddb1e4 100644 --- a/plugins/transcend/transcend-nvme.h +++ b/plugins/transcend/transcend-nvme.h @@ -4,18 +4,20 @@ #if !defined(TRANSCEND_NVME) || defined(CMD_HEADER_MULTI_READ) #define TRANSCEND_NVME + #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + #include "cmd.h" PLUGIN(NAME("transcend", "Transcend vendor specific extensions", NVME_VERSION), COMMAND_LIST( - ENTRY("healthvalue", "NVME health percentage", getHealthValue) - ENTRY("badblock", "Get NVME bad block number", getBadblock) - ENTRY("plphealthvalue", "Get NVME PLP Health.", getPLPHealth) + ENTRY("healthvalue", "NVME health percentage", get_health_value) + ENTRY("badblock", "Get NVME bad block number", get_bad_block) + ENTRY("plphealthvalue", "Get NVME PLP Health.", get_plp_health) ) ); -#endif +#endif /* TRANSCEND_NVME */ -#include "define_cmd.h" +#include "define_cmd.h" \ No newline at end of file From 69e6c7662573df41fdccb25c080a93cfe168c487 Mon Sep 17 00:00:00 2001 From: JerryWang Date: Mon, 4 Nov 2024 11:16:47 +0800 Subject: [PATCH 8/9] Add static to function and make minor adjustments. Signed-off-by: WBJisMyName --- plugins/transcend/transcend-nvme.c | 15 ++++++++------- plugins/transcend/transcend-nvme.h | 4 +--- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/plugins/transcend/transcend-nvme.c b/plugins/transcend/transcend-nvme.c index 2037611bd9..b560d62a46 100644 --- a/plugins/transcend/transcend-nvme.c +++ b/plugins/transcend/transcend-nvme.c @@ -12,6 +12,7 @@ #include "libnvme.h" #include "plugin.h" #include "transcend-nvme.h" +#include "common.h" #define CREATE_CMD @@ -33,17 +34,17 @@ static const int i_dis = 20; static const double full_value = 170; enum plp_error_code { - PLP_ERROR_NO_MATCH = -1, - PLP_ERROR_DATA_EXPIRED = -2 + PLP_ERROR_NO_MATCH = -1, + PLP_ERROR_DATA_EXPIRED = -2 }; -const char *string_list[] = { +static const char *string_list[] = { "UTE210T", "MTE712P", "MTE560P", "MTE662P", "MTE662P-I", "MTS970P", "MTS952P", "MTS952P-I", "MTS570P", "MTS400P", "SSD910T", "SSD470P", "SSD470P-I", "SSD452P", "SSD452P-I", "SSD420P", "MSA470P", "MSA452P" }; -const int list_size = ARRAY_SIZE(string_list); +static const int list_size = ARRAY_SIZE(string_list); static int get_plp_health(int argc, char **argv, struct command *cmd, struct plugin *plugin); static int read_useful_plp_value(const char *device); @@ -116,7 +117,7 @@ static int get_bad_block(int argc, char **argv, struct command *cmd, struct plug return result; } -const char *format_char_array(char *str, int str_size, unsigned char *chr, int chr_size) +static const char *format_char_array(char *str, int str_size, unsigned char *chr, int chr_size) { int b = 0; int n = 0; @@ -250,7 +251,7 @@ static int get_plp_health(int argc, char **argv, struct command *cmd, struct plu return result; } -int read_useful_plp_value(const char *device) +static int read_useful_plp_value(const char *device) { FILE *file; char log_file_path[256]; @@ -297,7 +298,7 @@ int read_useful_plp_value(const char *device) } } -void record_plp_value(const char *device, int value, bool is_replace) +static void record_plp_value(const char *device, int value, bool is_replace) { char log_file_path[256]; strncpy(log_file_path, PLP_RECORD_PATH, sizeof(log_file_path) - 1); diff --git a/plugins/transcend/transcend-nvme.h b/plugins/transcend/transcend-nvme.h index 021bddb1e4..665edb8ff8 100644 --- a/plugins/transcend/transcend-nvme.h +++ b/plugins/transcend/transcend-nvme.h @@ -5,8 +5,6 @@ #if !defined(TRANSCEND_NVME) || defined(CMD_HEADER_MULTI_READ) #define TRANSCEND_NVME -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) - #include "cmd.h" @@ -20,4 +18,4 @@ PLUGIN(NAME("transcend", "Transcend vendor specific extensions", NVME_VERSION), #endif /* TRANSCEND_NVME */ -#include "define_cmd.h" \ No newline at end of file +#include "define_cmd.h" From a2c64f7beaae81c49c734d24d7b61c2c7cc1d61f Mon Sep 17 00:00:00 2001 From: JerryWang Date: Thu, 7 Nov 2024 09:42:53 +0800 Subject: [PATCH 9/9] 1. Fixed indentation errors. (Use 8 characters tab) 2. Change function to Static function Signed-off-by: WBJisMyName --- plugins/transcend/transcend-nvme.c | 630 +++++++++++++++-------------- plugins/transcend/transcend-nvme.h | 12 +- 2 files changed, 342 insertions(+), 300 deletions(-) diff --git a/plugins/transcend/transcend-nvme.c b/plugins/transcend/transcend-nvme.c index b560d62a46..165d4fded5 100644 --- a/plugins/transcend/transcend-nvme.c +++ b/plugins/transcend/transcend-nvme.c @@ -16,341 +16,385 @@ #define CREATE_CMD -#define PLP_RECORD_PATH "PLPRec.txt" -#define PLP_DATA_EXPIRED_TIME 20 +#define PLP_RECORD_PATH "PLPRec.txt" +#define PLP_DATA_EXPIRED_TIME 20 -static const __u32 OP_BAD_BLOCK = 0xc2; + +/* Bad block command parameters */ +static const __u32 OP_BAD_BLOCK = 0xc2; static const __u32 DW10_BAD_BLOCK = 0x400; static const __u32 DW12_BAD_BLOCK = 0x5a; -static const __u32 OP_HEALTH = 0xc2; -static const __u32 DW10_HEALTH = 0x01; -static const __u32 DW12_HEALTH = 0xb3; +/* Health command parameters */ +static const __u32 OP_HEALTH = 0xc2; +static const __u32 DW10_HEALTH = 0x01; +static const __u32 DW12_HEALTH = 0xb3; -static const __u32 OP_ID = 0x06; -static const __u32 DW10_ID = 0x01; +/* ID command parameters */ +static const __u32 OP_ID = 0x06; +static const __u32 DW10_ID = 0x01; -static const int i_dis = 20; -static const double full_value = 170; +/* PLP constants */ +static const int i_dis = 20; +static const double full_value = 170; enum plp_error_code { - PLP_ERROR_NO_MATCH = -1, - PLP_ERROR_DATA_EXPIRED = -2 + PLP_ERROR_NO_MATCH = -1, + PLP_ERROR_DATA_EXPIRED = -2, }; static const char *string_list[] = { - "UTE210T", "MTE712P", "MTE560P", "MTE662P", "MTE662P-I", "MTS970P", - "MTS952P", "MTS952P-I", "MTS570P", "MTS400P", "SSD910T", "SSD470P", - "SSD470P-I", "SSD452P", "SSD452P-I", "SSD420P", "MSA470P", "MSA452P" + "UTE210T", + "MTE712P", + "MTE560P", + "MTE662P", + "MTE662P-I", + "MTS970P", + "MTS952P", + "MTS952P-I", + "MTS570P", + "MTS400P", + "SSD910T", + "SSD470P", + "SSD470P-I", + "SSD452P", + "SSD452P-I", + "SSD420P", + "MSA470P", + "MSA452P", }; static const int list_size = ARRAY_SIZE(string_list); -static int get_plp_health(int argc, char **argv, struct command *cmd, struct plugin *plugin); +static int get_plp_health(int argc, char **argv, struct command *cmd, + struct plugin *plugin); static int read_useful_plp_value(const char *device); static void record_plp_value(const char *device, int value, bool is_replace); -static int get_health_value(int argc, char **argv, struct command *cmd, struct plugin *plugin) +static int get_health_value(int argc, char **argv, struct command *cmd, + struct plugin *plugin) { - struct nvme_smart_log smart_log; - char *desc = "Get nvme health percentage."; - int percent_used = 0; - int health_value = 0; - struct nvme_dev *dev; - int result; - - OPT_ARGS(opts) = { - OPT_END() - }; - - result = parse_and_open(&dev, argc, argv, desc, opts); - if (result) { - printf("\nDevice not found\n"); - return PLP_ERROR_NO_MATCH; - } - result = nvme_get_log_smart(dev_fd(dev), 0xffffffff, false, &smart_log); - if (!result) { - printf("Transcend NVME health value: "); - percent_used = smart_log.percent_used; - - if (percent_used > 100 || percent_used < 0) { - printf("0%%\n"); - } else { - health_value = 100 - percent_used; - printf("%d%%\n", health_value); - } - } - dev_close(dev); - return result; + struct nvme_smart_log smart_log; + struct nvme_dev *dev; + char *desc = "Get nvme health percentage."; + int percent_used = 0; + int health_value = 0; + int ret; + + OPT_ARGS(opts) = { + OPT_END() + }; + + ret = parse_and_open(&dev, argc, argv, desc, opts); + if (ret) { + pr_err("Device not found\n"); + return -ENODEV; + } + + ret = nvme_get_log_smart(dev_fd(dev), 0xffffffff, false, &smart_log); + if (!ret) { + pr_info("Transcend NVME health value: "); + percent_used = smart_log.percent_used; + + if (percent_used > 100 || percent_used < 0) { + pr_info("0%%\n"); + } else { + health_value = 100 - percent_used; + pr_info("%d%%\n", health_value); + } + } + + dev_close(dev); + return ret; } -static int get_bad_block(int argc, char **argv, struct command *cmd, struct plugin *plugin) +static int get_bad_block(int argc, char **argv, struct command *cmd, + struct plugin *plugin) { - char *desc = "Get nvme bad block number."; - struct nvme_dev *dev; - int result; - - OPT_ARGS(opts) = { - OPT_END() - }; - - result = parse_and_open(&dev, argc, argv, desc, opts); - if (result) { - printf("\nDevice not found\n"); - return -1; - } - unsigned char data[1] = {0}; - struct nvme_passthru_cmd nvme_cmd; - - memset(&nvme_cmd, 0, sizeof(nvme_cmd)); - nvme_cmd.opcode = OP_BAD_BLOCK; - nvme_cmd.cdw10 = DW10_BAD_BLOCK; - nvme_cmd.cdw12 = DW12_BAD_BLOCK; - nvme_cmd.addr = (__u64)(uintptr_t)data; - nvme_cmd.data_len = 0x1; - result = nvme_submit_admin_passthru(dev_fd(dev), &nvme_cmd, NULL); - if (!result) { - int bad_block = data[0]; - printf("Transcend NVME badblock count: %d\n", bad_block); - } - dev_close(dev); - return result; + struct nvme_passthru_cmd nvme_cmd = { 0 }; + struct nvme_dev *dev; + char *desc = "Get nvme bad block number."; + unsigned char data[1] = { 0 }; + int ret; + + OPT_ARGS(opts) = { + OPT_END() + }; + + ret = parse_and_open(&dev, argc, argv, desc, opts); + if (ret) { + pr_err("Device not found\n"); + return -ENODEV; + } + + nvme_cmd.opcode = OP_BAD_BLOCK; + nvme_cmd.cdw10 = DW10_BAD_BLOCK; + nvme_cmd.cdw12 = DW12_BAD_BLOCK; + nvme_cmd.addr = (__u64)(uintptr_t)data; + nvme_cmd.data_len = 0x1; + + ret = nvme_submit_admin_passthru(dev_fd(dev), &nvme_cmd, NULL); + if (!ret) + pr_info("Transcend NVME badblock count: %d\n", data[0]); + + dev_close(dev); + return ret; } -static const char *format_char_array(char *str, int str_size, unsigned char *chr, int chr_size) +static const char *format_char_array(char *str, int str_size, + unsigned char *chr, int chr_size) { - int b = 0; - int n = 0; - int i; + int b = 0; + int n = 0; + int i; - while (b < chr_size && chr[b] == ' ') - b++; + while (b < chr_size && chr[b] == ' ') + b++; - while (b + n < chr_size && chr[b + n]) - n++; + while (b + n < chr_size && chr[b + n]) + n++; - while (n > 0 && chr[b + n - 1] == ' ') - n--; + while (n > 0 && chr[b + n - 1] == ' ') + n--; - if (n >= str_size) - n = str_size - 1; + if (n >= str_size) + n = str_size - 1; - for (i = 0; i < n; i++) { - char c = chr[b + i]; - str[i] = (' ' <= c && c <= '~' ? c : '?'); - } + for (i = 0; i < n; i++) { + char c = chr[b + i]; + str[i] = (' ' <= c && c <= '~' ? c : '?'); + } - str[n] = 0; - return str; + str[n] = 0; + return str; } -int contains_string(const char *str) +static int contains_string(const char *str) { - int i; - - for (i = 0; i < list_size; i++) { - if (strstr(str, string_list[i]) != NULL) { - return 1; - } - } - return 0; + int i; + + for (i = 0; i < list_size; i++) { + if (strstr(str, string_list[i])) + return 1; + } + + return 0; } -static int get_plp_health(int argc, char **argv, struct command *cmd, struct plugin *plugin) +static int get_plp_health(int argc, char **argv, struct command *cmd, + struct plugin *plugin) { - char *desc = "Get nvme PLP Health."; - struct nvme_dev *dev; - int result; - int txt_plp_health = -1; - int plp_health_percentage = -1; - OPT_ARGS(opts) = { - OPT_END() - }; - - result = parse_and_open(&dev, argc, argv, desc, opts); - if (result) { - printf("\nDevice not found\n"); - return -1; - } - - unsigned char data_id[4096]; - struct nvme_passthru_cmd nvme_cmd_id; - - memset(&nvme_cmd_id, 0, sizeof(nvme_cmd_id)); - nvme_cmd_id.opcode = OP_ID; - nvme_cmd_id.cdw10 = DW10_ID; - nvme_cmd_id.addr = (__u64)(uintptr_t)data_id; - nvme_cmd_id.data_len = 4096; - result = nvme_submit_admin_passthru(dev_fd(dev), &nvme_cmd_id, NULL); - if (result) { - printf("\nThis device is not supported.\n"); - dev_close(dev); - return -1; - } - char model_name[40]; - const char *model_str_byte; - model_str_byte = format_char_array((char *)model_name, sizeof(model_name), data_id, sizeof(data_id)); - if (!contains_string(model_str_byte)) { - printf("\nThis device is not supported.\n"); - dev_close(dev); - return -1; - } - - txt_plp_health = read_useful_plp_value(dev->name); - if (txt_plp_health >= 0) { - plp_health_percentage = txt_plp_health; - printf("Capacitor health for PLP: %d%%\n", plp_health_percentage); - } else { - unsigned char data[512]; - struct nvme_passthru_cmd nvme_cmd; - - memset(&nvme_cmd, 0, sizeof(nvme_cmd)); - nvme_cmd.opcode = OP_HEALTH; - nvme_cmd.cdw10 = DW10_HEALTH; - nvme_cmd.cdw12 = DW12_HEALTH; - nvme_cmd.addr = (__u64)(uintptr_t)data; - nvme_cmd.data_len = 512; - result = nvme_submit_admin_passthru(dev_fd(dev), &nvme_cmd, NULL); - if (result) { - printf("\nGet PLP Health Fail.\n"); - dev_close(dev); - return PLP_ERROR_NO_MATCH; - } else { - int t_dis = (int)(data[4 + 3] << 24) + (int)(data[4 + 2] << 16) + (int)(data[4 + 1] << 8) + (int)(data[4]); - int v_dis1 = (int)(data[0]); - int v_dis2 = (int)(data[1]); - if (v_dis1 != 0 || v_dis2 != 0) { - int normal_health = 0; - - if (v_dis1 - v_dis2 != 0) { - normal_health = (i_dis * t_dis) / (v_dis1 - v_dis2); - } else { - normal_health = 0; - } - if (normal_health >= 0) { - if (full_value - normal_health >= 0) { - plp_health_percentage = (normal_health / full_value) * 100; - } else { - plp_health_percentage = 100; - } - } else { - plp_health_percentage = 0; - } - printf("Capacitor health for PLP: %d%%\n", plp_health_percentage); - } - } - } - if (plp_health_percentage >= 0) { - if (txt_plp_health == PLP_ERROR_DATA_EXPIRED) { - record_plp_value(dev->name, plp_health_percentage, true); - } else { - record_plp_value(dev->name, plp_health_percentage, false); - } - } - dev_close(dev); - return result; + struct nvme_passthru_cmd nvme_cmd = { 0 }; + struct nvme_dev *dev; + char *desc = "Get nvme PLP Health."; + char model_name[40]; + unsigned char data_id[4096]; + unsigned char data[512]; + const char *model_str; + int txt_plp_health = -1; + int plp_health = -1; + int ret; + + OPT_ARGS(opts) = { + OPT_END() + }; + + ret = parse_and_open(&dev, argc, argv, desc, opts); + if (ret) { + pr_err("Device not found\n"); + return -ENODEV; + } + + /* Check if device is supported */ + memset(&nvme_cmd, 0, sizeof(nvme_cmd)); + nvme_cmd.opcode = OP_ID; + nvme_cmd.cdw10 = DW10_ID; + nvme_cmd.addr = (__u64)(uintptr_t)data_id; + nvme_cmd.data_len = 4096; + + ret = nvme_submit_admin_passthru(dev_fd(dev), &nvme_cmd, NULL); + if (ret) { + pr_err("Device is not supported\n"); + goto close_dev; + } + + model_str = format_char_array(model_name, sizeof(model_name), + data_id, sizeof(data_id)); + if (!contains_string(model_str)) { + pr_err("Device is not supported\n"); + ret = -EINVAL; + goto close_dev; + } + + /* Try reading from cache first */ + txt_plp_health = read_useful_plp_value(dev->name); + if (txt_plp_health >= 0) { + plp_health = txt_plp_health; + pr_info("Capacitor health for PLP: %d%%\n", plp_health); + goto record_value; + } + + /* Query device directly */ + memset(&nvme_cmd, 0, sizeof(nvme_cmd)); + nvme_cmd.opcode = OP_HEALTH; + nvme_cmd.cdw10 = DW10_HEALTH; + nvme_cmd.cdw12 = DW12_HEALTH; + nvme_cmd.addr = (__u64)(uintptr_t)data; + nvme_cmd.data_len = 512; + + ret = nvme_submit_admin_passthru(dev_fd(dev), &nvme_cmd, NULL); + if (ret) { + pr_err("Failed to get PLP Health\n"); + ret = -EIO; + goto close_dev; + } + + /* Calculate PLP health */ + { + int t_dis = (int)(data[4 + 3] << 24) + (int)(data[4 + 2] << 16) + + (int)(data[4 + 1] << 8) + (int)(data[4]); + int v_dis1 = (int)(data[0]); + int v_dis2 = (int)(data[1]); + int normal_health; + + if (v_dis1 == 0 && v_dis2 == 0) + goto close_dev; + + if (v_dis1 - v_dis2 != 0) + normal_health = (i_dis * t_dis) / (v_dis1 - v_dis2); + else + normal_health = 0; + + if (normal_health >= 0) { + if (full_value - normal_health >= 0) + plp_health = (normal_health / full_value) * 100; + else + plp_health = 100; + } else { + plp_health = 0; + } + + pr_info("Capacitor health for PLP: %d%%\n", plp_health); + } + +record_value: + if (plp_health >= 0) { + if (txt_plp_health == PLP_ERROR_DATA_EXPIRED) + record_plp_value(dev->name, plp_health, true); + else + record_plp_value(dev->name, plp_health, false); + } + +close_dev: + dev_close(dev); + return ret; } - static int read_useful_plp_value(const char *device) { - FILE *file; - char log_file_path[256]; - char str[256]; - char matched_str[256] = ""; - int ret = -1; - - snprintf(log_file_path, sizeof(log_file_path), "%s", PLP_RECORD_PATH); - file = fopen(log_file_path, "r"); - if (!file) { - return PLP_ERROR_NO_MATCH; - } - - while (fgets(str, sizeof(str), file)) { - if (strncmp(str, device, strlen(device)) == 0) { - strcpy(matched_str, str); - break; - } - } - - fclose(file); - - if (matched_str[0] == '\0') { - return PLP_ERROR_NO_MATCH; - } - - char *token; - token = strtok(matched_str, "#"); - token = strtok(NULL, "#"); - struct tm tm; - memset(&tm, 0, sizeof(tm)); - strptime(token, "%a %b %d %H:%M:%S %Y", &tm); - time_t t = mktime(&tm); - - time_t t_current = time(NULL); - int time_diff = difftime(t_current, t); - - if (time_diff <= PLP_DATA_EXPIRED_TIME) { - token = strtok(NULL, "#"); - ret = atoi(token); - return ret; - } else { - return PLP_ERROR_DATA_EXPIRED; - } + char log_file_path[256]; + char str[256]; + char matched_str[256] = ""; + FILE *file; + char *token; + struct tm tm = { 0 }; + time_t t, t_current; + int time_diff; + int ret = -1; + + snprintf(log_file_path, sizeof(log_file_path), "%s", PLP_RECORD_PATH); + file = fopen(log_file_path, "r"); + if (!file) + return PLP_ERROR_NO_MATCH; + + while (fgets(str, sizeof(str), file)) { + if (strncmp(str, device, strlen(device)) == 0) { + strcpy(matched_str, str); + break; + } + } + + fclose(file); + + if (matched_str[0] == '\0') + return PLP_ERROR_NO_MATCH; + + token = strtok(matched_str, "#"); + token = strtok(NULL, "#"); + + if (!strptime(token, "%a %b %d %H:%M:%S %Y", &tm)) + return PLP_ERROR_NO_MATCH; + + t = mktime(&tm); + t_current = time(NULL); + time_diff = difftime(t_current, t); + + if (time_diff > PLP_DATA_EXPIRED_TIME) + return PLP_ERROR_DATA_EXPIRED; + + token = strtok(NULL, "#"); + ret = atoi(token); + + return ret; } static void record_plp_value(const char *device, int value, bool is_replace) { - char log_file_path[256]; - strncpy(log_file_path, PLP_RECORD_PATH, sizeof(log_file_path) - 1); - log_file_path[sizeof(log_file_path) - 1] = '\0'; - char temp_file_path[] = "temp.txt"; - - time_t ct = time(0); - char *time_str = ctime(&ct); - if (time_str == NULL) { - perror("Error getting current time"); - return; - } - time_str[strcspn(time_str, "\n")] = '\0'; - - char line[256]; - snprintf(line, sizeof(line), "%s#%s#%d", device, time_str, value); - - if (is_replace) { - FILE *file_in = fopen(log_file_path, "r"); - FILE *file_out = fopen(temp_file_path, "w"); - if (file_in == NULL || file_out == NULL) { - perror("Error opening file"); - if (file_in != NULL) - fclose(file_in); - if (file_out != NULL) - fclose(file_out); - return; - } - - char str[256]; - while (fgets(str, sizeof(str), file_in)) { - if (strncmp(str, device, strlen(device)) == 0) { - fprintf(file_out, "%s\n", line); - } else { - fprintf(file_out, "%s", str); - } - } - fclose(file_in); - fclose(file_out); - - if (remove(log_file_path) == 0) { - rename(temp_file_path, log_file_path); - } else { - remove(temp_file_path); - } - } else { - FILE *out = fopen(log_file_path, "a"); - if (out == NULL) { - perror("Error opening file"); - return; - } - fprintf(out, "%s\n", line); - fclose(out); - } + char log_path[256]; + char tmp_path[] = "temp.txt"; + time_t cur_time; + char *time_str; + char line[256]; + FILE *fp_in, *fp_out; + + strncpy(log_path, PLP_RECORD_PATH, sizeof(log_path) - 1); + log_path[sizeof(log_path) - 1] = '\0'; + + cur_time = time(0); + time_str = ctime(&cur_time); + if (!time_str) { + perror("Failed to get current time"); + return; + } + time_str[strcspn(time_str, "\n")] = '\0'; + + snprintf(line, sizeof(line), "%s#%s#%d", device, time_str, value); + + if (!is_replace) { + fp_out = fopen(log_path, "a"); + if (!fp_out) { + perror("Failed to open log file"); + return; + } + fprintf(fp_out, "%s\n", line); + fclose(fp_out); + return; + } + + /* Handle replace case */ + fp_in = fopen(log_path, "r"); + fp_out = fopen(tmp_path, "w"); + if (!fp_in || !fp_out) { + perror("Failed to open files"); + if (fp_in) + fclose(fp_in); + if (fp_out) + fclose(fp_out); + return; + } + + while (fgets(line, sizeof(line), fp_in)) { + if (strncmp(line, device, strlen(device)) == 0) + fprintf(fp_out, "%s\n", line); + else + fprintf(fp_out, "%s", line); + } + + fclose(fp_in); + fclose(fp_out); + + if (remove(log_path) == 0) { + rename(tmp_path, log_path); + } else { + remove(tmp_path); + } } \ No newline at end of file diff --git a/plugins/transcend/transcend-nvme.h b/plugins/transcend/transcend-nvme.h index 665edb8ff8..04c18127c0 100644 --- a/plugins/transcend/transcend-nvme.h +++ b/plugins/transcend/transcend-nvme.h @@ -6,14 +6,12 @@ #define TRANSCEND_NVME #include "cmd.h" - - PLUGIN(NAME("transcend", "Transcend vendor specific extensions", NVME_VERSION), - COMMAND_LIST( - ENTRY("healthvalue", "NVME health percentage", get_health_value) - ENTRY("badblock", "Get NVME bad block number", get_bad_block) - ENTRY("plphealthvalue", "Get NVME PLP Health.", get_plp_health) - ) + COMMAND_LIST( + ENTRY("healthvalue", "NVME health percentage", get_health_value) + ENTRY("badblock", "Get NVME bad block number", get_bad_block) + ENTRY("plphealthvalue", "Get NVME PLP Health.", get_plp_health) + ) ); #endif /* TRANSCEND_NVME */